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) {