summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/crypto/engines/RC2WrapEngine.cs248
1 files changed, 93 insertions, 155 deletions
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
index 20768701f..0dd20c176 100644
--- a/crypto/src/crypto/engines/RC2WrapEngine.cs
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -111,96 +111,66 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param inLen
 		* @return
 		*/
-        public virtual byte[] Wrap(
-			byte[]	input,
-			int		inOff,
-			int		length)
+        public virtual byte[] Wrap(byte[] input, int inOff, int length)
 		{
 			if (!forWrapping)
-			{
 				throw new InvalidOperationException("Not initialized for wrapping");
-			}
 
-			int len = length + 1;
-			if ((len % 8) != 0)
-			{
-				len += 8 - (len % 8);
-			}
+			int len = (length + 8) & ~7;
+			int ivLen = iv.Length;
 
-			byte [] keyToBeWrapped = new byte[len];
+            // Let TEMP = IV || WKCKS.
+            byte[] TEMP = Arrays.CopyOf(iv, ivLen + len + 8);
+			TEMP[ivLen] = (byte)length;
+			Array.Copy(input, inOff, TEMP, ivLen + 1, length);
 
-			keyToBeWrapped[0] = (byte)length;
-			Array.Copy(input, inOff, keyToBeWrapped, 1, length);
-
-			byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
-
-			if (pad.Length > 0)
+            int padLen = len - length - 1;
+			if (padLen > 0)
 			{
-				sr.NextBytes(pad);
-				Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
-			}
+                sr.NextBytes(TEMP, ivLen + len - padLen, padLen);
+            }
 
-			// Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
-			byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+            // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+            CalculateCmsKeyChecksum(TEMP, ivLen, len, TEMP, ivLen + len);
 
-			// Let WKCKS = WK || CKS where || is concatenation.
-			byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
-
-			Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
-			Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
-
-			// Encrypt WKCKS in CBC mode using KEK as the key and IV as the
-			// initialization vector. Call the results TEMP1.
-			byte [] TEMP1 = new byte[WKCKS.Length];
-
-			Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
-
-			int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
-			int extraBytes = WKCKS.Length % engine.GetBlockSize();
-
-			if (extraBytes != 0)
-			{
-				throw new InvalidOperationException("Not multiple of block length");
-			}
+            int blockSize = engine.GetBlockSize();
 
-			engine.Init(true, paramPlusIV);
+            // Encrypt WKCKS in CBC mode using KEK as the key and IV as the initialization vector.
+            {
+                engine.Init(true, paramPlusIV);
 
-			for (int i = 0; i < noOfBlocks; i++)
-			{
-				int currentBytePos = i * engine.GetBlockSize();
+				int pos = ivLen;
+				while (pos < TEMP.Length)
+				{
+					engine.ProcessBlock(TEMP, pos, TEMP, pos);
+					pos += blockSize;
+				}
 
-				engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+				if (pos != TEMP.Length)
+					throw new InvalidOperationException("Not multiple of block length");
 			}
 
-			// Left TEMP2 = IV || TEMP1.
-			byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
-
-			Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
-			Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
-
-			// Reverse the order of the octets in TEMP2 and call the result TEMP3.
-			byte[] TEMP3 = new byte[TEMP2.Length];
-
-			for (int i = 0; i < TEMP2.Length; i++)
-			{
-				TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
-			}
+			// Reverse the order of the octets in TEMP.
+			Array.Reverse(TEMP);
 
-			// Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+			// Encrypt TEMP in CBC mode using the KEK and an initialization vector
 			// of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
 			// result. It is 40 octets long if a 168 bit key is being wrapped.
-			ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
-
-			this.engine.Init(true, param2);
-
-			for (int i = 0; i < noOfBlocks + 1; i++)
 			{
-				int currentBytePos = i * engine.GetBlockSize();
+                engine.Init(true, new ParametersWithIV(this.parameters, IV2));
 
-				engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
-			}
+                int pos = 0;
+                while (pos < TEMP.Length)
+                {
+                    engine.ProcessBlock(TEMP, pos, TEMP, pos);
+                    pos += blockSize;
+                }
 
-			return TEMP3;
+                if (pos != TEMP.Length)
+                    throw new InvalidOperationException("Not multiple of block length");
+            }
+
+            return TEMP;
 		}
 
 		/**
@@ -212,28 +182,16 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return
 		* @throws InvalidCipherTextException
 		*/
-        public virtual byte[] Unwrap(
-			byte[]	input,
-			int		inOff,
-			int		length)
+        public virtual byte[] Unwrap(byte[] input, int inOff, int length)
 		{
 			if (forWrapping)
-			{
 				throw new InvalidOperationException("Not set for unwrapping");
-			}
-
 			if (input == null)
-			{
 				throw new InvalidCipherTextException("Null pointer as ciphertext");
-			}
-
 			if (length % engine.GetBlockSize() != 0)
-			{
-				throw new InvalidCipherTextException("Ciphertext not multiple of "
-					+ engine.GetBlockSize());
-			}
+				throw new InvalidCipherTextException("Ciphertext not multiple of " + engine.GetBlockSize());
 
-			/*
+            /*
 			// Check if the length of the cipher text is reasonable given the key
 			// type. It must be 40 bytes for a 168 bit key and either 32, 40, or
 			// 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
@@ -249,82 +207,64 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 			*/
 
-			// Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
-			// and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
-			ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
-
-			this.engine.Init(false, param2);
+            int blockSize = engine.GetBlockSize();
 
-			byte [] TEMP3 = new byte[length];
+			byte[] TEMP = new byte[length];
 
-			Array.Copy(input, inOff, TEMP3, 0, length);
+            // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+            // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP.
+            {
+                engine.Init(false, new ParametersWithIV(this.parameters, IV2));
 
-			for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
-			{
-				int currentBytePos = i * engine.GetBlockSize();
-
-				engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
-			}
-
-			// Reverse the order of the octets in TEMP3 and call the result TEMP2.
-			byte[] TEMP2 = new byte[TEMP3.Length];
-
-			for (int i = 0; i < TEMP3.Length; i++)
-			{
-				TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
-			}
-
-			// Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
-			this.iv = new byte[8];
-
-			byte[] TEMP1 = new byte[TEMP2.Length - 8];
-
-			Array.Copy(TEMP2, 0, this.iv, 0, 8);
-			Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+                int pos = 0;
+				while (pos < TEMP.Length)
+				{
+					engine.ProcessBlock(input, inOff + pos, TEMP, pos);
+					pos += blockSize;
+				}
 
-			// Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
-			// found in the previous step. Call the result WKCKS.
-			this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+                if (pos != TEMP.Length)
+                    throw new InvalidOperationException("Not multiple of block length");
+            }
 
-			this.engine.Init(false, this.paramPlusIV);
+            // Reverse the order of the octets in TEMP.
+            Array.Reverse(TEMP);
 
-			byte[] LCEKPADICV = new byte[TEMP1.Length];
+			// Decompose TEMP into IV, the first 8 octets, and LCEKPADICV, the remaining octets.
+			this.iv = Arrays.CopyOf(TEMP, 8);
 
-			Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
+            // Decrypt LCEKPADICV using TRIPLedeS in CBC mode using the KEK and the IV
+            // found in the previous step. Call the result WKCKS.
+            this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
 
-			for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
 			{
-				int currentBytePos = i * engine.GetBlockSize();
+				this.engine.Init(false, this.paramPlusIV);
 
-				engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
-			}
+				int pos = 8;
+				while (pos < TEMP.Length)
+				{
+					engine.ProcessBlock(TEMP, pos, TEMP, pos);
+					pos += blockSize;
+				}
 
-			// Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
-			// those octets before the CKS.
-			byte[] result = new byte[LCEKPADICV.Length - 8];
-			byte[] CKStoBeVerified = new byte[8];
+                if (pos != TEMP.Length)
+                    throw new InvalidOperationException("Not multiple of block length");
+            }
 
-			Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
-			Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8);
+            // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
+            // those octets before the CKS.
 
-			// Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
-			// with the CKS extracted in the above step. If they are not equal, return error.
-			if (!CheckCmsKeyChecksum(result, CKStoBeVerified))
-			{
-				throw new InvalidCipherTextException(
-					"Checksum inside ciphertext is corrupted");
-			}
+            // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+            // with the CKS extracted in the above step. If they are not equal, return error.
+            if (!CheckCmsKeyChecksum(TEMP, 8, TEMP.Length - 16, TEMP, TEMP.Length - 8))
+				throw new InvalidCipherTextException("Checksum inside ciphertext is corrupted");
 
-			if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
-			{
-				throw new InvalidCipherTextException(
-					"too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
-			}
+			int padLen = TEMP.Length - 16 - TEMP[8] - 1;
+            if ((padLen & 7) != padLen)
+				throw new InvalidCipherTextException("Invalid padding length (" + padLen + ")");
 
 			// CEK is the wrapped key, now extracted for use in data decryption.
-			byte[] CEK = new byte[result[0]];
-			Array.Copy(result, 1, CEK, 0, CEK.Length);
-			return CEK;
+			return Arrays.CopyOfRange(TEMP, 9, 9 + TEMP[8]);
 		}
 
 		/**
@@ -340,15 +280,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @throws Exception
 		* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
 		*/
-		private byte[] CalculateCmsKeyChecksum(
-			byte[] key)
+		private void CalculateCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
 		{
-			sha1.BlockUpdate(key, 0, key.Length);
+			sha1.BlockUpdate(key, keyOff, keyLen);
 			sha1.DoFinal(digest, 0);
 
-			byte[] result = new byte[8];
-			Array.Copy(digest, 0, result, 0, 8);
-			return result;
+			Array.Copy(digest, 0, cks, cksOff, 8);
 		}
 
 		/**
@@ -357,11 +294,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return
 		* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
 		*/
-		private bool CheckCmsKeyChecksum(
-			byte[]	key,
-			byte[]	checksum)
+		private bool CheckCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
 		{
-			return Arrays.FixedTimeEquals(CalculateCmsKeyChecksum(key), checksum);
+            sha1.BlockUpdate(key, keyOff, keyLen);
+            sha1.DoFinal(digest, 0);
+
+            return Arrays.FixedTimeEquals(8, digest, 0, cks, cksOff);
 		}
 	}
 }