Skip to content

Commit ef47e51

Browse files
author
headius
committed
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.
git-svn-id: svn+ssh://rubyforge.org/var/svn/jruby-extras/trunk/jopenssl@822 8ba958d5-0c1a-0410-94a6-a65dfc1b28a6
1 parent f6565c1 commit ef47e51

File tree

3 files changed

+211
-83
lines changed

3 files changed

+211
-83
lines changed

src/java/org/jruby/ext/openssl/Cipher.java

Lines changed: 139 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,31 @@
2727
***** END LICENSE BLOCK *****/
2828
package org.jruby.ext.openssl;
2929

30-
import java.security.MessageDigest;
31-
import java.security.NoSuchAlgorithmException;
32-
import java.security.NoSuchProviderException;
3330
import java.util.ArrayList;
3431
import java.util.HashSet;
3532
import java.util.List;
3633
import java.util.Set;
3734

38-
import javax.crypto.spec.IvParameterSpec;
39-
35+
import org.bouncycastle.crypto.BlockCipher;
36+
import org.bouncycastle.crypto.BufferedBlockCipher;
37+
import org.bouncycastle.crypto.engines.AESEngine;
38+
import org.bouncycastle.crypto.engines.BlowfishEngine;
39+
import org.bouncycastle.crypto.engines.CAST5Engine;
40+
import org.bouncycastle.crypto.engines.CAST6Engine;
41+
import org.bouncycastle.crypto.engines.DESEngine;
42+
import org.bouncycastle.crypto.engines.DESedeEngine;
43+
import org.bouncycastle.crypto.engines.RC2Engine;
44+
import org.bouncycastle.crypto.modes.CBCBlockCipher;
45+
import org.bouncycastle.crypto.modes.CFBBlockCipher;
46+
import org.bouncycastle.crypto.modes.OFBBlockCipher;
47+
import org.bouncycastle.crypto.paddings.BlockCipherPadding;
48+
import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
49+
import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
50+
import org.bouncycastle.crypto.paddings.PKCS7Padding;
51+
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
52+
import org.bouncycastle.crypto.params.DESParameters;
53+
import org.bouncycastle.crypto.params.KeyParameter;
54+
import org.bouncycastle.crypto.params.ParametersWithIV;
4055
import org.jruby.Ruby;
4156
import org.jruby.RubyClass;
4257
import org.jruby.RubyModule;
@@ -179,14 +194,112 @@ public static IRubyObject ciphers(IRubyObject recv) {
179194
}
180195
return recv.getRuntime().newArray(ciphers);
181196
}
197+
198+
public static BlockCipherPadding getBlockCipherPadding(String pad) {
199+
// get appropriate padding
200+
if (pad.equals("PKCS5Padding")) {
201+
return new PKCS7Padding();
202+
} else if (pad.equals("PKCS7Padding")) {
203+
return new PKCS7Padding();
204+
} else if (pad.equals("ISO10126Padding")) {
205+
return new ISO10126d2Padding();
206+
} else if (pad.equals("ISO7816Padding")) {
207+
return new ISO7816d4Padding();
208+
} else if (pad.equals("NoPadding")) {
209+
return null;
210+
} else {
211+
// FIXME should be a ruby exception
212+
throw new RuntimeException("Unknown padding: " + pad);
213+
}
214+
}
215+
216+
public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion, String cipherMode) {
217+
BlockCipher cipher;
218+
219+
// get base cipher
220+
if (cipherBase.equals("AES")) {
221+
cipher = new AESEngine();
222+
} else if (cipherBase.equals("aes")) {
223+
cipher = new AESEngine();
224+
} else if (cipherBase.equals("DES") || cipherBase.equals("des")) {
225+
if (cipherVersion != null && cipherVersion.equals("EDE3")) {
226+
cipher = new DESedeEngine();
227+
} else {
228+
cipher = new DESEngine();
229+
}
230+
} else if (cipherBase.equals("Blowfish")) {
231+
cipher = new BlowfishEngine();
232+
} else if (cipherBase.equals("BLOWFISH")) {
233+
cipher = new BlowfishEngine();
234+
} else if (cipherBase.equals("blowfish")) {
235+
cipher = new BlowfishEngine();
236+
} else if (cipherBase.equals("RC2")) {
237+
cipher = new RC2Engine();
238+
} else if (cipherBase.equals("rc2")) {
239+
cipher = new RC2Engine();
240+
} else if (cipherBase.equals("CAST5")) {
241+
cipher = new CAST5Engine();
242+
} else if (cipherBase.equals("cast5")) {
243+
cipher = new CAST5Engine();
244+
} else if (cipherBase.equals("CAST6")) {
245+
cipher = new CAST6Engine();
246+
} else if (cipherBase.equals("cast6")) {
247+
cipher = new CAST6Engine();
248+
} else {
249+
// FIXME should be a ruby exception
250+
return null;
251+
}
252+
253+
// Wrap with mode-specific cipher
254+
if (cipherMode.equalsIgnoreCase("CBC")) {
255+
cipher = new CBCBlockCipher(cipher);
256+
} else if (cipherMode.equalsIgnoreCase("CFB")) {
257+
// FIXME: I have no number to put here! I'm using 8.
258+
cipher = new CFBBlockCipher(cipher, 8);
259+
} else if (cipherMode.equalsIgnoreCase("CFB1")) {
260+
// FIXME: Does 1 mean 1 * 8?
261+
cipher = new CFBBlockCipher(cipher, 8);
262+
} else if (cipherMode.equalsIgnoreCase("CFB8")) {
263+
// FIXME: Does 8 mean 8 * 8?
264+
cipher = new CFBBlockCipher(cipher, 8 * 8);
265+
} else if (cipherMode.equalsIgnoreCase("OFB")) {
266+
// FIXME: I have no number to put here! I'm using 8.
267+
cipher = new OFBBlockCipher(cipher, 8);
268+
}
269+
270+
return cipher;
271+
}
272+
273+
public static BufferedBlockCipher getCipher(Ruby runtime, String cipherBase, String cipherVersion, String cipherMode, String cipherPad) {
274+
BlockCipherPadding padding = getBlockCipherPadding(cipherPad);
275+
BlockCipher cipher = getBlockCipher(cipherBase, cipherVersion, cipherMode);
276+
277+
if (cipher != null) {
278+
if (!"ECB".equalsIgnoreCase(cipherMode) && padding != null) {
279+
return new PaddedBufferedBlockCipher(cipher, padding);
280+
} else {
281+
return new BufferedBlockCipher(cipher);
282+
}
283+
} else {
284+
throw runtime.newLoadError("unsupported cipher algorithm (" + cipherBase + "-" + cipherMode + "-" + cipherPad + ")");
285+
}
286+
}
287+
288+
public static KeyParameter getKeyParameter(String cipherBase, byte[] key) {
289+
if (cipherBase.equals("DES")) {
290+
return new DESParameters(key);
291+
} else {
292+
return new KeyParameter(key);
293+
}
294+
}
182295

