Title: [822] trunk/jopenssl/src/java/org/jruby/ext/openssl: Beginning of conversion away from JCE.
Revision
822
Author
headius
Date
2007-11-30 21:24:44 -0500 (Fri, 30 Nov 2007)

Log Message

Beginning of conversion away from JCE. Digest is completely converted and passes all tests. OpenSSLImpl just had one method to convert and appears to be completely converted and working. Cipher is converted but has one error at the moment.

Modified Paths

Diff

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/Cipher.java (821 => 822)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/Cipher.java	2007-11-29 23:12:04 UTC (rev 821)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/Cipher.java	2007-12-01 02:24:44 UTC (rev 822)
@@ -27,16 +27,31 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby.ext.openssl;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import javax.crypto.spec.IvParameterSpec;
-
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.engines.BlowfishEngine;
+import org.bouncycastle.crypto.engines.CAST5Engine;
+import org.bouncycastle.crypto.engines.CAST6Engine;
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+import org.bouncycastle.crypto.engines.RC2Engine;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.paddings.PKCS7Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
 import org.jruby.Ruby;
 import org.jruby.RubyClass;
 import org.jruby.RubyModule;
@@ -179,6 +194,104 @@
         }
         return recv.getRuntime().newArray(ciphers);
     }
+    
+    public static BlockCipherPadding getBlockCipherPadding(String pad) {
+        // get appropriate padding
+        if (pad.equals("PKCS5Padding")) {
+            return new PKCS7Padding();
+        } else if (pad.equals("PKCS7Padding")) {
+            return new PKCS7Padding();
+        } else if (pad.equals("ISO10126Padding")) {
+            return new ISO10126d2Padding();
+        } else if (pad.equals("ISO7816Padding")) {
+            return new ISO7816d4Padding();
+        } else if (pad.equals("NoPadding")) {
+            return null;
+        } else {
+            // FIXME should be a ruby exception
+            throw new RuntimeException("Unknown padding: " + pad);
+        }
+    }
+    
+    public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion, String cipherMode) {
+        BlockCipher cipher;
+        
+        // get base cipher
+        if (cipherBase.equals("AES")) {
+            cipher = new AESEngine();
+        } else if (cipherBase.equals("aes")) {
+            cipher = new AESEngine();
+        } else if (cipherBase.equals("DES") || cipherBase.equals("des")) {
+            if (cipherVersion != null && cipherVersion.equals("EDE3")) {
+                cipher = new DESedeEngine();
+            } else {
+                cipher = new DESEngine();
+            }
+        } else if (cipherBase.equals("Blowfish")) {
+            cipher = new BlowfishEngine();
+        } else if (cipherBase.equals("BLOWFISH")) {
+            cipher = new BlowfishEngine();
+        } else if (cipherBase.equals("blowfish")) {
+            cipher = new BlowfishEngine();
+        } else if (cipherBase.equals("RC2")) {
+            cipher = new RC2Engine();
+        } else if (cipherBase.equals("rc2")) {
+            cipher = new RC2Engine();
+        } else if (cipherBase.equals("CAST5")) {
+            cipher = new CAST5Engine();
+        } else if (cipherBase.equals("cast5")) {
+            cipher = new CAST5Engine();
+        } else if (cipherBase.equals("CAST6")) {
+            cipher = new CAST6Engine();
+        } else if (cipherBase.equals("cast6")) {
+            cipher = new CAST6Engine();
+        } else {
+            // FIXME should be a ruby exception
+            return null;
+        }
+        
+        // Wrap with mode-specific cipher
+        if (cipherMode.equalsIgnoreCase("CBC")) {
+            cipher = new CBCBlockCipher(cipher);
+        } else if (cipherMode.equalsIgnoreCase("CFB")) {
+            // FIXME: I have no number to put here! I'm using 8.
+            cipher = new CFBBlockCipher(cipher, 8);
+        } else if (cipherMode.equalsIgnoreCase("CFB1")) {
+            // FIXME: Does 1 mean 1 * 8?
+            cipher = new CFBBlockCipher(cipher, 8);
+        } else if (cipherMode.equalsIgnoreCase("CFB8")) {
+            // FIXME: Does 8 mean 8 * 8?
+            cipher = new CFBBlockCipher(cipher, 8 * 8);
+        } else if (cipherMode.equalsIgnoreCase("OFB")) {
+            // FIXME: I have no number to put here! I'm using 8.
+            cipher = new OFBBlockCipher(cipher, 8);
+        }
+        
+        return cipher;
+    }
+    
+    public static BufferedBlockCipher getCipher(Ruby runtime, String cipherBase, String cipherVersion, String cipherMode, String cipherPad) {
+        BlockCipherPadding padding = getBlockCipherPadding(cipherPad);
+        BlockCipher cipher = getBlockCipher(cipherBase, cipherVersion, cipherMode);
+        
+        if (cipher != null) {
+            if (!"ECB".equalsIgnoreCase(cipherMode) && padding != null) {
+                return new PaddedBufferedBlockCipher(cipher, padding);
+            } else {
+                return new BufferedBlockCipher(cipher);
+            }
+        } else {
+            throw runtime.newLoadError("unsupported cipher algorithm (" + cipherBase + "-" + cipherMode + "-" + cipherPad + ")");
+        }
+    }
+    
+    public static KeyParameter getKeyParameter(String cipherBase, byte[] key) {
+        if (cipherBase.equals("DES")) {
+            return new DESParameters(key);
+        } else {
+            return new KeyParameter(key);
+        }
+    }
 
     private RubyClass ciphErr;
     public Cipher(Ruby runtime, RubyClass type) {
@@ -186,7 +299,7 @@
         ciphErr = (RubyClass)(((RubyModule)(getRuntime().getModule("OpenSSL").getConstant("Cipher"))).getConstant("CipherError"));
     }
 
-    private javax.crypto.Cipher ciph;
+    private BufferedBlockCipher ciph;
     private String name;
     private String cryptoBase;
     private String cryptoVersion;
@@ -211,15 +324,7 @@
         realName = values[3];
         padding_type = values[4];
 
-        try {
-            ciph = javax.crypto.Cipher.getInstance(realName,"BC");
-        } catch(NoSuchAlgorithmException e) {
-            throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
-        } catch(NoSuchProviderException e) {
-            throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
-        } catch(javax.crypto.NoSuchPaddingException e) {
-            throw getRuntime().newLoadError("unsupported cipher padding (" + realName + ")");
-        }
+        ciph = getCipher(getRuntime(), cryptoBase, cryptoVersion, cryptoMode, padding_type);
 
         if(hasLen() && null != cryptoVersion) {
             try {
@@ -228,6 +333,7 @@
                 keyLen = -1;
             }
         }
+        
         if(keyLen == -1) {
             if("DES".equalsIgnoreCase(cryptoBase)) {
                 if("EDE3".equalsIgnoreCase(cryptoVersion)) {
@@ -281,15 +387,7 @@
         }
         padding = ((Cipher)obj).padding;
 
-        try {
-            ciph = javax.crypto.Cipher.getInstance(realName,"BC");
-        } catch(NoSuchAlgorithmException e) {
-            throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
-        } catch(NoSuchProviderException e) {
-            throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
-        } catch(javax.crypto.NoSuchPaddingException e) {
-            throw getRuntime().newLoadError("unsupported cipher padding (" + realName + ")");
-        }
+        ciph = getCipher(getRuntime(), cryptoBase, cryptoVersion, cryptoMode, padding_type);
 
         return this;
     }
@@ -378,7 +476,7 @@
         byte[] salt = null;
         int iter = 2048;
         IRubyObject vdigest = getRuntime().getNil();
-        MessageDigest digest = null;
+        org.bouncycastle.crypto.Digest digest = null;
         if(args.length>1) {
             if(!args[1].isNil()) {
                 salt = args[1].convertToString().getBytes();;
@@ -399,9 +497,9 @@
                 }
             }
             if(vdigest.isNil()) {
-                digest = MessageDigest.getInstance("MD5","BC");
+                digest = Digest.getDigest(getRuntime(), "MD5");
             } else {
-                digest = MessageDigest.getInstance(((Digest)vdigest).getAlgorithm(),"BC");
+                digest = Digest.getDigest(getRuntime(), ((Digest)vdigest).getAlgorithm());
             }
 
             OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen/8,ivLen/8,digest,salt,pass,iter);
