| package org.bouncycastle.crypto.test; |
| |
| import java.security.SecureRandom; |
| |
| import org.bouncycastle.crypto.Wrapper; |
| import org.bouncycastle.crypto.engines.AESWrapPadEngine; |
| import org.bouncycastle.crypto.params.KeyParameter; |
| import org.bouncycastle.crypto.params.ParametersWithIV; |
| import org.bouncycastle.util.Arrays; |
| import org.bouncycastle.util.encoders.Hex; |
| import org.bouncycastle.util.test.SimpleTest; |
| |
| /** |
| * This is a test harness I use because I cannot modify the BC test harness without |
| * invalidating the signature on their signed provider library. The code here is not |
| * high quality but it does test the RFC vectors as well as randomly generated values. |
| * The RFC test vectors are tested by making sure both the ciphertext and decrypted |
| * values match the expected values whereas the random values are just checked to make |
| * sure that: |
| * <p>unwrap(wrap(random_value, random_kek), random_kek) == random_value.</p> |
| */ |
| |
| public class AESWrapPadTest |
| extends SimpleTest |
| { |
| |
| private final int numOfRandomIterations = 100; |
| |
| public AESWrapPadTest() |
| { |
| |
| } |
| |
| private void wrapAndUnwrap(byte[] kek, byte[] key, byte[] expected) |
| throws Exception |
| { |
| Wrapper wrapper = new AESWrapPadEngine(); |
| |
| wrapper.init(true, new KeyParameter(kek)); |
| |
| byte[] cipherText = wrapper.wrap(key, 0, key.length); |
| if (!areEqual(cipherText, expected)) |
| { |
| fail("Wrapped value does not match expected."); |
| } |
| wrapper.init(false, new KeyParameter(kek)); |
| byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); |
| |
| if (!areEqual(key, plainText)) |
| { |
| fail("Unwrapped value does not match original."); |
| } |
| } |
| |
| private void wrapAndUnwrap(byte[] kek, byte[] key) |
| throws Exception |
| { |
| Wrapper wrapper = new AESWrapPadEngine(); |
| |
| wrapper.init(true, new KeyParameter(kek)); |
| |
| byte[] cipherText = wrapper.wrap(key, 0, key.length); |
| |
| wrapper.init(false, new KeyParameter(kek)); |
| byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); |
| |
| if (!areEqual(key, plainText)) |
| { |
| fail("Unwrapped value does not match original."); |
| } |
| } |
| |
| private void wrapWithIVTest() |
| throws Exception |
| { |
| byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); |
| byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738"); |
| byte[] expected = Hex.decode("5cbdb3fb71351d0e628b85dbcba1a1890d4db26d1335e11d1aabea11124caad0"); |
| |
| Wrapper wrapper = new AESWrapPadEngine(); |
| |
| wrapper.init(true, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333"))); |
| |
| byte[] cipherText = wrapper.wrap(key, 0, key.length); |
| if (!areEqual(cipherText, expected)) |
| { |
| fail("Wrapped value does not match expected."); |
| } |
| wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333"))); |
| byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); |
| |
| if (!areEqual(key, plainText)) |
| { |
| fail("Unwrapped value does not match original."); |
| } |
| } |
| |
| public String getName() |
| { |
| return "AESWrapPad"; |
| } |
| |
| public void performTest() |
| throws Exception |
| { |
| // test RFC 5649 test vectors |
| byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); |
| byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738"); |
| byte[] wrap = Hex.decode("138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"); |
| |
| wrapAndUnwrap(kek, key, wrap); |
| |
| wrap = Hex.decode("afbeb0f07dfbf5419200f2ccb50bb24f"); |
| key = Hex.decode("466f7250617369"); |
| wrapAndUnwrap(kek, key, wrap); |
| |
| wrapWithIVTest(); |
| |
| // |
| // offset test |
| // |
| Wrapper wrapper = new AESWrapPadEngine(); |
| |
| byte[] pText = new byte[5 + key.length]; |
| byte[] cText; |
| |
| System.arraycopy(key, 0, pText, 5, key.length); |
| |
| wrapper.init(true, new KeyParameter(kek)); |
| |
| cText = wrapper.wrap(pText, 5, key.length); |
| if (!Arrays.areEqual(cText, wrap)) |
| { |
| fail("failed offset wrap test expected " + new String(Hex.encode(wrap)) + " got " + new String(Hex.encode(cText))); |
| } |
| |
| wrapper.init(false, new KeyParameter(kek)); |
| |
| cText = new byte[6 + wrap.length]; |
| System.arraycopy(wrap, 0, cText, 6, wrap.length); |
| |
| pText = wrapper.unwrap(cText, 6, wrap.length); |
| if (!Arrays.areEqual(pText, key)) |
| { |
| fail("failed offset unwrap test expected " + new String(Hex.encode(key)) + " got " + new String(Hex.encode(pText))); |
| } |
| |
| // test random values |
| SecureRandom rnd = new SecureRandom(); |
| for (int i = 0; i < numOfRandomIterations; i++) |
| { |
| int kekLength = 128; |
| boolean shouldIncrease = (rnd.nextInt() & 0x01) != 0; |
| if (shouldIncrease) |
| { |
| kekLength = 256; |
| } |
| kek = new byte[kekLength / 8]; |
| rnd.nextBytes(kek); |
| int keyToWrapSize = RNGUtils.nextInt(rnd, 256 / 8 - 8) + 8; |
| byte[] keyToWrap = new byte[keyToWrapSize]; |
| rnd.nextBytes(keyToWrap); |
| wrapAndUnwrap(kek, keyToWrap); |
| } |
| } |
| |
| public static void main( |
| String[] args) |
| { |
| runTest(new AESWrapPadTest()); |
| } |
| } |
| |