package org.bouncycastle.crypto.test; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Wrapper; import org.bouncycastle.crypto.engines.DESEngine; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.engines.RFC3211WrapEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; import java.security.SecureRandom; /** * Wrap Test based on RFC3211 test vectors */ public class RFC3211WrapTest extends SimpleTest { SecureRandom r1 = new SecureRandom() { int[] ints = { 0xC4, 0x36, 0xF5, 0x41 }; int count = 0; public int nextInt() { return ints[count++]; } }; SecureRandom r2 = new SecureRandom() { int[] ints = { 0xFA, 0x06, 0x0A, 0x45 }; int count = 0; public int nextInt() { return ints[count++]; } }; public String getName() { return "RFC3211Wrap"; } private void wrapTest( int id, BlockCipher engine, byte[] kek, byte[] iv, SecureRandom rand, byte[] in, byte[] out) throws Exception { Wrapper wrapper = new RFC3211WrapEngine(engine); wrapper.init(true, new ParametersWithRandom(new ParametersWithIV(new KeyParameter(kek), iv), rand)); byte[] cText = wrapper.wrap(in, 0, in.length); if (!Arrays.areEqual(cText, out)) { fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); } wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), iv)); byte[] pText = wrapper.unwrap(out, 0, out.length); if (!Arrays.areEqual(pText, in)) { fail("rfailed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); } } private void testCorruption() throws InvalidCipherTextException { byte[] kek = Hex.decode("D1DAA78615F287E6"); byte[] iv = Hex.decode("EFE598EF21B33D6D"); Wrapper wrapper = new RFC3211WrapEngine(new DESEngine()); wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), iv)); byte[] block = Hex.decode("ff739D838C627C897323A2F8C436F541"); encryptBlock(kek, iv, block); try { wrapper.unwrap(block, 0, block.length); fail("bad length not detected"); } catch (InvalidCipherTextException e) { if (!e.getMessage().equals("wrapped key corrupted")) { fail("wrong exception on length"); } } block = Hex.decode("08639D838C627C897323A2F8C436F541"); testChecksum(kek, iv, block, wrapper); block = Hex.decode("08736D838C627C897323A2F8C436F541"); testChecksum(kek, iv, block, wrapper); block = Hex.decode("08739D638C627C897323A2F8C436F541"); testChecksum(kek, iv, block, wrapper); } private void testChecksum(byte[] kek, byte[] iv, byte[] block, Wrapper wrapper) { encryptBlock(kek, iv, block); try { wrapper.unwrap(block, 0, block.length); fail("bad checksum not detected"); } catch (InvalidCipherTextException e) { if (!e.getMessage().equals("wrapped key fails checksum")) { fail("wrong exception"); } } } private void encryptBlock(byte[] key, byte[] iv, byte[] cekBlock) { BlockCipher engine = new CBCBlockCipher(new DESEngine()); engine.init(true, new ParametersWithIV(new KeyParameter(key), iv)); for (int i = 0; i < cekBlock.length; i += 8) { engine.processBlock(cekBlock, i, cekBlock, i); } for (int i = 0; i < cekBlock.length; i += 8) { engine.processBlock(cekBlock, i, cekBlock, i); } } public void performTest() throws Exception { wrapTest(1, new DESEngine(), Hex.decode("D1DAA78615F287E6"), Hex.decode("EFE598EF21B33D6D"), r1, Hex.decode("8C627C897323A2F8"), Hex.decode("B81B2565EE373CA6DEDCA26A178B0C10")); wrapTest(2, new DESedeEngine(), Hex.decode("6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"), Hex.decode("BAF1CA7931213C4E"), r2, Hex.decode("8C637D887223A2F965B566EB014B0FA5D52300A3F7EA40FFFC577203C71BAF3B"), Hex.decode("C03C514ABDB9E2C5AAC038572B5E24553876B377AAFB82ECA5A9D73F8AB143D9EC74E6CAD7DB260C")); testCorruption(); Wrapper wrapper = new RFC3211WrapEngine(new DESEngine()); ParametersWithIV params = new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]); byte[] buf = new byte[16]; try { wrapper.init(true, params); wrapper.unwrap(buf, 0, buf.length); fail("failed unwrap state test."); } catch (IllegalStateException e) { // expected } catch (InvalidCipherTextException e) { fail("unexpected exception: " + e, e); } try { wrapper.init(false, params); wrapper.wrap(buf, 0, buf.length); fail("failed unwrap state test."); } catch (IllegalStateException e) { // expected } // // short test // try { wrapper.init(false, params); wrapper.unwrap(buf, 0, buf.length / 2); fail("failed unwrap short test."); } catch (InvalidCipherTextException e) { // expected } } public static void main( String[] args) { runTest(new RFC3211WrapTest()); } }