001: package org.bouncycastle.jce.provider.test;
002:
003: import java.security.AlgorithmParameters;
004: import java.security.Security;
005: import java.security.spec.InvalidParameterSpecException;
006:
007: import javax.crypto.Cipher;
008: import javax.crypto.Mac;
009: import javax.crypto.SecretKey;
010: import javax.crypto.SecretKeyFactory;
011: import javax.crypto.spec.IvParameterSpec;
012: import javax.crypto.spec.PBEKeySpec;
013: import javax.crypto.spec.PBEParameterSpec;
014: import javax.crypto.spec.SecretKeySpec;
015:
016: import org.bouncycastle.crypto.Digest;
017: import org.bouncycastle.crypto.PBEParametersGenerator;
018: import org.bouncycastle.crypto.digests.SHA1Digest;
019: import org.bouncycastle.crypto.digests.SHA256Digest;
020: import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
021: import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
022: import org.bouncycastle.crypto.params.KeyParameter;
023: import org.bouncycastle.crypto.params.ParametersWithIV;
024: import org.bouncycastle.jce.provider.BouncyCastleProvider;
025: import org.bouncycastle.util.encoders.Hex;
026: import org.bouncycastle.util.test.SimpleTest;
027:
028: /**
029: * test out the various PBE modes, making sure the JCE implementations
030: * are compatible woth the light weight ones.
031: */
032: public class PBETest extends SimpleTest {
033: private class OpenSSLTest extends SimpleTest {
034: char[] password;
035: String baseAlgorithm;
036: String algorithm;
037: int keySize;
038: int ivSize;
039:
040: OpenSSLTest(String baseAlgorithm, String algorithm,
041: int keySize, int ivSize) {
042: this .password = algorithm.toCharArray();
043: this .baseAlgorithm = baseAlgorithm;
044: this .algorithm = algorithm;
045: this .keySize = keySize;
046: this .ivSize = ivSize;
047: }
048:
049: public String getName() {
050: return "OpenSSLPBE";
051: }
052:
053: public void performTest() throws Exception {
054: byte[] salt = new byte[16];
055: int iCount = 100;
056:
057: for (int i = 0; i != salt.length; i++) {
058: salt[i] = (byte) i;
059: }
060:
061: OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
062:
063: pGen.init(PBEParametersGenerator
064: .PKCS5PasswordToBytes(password), salt, iCount);
065:
066: ParametersWithIV params = (ParametersWithIV) pGen
067: .generateDerivedParameters(keySize, ivSize);
068:
069: SecretKeySpec encKey = new SecretKeySpec(
070: ((KeyParameter) params.getParameters()).getKey(),
071: baseAlgorithm);
072:
073: Cipher c;
074:
075: if (baseAlgorithm.equals("RC4")) {
076: c = Cipher.getInstance(baseAlgorithm, "BC");
077:
078: c.init(Cipher.ENCRYPT_MODE, encKey);
079: } else {
080: c = Cipher.getInstance(baseAlgorithm
081: + "/CBC/PKCS7Padding", "BC");
082:
083: c.init(Cipher.ENCRYPT_MODE, encKey,
084: new IvParameterSpec(params.getIV()));
085: }
086:
087: byte[] enc = c.doFinal(salt);
088:
089: c = Cipher.getInstance(algorithm, "BC");
090:
091: PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount);
092: SecretKeyFactory fact = SecretKeyFactory.getInstance(
093: algorithm, "BC");
094:
095: c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec));
096:
097: byte[] dec = c.doFinal(enc);
098:
099: if (!arrayEquals(salt, dec)) {
100: fail("" + algorithm
101: + "failed encryption/decryption test");
102: }
103: }
104: }
105:
106: private class PKCS12Test extends SimpleTest {
107: char[] password;
108: String baseAlgorithm;
109: String algorithm;
110: Digest digest;
111: int keySize;
112: int ivSize;
113:
114: PKCS12Test(String baseAlgorithm, String algorithm,
115: Digest digest, int keySize, int ivSize) {
116: this .password = algorithm.toCharArray();
117: this .baseAlgorithm = baseAlgorithm;
118: this .algorithm = algorithm;
119: this .digest = digest;
120: this .keySize = keySize;
121: this .ivSize = ivSize;
122: }
123:
124: public String getName() {
125: return "PKCS12PBE";
126: }
127:
128: public void performTest() throws Exception {
129: byte[] salt = new byte[digest.getDigestSize()];
130: int iCount = 100;
131:
132: digest.doFinal(salt, 0);
133:
134: PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(
135: digest);
136:
137: pGen.init(PBEParametersGenerator
138: .PKCS12PasswordToBytes(password), salt, iCount);
139:
140: ParametersWithIV params = (ParametersWithIV) pGen
141: .generateDerivedParameters(keySize, ivSize);
142:
143: SecretKeySpec encKey = new SecretKeySpec(
144: ((KeyParameter) params.getParameters()).getKey(),
145: baseAlgorithm);
146:
147: Cipher c;
148:
149: if (baseAlgorithm.equals("RC4")) {
150: c = Cipher.getInstance(baseAlgorithm, "BC");
151:
152: c.init(Cipher.ENCRYPT_MODE, encKey);
153: } else {
154: c = Cipher.getInstance(baseAlgorithm
155: + "/CBC/PKCS7Padding", "BC");
156:
157: c.init(Cipher.ENCRYPT_MODE, encKey,
158: new IvParameterSpec(params.getIV()));
159: }
160:
161: byte[] enc = c.doFinal(salt);
162:
163: c = Cipher.getInstance(algorithm, "BC");
164:
165: PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount);
166: SecretKeyFactory fact = SecretKeyFactory.getInstance(
167: algorithm, "BC");
168:
169: c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec));
170:
171: byte[] dec = c.doFinal(enc);
172:
173: if (!arrayEquals(salt, dec)) {
174: fail("" + algorithm
175: + "failed encryption/decryption test");
176: }
177:
178: //
179: // get the parameters
180: //
181: AlgorithmParameters param = checkParameters(c, salt, iCount);
182:
183: //
184: // try using parameters
185: //
186: c = Cipher.getInstance(algorithm, "BC");
187:
188: keySpec = new PBEKeySpec(password);
189:
190: c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec),
191: param);
192:
193: checkParameters(c, salt, iCount);
194:
195: dec = c.doFinal(enc);
196:
197: if (!arrayEquals(salt, dec)) {
198: fail("" + algorithm
199: + "failed encryption/decryption test");
200: }
201:
202: //
203: // try using PBESpec
204: //
205: c = Cipher.getInstance(algorithm, "BC");
206:
207: keySpec = new PBEKeySpec(password);
208:
209: c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec),
210: param.getParameterSpec(PBEParameterSpec.class));
211:
212: checkParameters(c, salt, iCount);
213:
214: dec = c.doFinal(enc);
215:
216: if (!arrayEquals(salt, dec)) {
217: fail("" + algorithm
218: + "failed encryption/decryption test");
219: }
220: }
221:
222: private AlgorithmParameters checkParameters(Cipher c,
223: byte[] salt, int iCount)
224: throws InvalidParameterSpecException {
225: AlgorithmParameters param = c.getParameters();
226: PBEParameterSpec spec = (PBEParameterSpec) param
227: .getParameterSpec(PBEParameterSpec.class);
228:
229: if (!arrayEquals(salt, spec.getSalt())) {
230: fail("" + algorithm + "failed salt test");
231: }
232:
233: if (iCount != spec.getIterationCount()) {
234: fail("" + algorithm + "failed count test");
235: }
236: return param;
237: }
238: }
239:
240: private PKCS12Test[] pkcs12Tests = {
241: new PKCS12Test("DESede", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC",
242: new SHA1Digest(), 192, 64),
243: new PKCS12Test("DESede", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC",
244: new SHA1Digest(), 128, 64),
245: new PKCS12Test("RC4", "PBEWITHSHAAND128BITRC4",
246: new SHA1Digest(), 128, 0),
247: new PKCS12Test("RC4", "PBEWITHSHAAND40BITRC4",
248: new SHA1Digest(), 40, 0),
249: new PKCS12Test("RC2", "PBEWITHSHAAND128BITRC2-CBC",
250: new SHA1Digest(), 128, 64),
251: new PKCS12Test("RC2", "PBEWITHSHAAND40BITRC2-CBC",
252: new SHA1Digest(), 40, 64),
253: new PKCS12Test("AES", "PBEWithSHA1And128BitAES-CBC-BC",
254: new SHA1Digest(), 128, 128),
255: new PKCS12Test("AES", "PBEWithSHA1And192BitAES-CBC-BC",
256: new SHA1Digest(), 192, 128),
257: new PKCS12Test("AES", "PBEWithSHA1And256BitAES-CBC-BC",
258: new SHA1Digest(), 256, 128),
259: new PKCS12Test("AES", "PBEWithSHA256And128BitAES-CBC-BC",
260: new SHA256Digest(), 128, 128),
261: new PKCS12Test("AES", "PBEWithSHA256And192BitAES-CBC-BC",
262: new SHA256Digest(), 192, 128),
263: new PKCS12Test("AES", "PBEWithSHA256And256BitAES-CBC-BC",
264: new SHA256Digest(), 256, 128),
265: new PKCS12Test("Twofish", "PBEWithSHAAndTwofish-CBC",
266: new SHA1Digest(), 256, 128),
267: new PKCS12Test("IDEA", "PBEWithSHAAndIDEA-CBC",
268: new SHA1Digest(), 128, 64) };
269:
270: private OpenSSLTest openSSLTests[] = {
271: new OpenSSLTest("AES",
272: "PBEWITHMD5AND128BITAES-CBC-OPENSSL", 128, 128),
273: new OpenSSLTest("AES",
274: "PBEWITHMD5AND192BITAES-CBC-OPENSSL", 192, 128),
275: new OpenSSLTest("AES",
276: "PBEWITHMD5AND256BITAES-CBC-OPENSSL", 256, 128) };
277:
278: static byte[] message = Hex.decode("4869205468657265");
279:
280: private byte[] hMac1 = Hex
281: .decode("bcc42174ccb04f425d9a5c8c4a95d6fd7c372911");
282: private byte[] hMac2 = Hex
283: .decode("cb1d8bdb6aca9e3fa8980d6eb41ab28a7eb2cfd6");
284:
285: private Cipher makePBECipherUsingParam(String algorithm, int mode,
286: char[] password, byte[] salt, int iterationCount)
287: throws Exception {
288: PBEKeySpec pbeSpec = new PBEKeySpec(password);
289: SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
290: algorithm, "BC");
291: PBEParameterSpec defParams = new PBEParameterSpec(salt,
292: iterationCount);
293:
294: Cipher cipher = Cipher.getInstance(algorithm, "BC");
295:
296: cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
297:
298: return cipher;
299: }
300:
301: private Cipher makePBECipherWithoutParam(String algorithm,
302: int mode, char[] password, byte[] salt, int iterationCount)
303: throws Exception {
304: PBEKeySpec pbeSpec = new PBEKeySpec(password, salt,
305: iterationCount);
306: SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
307: algorithm, "BC");
308:
309: Cipher cipher = Cipher.getInstance(algorithm, "BC");
310:
311: cipher.init(mode, keyFact.generateSecret(pbeSpec));
312:
313: return cipher;
314: }
315:
316: private boolean arrayEquals(byte[] a, byte[] b) {
317: if (a.length != b.length) {
318: return false;
319: }
320:
321: for (int i = 0; i != a.length; i++) {
322: if (a[i] != b[i]) {
323: return false;
324: }
325: }
326:
327: return true;
328: }
329:
330: public void testPBEHMac(String hmacName, byte[] output) {
331: SecretKey key;
332: byte[] out;
333: Mac mac;
334:
335: try {
336: SecretKeyFactory fact = SecretKeyFactory.getInstance(
337: hmacName, "BC");
338:
339: key = fact.generateSecret(new PBEKeySpec("hello"
340: .toCharArray()));
341:
342: mac = Mac.getInstance(hmacName, "BC");
343: } catch (Exception e) {
344: fail("Failed - exception " + e.toString(), e);
345: return;
346: }
347:
348: try {
349: mac.init(key, new PBEParameterSpec(new byte[20], 100));
350: } catch (Exception e) {
351: fail("Failed - exception " + e.toString(), e);
352: return;
353: }
354:
355: mac.reset();
356:
357: mac.update(message, 0, message.length);
358:
359: out = mac.doFinal();
360:
361: if (!arrayEquals(out, output)) {
362: fail("Failed - expected " + new String(Hex.encode(output))
363: + " got " + new String(Hex.encode(out)));
364: }
365: }
366:
367: public void performTest() throws Exception {
368: byte[] input = Hex
369: .decode("1234567890abcdefabcdef1234567890fedbca098765");
370:
371: //
372: // DES
373: //
374: Cipher cEnc = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC");
375:
376: cEnc.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Hex
377: .decode("30e69252758e5346"), "DES"),
378: new IvParameterSpec(Hex.decode("7c1c1ab9c454a688")));
379:
380: byte[] out = cEnc.doFinal(input);
381:
382: char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' };
383:
384: Cipher cDec = makePBECipherUsingParam("PBEWithSHA1AndDES",
385: Cipher.DECRYPT_MODE, password, Hex
386: .decode("7d60435f02e9e0ae"), 2048);
387:
388: byte[] in = cDec.doFinal(out);
389:
390: if (!arrayEquals(input, in)) {
391: fail("DES failed");
392: }
393:
394: cDec = makePBECipherWithoutParam("PBEWithSHA1AndDES",
395: Cipher.DECRYPT_MODE, password, Hex
396: .decode("7d60435f02e9e0ae"), 2048);
397:
398: in = cDec.doFinal(out);
399:
400: if (!arrayEquals(input, in)) {
401: fail("DES failed without param");
402: }
403:
404: //
405: // DESede
406: //
407: cEnc = Cipher.getInstance("DESede/CBC/PKCS7Padding", "BC");
408:
409: cEnc
410: .init(
411: Cipher.ENCRYPT_MODE,
412: new SecretKeySpec(
413: Hex
414: .decode("732f2d33c801732b7206756cbd44f9c1c103ddd97c7cbe8e"),
415: "DES"), new IvParameterSpec(Hex
416: .decode("b07bf522c8d608b8")));
417:
418: out = cEnc.doFinal(input);
419:
420: cDec = makePBECipherUsingParam(
421: "PBEWithSHAAnd3-KeyTripleDES-CBC", Cipher.DECRYPT_MODE,
422: password, Hex.decode("7d60435f02e9e0ae"), 2048);
423:
424: in = cDec.doFinal(out);
425:
426: if (!arrayEquals(input, in)) {
427: fail("DESede failed");
428: }
429:
430: //
431: // 40Bit RC2
432: //
433: cEnc = Cipher.getInstance("RC2/CBC/PKCS7Padding", "BC");
434:
435: cEnc.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Hex
436: .decode("732f2d33c8"), "RC2"), new IvParameterSpec(Hex
437: .decode("b07bf522c8d608b8")));
438:
439: out = cEnc.doFinal(input);
440:
441: cDec = makePBECipherUsingParam("PBEWithSHAAnd40BitRC2-CBC",
442: Cipher.DECRYPT_MODE, password, Hex
443: .decode("7d60435f02e9e0ae"), 2048);
444:
445: in = cDec.doFinal(out);
446:
447: if (!arrayEquals(input, in)) {
448: fail("RC2 failed");
449: }
450:
451: //
452: // 128bit RC4
453: //
454: cEnc = Cipher.getInstance("RC4", "BC");
455:
456: cEnc.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Hex
457: .decode("732f2d33c801732b7206756cbd44f9c1"), "RC4"));
458:
459: out = cEnc.doFinal(input);
460:
461: cDec = makePBECipherUsingParam("PBEWithSHAAnd128BitRC4",
462: Cipher.DECRYPT_MODE, password, Hex
463: .decode("7d60435f02e9e0ae"), 2048);
464:
465: in = cDec.doFinal(out);
466:
467: if (!arrayEquals(input, in)) {
468: fail("RC4 failed");
469: }
470:
471: cDec = makePBECipherWithoutParam("PBEWithSHAAnd128BitRC4",
472: Cipher.DECRYPT_MODE, password, Hex
473: .decode("7d60435f02e9e0ae"), 2048);
474:
475: in = cDec.doFinal(out);
476:
477: if (!arrayEquals(input, in)) {
478: fail("RC4 failed without param");
479: }
480:
481: for (int i = 0; i != pkcs12Tests.length; i++) {
482: pkcs12Tests[i].perform();
483: }
484:
485: for (int i = 0; i != openSSLTests.length; i++) {
486: openSSLTests[i].perform();
487: }
488:
489: testPBEHMac("PBEWithHMacSHA1", hMac1);
490: testPBEHMac("PBEWithHMacRIPEMD160", hMac2);
491: }
492:
493: public String getName() {
494: return "PBETest";
495: }
496:
497: public static void main(String[] args) {
498: Security.addProvider(new BouncyCastleProvider());
499:
500: runTest(new PBETest());
501: }
502: }
|