From 44a91fea962afb5b6a1f88567e196f13397ef572 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 22 Jul 2023 18:32:28 +0700 Subject: Add Rfc5649WrapEngine --- crypto/src/crypto/engines/AesWrapPadEngine.cs | 13 + crypto/src/crypto/engines/AriaWrapPadEngine.cs | 13 + crypto/src/crypto/engines/RFC3394WrapEngine.cs | 119 ++++--- crypto/src/crypto/engines/Rfc5649WrapEngine.cs | 271 ++++++++++++++++ crypto/src/security/GeneratorUtilities.cs | 15 +- crypto/src/security/ParameterUtilities.cs | 15 +- crypto/src/security/WrapperUtilities.cs | 17 + crypto/test/src/test/AESTest.cs | 98 +++++- crypto/test/src/test/AriaTest.cs | 428 +++++++++++++++++++++++++ crypto/test/src/test/BaseBlockCipherTest.cs | 27 +- 10 files changed, 925 insertions(+), 91 deletions(-) create mode 100644 crypto/src/crypto/engines/AesWrapPadEngine.cs create mode 100644 crypto/src/crypto/engines/AriaWrapPadEngine.cs create mode 100644 crypto/src/crypto/engines/Rfc5649WrapEngine.cs create mode 100644 crypto/test/src/test/AriaTest.cs diff --git a/crypto/src/crypto/engines/AesWrapPadEngine.cs b/crypto/src/crypto/engines/AesWrapPadEngine.cs new file mode 100644 index 000000000..534dfd128 --- /dev/null +++ b/crypto/src/crypto/engines/AesWrapPadEngine.cs @@ -0,0 +1,13 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Engines +{ + public class AesWrapPadEngine + : Rfc5649WrapEngine + { + public AesWrapPadEngine() + : base(AesUtilities.CreateEngine()) + { + } + } +} diff --git a/crypto/src/crypto/engines/AriaWrapPadEngine.cs b/crypto/src/crypto/engines/AriaWrapPadEngine.cs new file mode 100644 index 000000000..49bebcd80 --- /dev/null +++ b/crypto/src/crypto/engines/AriaWrapPadEngine.cs @@ -0,0 +1,13 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Engines +{ + public class AriaWrapPadEngine + : Rfc5649WrapEngine + { + public AriaWrapPadEngine() + : base(new AriaEngine()) + { + } + } +} diff --git a/crypto/src/crypto/engines/RFC3394WrapEngine.cs b/crypto/src/crypto/engines/RFC3394WrapEngine.cs index e1368f25b..5713bb08a 100644 --- a/crypto/src/crypto/engines/RFC3394WrapEngine.cs +++ b/crypto/src/crypto/engines/RFC3394WrapEngine.cs @@ -5,23 +5,23 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Engines { - /// - /// An implementation of the AES Key Wrapper from the NIST Key Wrap - /// Specification as described in RFC 3394. - ///

- /// For further details see: http://www.ietf.org/rfc/rfc3394.txt - /// and http://csrc.nist.gov/encryption/kms/key-wrap.pdf. - /// - public class Rfc3394WrapEngine + ///

An implementation of the AES Key Wrap with Padding specification as described in RFC 3349. + /// + /// For further details see: Schaad, J. and R. Housley, "Advanced Encryption Standard (AES) Key Wrap Algorithm", + /// RFC 3394, DOI 10.17487/RFC3394, September 2002, , and + /// http://csrc.nist.gov/encryption/kms/key-wrap.pdf. + /// + public class Rfc3394WrapEngine : IWrapper { - private readonly IBlockCipher engine; - private readonly bool wrapCipherMode; + private static readonly byte[] DefaultIV = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 }; - private KeyParameter param; - private bool forWrapping; + private readonly IBlockCipher m_engine; + private readonly bool m_wrapCipherMode; + private readonly byte[] m_iv = new byte[8]; - private byte[] iv = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 }; + private KeyParameter m_key = null; + private bool m_forWrapping = true; public Rfc3394WrapEngine(IBlockCipher engine) : this(engine, false) @@ -30,13 +30,15 @@ namespace Org.BouncyCastle.Crypto.Engines public Rfc3394WrapEngine(IBlockCipher engine, bool useReverseDirection) { - this.engine = engine; - this.wrapCipherMode = !useReverseDirection; + m_engine = engine; + m_wrapCipherMode = !useReverseDirection; } + public virtual string AlgorithmName => m_engine.AlgorithmName; + public virtual void Init(bool forWrapping, ICipherParameters parameters) { - this.forWrapping = forWrapping; + m_forWrapping = forWrapping; if (parameters is ParametersWithRandom withRandom) { @@ -45,17 +47,17 @@ namespace Org.BouncyCastle.Crypto.Engines if (parameters is KeyParameter keyParameter) { - this.param = keyParameter; - } - else if (parameters is ParametersWithIV withIV) + m_key = keyParameter; + Array.Copy(DefaultIV, 0, m_iv, 0, 8); + } + else if (parameters is ParametersWithIV withIV) { byte[] iv = withIV.GetIV(); - if (iv.Length != 8) - throw new ArgumentException("IV length not equal to 8", "parameters"); + throw new ArgumentException("IV length not equal to 8", nameof(parameters)); - this.iv = iv; - this.param = (KeyParameter)withIV.Parameters; + m_key = (KeyParameter)withIV.Parameters; + Array.Copy(iv, 0, m_iv, 0, 8); } else { @@ -63,14 +65,9 @@ namespace Org.BouncyCastle.Crypto.Engines } } - public virtual string AlgorithmName - { - get { return engine.AlgorithmName; } - } - public virtual byte[] Wrap(byte[] input, int inOff, int inLen) { - if (!forWrapping) + if (!m_forWrapping) throw new InvalidOperationException("not set for wrapping"); if (inLen < 8) throw new DataLengthException("wrap data must be at least 8 bytes"); @@ -80,35 +77,33 @@ namespace Org.BouncyCastle.Crypto.Engines if ((n * 8) != inLen) throw new DataLengthException("wrap data must be a multiple of 8 bytes"); - engine.Init(wrapCipherMode, param); + m_engine.Init(m_wrapCipherMode, m_key); - byte[] block = new byte[inLen + iv.Length]; - Array.Copy(iv, 0, block, 0, iv.Length); - Array.Copy(input, inOff, block, iv.Length, inLen); + byte[] block = new byte[inLen + 8]; + Array.Copy(m_iv, 0, block, 0, 8); + Array.Copy(input, inOff, block, 8, inLen); if (n == 1) { - engine.ProcessBlock(block, 0, block, 0); + m_engine.ProcessBlock(block, 0, block, 0); } else { - byte[] buf = new byte[8 + iv.Length]; + byte[] buf = new byte[16]; for (int j = 0; j != 6; j++) { for (int i = 1; i <= n; i++) { - Array.Copy(block, 0, buf, 0, iv.Length); - Array.Copy(block, 8 * i, buf, iv.Length, 8); - engine.ProcessBlock(buf, 0, buf, 0); + Array.Copy(block, 0, buf, 0, 8); + Array.Copy(block, 8 * i, buf, 8, 8); + m_engine.ProcessBlock(buf, 0, buf, 0); - int t = n * j + i; - for (int k = 1; t != 0; k++) + uint t = (uint)(n * j + i); + for (int k = 1; t != 0U; k++) { - byte v = (byte)t; - - buf[iv.Length - k] ^= v; - t = (int) ((uint)t >> 8); + buf[8 - k] ^= (byte)t; + t >>= 8; } Array.Copy(buf, 0, block, 0, 8); @@ -122,7 +117,7 @@ namespace Org.BouncyCastle.Crypto.Engines public virtual byte[] Unwrap(byte[] input, int inOff, int inLen) { - if (forWrapping) + if (m_forWrapping) throw new InvalidOperationException("not set for unwrapping"); if (inLen < 16) throw new InvalidCipherTextException("unwrap data too short"); @@ -132,49 +127,47 @@ namespace Org.BouncyCastle.Crypto.Engines if ((n * 8) != inLen) throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes"); - engine.Init(!wrapCipherMode, param); + m_engine.Init(!m_wrapCipherMode, m_key); - byte[] block = new byte[inLen - iv.Length]; - byte[] a = new byte[iv.Length]; - byte[] buf = new byte[8 + iv.Length]; + byte[] block = new byte[inLen - 8]; + byte[] a = new byte[8]; + byte[] buf = new byte[16]; n = n - 1; if (n == 1) { - engine.ProcessBlock(input, inOff, buf, 0); - Array.Copy(buf, 0, a, 0, iv.Length); - Array.Copy(buf, iv.Length, block, 0, 8); + m_engine.ProcessBlock(input, inOff, buf, 0); + Array.Copy(buf, 0, a, 0, 8); + Array.Copy(buf, 8, block, 0, 8); } else { - Array.Copy(input, inOff, a, 0, iv.Length); - Array.Copy(input, inOff + iv.Length, block, 0, inLen - iv.Length); + Array.Copy(input, inOff, a, 0, 8); + Array.Copy(input, inOff + 8, block, 0, inLen - 8); for (int j = 5; j >= 0; j--) { for (int i = n; i >= 1; i--) { - Array.Copy(a, 0, buf, 0, iv.Length); - Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8); + Array.Copy(a, 0, buf, 0, 8); + Array.Copy(block, 8 * (i - 1), buf, 8, 8); - int t = n * j + i; + uint t = (uint)(n * j + i); for (int k = 1; t != 0; k++) { - byte v = (byte)t; - - buf[iv.Length - k] ^= v; - t = (int) ((uint)t >> 8); + buf[8 - k] ^= (byte)t; + t >>= 8; } - engine.ProcessBlock(buf, 0, buf, 0); + m_engine.ProcessBlock(buf, 0, buf, 0); Array.Copy(buf, 0, a, 0, 8); Array.Copy(buf, 8, block, 8 * (i - 1), 8); } } } - if (!Arrays.FixedTimeEquals(a, iv)) + if (!Arrays.FixedTimeEquals(a, m_iv)) throw new InvalidCipherTextException("checksum failed"); return block; diff --git a/crypto/src/crypto/engines/Rfc5649WrapEngine.cs b/crypto/src/crypto/engines/Rfc5649WrapEngine.cs new file mode 100644 index 000000000..09830c7e8 --- /dev/null +++ b/crypto/src/crypto/engines/Rfc5649WrapEngine.cs @@ -0,0 +1,271 @@ +using System; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Engines +{ + /// An implementation of the AES Key Wrap with Padding specification as described in RFC 5649. + /// + /// For further details see: Housley, R. and M. Dworkin, "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm", + /// RFC 5649, DOI 10.17487/RFC5649, September 2009, , and + /// http://csrc.nist.gov/encryption/kms/key-wrap.pdf. + /// + public class Rfc5649WrapEngine + : IWrapper + { + // The AIV as defined in the RFC + private static readonly byte[] DefaultIV = { 0xa6, 0x59, 0x59, 0xa6 }; + + private readonly IBlockCipher m_engine; + private readonly byte[] m_preIV = new byte[4]; + + private KeyParameter m_key = null; + private bool m_forWrapping = true; + + public Rfc5649WrapEngine(IBlockCipher engine) + { + m_engine = engine; + } + + public virtual string AlgorithmName => m_engine.AlgorithmName; + + public virtual void Init(bool forWrapping, ICipherParameters parameters) + { + m_forWrapping = forWrapping; + + if (parameters is ParametersWithRandom withRandom) + { + parameters = withRandom.Parameters; + } + + if (parameters is KeyParameter keyParameter) + { + m_key = keyParameter; + Array.Copy(DefaultIV, 0, m_preIV, 0, 4); + } + else if (parameters is ParametersWithIV withIV) + { + byte[] iv = withIV.GetIV(); + if (iv.Length != 4) + throw new ArgumentException("IV length not equal to 4", nameof(parameters)); + + m_key = (KeyParameter)withIV.Parameters; + Array.Copy(iv, 0, m_preIV, 0, 4); + } + else + { + // TODO Throw an exception for bad parameters? + } + } + + public virtual byte[] Wrap(byte[] input, int inOff, int length) + { + if (!m_forWrapping) + throw new InvalidOperationException("not set for wrapping"); + + byte[] iv = new byte[8]; + + // copy in the fixed portion of the AIV + Array.Copy(m_preIV, 0, iv, 0, 4); + // copy in the MLI (size of key to be wrapped) after the AIV + Pack.UInt32_To_BE((uint)length, iv, 4); + + // get the relevant plaintext to be wrapped + byte[] relevantPlaintext = new byte[length]; + Array.Copy(input, inOff, relevantPlaintext, 0, length); + byte[] paddedPlaintext = PadPlaintext(relevantPlaintext); + + if (paddedPlaintext.Length == 8) + { + // if the padded plaintext contains exactly 8 octets, + // then prepend iv and encrypt using AES in ECB mode. + + // prepend the IV to the plaintext + byte[] paddedPlainTextWithIV = new byte[paddedPlaintext.Length + iv.Length]; + Array.Copy(iv, 0, paddedPlainTextWithIV, 0, iv.Length); + Array.Copy(paddedPlaintext, 0, paddedPlainTextWithIV, iv.Length, paddedPlaintext.Length); + + m_engine.Init(true, m_key); + for (int i = 0, blockSize = m_engine.GetBlockSize(); i < paddedPlainTextWithIV.Length; i += blockSize) + { + m_engine.ProcessBlock(paddedPlainTextWithIV, i, paddedPlainTextWithIV, i); + } + + return paddedPlainTextWithIV; + } + else + { + // otherwise, apply the RFC 3394 wrap to + // the padded plaintext with the new IV + Rfc3394WrapEngine wrapper = new Rfc3394WrapEngine(m_engine); + ParametersWithIV paramsWithIV = new ParametersWithIV(m_key, iv); + wrapper.Init(true, paramsWithIV); + return wrapper.Wrap(paddedPlaintext, 0, paddedPlaintext.Length); + } + } + + public virtual byte[] Unwrap(byte[] input, int inOff, int length) + { + if (m_forWrapping) + throw new InvalidOperationException("not set for unwrapping"); + + int n = length / 8; + + if ((n * 8) != length) + throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes"); + + if (n <= 1) + throw new InvalidCipherTextException("unwrap data must be at least 16 bytes"); + + byte[] relevantCiphertext = new byte[length]; + Array.Copy(input, inOff, relevantCiphertext, 0, length); + byte[] decrypted = new byte[length]; + byte[] paddedPlaintext; + + byte[] extractedAIV = new byte[8]; + + if (n == 2) + { + // When there are exactly two 64-bit blocks of ciphertext, + // they are decrypted as a single block using AES in ECB. + m_engine.Init(false, m_key); + for (int i = 0, blockSize = m_engine.GetBlockSize(); i < relevantCiphertext.Length; i += blockSize) + { + m_engine.ProcessBlock(relevantCiphertext, i, decrypted, i); + } + + // extract the AIV + Array.Copy(decrypted, 0, extractedAIV, 0, 8); + paddedPlaintext = new byte[decrypted.Length - 8]; + Array.Copy(decrypted, 8, paddedPlaintext, 0, paddedPlaintext.Length); + } + else + { + // Otherwise, unwrap as per RFC 3394 but don't check IV the same way + decrypted = Rfc3394UnwrapNoIvCheck(input, inOff, length, extractedAIV); + paddedPlaintext = decrypted; + } + + // Decompose the extracted AIV to the fixed portion and the MLI + byte[] extractedHighOrderAIV = new byte[4]; + Array.Copy(extractedAIV, 0, extractedHighOrderAIV, 0, 4); + int mli = (int)Pack.BE_To_UInt32(extractedAIV, 4); + + // Even if a check fails we still continue and check everything + // else in order to avoid certain timing based side-channel attacks. + + // Check the fixed portion of the AIV + bool isValid = Arrays.FixedTimeEquals(extractedHighOrderAIV, m_preIV); + + // Check the MLI against the actual length + int upperBound = paddedPlaintext.Length; + int lowerBound = upperBound - 8; + if (mli <= lowerBound) + { + isValid = false; + } + if (mli > upperBound) + { + isValid = false; + } + + // Check the number of padding zeros + int expectedZeros = upperBound - mli; + if (expectedZeros >= 8 || expectedZeros < 0) + { + // We have to pick a "typical" amount of padding to avoid timing attacks. + isValid = false; + expectedZeros = 4; + } + + byte[] zeros = new byte[expectedZeros]; + byte[] pad = new byte[expectedZeros]; + Array.Copy(paddedPlaintext, paddedPlaintext.Length - expectedZeros, pad, 0, expectedZeros); + if (!Arrays.FixedTimeEquals(pad, zeros)) + { + isValid = false; + } + + if (!isValid) + throw new InvalidCipherTextException("checksum failed"); + + // Extract the plaintext from the padded plaintext + byte[] plaintext = new byte[mli]; + Array.Copy(paddedPlaintext, 0, plaintext, 0, plaintext.Length); + + return plaintext; + } + + /** + * Performs steps 1 and 2 of the unwrap process defined in RFC 3394. + * This code is duplicated from RFC3394WrapEngine because that class + * will throw an error during unwrap because the IV won't match up. + * + * @param in + * @param inOff + * @param inLen + * @return Unwrapped data. + */ + private byte[] Rfc3394UnwrapNoIvCheck(byte[] input, int inOff, int inLen, byte[] extractedAIV) + { + byte[] block = new byte[inLen - 8]; + byte[] buf = new byte[16]; + + Array.Copy(input, inOff, buf, 0, 8); + Array.Copy(input, inOff + 8, block, 0, inLen - 8); + + m_engine.Init(false, m_key); + + int n = inLen / 8; + n = n - 1; + + for (int j = 5; j >= 0; j--) + { + for (int i = n; i >= 1; i--) + { + Array.Copy(block, 8 * (i - 1), buf, 8, 8); + + uint t = (uint)(n * j + i); + for (int k = 1; t != 0U; k++) + { + buf[8 - k] ^= (byte)t; + t >>= 8; + } + + m_engine.ProcessBlock(buf, 0, buf, 0); + + Array.Copy(buf, 8, block, 8 * (i - 1), 8); + } + } + + Array.Copy(buf, 0, extractedAIV, 0, 8); + + return block; + } + + /** + * Pads the plaintext (i.e., the key to be wrapped) + * as per section 4.1 of RFC 5649. + * + * @param plaintext The key being wrapped. + * @return The padded key. + */ + private static byte[] PadPlaintext(byte[] plaintext) + { + int plaintextLength = plaintext.Length; + int numOfZerosToAppend = (8 - (plaintextLength % 8)) % 8; + byte[] paddedPlaintext = new byte[plaintextLength + numOfZerosToAppend]; + Array.Copy(plaintext, 0, paddedPlaintext, 0, plaintextLength); + if (numOfZerosToAppend != 0) + { + // plaintext (i.e., key to be wrapped) does not have + // a multiple of 8 octet blocks so it must be padded + byte[] zeros = new byte[numOfZerosToAppend]; + Array.Copy(zeros, 0, paddedPlaintext, plaintextLength, numOfZerosToAppend); + } + return paddedPlaintext; + } + } +} diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs index e9525b377..c310cf399 100644 --- a/crypto/src/security/GeneratorUtilities.cs +++ b/crypto/src/security/GeneratorUtilities.cs @@ -45,7 +45,8 @@ namespace Org.BouncyCastle.Security NistObjectIdentifiers.IdAes128Ecb, NistObjectIdentifiers.IdAes128Gcm, NistObjectIdentifiers.IdAes128Ofb, - NistObjectIdentifiers.IdAes128Wrap); + NistObjectIdentifiers.IdAes128Wrap, + NistObjectIdentifiers.IdAes128WrapPad); AddKgAlgorithm("AES192", SecurityUtilities.WrongAes192, NistObjectIdentifiers.IdAes192Cbc, @@ -54,7 +55,8 @@ namespace Org.BouncyCastle.Security NistObjectIdentifiers.IdAes192Ecb, NistObjectIdentifiers.IdAes192Gcm, NistObjectIdentifiers.IdAes192Ofb, - NistObjectIdentifiers.IdAes192Wrap); + NistObjectIdentifiers.IdAes192Wrap, + NistObjectIdentifiers.IdAes192WrapPad); AddKgAlgorithm("AES256", SecurityUtilities.WrongAes256, NistObjectIdentifiers.IdAes256Cbc, @@ -63,7 +65,8 @@ namespace Org.BouncyCastle.Security NistObjectIdentifiers.IdAes256Ecb, NistObjectIdentifiers.IdAes256Gcm, NistObjectIdentifiers.IdAes256Ofb, - NistObjectIdentifiers.IdAes256Wrap); + NistObjectIdentifiers.IdAes256Wrap, + NistObjectIdentifiers.IdAes256WrapPad); AddKgAlgorithm("BLOWFISH", "1.3.6.1.4.1.3029.1.2"); AddKgAlgorithm("CAMELLIA", @@ -76,6 +79,8 @@ namespace Org.BouncyCastle.Security NsriObjectIdentifiers.id_aria128_ctr, NsriObjectIdentifiers.id_aria128_ecb, NsriObjectIdentifiers.id_aria128_gcm, + NsriObjectIdentifiers.id_aria128_kw, + NsriObjectIdentifiers.id_aria128_kwp, NsriObjectIdentifiers.id_aria128_ocb2, NsriObjectIdentifiers.id_aria128_ofb); AddKgAlgorithm("ARIA192", @@ -85,6 +90,8 @@ namespace Org.BouncyCastle.Security NsriObjectIdentifiers.id_aria192_ctr, NsriObjectIdentifiers.id_aria192_ecb, NsriObjectIdentifiers.id_aria192_gcm, + NsriObjectIdentifiers.id_aria192_kw, + NsriObjectIdentifiers.id_aria192_kwp, NsriObjectIdentifiers.id_aria192_ocb2, NsriObjectIdentifiers.id_aria192_ofb); AddKgAlgorithm("ARIA256", @@ -94,6 +101,8 @@ namespace Org.BouncyCastle.Security NsriObjectIdentifiers.id_aria256_ctr, NsriObjectIdentifiers.id_aria256_ecb, NsriObjectIdentifiers.id_aria256_gcm, + NsriObjectIdentifiers.id_aria256_kw, + NsriObjectIdentifiers.id_aria256_kwp, NsriObjectIdentifiers.id_aria256_ocb2, NsriObjectIdentifiers.id_aria256_ofb); AddKgAlgorithm("CAMELLIA128", diff --git a/crypto/src/security/ParameterUtilities.cs b/crypto/src/security/ParameterUtilities.cs index c1f4492b3..690195443 100644 --- a/crypto/src/security/ParameterUtilities.cs +++ b/crypto/src/security/ParameterUtilities.cs @@ -36,7 +36,8 @@ namespace Org.BouncyCastle.Security NistObjectIdentifiers.IdAes128Ecb, NistObjectIdentifiers.IdAes128Gcm, NistObjectIdentifiers.IdAes128Ofb, - NistObjectIdentifiers.IdAes128Wrap); + NistObjectIdentifiers.IdAes128Wrap, + NistObjectIdentifiers.IdAes128WrapPad); AddAlgorithm("AES192", SecurityUtilities.WrongAes192, NistObjectIdentifiers.IdAes192Cbc, @@ -45,7 +46,8 @@ namespace Org.BouncyCastle.Security NistObjectIdentifiers.IdAes192Ecb, NistObjectIdentifiers.IdAes192Gcm, NistObjectIdentifiers.IdAes192Ofb, - NistObjectIdentifiers.IdAes192Wrap); + NistObjectIdentifiers.IdAes192Wrap, + NistObjectIdentifiers.IdAes192WrapPad); AddAlgorithm("AES256", SecurityUtilities.WrongAes256, NistObjectIdentifiers.IdAes256Cbc, @@ -54,7 +56,8 @@ namespace Org.BouncyCastle.Security NistObjectIdentifiers.IdAes256Ecb, NistObjectIdentifiers.IdAes256Gcm, NistObjectIdentifiers.IdAes256Ofb, - NistObjectIdentifiers.IdAes256Wrap); + NistObjectIdentifiers.IdAes256Wrap, + NistObjectIdentifiers.IdAes256WrapPad); AddAlgorithm("ARIA"); AddAlgorithm("ARIA128", NsriObjectIdentifiers.id_aria128_cbc, @@ -63,6 +66,8 @@ namespace Org.BouncyCastle.Security NsriObjectIdentifiers.id_aria128_ctr, NsriObjectIdentifiers.id_aria128_ecb, NsriObjectIdentifiers.id_aria128_gcm, + NsriObjectIdentifiers.id_aria128_kw, + NsriObjectIdentifiers.id_aria128_kwp, NsriObjectIdentifiers.id_aria128_ocb2, NsriObjectIdentifiers.id_aria128_ofb); AddAlgorithm("ARIA192", @@ -72,6 +77,8 @@ namespace Org.BouncyCastle.Security NsriObjectIdentifiers.id_aria192_ctr, NsriObjectIdentifiers.id_aria192_ecb, NsriObjectIdentifiers.id_aria192_gcm, + NsriObjectIdentifiers.id_aria192_kw, + NsriObjectIdentifiers.id_aria192_kwp, NsriObjectIdentifiers.id_aria192_ocb2, NsriObjectIdentifiers.id_aria192_ofb); AddAlgorithm("ARIA256", @@ -81,6 +88,8 @@ namespace Org.BouncyCastle.Security NsriObjectIdentifiers.id_aria256_ctr, NsriObjectIdentifiers.id_aria256_ecb, NsriObjectIdentifiers.id_aria256_gcm, + NsriObjectIdentifiers.id_aria256_kw, + NsriObjectIdentifiers.id_aria256_kwp, NsriObjectIdentifiers.id_aria256_ocb2, NsriObjectIdentifiers.id_aria256_ofb); AddAlgorithm("BLOWFISH", diff --git a/crypto/src/security/WrapperUtilities.cs b/crypto/src/security/WrapperUtilities.cs index e7383a054..782259d9c 100644 --- a/crypto/src/security/WrapperUtilities.cs +++ b/crypto/src/security/WrapperUtilities.cs @@ -23,8 +23,10 @@ namespace Org.BouncyCastle.Security { AESRFC3211WRAP, AESWRAP, + AESWRAPPAD, ARIARFC3211WRAP, ARIAWRAP, + ARIAWRAPPAD, CAMELLIARFC3211WRAP, CAMELLIAWRAP, DESRFC3211WRAP, @@ -47,11 +49,22 @@ namespace Org.BouncyCastle.Security Algorithms[NistObjectIdentifiers.IdAes192Wrap.Id] = "AESWRAP"; Algorithms[NistObjectIdentifiers.IdAes256Wrap.Id] = "AESWRAP"; + Algorithms["AESKWP"] = "AESWRAPPAD"; + Algorithms[NistObjectIdentifiers.IdAes128WrapPad.Id] = "AESWRAPPAD"; + Algorithms[NistObjectIdentifiers.IdAes192WrapPad.Id] = "AESWRAPPAD"; + Algorithms[NistObjectIdentifiers.IdAes256WrapPad.Id] = "AESWRAPPAD"; + Algorithms["AESRFC5649WRAP"] = "AESWRAPPAD"; + Algorithms["ARIAKW"] = "ARIAWRAP"; Algorithms[NsriObjectIdentifiers.id_aria128_kw.Id] = "ARIAWRAP"; Algorithms[NsriObjectIdentifiers.id_aria192_kw.Id] = "ARIAWRAP"; Algorithms[NsriObjectIdentifiers.id_aria256_kw.Id] = "ARIAWRAP"; + Algorithms["ARIAKWP"] = "ARIAWRAPPAD"; + Algorithms[NsriObjectIdentifiers.id_aria128_kwp.Id] = "ARIAWRAPPAD"; + Algorithms[NsriObjectIdentifiers.id_aria192_kwp.Id] = "ARIAWRAPPAD"; + Algorithms[NsriObjectIdentifiers.id_aria256_kwp.Id] = "ARIAWRAPPAD"; + Algorithms[NttObjectIdentifiers.IdCamellia128Wrap.Id] = "CAMELLIAWRAP"; Algorithms[NttObjectIdentifiers.IdCamellia192Wrap.Id] = "CAMELLIAWRAP"; Algorithms[NttObjectIdentifiers.IdCamellia256Wrap.Id] = "CAMELLIAWRAP"; @@ -85,10 +98,14 @@ namespace Org.BouncyCastle.Security return new Rfc3211WrapEngine(AesUtilities.CreateEngine()); case WrapAlgorithm.AESWRAP: return new AesWrapEngine(); + case WrapAlgorithm.AESWRAPPAD: + return new AesWrapPadEngine(); case WrapAlgorithm.ARIARFC3211WRAP: return new Rfc3211WrapEngine(new AriaEngine()); case WrapAlgorithm.ARIAWRAP: return new AriaWrapEngine(); + case WrapAlgorithm.ARIAWRAPPAD: + return new AriaWrapPadEngine(); case WrapAlgorithm.CAMELLIARFC3211WRAP: return new Rfc3211WrapEngine(new CamelliaEngine()); case WrapAlgorithm.CAMELLIAWRAP: diff --git a/crypto/test/src/test/AESTest.cs b/crypto/test/src/test/AESTest.cs index a0545239e..932f959b3 100644 --- a/crypto/test/src/test/AESTest.cs +++ b/crypto/test/src/test/AESTest.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Text; using NUnit.Framework; @@ -10,6 +9,7 @@ using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; namespace Org.BouncyCastle.Tests { @@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Tests { for (int i = 0; i != cipherTests.Length; i += 4) { - doCipherTest(int.Parse(cipherTests[i]), + DoCipherTest(int.Parse(cipherTests[i]), Hex.Decode(cipherTests[i + 1]), Hex.Decode(cipherTests[i + 2]), Hex.Decode(cipherTests[i + 3])); @@ -97,7 +97,27 @@ namespace Org.BouncyCastle.Tests wrapTest(1, "AESWrap", kek1, in1, out1); } - [Test] + [Test] + public void TestWrapRfc3211() + { + byte[] kek2 = Hex.Decode("000102030405060708090a0b0c0d0e0f"); + byte[] in2 = Hex.Decode("00112233445566778899aabbccddeeff"); + byte[] out2 = Hex.Decode("7c8798dfc802553b3f00bb4315e3a087322725c92398b9c112c74d0925c63b61"); + + wrapTest(2, "AESRFC3211WRAP", kek2, kek2, FixedSecureRandom.From(Hex.Decode("9688df2af1b7b1ac9688df2a")), in2, out2); + } + + [Test] + public void TestWrapRfc5649() + { + byte[] kek3 = Hex.Decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); + byte[] in3 = Hex.Decode("c37b7e6492584340bed12207808941155068f738"); + byte[] out3 = Hex.Decode("138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"); + + wrapTest(3, "AESWrapPad", kek3, in3, out3); + } + + [Test] public void TestWrapOids() { string[] wrapOids = @@ -110,11 +130,20 @@ namespace Org.BouncyCastle.Tests wrapOidTest(wrapOids, "AESWrap"); } - private void doCipherTest( - int strength, - byte[] keyBytes, - byte[] input, - byte[] output) + [Test] + public void TestWrapPadOids() + { + string[] wrapPadOids = + { + NistObjectIdentifiers.IdAes128WrapPad.Id, + NistObjectIdentifiers.IdAes192WrapPad.Id, + NistObjectIdentifiers.IdAes256WrapPad.Id + }; + + wrapOidTest(wrapPadOids, "AESWrapPad"); + } + + private void DoCipherTest(int strength, byte[] keyBytes, byte[] input, byte[] output) { KeyParameter key = ParameterUtilities.CreateKeyParameter("AES", keyBytes); @@ -343,15 +372,60 @@ namespace Org.BouncyCastle.Tests } } + [Test] + public void TestOcb() + { + byte[] K = Hex.Decode("000102030405060708090A0B0C0D0E0F"); + byte[] P = Hex.Decode("000102030405060708090A0B0C0D0E0F"); + byte[] N = Hex.Decode("000102030405060708090A0B"); + string T = "4CBB3E4BD6B456AF"; + byte[] C = Hex.Decode("BEA5E8798DBE7110031C144DA0B2612213CC8B747807121A" + T); + + KeyParameter key = ParameterUtilities.CreateKeyParameter("AES", K); + IBufferedCipher inCipher = CipherUtilities.GetCipher("AES/OCB/NoPadding"); + IBufferedCipher outCipher = CipherUtilities.GetCipher("AES/OCB/NoPadding"); + + inCipher.Init(true, new ParametersWithIV(key, N)); + + byte[] enc = inCipher.DoFinal(P); + if (!AreEqual(enc, C)) + { + Fail("ciphertext doesn't match in OCB"); + } + + outCipher.Init(false, new ParametersWithIV(key, N)); + + byte[] dec = outCipher.DoFinal(C); + if (!AreEqual(dec, P)) + { + Fail("plaintext doesn't match in OCB"); + } + + try + { + inCipher = CipherUtilities.GetCipher("AES/OCB/PKCS5Padding"); + + Fail("bad padding missed in OCB"); + } + catch (SecurityUtilityException) + { + // expected + } + } + public override void PerformTest() { TestCiphers(); TestWrap(); - TestOids(); + TestWrapRfc3211(); + TestWrapRfc5649(); + TestOids(); TestWrapOids(); - TestEax(); + TestWrapPadOids(); + TestEax(); TestCcm(); TestGcm(); - } - } + TestOcb(); + } + } } diff --git a/crypto/test/src/test/AriaTest.cs b/crypto/test/src/test/AriaTest.cs new file mode 100644 index 000000000..3e95ae947 --- /dev/null +++ b/crypto/test/src/test/AriaTest.cs @@ -0,0 +1,428 @@ +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Nsri; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Tests +{ + /// Basic test class for the ARIA cipher vectors from FIPS-197 + [TestFixture] + public class AriaTest + : BaseBlockCipherTest + { + internal static readonly string[] cipherTests = + { + "128", + "000102030405060708090a0b0c0d0e0f", + "00112233445566778899aabbccddeeff", + "d718fbd6ab644c739da95f3be6451778", + "192", + "000102030405060708090a0b0c0d0e0f1011121314151617", + "00112233445566778899aabbccddeeff", + "26449c1805dbe7aa25a468ce263a9e79", + "256", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "00112233445566778899aabbccddeeff", + "f92bd7c79fb72e2f2b8f80c1972d24fc" + }; + + public AriaTest() + : base("ARIA") + { + } + + [Test] + public void TestCiphers() + { + for (int i = 0; i != cipherTests.Length; i += 4) + { + DoCipherTest(int.Parse(cipherTests[i]), + Hex.Decode(cipherTests[i + 1]), + Hex.Decode(cipherTests[i + 2]), + Hex.Decode(cipherTests[i + 3])); + } + } + + [Test] + public void TestOids() + { + string[] oids = { + NsriObjectIdentifiers.id_aria128_ecb.Id, + NsriObjectIdentifiers.id_aria128_cbc.Id, + NsriObjectIdentifiers.id_aria128_ofb.Id, + NsriObjectIdentifiers.id_aria128_cfb.Id, + NsriObjectIdentifiers.id_aria192_ecb.Id, + NsriObjectIdentifiers.id_aria192_cbc.Id, + NsriObjectIdentifiers.id_aria192_ofb.Id, + NsriObjectIdentifiers.id_aria192_cfb.Id, + NsriObjectIdentifiers.id_aria256_ecb.Id, + NsriObjectIdentifiers.id_aria256_cbc.Id, + NsriObjectIdentifiers.id_aria256_ofb.Id, + NsriObjectIdentifiers.id_aria256_cfb.Id + }; + + string[] names = { + "ARIA/ECB/PKCS7Padding", + "ARIA/CBC/PKCS7Padding", + "ARIA/OFB/NoPadding", + "ARIA/CFB/NoPadding", + "ARIA/ECB/PKCS7Padding", + "ARIA/CBC/PKCS7Padding", + "ARIA/OFB/NoPadding", + "ARIA/CFB/NoPadding", + "ARIA/ECB/PKCS7Padding", + "ARIA/CBC/PKCS7Padding", + "ARIA/OFB/NoPadding", + "ARIA/CFB/NoPadding" + }; + + oidTest(oids, names, 4); + } + + [Test] + public void TestWrap() + { + byte[] kek1 = Hex.Decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.Decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.Decode("a93f148d4909d85f1aae656909879275ae597b3acf9d60db"); + + wrapTest(1, "ARIAWrap", kek1, in1, out1); + } + + [Test] + public void TestWrapRfc3211() + { + byte[] kek2 = Hex.Decode("000102030405060708090a0b0c0d0e0f"); + byte[] in2 = Hex.Decode("00112233445566778899aabbccddeeff"); + byte[] out2 = Hex.Decode("9b2d3cac0acf9d4bde7c1bdb0313fbef931f025acc77bf57d3d1cabc88b514d0"); + + wrapTest(2, "ARIARFC3211WRAP", kek2, kek2, FixedSecureRandom.From(Hex.Decode("9688df2af1b7b1ac9688df2a")), in2, out2); + } + + [Test] + public void TestWrapRfc5649() + { + byte[] kek3 = Hex.Decode("000102030405060708090a0b0c0d0e0f"); + byte[] in3 = Hex.Decode("00112233445566778899aabbccddeeff"); + byte[] out3 = Hex.Decode("ac0e22699a036ced63adeb75f4946f82dc98ad8af43b24d5"); + + wrapTest(3, "ARIAWrapPad", kek3, in3, out3); + } + + [Test] + public void TestWrapOids() + { + string[] wrapOids = + { + NsriObjectIdentifiers.id_aria128_kw.Id, + NsriObjectIdentifiers.id_aria192_kw.Id, + NsriObjectIdentifiers.id_aria256_kw.Id + }; + + wrapOidTest(wrapOids, "ARIAWrap"); + } + + [Test] + public void TestWrapPadOids() + { + string[] wrapPadOids = + { + NsriObjectIdentifiers.id_aria128_kwp.Id, + NsriObjectIdentifiers.id_aria192_kwp.Id, + NsriObjectIdentifiers.id_aria256_kwp.Id + }; + + wrapOidTest(wrapPadOids, "ARIAWrapPad"); + } + + private void DoCipherTest(int strength, byte[] keyBytes, byte[] input, byte[] output) + { + KeyParameter key = ParameterUtilities.CreateKeyParameter("ARIA", keyBytes); + + IBufferedCipher inCipher = CipherUtilities.GetCipher("ARIA/ECB/NoPadding"); + IBufferedCipher outCipher = CipherUtilities.GetCipher("ARIA/ECB/NoPadding"); + + try + { + outCipher.Init(true, key); + } + catch (Exception e) + { + Fail("ARIA failed initialisation - " + e, e); + } + + try + { + inCipher.Init(false, key); + } + catch (Exception e) + { + Fail("ARIA failed initialisation - " + e, e); + } + + // + // encryption pass + // + MemoryStream bOut = new MemoryStream(); + + CipherStream cOut = new CipherStream(bOut, null, outCipher); + + try + { + for (int i = 0; i != input.Length / 2; i++) + { + cOut.WriteByte(input[i]); + } + cOut.Write(input, input.Length / 2, input.Length - input.Length / 2); + cOut.Close(); + } + catch (IOException e) + { + Fail("ARIA failed encryption - " + e, e); + } + + byte[] bytes = bOut.ToArray(); + + if (!AreEqual(bytes, output)) + { + Fail("ARIA failed encryption - expected " + + Hex.ToHexString(output) + " got " + + Hex.ToHexString(bytes)); + } + + // + // decryption pass + // + MemoryStream bIn = new MemoryStream(bytes, false); + + CipherStream cIn = new CipherStream(bIn, inCipher, null); + + try + { +// DataInputStream dIn = new DataInputStream(cIn); + BinaryReader dIn = new BinaryReader(cIn); + + bytes = new byte[input.Length]; + + for (int i = 0; i != input.Length / 2; i++) + { +// bytes[i] = (byte)dIn.read(); + bytes[i] = dIn.ReadByte(); + } + + int remaining = bytes.Length - input.Length / 2; +// dIn.readFully(bytes, input.Length / 2, remaining); + byte[] extra = dIn.ReadBytes(remaining); + if (extra.Length < remaining) + throw new EndOfStreamException(); + extra.CopyTo(bytes, input.Length / 2); + } + catch (Exception e) + { + Fail("ARIA failed encryption - " + e, e); + } + + if (!AreEqual(bytes, input)) + { + Fail("ARIA failed decryption - expected " + + Hex.ToHexString(input) + " got " + + Hex.ToHexString(bytes)); + } + } + + [Test] + public void TestEax() + { + byte[] K = Hex.Decode("233952DEE4D5ED5F9B9C6D6FF80FF478"); + byte[] N = Hex.Decode("62EC67F9C3A4A407FCB2A8C49031A8B3"); + byte[] P = Hex.Decode("68656c6c6f20776f726c642121"); + byte[] C = Hex.Decode("85fe63d6cfb872d2420e65425c074dfad6fe752e03"); + + KeyParameter key = ParameterUtilities.CreateKeyParameter("ARIA", K); + IBufferedCipher inCipher = CipherUtilities.GetCipher("ARIA/EAX/NoPadding"); + IBufferedCipher outCipher = CipherUtilities.GetCipher("ARIA/EAX/NoPadding"); + + inCipher.Init(true, new ParametersWithIV(key, N)); + + byte[] enc = inCipher.DoFinal(P); + if (!AreEqual(enc, C)) + { + Fail("ciphertext doesn't match in EAX"); + } + + outCipher.Init(false, new ParametersWithIV(key, N)); + + byte[] dec = outCipher.DoFinal(C); + if (!AreEqual(dec, P)) + { + Fail("plaintext doesn't match in EAX"); + } + + try + { + inCipher = CipherUtilities.GetCipher("ARIA/EAX/PKCS5Padding"); + + Fail("bad padding missed in EAX"); + } + catch (SecurityUtilityException) + { + // expected + } + } + + [Test] + public void TestCcm() + { + byte[] K = Hex.Decode("404142434445464748494a4b4c4d4e4f"); + byte[] N = Hex.Decode("10111213141516"); + byte[] P = Hex.Decode("68656c6c6f20776f726c642121"); + byte[] C = Hex.Decode("0af625ff69cd9dbe65fae181d654717eb7a0263bcd"); + + KeyParameter key = ParameterUtilities.CreateKeyParameter("ARIA", K); + + IBufferedCipher inCipher = CipherUtilities.GetCipher("ARIA/CCM/NoPadding"); + IBufferedCipher outCipher = CipherUtilities.GetCipher("ARIA/CCM/NoPadding"); + + inCipher.Init(true, new ParametersWithIV(key, N)); + + byte[] enc = inCipher.DoFinal(P); + if (!AreEqual(enc, C)) + { + Fail("ciphertext doesn't match in CCM"); + } + + outCipher.Init(false, new ParametersWithIV(key, N)); + + byte[] dec = outCipher.DoFinal(C); + if (!AreEqual(dec, P)) + { + Fail("plaintext doesn't match in CCM"); + } + + try + { + inCipher = CipherUtilities.GetCipher("ARIA/CCM/PKCS5Padding"); + + Fail("bad padding missed in CCM"); + } + catch (SecurityUtilityException) + { + // expected + } + } + + [Test] + public void TestGcm() + { + // Test Case 15 from McGrew/Viega + byte[] K = Hex.Decode( + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308"); + byte[] P = Hex.Decode( + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255"); + byte[] N = Hex.Decode("cafebabefacedbaddecaf888"); + string T = "c8f245c8619ca9ba7d6d9545e7f48214"; + byte[] C = Hex.Decode( + "c3aa0e01a4f8b5dfdb25d0f1c78c275e516114080e2be7a7f7bffd4504b19a8552f80ad5b55f3d911725489629996d398d5ed6f077e22924c5b8ebe20a219693" + + T); + + KeyParameter key = ParameterUtilities.CreateKeyParameter("ARIA", K); + IBufferedCipher inCipher = CipherUtilities.GetCipher("ARIA/GCM/NoPadding"); + IBufferedCipher outCipher = CipherUtilities.GetCipher("ARIA/GCM/NoPadding"); + + inCipher.Init(true, new ParametersWithIV(key, N)); + + byte[] enc = inCipher.DoFinal(P); + if (!AreEqual(enc, C)) + { + Fail("ciphertext doesn't match in GCM"); + } + + outCipher.Init(false, new ParametersWithIV(key, N)); + + byte[] dec = outCipher.DoFinal(C); + if (!AreEqual(dec, P)) + { + Fail("plaintext doesn't match in GCM"); + } + + try + { + inCipher = CipherUtilities.GetCipher("ARIA/GCM/PKCS5Padding"); + + Fail("bad padding missed in GCM"); + } + catch (SecurityUtilityException) + { + // expected + } + } + + [Test] + public void TestOcb() + { + byte[] K = Hex.Decode("000102030405060708090A0B0C0D0E0F"); + byte[] P = Hex.Decode("000102030405060708090A0B0C0D0E0F"); + byte[] N = Hex.Decode("000102030405060708090A0B"); + string T = "0027ce4f3aaeec75"; + byte[] C = Hex.Decode("7bcae9eac9f1f54704a630e309099a87f53a1c1559de1b3b" + T); + + KeyParameter key = ParameterUtilities.CreateKeyParameter("ARIA", K); + IBufferedCipher inCipher = CipherUtilities.GetCipher("ARIA/OCB/NoPadding"); + IBufferedCipher outCipher = CipherUtilities.GetCipher("ARIA/OCB/NoPadding"); + + inCipher.Init(true, new ParametersWithIV(key, N)); + + byte[] enc = inCipher.DoFinal(P); + if (!AreEqual(enc, C)) + { + Fail("ciphertext doesn't match in OCB"); + } + + outCipher.Init(false, new ParametersWithIV(key, N)); + + byte[] dec = outCipher.DoFinal(C); + if (!AreEqual(dec, P)) + { + Fail("plaintext doesn't match in OCB"); + } + + try + { + inCipher = CipherUtilities.GetCipher("ARIA/OCB/PKCS5Padding"); + + Fail("bad padding missed in OCB"); + } + catch (SecurityUtilityException) + { + // expected + } + } + + public override void PerformTest() + { + TestCiphers(); + TestWrap(); + TestWrapRfc3211(); + TestWrapRfc5649(); + TestOids(); + TestWrapOids(); + TestWrapPadOids(); + TestEax(); + TestCcm(); + TestGcm(); + TestOcb(); + } + } +} diff --git a/crypto/test/src/test/BaseBlockCipherTest.cs b/crypto/test/src/test/BaseBlockCipherTest.cs index 2997126f6..2381d92b0 100644 --- a/crypto/test/src/test/BaseBlockCipherTest.cs +++ b/crypto/test/src/test/BaseBlockCipherTest.cs @@ -94,23 +94,30 @@ namespace Org.BouncyCastle.Tests } } - protected void wrapTest( - int id, - string wrappingAlgorithm, - byte[] kek, - byte[] inBytes, - byte[] outBytes) + protected void wrapTest(int id, string wrappingAlgorithm, byte[] kek, byte[] inBytes, byte[] outBytes) { + wrapTest(id, wrappingAlgorithm, kek, null, null, inBytes, outBytes); + } + + protected void wrapTest(int id, string wrappingAlgorithm, byte[] kek, byte[] iv, SecureRandom rand, + byte[] inBytes, byte[] outBytes) + { IWrapper wrapper = WrapperUtilities.GetWrapper(wrappingAlgorithm); - wrapper.Init(true, ParameterUtilities.CreateKeyParameter(algorithm, kek)); + ICipherParameters cp = ParameterUtilities.CreateKeyParameter(algorithm, kek); + if (iv != null) + { + cp = new ParametersWithIV(cp, iv); + } + + wrapper.Init(true, ParameterUtilities.WithRandom(cp, rand)); try { byte[] cText = wrapper.Wrap(inBytes, 0, inBytes.Length); if (!AreEqual(cText, outBytes)) { - Fail("failed wrap test " + id + " expected " + Fail("failed wrap test " + id + " expected " + Hex.ToHexString(outBytes) + " got " + Hex.ToHexString(cText)); } @@ -124,7 +131,7 @@ namespace Org.BouncyCastle.Tests Fail("failed wrap test exception " + e.ToString(), e); } - wrapper.Init(false, ParameterUtilities.CreateKeyParameter(algorithm, kek)); + wrapper.Init(false, cp); try { @@ -132,7 +139,7 @@ namespace Org.BouncyCastle.Tests if (!AreEqual(pTextBytes, inBytes)) { - Fail("failed unwrap test " + id + " expected " + Fail("failed unwrap test " + id + " expected " + Hex.ToHexString(inBytes) + " got " + Hex.ToHexString(pTextBytes)); } -- cgit 1.4.1