@@ -420,12 +518,12 @@
     private void doInitialize() {
         ciphInited = true;
         try {
-            assert key.length * 8 == keyLen : "Key wrong length";
-            assert iv.length * 8 == ivLen : "IV wrong length";
+            assert key.length * 8 >= keyLen : "Key wrong length";
+            assert iv.length * 8 >= ivLen : "IV wrong length";
             if(!"ECB".equalsIgnoreCase(cryptoMode) && this.iv != null) {
-                this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(this.key), new IvParameterSpec(this.iv));
+                this.ciph.init(encryptMode, new ParametersWithIV(getKeyParameter(cryptoBase, key), iv));
             } else {
-                this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(this.key));
+                this.ciph.init(encryptMode, getKeyParameter(cryptoBase, key));
             }
         } catch(Exception e) {
             e.printStackTrace();
@@ -445,9 +543,11 @@
         }
 
         byte[] str = new byte[0];
+        int count;
         try {
-            byte[] out = ciph.update(val);
-            if(out != null) {
+            byte[] out = new byte[ciph.getUpdateOutputSize(val.length)];
+            count = ciph.processBytes(val, 0, val.length, out, 0);
+            if(count != 0) {
                 str = out;
             }
         } catch(Exception e) {
@@ -455,7 +555,7 @@
             throw new RaiseException(getRuntime(), ciphErr, null, true);
         }
 
-        return RubyString.newString(getRuntime(), new ByteList(str,false));
+        return RubyString.newString(getRuntime(), new ByteList(str, 0, count, false));
     }
 
     public IRubyObject update_deprecated(IRubyObject data) {
@@ -470,8 +570,10 @@
 
         //TODO: implement correctly
         ByteList str = new ByteList(ByteList.NULL_ARRAY);
+        int count;
         try {
-            byte[] out = ciph.doFinal();
+            byte[] out = new byte[ciph.getOutputSize(0)];
+            count = ciph.doFinal(out, 0);
             if(out != null) {
                 str = new ByteList(out,false);
             }
@@ -480,7 +582,7 @@
             throw new RaiseException(getRuntime(), ciphErr, null, true);
         }
 
-        return getRuntime().newString(str);
+        return getRuntime().newString(new ByteList(str, 0, count));
     }
 
     public IRubyObject set_padding(IRubyObject padding) {
@@ -490,7 +592,7 @@
     }
 
     String getAlgorithm() {
-        return this.ciph.getAlgorithm();
+        return this.ciph.getUnderlyingCipher().getAlgorithmName();
     }
 }
 

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/Digest.java (821 => 822)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/Digest.java	2007-11-29 23:12:04 UTC (rev 821)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/Digest.java	2007-12-01 02:24:44 UTC (rev 822)
@@ -27,9 +27,13 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby.ext.openssl;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
 import org.jruby.Ruby;
 import org.jruby.RubyClass;
 import org.jruby.RubyModule;
@@ -88,25 +92,49 @@
         }
         return inp;
     }
