package org.bouncycastle.jce.provider.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.security.Key; import java.security.SecureRandom; import java.security.Security; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; /** * basic test class for key generation for a DES-EDE block cipher, basically * this just exercises the provider, and makes sure we are behaving sensibly, * correctness of the implementation is shown in the lightweight test classes. */ public class DESedeTest extends SimpleTest { static String[] cipherTests1 = { "112", "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394", "128", "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394", "168", "50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89", "192", "50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89", }; static byte[] input1 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); /** * a fake random number generator - we just want to make sure the random numbers * aren't random so that we get the same output, while still getting to test the * key generation facilities. */ private class FixedSecureRandom extends SecureRandom { byte[] seed = { (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59, (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4, (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde, (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f }; public void nextBytes( byte[] bytes) { int offset = 0; while ((offset + seed.length) < bytes.length) { System.arraycopy(seed, 0, bytes, offset, seed.length); offset += seed.length; } System.arraycopy(seed, 0, bytes, offset, bytes.length - offset); } } public String getName() { return "DESEDE"; } private boolean equalArray( byte[] a, byte[] b) { if (a.length != b.length) { return false; } for (int i = 0; i != a.length; i++) { if (a[i] != b[i]) { return false; } } return true; } private boolean equalArray( byte[] a, byte[] b, int length) { if (a.length < length) { return false; } if (b.length < length) { return false; } for (int i = 0; i != length; i++) { if (a[i] != b[i]) { return false; } } return true; } private void wrapTest( int id, byte[] kek, byte[] iv, byte[] in, byte[] out) { try { Cipher wrapper = Cipher.getInstance("DESedeWrap", "BC"); wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, "DESEDE"), new IvParameterSpec(iv)); try { byte[] cText = wrapper.wrap(new SecretKeySpec(in, "DESEDE")); if (!equalArray(cText, out)) { fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); } } catch (Exception e) { fail("failed wrap test exception " + e.toString()); } wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, "DESEDE")); try { Key pText = wrapper.unwrap(out, "DESede", Cipher.SECRET_KEY); if (!equalArray(pText.getEncoded(), in)) { fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded()))); } } catch (Exception e) { fail("failed unwrap test exception " + e.toString()); } } catch (Exception ex) { fail("failed exception " + ex.toString()); } } public void test( int strength, byte[] input, byte[] output) { Key key = null; KeyGenerator keyGen; SecureRandom rand; Cipher in = null; Cipher out = null; CipherInputStream cIn; CipherOutputStream cOut; ByteArrayInputStream bIn; ByteArrayOutputStream bOut; rand = new FixedSecureRandom(); try { keyGen = KeyGenerator.getInstance("DESEDE", "BC"); keyGen.init(strength, rand); key = keyGen.generateKey(); in = Cipher.getInstance("DESEDE/ECB/PKCS7Padding", "BC"); out = Cipher.getInstance("DESEDE/ECB/PKCS7Padding", "BC"); out.init(Cipher.ENCRYPT_MODE, key, rand); } catch (Exception e) { fail("DESEDE failed initialisation - " + e.toString()); } try { in.init(Cipher.DECRYPT_MODE, key); } catch (Exception e) { fail("DESEDE failed initialisation - " + e.toString()); } // // encryption pass // bOut = new ByteArrayOutputStream(); cOut = new CipherOutputStream(bOut, out); try { for (int i = 0; i != input.length / 2; i++) { cOut.write(input[i]); } cOut.write(input, input.length / 2, input.length - input.length / 2); cOut.close(); } catch (IOException e) { fail("DESEDE failed encryption - " + e.toString()); } byte[] bytes; bytes = bOut.toByteArray(); if (!equalArray(bytes, output)) { fail("DESEDE failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); } // // decryption pass // bIn = new ByteArrayInputStream(bytes); cIn = new CipherInputStream(bIn, in); try { DataInputStream dIn = new DataInputStream(cIn); bytes = new byte[input.length]; for (int i = 0; i != input.length / 2; i++) { bytes[i] = (byte)dIn.read(); } dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); } catch (Exception e) { fail("DESEDE failed encryption - " + e.toString()); } if (!equalArray(bytes, input)) { fail("DESEDE failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); } // // keyspec test // try { SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede", "BC"); DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class); if (!equalArray(key.getEncoded(), keySpec.getKey(), 16)) { fail("DESEDE KeySpec does not match key."); } } catch (Exception e) { fail("DESEDE failed keyspec - " + e.toString()); } } public void performTest() { for (int i = 0; i != cipherTests1.length; i += 2) { test(Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1])); } byte[] kek1 = Hex.decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f"); byte[] iv1 = Hex.decode("5dd4cbfc96f5453b"); byte[] in1 = Hex.decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98"); byte[] out1 = Hex.decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4"); wrapTest(1, kek1, iv1, in1, out1); } public static void main( String[] args) { Security.addProvider(new BouncyCastleProvider()); runTest(new DESedeTest()); } }