summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-07-22 18:32:28 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-07-22 18:32:28 +0700
commit44a91fea962afb5b6a1f88567e196f13397ef572 (patch)
tree08d5295aa38572898a20bd0dc32ed2b3bd28ab52
parentAdd explanatory comment for "wrong AES OIDs" (diff)
downloadBouncyCastle.NET-ed25519-44a91fea962afb5b6a1f88567e196f13397ef572.tar.xz
Add Rfc5649WrapEngine
-rw-r--r--crypto/src/crypto/engines/AesWrapPadEngine.cs13
-rw-r--r--crypto/src/crypto/engines/AriaWrapPadEngine.cs13
-rw-r--r--crypto/src/crypto/engines/RFC3394WrapEngine.cs119
-rw-r--r--crypto/src/crypto/engines/Rfc5649WrapEngine.cs271
-rw-r--r--crypto/src/security/GeneratorUtilities.cs15
-rw-r--r--crypto/src/security/ParameterUtilities.cs15
-rw-r--r--crypto/src/security/WrapperUtilities.cs17
-rw-r--r--crypto/test/src/test/AESTest.cs98
-rw-r--r--crypto/test/src/test/AriaTest.cs428
-rw-r--r--crypto/test/src/test/BaseBlockCipherTest.cs27
10 files changed, 925 insertions, 91 deletions
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));
 				}