summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src')
-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
7 files changed, 394 insertions, 69 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: