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
{
- /// <remarks>
- /// An implementation of the AES Key Wrapper from the NIST Key Wrap
- /// Specification as described in RFC 3394.
- /// <p/>
- /// For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
- /// and <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
- /// </remarks>
- public class Rfc3394WrapEngine
+ /// <summary>An implementation of the AES Key Wrap with Padding specification as described in RFC 3349.</summary>
+ /// <remarks>
+ /// For further details see: Schaad, J. and R. Housley, "Advanced Encryption Standard (AES) Key Wrap Algorithm",
+ /// RFC 3394, DOI 10.17487/RFC3394, September 2002, <https://www.rfc-editor.org/info/rfc3394>, and
+ /// http://csrc.nist.gov/encryption/kms/key-wrap.pdf.
+ /// </remarks>
+ 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
+{
+ /// <summary>An implementation of the AES Key Wrap with Padding specification as described in RFC 5649.</summary>
+ /// <remarks>
+ /// 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, <https://www.rfc-editor.org/info/rfc5649>, and
+ /// http://csrc.nist.gov/encryption/kms/key-wrap.pdf.
+ /// </remarks>
+ 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
+{
+ /// <remarks>Basic test class for the ARIA cipher vectors from FIPS-197</remarks>
+ [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));
}
|