Title: [830] trunk/jopenssl/src/java/org/jruby/ext/openssl: Revert coding to BC-specific api, instead use do/ getWithBCProvider everywhere
Revision
830
Author
nicksieger
Date
2007-12-12 16:59:09 -0500 (Wed, 12 Dec 2007)

Log Message

Revert coding to BC-specific api, instead use do/getWithBCProvider everywhere

Modified Paths

Added Paths

Diff

Added: trunk/jopenssl/src/java/org/jruby/ext/openssl/Callable.java (0 => 830)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/Callable.java	                        (rev 0)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/Callable.java	2007-12-12 21:59:09 UTC (rev 830)
@@ -0,0 +1,10 @@
+package org.jruby.ext.openssl;
+
+/**
+ * Duplicate of java.util.concurrent.Callable, but pre-1.5.
+ * 
+ * @author nicksieger
+ */
+public interface Callable {
+    Object call();
+}

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


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/Cipher.java	2007-12-12 21:37:38 UTC (rev 829)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/Cipher.java	2007-12-12 21:59:09 UTC (rev 830)
@@ -27,31 +27,16 @@
  ***** 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 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 javax.crypto.spec.IvParameterSpec;
+
 import org.jruby.Ruby;
 import org.jruby.RubyClass;
 import org.jruby.RubyModule;
@@ -70,10 +55,9 @@
  */
 public class Cipher extends RubyObject {
 
-	// set to enable debug output
-	private static final boolean DEBUG = false;
-	
-	private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator() {
+    // set to enable debug output
+    private static final boolean DEBUG = false;
+    private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator() {
         public IRubyObject allocate(Ruby runtime, RubyClass klass) {
             return new Cipher(runtime, klass);
         }
@@ -167,13 +151,18 @@
         return new String[]{cryptoBase,cryptoVersion,cryptoMode,realName,padding_type};
     }
 
-    private static boolean tryCipher(String rubyName) {
-        try {
-            javax.crypto.Cipher.getInstance(rubyToJavaCipher(rubyName, null)[3],OpenSSLReal.PROVIDER);
-            return true;
-        } catch(Exception e) {
-            return false;
-        }
+    private static boolean tryCipher(final String rubyName) {
+        return ((Boolean) (OpenSSLReal.getWithBCProvider(new Callable() {
+            public Object call() {
+                try {
+                    javax.crypto.Cipher.getInstance(rubyToJavaCipher(rubyName, null)[3], OpenSSLReal.PROVIDER);
+                    return Boolean.TRUE;
+                } catch (Exception e) {
+                    return Boolean.FALSE;
+                }
+
+            }
+        }))).booleanValue();
     }
 
     public static IRubyObject ciphers(IRubyObject recv) {
@@ -198,121 +187,14 @@
         }
         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 ("EDE3".equals(cipherVersion) || "ede3".equals(cipherVersion)) { 
-                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;
-        }
-
-        // see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
-        // for a good, widely-cited (if not necessarily definitive) description
-        // of block cipher modes, with test inputs/outputs.
-        // (however, it doesn't answer questions about the BC implementation)
-
-        // 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?
-            // BD: '1' means '1' (bit), but reportedly (and apparently,
-            // from a look at the code) this is not supported by BC,
-            // which only supports multiples of 8.
-            cipher = new CFBBlockCipher(cipher, 1); // this will fail
-        } else if (cipherMode.equalsIgnoreCase("CFB8")) {
-            // FIXME: Does 8 mean 8 * 8?
-            // BD: '8' means '8' (bits).  other common CFB modes are 64 and 128
-            cipher = new CFBBlockCipher(cipher, 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") || cipherBase.equals("des")) {
-            return new DESParameters(key);
-        } else {
-            return new KeyParameter(key);
-        }
-    }
-
     private RubyClass ciphErr;
     public Cipher(Ruby runtime, RubyClass type) {
         super(runtime,type);
         ciphErr = (RubyClass)(((RubyModule)(getRuntime().getModule("OpenSSL").getConstant("Cipher"))).getConstant("CipherError"));
     }
 
-    private BufferedBlockCipher ciph;
+    private javax.crypto.Cipher ciph;
     private String name;
     private String cryptoBase;
     private String cryptoVersion;
@@ -355,9 +237,8 @@
         cryptoMode = values[2];
         realName = values[3];
         padding_type = values[4];
+        ciph = getCipher();
 
-        ciph = getCipher(getRuntime(), cryptoBase, cryptoVersion, cryptoMode, padding_type);
-
         if(hasLen() && null != cryptoVersion) {
             try {
                 keyLen = Integer.parseInt(cryptoVersion) / 8;
@@ -365,7 +246,6 @@
                 keyLen = -1;
             }
         }
-
         if(keyLen == -1) {
             if("DES".equalsIgnoreCase(cryptoBase)) {
                 ivLen = 8;
@@ -421,7 +301,7 @@
         }
         padding = ((Cipher)obj).padding;
 
-        ciph = getCipher(getRuntime(), cryptoBase, cryptoVersion, cryptoMode, padding_type);
+        ciph = getCipher();
 
         return this;
     }
@@ -500,6 +380,22 @@
         return this;
     }
 
+    private javax.crypto.Cipher getCipher() {
+        return (javax.crypto.Cipher) OpenSSLReal.getWithBCProvider(new Callable() {
+            public Object call() {
+                try {
+                    return 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 + ")");
+                }
+            }
+        });
+    }
+
     private boolean hasLen() {
         return hasLen(this.cryptoBase);
     }