+    
+    public static org.bouncycastle.crypto.Digest getDigest(Ruby runtime, String name) {
+        if (name.equals("MD5")) {
+            return new MD5Digest();
+        } else if (name.equals("SHA")) {
+            return new SHA1Digest();
+        } else if (name.equals("SHA1")) {
+            return new SHA1Digest();
+        } else if (name.equals("SHA224")) {
+            return new SHA224Digest();
+        } else if (name.equals("SHA256")) {
+            return new SHA256Digest();
+        } else if (name.equals("SHA384")) {
+            return new SHA384Digest();
+        } else if (name.equals("SHA512")) {
+            return new SHA512Digest();
+        } else {
+            throw runtime.newNotImplementedError("Unsupported digest algorithm (" + name + ")");
+        }
+    }
 
     public static IRubyObject s_digest(IRubyObject recv, IRubyObject str, IRubyObject data) {
         String name = str.toString();
-        try {
-            MessageDigest md = MessageDigest.getInstance(transformDigest(name));
-            return RubyString.newString(recv.getRuntime(), md.digest(data.convertToString().getBytes()));
-        } catch(NoSuchAlgorithmException e) {
-            throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
-        }
+
+        org.bouncycastle.crypto.Digest md = getDigest(recv.getRuntime(), name);
+        byte[] bytes = data.convertToString().getBytes();
+        
+        md.update(bytes, 0, bytes.length);
+        byte[] digest = new byte[md.getDigestSize()];
+        md.doFinal(digest, 0);
+        return RubyString.newString(recv.getRuntime(), new ByteList(digest));
     }
 
     public static IRubyObject s_hexdigest(IRubyObject recv, IRubyObject str, IRubyObject data) {
         String name = str.toString();
-        try {
-            MessageDigest md = MessageDigest.getInstance(transformDigest(name));
-            return RubyString.newString(recv.getRuntime(), ByteList.plain(Utils.toHex(md.digest(data.convertToString().getBytes()))));
-        } catch(NoSuchAlgorithmException e) {
-            throw recv.getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
-        }
+
+        org.bouncycastle.crypto.Digest md = getDigest(recv.getRuntime(), transformDigest(name));
+        byte[] bytes = data.convertToString().getBytes();
+        
+        md.update(bytes, 0, bytes.length);
+        byte[] digest = new byte[md.getDigestSize()];
+        md.doFinal(digest, 0);
+        return RubyString.newString(recv.getRuntime(), ByteList.plain(Utils.toHex(digest)));
     }
 
     public Digest(Ruby runtime, RubyClass type) {
@@ -114,16 +142,12 @@
         data = "" StringBuffer();
 
         if(!(type.toString().equals("OpenSSL::Digest::Digest"))) {
-            try {
-                name = type.toString();
-                md = MessageDigest.getInstance(transformDigest(type.toString()));
-            } catch(NoSuchAlgorithmException e) {
-                throw runtime.newNotImplementedError("Unsupported digest algorithm (" + type.toString() + ")");
-            }
+            name = type.toString();
+            md = getDigest(runtime, transformDigest(type.toString()));
         }
     }
 
-    private MessageDigest md;
+    private org.bouncycastle.crypto.Digest md;
     private StringBuffer data;
     private String name;
 
@@ -136,11 +160,8 @@
         type = args[0];
 
         name = type.toString();
-        try {
-            md = MessageDigest.getInstance(transformDigest(name));
-        } catch(NoSuchAlgorithmException e) {
-            throw getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
-        }
+        md = getDigest(getRuntime(), transformDigest(name));
+            
         if(!data.isNil()) {
             update(data);
         }
@@ -153,19 +174,16 @@
         }
         checkFrozen();
         data = "" StringBuffer(((Digest)obj).data.toString());