183296
private RubyClass ciphErr;
184297
public Cipher(Ruby runtime, RubyClass type) {
185298
super(runtime,type);
186299
ciphErr = (RubyClass)(((RubyModule)(getRuntime().getModule("OpenSSL").getConstant("Cipher"))).getConstant("CipherError"));
187300
}
188301

189-
private javax.crypto.Cipher ciph;
302+
private BufferedBlockCipher ciph;
190303
private String name;
191304
private String cryptoBase;
192305
private String cryptoVersion;
@@ -211,15 +324,7 @@ public IRubyObject initialize(IRubyObject str, Block unusedBlock) {
211324
realName = values[3];
212325
padding_type = values[4];
213326

214-
try {
215-
ciph = javax.crypto.Cipher.getInstance(realName,"BC");
216-
} catch(NoSuchAlgorithmException e) {
217-
throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
218-
} catch(NoSuchProviderException e) {
219-
throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
220-
} catch(javax.crypto.NoSuchPaddingException e) {
221-
throw getRuntime().newLoadError("unsupported cipher padding (" + realName + ")");
222-
}
327+
ciph = getCipher(getRuntime(), cryptoBase, cryptoVersion, cryptoMode, padding_type);
223328

224329
if(hasLen() && null != cryptoVersion) {
225330
try {
@@ -228,6 +333,7 @@ public IRubyObject initialize(IRubyObject str, Block unusedBlock) {
228333
keyLen = -1;
229334
}
230335
}
336+
231337
if(keyLen == -1) {
232338
if("DES".equalsIgnoreCase(cryptoBase)) {
233339
if("EDE3".equalsIgnoreCase(cryptoVersion)) {
@@ -281,15 +387,7 @@ public IRubyObject initialize_copy(IRubyObject obj) {
281387
}
282388
padding = ((Cipher)obj).padding;
283389

284-
try {
285-
ciph = javax.crypto.Cipher.getInstance(realName,"BC");
286-
} catch(NoSuchAlgorithmException e) {
287-
throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
288-
} catch(NoSuchProviderException e) {
289-
throw getRuntime().newLoadError("unsupported cipher algorithm (" + realName + ")");
290-
} catch(javax.crypto.NoSuchPaddingException e) {
291-
throw getRuntime().newLoadError("unsupported cipher padding (" + realName + ")");
292-
}
390+
ciph = getCipher(getRuntime(), cryptoBase, cryptoVersion, cryptoMode, padding_type);
293391

294392
return this;
295393
}
@@ -378,7 +476,7 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
378476
byte[] salt = null;
379477
int iter = 2048;
380478
IRubyObject vdigest = getRuntime().getNil();
381-
MessageDigest digest = null;
479+
org.bouncycastle.crypto.Digest digest = null;
382480
if(args.length>1) {
383481
if(!args[1].isNil()) {
384482
salt = args[1].convertToString().getBytes();;
@@ -399,9 +497,9 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
399497
}
400498
}
401499
if(vdigest.isNil()) {
402-
digest = MessageDigest.getInstance("MD5","BC");
500+
digest = Digest.getDigest(getRuntime(), "MD5");
403501
} else {
404-
digest = MessageDigest.getInstance(((Digest)vdigest).getAlgorithm(),"BC");
502+
digest = Digest.getDigest(getRuntime(), ((Digest)vdigest).getAlgorithm());
405503
}
406504

407505
OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen/8,ivLen/8,digest,salt,pass,iter);
@@ -420,12 +518,12 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
420518
private void doInitialize() {
421519
ciphInited = true;
422520
try {
423-
assert key.length * 8 == keyLen : "Key wrong length";
424-
assert iv.length * 8 == ivLen : "IV wrong length";
521+
assert key.length * 8 >= keyLen : "Key wrong length";
522+
assert iv.length * 8 >= ivLen : "IV wrong length";
425523
if(!"ECB".equalsIgnoreCase(cryptoMode) && this.iv != null) {
426-
this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(this.key), new IvParameterSpec(this.iv));
524+
this.ciph.init(encryptMode, new ParametersWithIV(getKeyParameter(cryptoBase, key), iv));
427525
} else {
428-
this.ciph.init(encryptMode ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE, new SimpleSecretKey(this.key));
526+
this.ciph.init(encryptMode, getKeyParameter(cryptoBase, key));
429527
}
430528
} catch(Exception e) {
431529
e.printStackTrace();
@@ -445,17 +543,19 @@ public IRubyObject update(IRubyObject data) {
445543
}
446544

447545
byte[] str = new byte[0];
546+
int count;
448547
try {
449-
byte[] out = ciph.update(val);
450-
if(out != null) {
548+
byte[] out = new byte[ciph.getUpdateOutputSize(val.length)];
549+
count = ciph.processBytes(val, 0, val.length, out, 0);
550+
if(count != 0) {
451551
str = out;
452552
}
453553
} catch(Exception e) {
454554
e.printStackTrace();
455555
throw new RaiseException(getRuntime(), ciphErr, null, true);
456556
}
457557

458-
return RubyString.newString(getRuntime(), new ByteList(str,false));
558+
return RubyString.newString(getRuntime(), new ByteList(str, 0, count, false));
459559
}
460560

461561
public IRubyObject update_deprecated(IRubyObject data) {
@@ -470,8 +570,10 @@ public IRubyObject _final() {
470570

471571
//TODO: implement correctly
472572
ByteList str = new ByteList(ByteList.NULL_ARRAY);
573+
int count;
473574
try {
474-
byte[] out = ciph.doFinal();
575+
byte[] out = new byte[ciph.getOutputSize(0)];
576+
count = ciph.doFinal(out, 0);
475577
if(out != null) {
476578
str = new ByteList(out,false);
477579
}
@@ -480,7 +582,7 @@ public IRubyObject _final() {
480582
throw new RaiseException(getRuntime(), ciphErr, null, true);
481583
}
482584

483-
return getRuntime().newString(str);
585+
return getRuntime().newString(new ByteList(str, 0, count));
484586
}
485587

486588
public IRubyObject set_padding(IRubyObject padding) {
@@ -490,7 +592,7 @@ public IRubyObject set_padding(IRubyObject padding) {
490592
}
491593

492594
String getAlgorithm() {
493-
return this.ciph.getAlgorithm();
595+
return this.ciph.getUnderlyingCipher().getAlgorithmName();
494596
}
495597
}
496598

0 commit comments

Comments
 (0)