@@ -514,7 +410,7 @@
         byte[] salt = null;
         int iter = 2048;
         IRubyObject vdigest = getRuntime().getNil();
-        org.bouncycastle.crypto.Digest digest = null;
+        MessageDigest digest = null;
         if(args.length>1) {
             if(!args[1].isNil()) {
                 salt = args[1].convertToString().getBytes();;
@@ -528,25 +424,27 @@
                 }
             }
         }
-        try {
-            if(null != salt) {
-                if(salt.length != 8) {
-                    throw new RaiseException(getRuntime(), ciphErr, "salt must be an 8-octet string", true);
+        if (null != salt) {
+            if (salt.length != 8) {
+                throw new RaiseException(getRuntime(), ciphErr, "salt must be an 8-octet string", true);
+            }
+        }
+
+        final String algorithm = vdigest.isNil() ? "MD5" : ((Digest) vdigest).getAlgorithm();
+
+        digest = (MessageDigest) OpenSSLReal.getWithBCProvider(new Callable() {
+            public Object call() {
+                try {
+                    return MessageDigest.getInstance(algorithm, "BC");
+                } catch (Exception e) {
+                    throw new RaiseException(getRuntime(), ciphErr, e.getMessage(), true);
                 }
             }
-            if(vdigest.isNil()) {
-                digest = Digest.getDigest(getRuntime(), "MD5");
-            } else {
-                digest = Digest.getDigest(getRuntime(), ((Digest)vdigest).getAlgorithm());
-            }
+        });
 
-            OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen,ivLen,digest,salt,pass,iter);
-            this.key = result.getKey();
-            this.iv = result.getIv();
-        } catch(Exception e) {
-            e.printStackTrace();
-            throw new RaiseException(getRuntime(), ciphErr, null, true);
-        }
+        OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen, ivLen, digest, salt, pass, iter);
+        this.key = result.getKey();
+        this.iv = result.getIv();
 
         doInitialize();
 
@@ -560,14 +458,12 @@
 
         ciphInited = true;
         try {
-            // FIXME: I had to make these >= where they were == before; why?
-
-            assert key.length >= keyLen : "Key wrong length";
-            assert iv.length >= 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, new ParametersWithIV(getKeyParameter(cryptoBase, key), iv));
+                this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(this.key), new IvParameterSpec(this.iv));
             } else {
-                this.ciph.init(encryptMode, getKeyParameter(cryptoBase, key));
+                this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(this.key));
             }
         } catch(Exception e) {
             e.printStackTrace();
@@ -589,11 +485,9 @@
         }
 
         byte[] str = new byte[0];
