1 29 package org.jruby; 30 31 import java.security.MessageDigest ; 32 import java.security.NoSuchAlgorithmException ; 33 import java.security.NoSuchProviderException ; 34 35 import org.jruby.runtime.Block; 36 import org.jruby.runtime.CallbackFactory; 37 import org.jruby.runtime.ObjectAllocator; 38 import org.jruby.runtime.builtin.IRubyObject; 39 import org.jruby.util.ByteList; 40 41 44 public class RubyDigest { 45 private static String provider = null; 46 47 public static void createDigest(Ruby runtime) { 48 try { 49 Class c = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider"); 50 java.security.Security.insertProviderAt((java.security.Provider )c.newInstance(),2); 51 provider = "BC"; 52 } catch(Exception e) { 53 provider = null; 54 } 55 56 RubyModule mDigest = runtime.defineModule("Digest"); 57 RubyClass cDigestBase = mDigest.defineClassUnder("Base",runtime.getObject(), Base.BASE_ALLOCATOR); 58 59 CallbackFactory basecb = runtime.callbackFactory(Base.class); 60 61 cDigestBase.getMetaClass().defineFastMethod("digest",basecb.getFastSingletonMethod("s_digest",RubyKernel.IRUBY_OBJECT)); 62 cDigestBase.getMetaClass().defineFastMethod("hexdigest",basecb.getFastSingletonMethod("s_hexdigest",RubyKernel.IRUBY_OBJECT)); 63 64 cDigestBase.defineMethod("initialize",basecb.getOptMethod("initialize")); 65 cDigestBase.defineFastMethod("initialize_copy",basecb.getFastMethod("initialize_copy",RubyKernel.IRUBY_OBJECT)); 66 cDigestBase.defineFastMethod("update",basecb.getFastMethod("update",RubyKernel.IRUBY_OBJECT)); 67 cDigestBase.defineFastMethod("<<",basecb.getFastMethod("update",RubyKernel.IRUBY_OBJECT)); 68 cDigestBase.defineFastMethod("digest",basecb.getFastMethod("digest")); 69 cDigestBase.defineFastMethod("hexdigest",basecb.getFastMethod("hexdigest")); 70 cDigestBase.defineFastMethod("to_s",basecb.getFastMethod("hexdigest")); 71 cDigestBase.defineFastMethod("==",basecb.getFastMethod("eq",RubyKernel.IRUBY_OBJECT)); 72 } 73 74 public static void createDigestMD5(Ruby runtime) { 75 runtime.getLoadService().require("digest.so"); 76 RubyModule mDigest = runtime.getModule("Digest"); 77 RubyClass cDigestBase = mDigest.getClass("Base"); 78 RubyClass cDigest_MD5 = mDigest.defineClassUnder("MD5",cDigestBase,cDigestBase.getAllocator()); 79 cDigest_MD5.setClassVar("metadata",runtime.newString("MD5")); 80 } 81 82 public static void createDigestRMD160(Ruby runtime) { 83 runtime.getLoadService().require("digest.so"); 84 85 if(provider == null) { 86 throw runtime.newLoadError("RMD160 not supported without BouncyCastle"); 87 } 88 89 RubyModule mDigest = runtime.getModule("Digest"); 90 RubyClass cDigestBase = mDigest.getClass("Base"); 91 RubyClass cDigest_RMD160 = mDigest.defineClassUnder("RMD160",cDigestBase,cDigestBase.getAllocator()); 92 cDigest_RMD160.setClassVar("metadata",runtime.newString("RIPEMD160")); 93 } 94 95 public static void createDigestSHA1(Ruby runtime) { 96 runtime.getLoadService().require("digest.so"); 97 RubyModule mDigest = runtime.getModule("Digest"); 98 RubyClass cDigestBase = mDigest.getClass("Base"); 99 RubyClass cDigest_SHA1 = mDigest.defineClassUnder("SHA1",cDigestBase,cDigestBase.getAllocator()); 100 cDigest_SHA1.setClassVar("metadata",runtime.newString("SHA1")); 101 } 102 103 public static void createDigestSHA2(Ruby runtime) { 104 runtime.getLoadService().require("digest.so"); 105 106 try { 107 if(provider == null) { 108 MessageDigest.getInstance("SHA-256"); 109 } else { 110 MessageDigest.getInstance("SHA-256",provider); 111 } 112 } catch(NoSuchAlgorithmException e) { 113 throw runtime.newLoadError("SHA2 not supported"); 114 } catch(NoSuchProviderException e) { 115 throw runtime.newLoadError("SHA2 not supported"); 116 } 117 118 RubyModule mDigest = runtime.getModule("Digest"); 119 RubyClass cDigestBase = mDigest.getClass("Base"); 120 RubyClass cDigest_SHA2_256 = mDigest.defineClassUnder("SHA256",cDigestBase,cDigestBase.getAllocator()); 121 cDigest_SHA2_256.setClassVar("metadata",runtime.newString("SHA-256")); 122 RubyClass cDigest_SHA2_384 = mDigest.defineClassUnder("SHA384",cDigestBase,cDigestBase.getAllocator()); 123 cDigest_SHA2_384.setClassVar("metadata",runtime.newString("SHA-384")); 124 RubyClass cDigest_SHA2_512 = mDigest.defineClassUnder("SHA512",cDigestBase,cDigestBase.getAllocator()); 125 cDigest_SHA2_512.setClassVar("metadata",runtime.newString("SHA-512")); 126 } 127 128 public static class Base extends RubyObject { 129 protected static ObjectAllocator BASE_ALLOCATOR = new ObjectAllocator() { 130 public IRubyObject allocate(Ruby runtime, RubyClass klass) { 131 return new Base(runtime, klass); 132 } 133 }; 134 public static IRubyObject s_digest(IRubyObject recv, IRubyObject str) { 135 String name = ((RubyClass)recv).getClassVar("metadata").toString(); 136 try { 137 MessageDigest md = provider == null ? MessageDigest.getInstance(name) : MessageDigest.getInstance(name, provider); 138 return RubyString.newString(recv.getRuntime(), md.digest(str.convertToString().getBytes())); 139 } catch(NoSuchAlgorithmException e) { 140 throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")"); 141 } catch(NoSuchProviderException e) { 142 throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")"); 143 } 144 } 145 public static IRubyObject s_hexdigest(IRubyObject recv, IRubyObject str) { 146 String name = ((RubyClass)recv).getClassVar("metadata").toString(); 147 try { 148 MessageDigest md = provider == null ? MessageDigest.getInstance(name) : MessageDigest.getInstance(name, provider); 149 return RubyString.newString(recv.getRuntime(), ByteList.plain(toHex(md.digest(str.convertToString().getBytes())))); 150 } catch(NoSuchAlgorithmException e) { 151 throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")"); 152 } catch(NoSuchProviderException e) { 153 throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")"); 154 } 155 } 156 157 private MessageDigest algo; 158 private StringBuffer data; 159 160 public Base(Ruby runtime, RubyClass type) { 161 super(runtime,type); 162 data = new StringBuffer (); 163 164 if(type == runtime.getModule("Digest").getClass("Base")) { 165 throw runtime.newNotImplementedError("Digest::Base is an abstract class"); 166 } 167 if(!type.isClassVarDefined("metadata")) { 168 throw runtime.newNotImplementedError("the " + type + "() function is unimplemented on this machine"); 169 } 170 try { 171 setAlgorithm(type.getClassVar("metadata")); 172 } catch(NoSuchAlgorithmException e) { 173 throw runtime.newNotImplementedError("the " + type + "() function is unimplemented on this machine"); 174 } catch(NoSuchProviderException e) { 175 throw runtime.newNotImplementedError("the " + type + "() function is unimplemented on this machine"); 176 } 177 178 } 179 180 public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { 181 if(args.length > 0 && !args[0].isNil()) { 182 update(args[0]); 183 } 184 return this; 185 } 186 187 public IRubyObject initialize_copy(IRubyObject obj) { 188 if(this == obj) { 189 return this; 190 } 191 ((RubyObject)obj).checkFrozen(); 192 193 data = new StringBuffer (((Base)obj).data.toString()); 194 String name = ((Base)obj).algo.getAlgorithm(); 195 try { 196 algo = provider == null ? MessageDigest.getInstance(name) : MessageDigest.getInstance(name, provider); 197 } catch(NoSuchAlgorithmException e) { 198 throw getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")"); 199 } catch(NoSuchProviderException e) { 200 throw getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")"); 201 } 202 return this; 203 } 204 205 public IRubyObject update(IRubyObject obj) { 206 data.append(obj); 207 return this; 208 } 209 210 public IRubyObject digest() { 211 algo.reset(); 212 return RubyString.newString(getRuntime(), algo.digest(ByteList.plain(data))); 213 } 214 215 public IRubyObject hexdigest() { 216 algo.reset(); 217 return RubyString.newString(getRuntime(), ByteList.plain(toHex(algo.digest(ByteList.plain(data))))); 218 } 219 220 public IRubyObject eq(IRubyObject oth) { 221 boolean ret = this == oth; 222 if(!ret && oth instanceof Base) { 223 Base b = (Base)oth; 224 ret = this.algo.getAlgorithm().equals(b.algo.getAlgorithm()) && 225 this.digest().equals(b.digest()); 226 } 227 228 return ret ? getRuntime().getTrue() : getRuntime().getFalse(); 229 } 230 231 private void setAlgorithm(IRubyObject algo) throws NoSuchAlgorithmException , NoSuchProviderException { 232 this.algo = provider == null ? MessageDigest.getInstance(algo.toString()) : MessageDigest.getInstance(algo.toString(),provider); 233 } 234 235 private static String toHex(byte[] val) { 236 StringBuffer out = new StringBuffer (); 237 for(int i=0,j=val.length;i<j;i++) { 238 String ve = Integer.toString((((int)((char)val[i])) & 0xFF),16); 239 if(ve.length() == 1) { 240 ve = "0" + ve; 241 } 242 out.append(ve); 243 } 244 return out.toString(); 245 } 246 } 247 } | Popular Tags |