-        name = ((Digest)obj).md.getAlgorithm();
-        try {
-            md = MessageDigest.getInstance(transformDigest(name));
-        } catch(NoSuchAlgorithmException e) {
-            throw getRuntime().newNotImplementedError("Unsupported digest algorithm (" + name + ")");
-        }
+        name = ((Digest)obj).md.getAlgorithmName();
+        md = getDigest(getRuntime(), transformDigest(name));
 
         return this;
     }
 
     public IRubyObject update(IRubyObject obj) {
         data.append(obj);
-        md.update(obj.convertToString().getBytes());
+        byte[] bytes = obj.convertToString().getBytes();
+        md.update(bytes, 0, bytes.length);
         return this;
     }
 
@@ -177,7 +195,11 @@
 
     public IRubyObject digest() {
         md.reset();
-        return RubyString.newString(getRuntime(), md.digest(ByteList.plain(data)));
+        byte[] bytes = ByteList.plain(data);
+        md.update(bytes, 0, bytes.length);
+        byte[] digest = new byte[md.getDigestSize()];
+        md.doFinal(digest, 0);
+        return RubyString.newString(getRuntime(), digest);
     }
 
     public IRubyObject name() {
@@ -185,19 +207,23 @@
     }
 
     public IRubyObject size() {
-        return getRuntime().newFixnum(md.getDigestLength());
+        return getRuntime().newFixnum(md.getDigestSize());
     }
 
     public IRubyObject hexdigest() {
         md.reset();
-        return RubyString.newString(getRuntime(), ByteList.plain(Utils.toHex(md.digest(ByteList.plain(data)))));
+        byte[] bytes = ByteList.plain(data);
+        md.update(bytes, 0, bytes.length);
+        byte[] digest = new byte[md.getDigestSize()];
+        md.doFinal(digest, 0);
+        return RubyString.newString(getRuntime(), ByteList.plain(Utils.toHex(digest)));
     }
 
     public IRubyObject eq(IRubyObject oth) {
         boolean ret = this == oth;
         if(!ret && oth instanceof Digest) {
             Digest b = (Digest)oth;
-            ret = this.md.getAlgorithm().equals(b.md.getAlgorithm()) &&
+            ret = this.md.getAlgorithmName().equals(b.md.getAlgorithmName()) &&
                 this.digest().equals(b.digest());
         }
 
@@ -205,7 +231,7 @@
     }
 
     String getAlgorithm() {
-        return this.md.getAlgorithm();
+        return this.md.getAlgorithmName().replace("-", "");
     }
 }
 

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLImpl.java (821 => 822)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLImpl.java	2007-11-29 23:12:04 UTC (rev 821)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLImpl.java	2007-12-01 02:24:44 UTC (rev 822)
@@ -27,8 +27,6 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby.ext.openssl;
 
-import java.security.MessageDigest;
-
 import org.jruby.Ruby;
 import org.jruby.runtime.builtin.IRubyObject;
 
@@ -270,7 +268,7 @@
         return null;
     }
 
-    public static KeyAndIv EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) {
+    public static KeyAndIv EVP_BytesToKey(int key_len, int iv_len, org.bouncycastle.crypto.Digest md, byte[] salt, byte[] data, int count) {
         byte[] key = new byte[key_len];
         byte[]  iv = new byte[iv_len];
         int key_ix = 0;
@@ -286,17 +284,19 @@
         for(;;) {
             md.reset();
             if(addmd++ > 0) {
-                md.update(md_buf);
+                md.update(md_buf, 0, md_buf.length);
             }
-            md.update(data);
+            md.update(data, 0, data.length);
             if(null != salt) {
                 md.update(salt,0,8);
             }
-            md_buf = md.digest();
+            md_buf = new byte[md.getDigestSize()];
+            md.doFinal(md_buf, 0);
             for(i=1;i<count;i++) {
                 md.reset();
-                md.update(md_buf);
-                md_buf = md.digest();
+                md.update(md_buf, 0, md_buf.length);
+                md_buf = new byte[md.getDigestSize()];
+                md.doFinal(md_buf, 0);
             }
             i=0;
             if(nkey > 0) {
_______________________________________________
Jruby-extras-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/jruby-extras-devel

Reply via email to