-        int count;
         try {
-            byte[] out = new byte[ciph.getUpdateOutputSize(val.length)];
-            count = ciph.processBytes(val, 0, val.length, out, 0);
-            if(count != 0) {
+            byte[] out = ciph.update(val);
+            if(out != null) {
                 str = out;
             }
         } catch(Exception e) {
@@ -601,7 +495,7 @@
             throw new RaiseException(getRuntime(), ciphErr, null, true);
         }
 
-        return RubyString.newString(getRuntime(), new ByteList(str, 0, count, false));
+        return RubyString.newString(getRuntime(), new ByteList(str,false));
     }
 
     public IRubyObject update_deprecated(IRubyObject data) {
@@ -616,19 +510,16 @@
 
         //TODO: implement correctly
         ByteList str = new ByteList(ByteList.NULL_ARRAY);
-        int count;
         try {
-            byte[] out = new byte[ciph.getOutputSize(0)];
-            count = ciph.doFinal(out, 0);
+            byte[] out = ciph.doFinal();
             if(out != null) {
                 str = new ByteList(out,false);
             }
         } catch(Exception e) {
-            e.printStackTrace();
-            throw new RaiseException(getRuntime(), ciphErr, null, true);
+            throw new RaiseException(getRuntime(), ciphErr, e.getMessage(), true);
         }
 
-        return getRuntime().newString(new ByteList(str, 0, count));
+        return getRuntime().newString(str);
     }
 
     public IRubyObject set_padding(IRubyObject padding) {
@@ -638,7 +529,6 @@
     }
 
     String getAlgorithm() {
-        return this.ciph.getUnderlyingCipher().getAlgorithmName();
+        return this.ciph.getAlgorithm();
     }
 }
-

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


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLImpl.java	2007-12-12 21:37:38 UTC (rev 829)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLImpl.java	2007-12-12 21:59:09 UTC (rev 830)
@@ -27,6 +27,8 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby.ext.openssl;
 
+import java.security.MessageDigest;
+
 import org.jruby.Ruby;
 import org.jruby.runtime.builtin.IRubyObject;
 
@@ -268,7 +270,7 @@
         return null;
     }
 
-    public static KeyAndIv EVP_BytesToKey(int key_len, int iv_len, org.bouncycastle.crypto.Digest md, byte[] salt, byte[] data, int count) {
+    public static KeyAndIv EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data, int count) {
         byte[] key = new byte[key_len];
         byte[]  iv = new byte[iv_len];
         int key_ix = 0;
@@ -284,19 +286,17 @@
         for(;;) {
             md.reset();
             if(addmd++ > 0) {
-                md.update(md_buf, 0, md_buf.length);
+                md.update(md_buf);
             }
-            md.update(data, 0, data.length);
+            md.update(data);
             if(null != salt) {
                 md.update(salt,0,8);
             }
-            md_buf = new byte[md.getDigestSize()];
-            md.doFinal(md_buf, 0);
+            md_buf = md.digest();
             for(i=1;i<count;i++) {
                 md.reset();
-                md.update(md_buf, 0, md_buf.length);
-                md_buf = new byte[md.getDigestSize()];
-                md.doFinal(md_buf, 0);
+                md.update(md_buf);
+                md_buf = md.digest();
             }
             i=0;
             if(nkey > 0) {

Modified: trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLReal.java (829 => 830)


--- trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLReal.java	2007-12-12 21:37:38 UTC (rev 829)
+++ trunk/jopenssl/src/java/org/jruby/ext/openssl/OpenSSLReal.java	2007-12-12 21:59:09 UTC (rev 830)
@@ -37,18 +37,38 @@
 public class OpenSSLReal {
     public static java.security.Provider PROVIDER;
     
-    public static void doWithBCProvider(Runnable toRun) {
-        try {
-            java.security.Security.insertProviderAt(PROVIDER,1);
-            toRun.run();
-        } finally {
-            java.security.Security.removeProvider("BC");
+    public static void doWithBCProvider(final Runnable toRun) {
+        getWithBCProvider(new Callable() {
+            public Object call() {
+                toRun.run();
+                return null;
+            }
+        });
+    }
+ 
+    public static Object getWithBCProvider(Callable toRun) {
+        if (PROVIDER != null) {
+            synchronized (java.security.Security.class) {
+                try {
+                    java.security.Security.insertProviderAt(PROVIDER, 2);
+                    return toRun.call();
+                } finally {
+                    java.security.Security.removeProvider("BC");
+                }
+            }
+        } else {
+            return toRun.call();
         }
     }
 
     public static void createOpenSSL(Ruby runtime) {
-        if(PROVIDER == null) {
-            PROVIDER = new org.bouncycastle.jce.provider.BouncyCastleProvider();
+        if (PROVIDER == null) {
+            try {
+                PROVIDER = (java.security.Provider)
+                        Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance();
+            } catch (Exception exception) {
+                // no bouncy castle available
+            }
         }
 
         RubyModule ossl = runtime.getOrCreateModule("OpenSSL");
_______________________________________________
Jruby-extras-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/jruby-extras-devel

Reply via email to