Skip to content

Commit 659dd94

Browse files
author
bill_dortch
committed
Add OpenSSL::BN and OpenSSL::PKey::DH classes, plus additional (missing) features to support Net::SSH and other applications. See http://jira.codehaus.org/browse/JRUBY-1670 for more info.
git-svn-id: svn+ssh://rubyforge.org/var/svn/jruby-extras/trunk/jopenssl@827 8ba958d5-0c1a-0410-94a6-a65dfc1b28a6
1 parent 9f6cf1b commit 659dd94

File tree

9 files changed

+1636
-65
lines changed

9 files changed

+1636
-65
lines changed

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

Lines changed: 786 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@
6969
* @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
7070
*/
7171
public class Cipher extends RubyObject {
72-
private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator() {
72+
73+
// set to enable debug output
74+
private static final boolean DEBUG = false;
75+
76+
private static ObjectAllocator CIPHER_ALLOCATOR = new ObjectAllocator() {
7377
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
7478
return new Cipher(runtime, klass);
7579
}
@@ -215,14 +219,14 @@ public static BlockCipherPadding getBlockCipherPadding(String pad) {
215219

216220
public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion, String cipherMode) {
217221
BlockCipher cipher;
218-
222+
219223
// get base cipher
220224
if (cipherBase.equals("AES")) {
221225
cipher = new AESEngine();
222226
} else if (cipherBase.equals("aes")) {
223227
cipher = new AESEngine();
224228
} else if (cipherBase.equals("DES") || cipherBase.equals("des")) {
225-
if (cipherVersion != null && cipherVersion.equals("EDE3")) {
229+
if ("EDE3".equals(cipherVersion) || "ede3".equals(cipherVersion)) {
226230
cipher = new DESedeEngine();
227231
} else {
228232
cipher = new DESEngine();
@@ -249,7 +253,12 @@ public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion
249253
// FIXME should be a ruby exception
250254
return null;
251255
}
252-
256+
257+
// see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
258+
// for a good, widely-cited (if not necessarily definitive) description
259+
// of block cipher modes, with test inputs/outputs.
260+
// (however, it doesn't answer questions about the BC implementation)
261+
253262
// Wrap with mode-specific cipher
254263
if (cipherMode.equalsIgnoreCase("CBC")) {
255264
cipher = new CBCBlockCipher(cipher);
@@ -258,15 +267,19 @@ public static BlockCipher getBlockCipher(String cipherBase, String cipherVersion
258267
cipher = new CFBBlockCipher(cipher, 8);
259268
} else if (cipherMode.equalsIgnoreCase("CFB1")) {
260269
// FIXME: Does 1 mean 1 * 8?
261-
cipher = new CFBBlockCipher(cipher, 8);
270+
// BD: '1' means '1' (bit), but reportedly (and apparently,
271+
// from a look at the code) this is not supported by BC,
272+
// which only supports multiples of 8.
273+
cipher = new CFBBlockCipher(cipher, 1); // this will fail
262274
} else if (cipherMode.equalsIgnoreCase("CFB8")) {
263275
// FIXME: Does 8 mean 8 * 8?
264-
cipher = new CFBBlockCipher(cipher, 8 * 8);
276+
// BD: '8' means '8' (bits). other common CFB modes are 64 and 128
277+
cipher = new CFBBlockCipher(cipher, 8);
265278
} else if (cipherMode.equalsIgnoreCase("OFB")) {
266279
// FIXME: I have no number to put here! I'm using 8.
267280
cipher = new OFBBlockCipher(cipher, 8);
268281
}
269-
282+
270283
return cipher;
271284
}
272285

@@ -286,7 +299,7 @@ public static BufferedBlockCipher getCipher(Ruby runtime, String cipherBase, Str
286299
}
287300

288301
public static KeyParameter getKeyParameter(String cipherBase, byte[] key) {
289-
if (cipherBase.equals("DES")) {
302+
if (cipherBase.equals("DES") || cipherBase.equals("des")) {
290303
return new DESParameters(key);
291304
} else {
292305
return new KeyParameter(key);
@@ -314,6 +327,25 @@ public Cipher(Ruby runtime, RubyClass type) {
314327
private byte[] key;
315328
private byte[] iv;
316329
private String padding;
330+
331+
private void dumpVars() {
332+
System.out.println("***** Cipher instance vars ****");
333+
System.out.println("name = " + name);
334+
System.out.println("cryptoBase = " + cryptoBase);
335+
System.out.println("cryptoVersion = " + cryptoVersion);
336+
System.out.println("cryptoMode = " + cryptoMode);
337+
System.out.println("padding_type = " + padding_type);
338+
System.out.println("realName = " + realName);
339+
System.out.println("keyLen = " + keyLen);
340+
System.out.println("ivLen = " + ivLen);
341+
System.out.println("ciph block size = " + ciph.getBlockSize());
342+
System.out.println("encryptMode = " + encryptMode);
343+
System.out.println("ciphInited = " + ciphInited);
344+
System.out.println("key.length = " + (key == null ? 0 : key.length));
345+
System.out.println("iv.length = " + (iv == null ? 0 : iv.length));
346+
System.out.println("padding = " + padding);
347+
System.out.println("*******************************");
348+
}
317349

318350
public IRubyObject initialize(IRubyObject str, Block unusedBlock) {
319351
name = str.toString();
@@ -328,31 +360,33 @@ public IRubyObject initialize(IRubyObject str, Block unusedBlock) {
328360

329361
if(hasLen() && null != cryptoVersion) {
330362
try {
331-
keyLen = Integer.parseInt(cryptoVersion);
363+
keyLen = Integer.parseInt(cryptoVersion) / 8;
332364
} catch(NumberFormatException e) {
333365
keyLen = -1;
334366
}
335367
}
336-
368+
337369
if(keyLen == -1) {
338370
if("DES".equalsIgnoreCase(cryptoBase)) {
371+
ivLen = 8;
339372
if("EDE3".equalsIgnoreCase(cryptoVersion)) {
340-
keyLen = 168;
373+
keyLen = 24;
341374
} else {
342-
keyLen = 56;
375+
keyLen = 8;
343376
}
344377
} else {
345-
keyLen = 128;
378+
keyLen = 16;
346379
}
347380
}
348381

349382
if(ivLen == -1) {
350383
if("AES".equalsIgnoreCase(cryptoBase)) {
351-
ivLen = 16*8;
384+
ivLen = 16;
352385
} else {
353-
ivLen = 8*8;
386+
ivLen = 8;
354387
}
355388
}
389+
356390
return this;
357391
}
358392

@@ -410,28 +444,32 @@ public IRubyObject set_key_len(IRubyObject len) {
410444
}
411445

412446
public IRubyObject set_key(IRubyObject key) {
413-
if(key.toString().length()*8 < keyLen) {
414-
throw new RaiseException(getRuntime(), ciphErr, "key length to short", true);
415-
}
447+
byte[] keyBytes;
416448
try {
417-
this.key = key.convertToString().getBytes();
449+
keyBytes = key.convertToString().getBytes();
418450
} catch(Exception e) {
419451
e.printStackTrace();
420452
throw new RaiseException(getRuntime(), ciphErr, null, true);
421453
}
454+
if(keyBytes.length < keyLen) {
455+
throw new RaiseException(getRuntime(), ciphErr, "key length to short", true);
456+
}
457+
this.key = keyBytes;
422458
return key;
423459
}
424460

425461
public IRubyObject set_iv(IRubyObject iv) {
426-
if(iv.toString().length()*8 < ivLen) {
427-
throw new RaiseException(getRuntime(), ciphErr, "iv length to short", true);
428-
}
462+
byte[] ivBytes;
429463
try {
430-
this.iv = iv.convertToString().getBytes();
464+
ivBytes = iv.convertToString().getBytes();
431465
} catch(Exception e) {
432466
e.printStackTrace();
433467
throw new RaiseException(getRuntime(), ciphErr, null, true);
434468
}
469+
if(ivBytes.length < ivLen) {
470+
throw new RaiseException(getRuntime(), ciphErr, "iv length to short", true);
471+
}
472+
this.iv = ivBytes;
435473
return iv;
436474
}
437475

@@ -502,7 +540,7 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
502540
digest = Digest.getDigest(getRuntime(), ((Digest)vdigest).getAlgorithm());
503541
}
504542

505-
OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen/8,ivLen/8,digest,salt,pass,iter);
543+
OpenSSLImpl.KeyAndIv result = OpenSSLImpl.EVP_BytesToKey(keyLen,ivLen,digest,salt,pass,iter);
506544
this.key = result.getKey();
507545
this.iv = result.getIv();
508546
} catch(Exception e) {
@@ -516,11 +554,16 @@ public IRubyObject pkcs5_keyivgen(IRubyObject[] args) {
516554
}
517555

518556
private void doInitialize() {
557+
558+
if (DEBUG) System.out.println("*** doInitialize");
559+
if (DEBUG) dumpVars();
560+
519561
ciphInited = true;
520562
try {
521563
// FIXME: I had to make these >= where they were == before; why?
522-
assert key.length * 8 >= keyLen : "Key wrong length";
523-
assert iv.length * 8 >= ivLen : "IV wrong length";
564+
565+
assert key.length >= keyLen : "Key wrong length";
566+
assert iv.length >= ivLen : "IV wrong length";
524567
if(!"ECB".equalsIgnoreCase(cryptoMode) && this.iv != null) {
525568
this.ciph.init(encryptMode, new ParametersWithIV(getKeyParameter(cryptoBase, key), iv));
526569
} else {
@@ -533,6 +576,8 @@ private void doInitialize() {
533576
}
534577

535578
public IRubyObject update(IRubyObject data) {
579+
if (DEBUG) System.out.println("*** update ["+data+"]");
580+
536581
//TODO: implement correctly
537582
byte[] val = data.convertToString().getBytes();
538583
if(val.length == 0) {

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* rights and limitations under the License.
1313
*
1414
* Copyright (C) 2006, 2007 Ola Bini <ola@ologix.com>
15-
*
15+
*
1616
* Alternatively, the contents of this file may be used under the terms of
1717
* either of the GNU General Public License Version 2 or later (the "GPL"),
1818
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -54,7 +54,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
5454
return new Digest(runtime, klass);
5555
}
5656
};
57-
57+
5858
public static void createDigest(Ruby runtime, RubyModule ossl) {
5959
RubyModule mDigest = ossl.defineModuleUnder("Digest");
6060
RubyClass cDigest = mDigest.defineClassUnder("Digest",runtime.getObject(),DIGEST_ALLOCATOR);
@@ -92,7 +92,7 @@ private static String transformDigest(String inp) {
9292
}
9393
return inp;
9494
}
95-
95+
9696
public static org.bouncycastle.crypto.Digest getDigest(Ruby runtime, String name) {
9797
if (name.equals("MD5")) {
9898
return new MD5Digest();
@@ -118,7 +118,7 @@ public static IRubyObject s_digest(IRubyObject recv, IRubyObject str, IRubyObjec
118118

119119
org.bouncycastle.crypto.Digest md = getDigest(recv.getRuntime(), name);
120120
byte[] bytes = data.convertToString().getBytes();
121-
121+
122122
md.update(bytes, 0, bytes.length);
123123
byte[] digest = new byte[md.getDigestSize()];
124124
md.doFinal(digest, 0);
@@ -130,7 +130,7 @@ public static IRubyObject s_hexdigest(IRubyObject recv, IRubyObject str, IRubyOb
130130

131131
org.bouncycastle.crypto.Digest md = getDigest(recv.getRuntime(), transformDigest(name));
132132
byte[] bytes = data.convertToString().getBytes();
133-
133+
134134
md.update(bytes, 0, bytes.length);
135135
byte[] digest = new byte[md.getDigestSize()];
136136
md.doFinal(digest, 0);
@@ -151,6 +151,11 @@ public Digest(Ruby runtime, RubyClass type) {
151151
private StringBuffer data;
152152
private String name;
153153

154+
155+
public String getName() {
156+
return name;
157+
}
158+
154159
public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) {
155160
IRubyObject type;
156161
IRubyObject data = getRuntime().getNil();
@@ -161,7 +166,7 @@ public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) {
161166

162167
name = type.toString();
163168
md = getDigest(getRuntime(), transformDigest(name));
164-
169+
165170
if(!data.isNil()) {
166171
update(data);
167172
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public static void createOpenSSL(Ruby runtime) {
5656
ossl.defineClassUnder("OpenSSLError",standardError,standardError.getAllocator());
5757

5858
ASN1.createASN1(runtime, ossl);
59+
BN.createBN(runtime, ossl);
5960
Digest.createDigest(runtime, ossl);
6061
Cipher.createCipher(runtime, ossl);
6162
Random.createRandom(runtime, ossl);

0 commit comments

Comments
 (0)