summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-05-29 17:34:36 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-05-29 17:34:36 +0700
commit3e1cd145fc0c700ea267dc4e30e6f0ebd99f9c04 (patch)
tree1dacd33f47bb0fe7195d9c09ba87a3e177bf643c
parentCorrect the error message (diff)
downloadBouncyCastle.NET-ed25519-3e1cd145fc0c700ea267dc4e30e6f0ebd99f9c04.tar.xz
HC128Engine: require exactly 128 bits of IV
-rw-r--r--crypto/Readme.html1
-rw-r--r--crypto/src/crypto/engines/HC128Engine.cs91
-rw-r--r--crypto/src/crypto/engines/HC256Engine.cs112
-rw-r--r--crypto/test/src/test/CipherStreamTest.cs2
4 files changed, 71 insertions, 135 deletions
diff --git a/crypto/Readme.html b/crypto/Readme.html
index a7c903371..cfbfd33f3 100644
--- a/crypto/Readme.html
+++ b/crypto/Readme.html
@@ -333,6 +333,7 @@
         <h5>Defects Fixed</h5>
         <ul>
             <li>AsconEngine: Fixed a buffering bug when decrypting across multiple ProcessBytes calls (ascon128a unaffected).</li>
+            <li>HC128Engine now strictly requires 128 bits of IV.</li>
         </ul>
         <h5>Additional Features and Functionality</h5>
         <ul>
diff --git a/crypto/src/crypto/engines/HC128Engine.cs b/crypto/src/crypto/engines/HC128Engine.cs
index 6971361dd..3fda071a7 100644
--- a/crypto/src/crypto/engines/HC128Engine.cs
+++ b/crypto/src/crypto/engines/HC128Engine.cs
@@ -22,38 +22,28 @@ namespace Org.BouncyCastle.Crypto.Engines
 	public class HC128Engine
 		: IStreamCipher
 	{
-		private uint[] p = new uint[512];
-		private uint[] q = new uint[512];
+		private readonly uint[] p = new uint[512];
+		private readonly uint[] q = new uint[512];
 		private uint cnt = 0;
 
 		private static uint F1(uint x)
 		{
-			return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
+			return Integers.RotateRight(x, 7) ^ Integers.RotateRight(x, 18) ^ (x >> 3);
 		}
 
 		private static uint F2(uint x)
 		{
-			return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
+			return Integers.RotateRight(x, 17) ^ Integers.RotateRight(x, 19) ^ (x >> 10);
 		}
 
 		private uint G1(uint x, uint y, uint z)
 		{
-			return (RotateRight(x, 10) ^ RotateRight(z, 23)) + RotateRight(y, 8);
+			return (Integers.RotateRight(x, 10) ^ Integers.RotateRight(z, 23)) + Integers.RotateRight(y, 8);
 		}
 
 		private uint G2(uint x, uint y, uint z)
 		{
-			return (RotateLeft(x, 10) ^ RotateLeft(z, 23)) + RotateLeft(y, 8);
-		}
-
-		private static uint RotateLeft(uint	x, int bits)
-		{
-			return (x << bits) | (x >> -bits);
-		}
-
-		private static uint RotateRight(uint x, int bits)
-		{
-			return (x >> bits) | (x << -bits);
+			return (Integers.RotateLeft(x, 10) ^ Integers.RotateLeft(z, 23)) + Integers.RotateLeft(y, 8);
 		}
 
 		private uint H1(uint x)
@@ -106,22 +96,18 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (key.Length != 16)
 				throw new ArgumentException("The key must be 128 bits long");
+            if (iv.Length != 16)
+                throw new ArgumentException("The IV must be 128 bits long");
 
             idx = 0;
             cnt = 0;
 
 			uint[] w = new uint[1280];
 
-			for (int i = 0; i < 16; i++)
-			{
-				w[i >> 2] |= ((uint)key[i] << (8 * (i & 0x3)));
-			}
+			Pack.LE_To_UInt32(key, 0, w, 0, 4);
 			Array.Copy(w, 0, w, 4, 4);
 
-			for (int i = 0; i < iv.Length && i < 16; i++)
-			{
-				w[(i >> 2) + 8] |= ((uint)iv[i] << (8 * (i & 0x3)));
-			}
+			Pack.LE_To_UInt32(iv, 0, w, 8, 4);
 			Array.Copy(w, 8, w, 12, 4);
 
 			for (uint i = 16; i < 1280; i++)
@@ -144,10 +130,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			cnt = 0;
 		}
 
-        public virtual string AlgorithmName
-		{
-			get { return "HC-128"; }
-		}
+        public virtual string AlgorithmName => "HC-128";
 
 		/**
 		* Initialise a HC-128 cipher.
@@ -158,38 +141,27 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @throws ArgumentException if the params argument is
 		*                                  inappropriate (ie. the key is not 128 bit long).
 		*/
-        public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
 		{
-			ICipherParameters keyParam = parameters;
+            if (!(parameters is ParametersWithIV ivParams))
+                throw new ArgumentException("HC-128 Init parameters must include an IV");
 
-			if (parameters is ParametersWithIV)
-			{
-				iv = ((ParametersWithIV)parameters).GetIV();
-				keyParam = ((ParametersWithIV)parameters).Parameters;
-			}
-			else
-			{
-				iv = new byte[0];
-			}
+            if (!(ivParams.Parameters is KeyParameter keyParams))
+            {
+                throw new ArgumentException(
+                    "Invalid parameter passed to HC128 init - " + Platform.GetTypeName(parameters),
+                    "parameters");
+            }
 
-			if (keyParam is KeyParameter)
-			{
-				key = ((KeyParameter)keyParam).GetKey();
-				Init();
-			}
-			else
-			{
-				throw new ArgumentException(
-					"Invalid parameter passed to HC128 init - " + Platform.GetTypeName(parameters),
-					"parameters");
-			}
+            key = keyParams.GetKey();
+            iv = ivParams.GetIV();
 
-			initialised = true;
-		}
+            Init();
+
+            initialised = true;
+        }
 
-		private byte[] buf = new byte[4];
+        private readonly byte[] buf = new byte[4];
 		private int idx = 0;
 
 		private byte GetByte()
@@ -199,16 +171,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 				Pack.UInt32_To_LE(Step(), buf);				
 			}
 			byte ret = buf[idx];
-			idx = idx + 1 & 0x3;
+			idx = (idx + 1) & 0x3;
 			return ret;
 		}
 
-        public virtual void ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		len,
-			byte[]	output,
-			int		outOff)
+        public virtual void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
 		{
 			if (!initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
diff --git a/crypto/src/crypto/engines/HC256Engine.cs b/crypto/src/crypto/engines/HC256Engine.cs
index 8a17af433..1ace7bbc0 100644
--- a/crypto/src/crypto/engines/HC256Engine.cs
+++ b/crypto/src/crypto/engines/HC256Engine.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/**
+    /**
 	* HC-256 is a software-efficient stream cipher created by Hongjun Wu. It 
 	* generates keystream from a 256-bit secret key and a 256-bit initialization 
 	* vector.
@@ -20,11 +20,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 	* http://www.ecrypt.eu.org/stream/hcp3.html
 	* </p>
 	*/
-	public class HC256Engine
+    public class HC256Engine
 		: IStreamCipher
 	{
-		private uint[] p = new uint[1024];
-		private uint[] q = new uint[1024];
+		private readonly uint[] p = new uint[1024];
+		private readonly uint[] q = new uint[1024];
 		private uint cnt = 0;
 
 		private uint Step()
@@ -33,31 +33,31 @@ namespace Org.BouncyCastle.Crypto.Engines
 			uint ret;
 			if (cnt < 1024)
 			{
-				uint x = p[(j - 3 & 0x3FF)];
-				uint y = p[(j - 1023 & 0x3FF)];
-				p[j] += p[(j - 10 & 0x3FF)]
-					+ (RotateRight(x, 10) ^ RotateRight(y, 23))
-					+ q[((x ^ y) & 0x3FF)];
+				uint x = p[(j - 3) & 0x3FF];
+				uint y = p[(j - 1023) & 0x3FF];
+				p[j] += p[(j - 10) & 0x3FF]
+					+ (Integers.RotateRight(x, 10) ^ Integers.RotateRight(y, 23))
+					+ q[(x ^ y) & 0x3FF];
 
-				x = p[(j - 12 & 0x3FF)];
+				x = p[(j - 12) & 0x3FF];
 				ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256]
 					+ q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768])
 					^ p[j];
 			}
 			else
 			{
-				uint x = q[(j - 3 & 0x3FF)];
-				uint y = q[(j - 1023 & 0x3FF)];
-				q[j] += q[(j - 10 & 0x3FF)]
-					+ (RotateRight(x, 10) ^ RotateRight(y, 23))
-					+ p[((x ^ y) & 0x3FF)];
+				uint x = q[(j - 3) & 0x3FF];
+				uint y = q[(j - 1023) & 0x3FF];
+				q[j] += q[(j - 10) & 0x3FF]
+					+ (Integers.RotateRight(x, 10) ^ Integers.RotateRight(y, 23))
+					+ p[(x ^ y) & 0x3FF];
 
-				x = q[(j - 12 & 0x3FF)];
+				x = q[(j - 12) & 0x3FF];
 				ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256]
 					+ p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768])
 					^ q[j];
 			}
-			cnt = cnt + 1 & 0x7FF;
+			cnt = (cnt + 1) & 0x7FF;
 			return ret;
 		}
 
@@ -68,7 +68,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (key.Length != 32 && key.Length != 16)
 				throw new ArgumentException("The key must be 128/256 bits long");
-
 			if (iv.Length < 16)
 				throw new ArgumentException("The IV must be at least 128 bits long");
 
@@ -97,23 +96,16 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			uint[] w = new uint[2560];
 
-			for (int i = 0; i < 32; i++)
-			{
-				w[i >> 2] |= ((uint)key[i] << (8 * (i & 0x3)));
-			}
-
-			for (int i = 0; i < 32; i++)
-			{
-				w[(i >> 2) + 8] |= ((uint)iv[i] << (8 * (i & 0x3)));
-			}
+			Pack.LE_To_UInt32(key, 0, w, 0, 8);
+            Pack.LE_To_UInt32(iv, 0, w, 8, 8);
 
 			for (uint i = 16; i < 2560; i++)
 			{
 				uint x = w[i - 2];
 				uint y = w[i - 15];
-				w[i] = (RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10))
+				w[i] = (Integers.RotateRight(x, 17) ^ Integers.RotateRight(x, 19) ^ (x >> 10))
 					+ w[i - 7]
-					+ (RotateRight(y, 7) ^ RotateRight(y, 18) ^ (y >> 3))
+					+ (Integers.RotateRight(y, 7) ^ Integers.RotateRight(y, 18) ^ (y >> 3))
 					+ w[i - 16] + i;
 			}
 
@@ -128,10 +120,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			cnt = 0;
 		}
 
-        public virtual string AlgorithmName
-		{
-			get { return "HC-256"; }
-		}
+        public virtual string AlgorithmName => "HC-256";
 
 		/**
 		* Initialise a HC-256 cipher.
@@ -142,38 +131,27 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @throws ArgumentException if the params argument is
 		*                                  inappropriate (ie. the key is not 256 bit long).
 		*/
-        public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
 		{
-			ICipherParameters keyParam = parameters;
+            if (!(parameters is ParametersWithIV ivParams))
+                throw new ArgumentException("HC-256 Init parameters must include an IV");
 
-			if (parameters is ParametersWithIV)
-			{
-				iv = ((ParametersWithIV)parameters).GetIV();
-				keyParam = ((ParametersWithIV)parameters).Parameters;
-			}
-			else
-			{
-				iv = new byte[0];
-			}
+            if (!(ivParams.Parameters is KeyParameter keyParams))
+            {
+                throw new ArgumentException(
+                    "Invalid parameter passed to HC256 init - " + Platform.GetTypeName(parameters),
+                    "parameters");
+            }
 
-			if (keyParam is KeyParameter)
-			{
-				key = ((KeyParameter)keyParam).GetKey();
-				Init();
-			}
-			else
-			{
-				throw new ArgumentException(
-					"Invalid parameter passed to HC256 init - " + Platform.GetTypeName(parameters),
-					"parameters");
-			}
+            key = keyParams.GetKey();
+            iv = ivParams.GetIV();
 
-			initialised = true;
-		}
+            Init();
+
+            initialised = true;
+        }
 
-		private byte[] buf = new byte[4];
+        private readonly byte[] buf = new byte[4];
 		private int idx = 0;
 
 		private byte GetByte()
@@ -183,16 +161,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 				Pack.UInt32_To_LE(Step(), buf);
 			}
 			byte ret = buf[idx];
-			idx = idx + 1 & 0x3;
+			idx = (idx + 1) & 0x3;
 			return ret;
 		}
 
-        public virtual void ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		len,
-			byte[]	output,
-			int		outOff)
+        public virtual void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
 		{
 			if (!initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -230,10 +203,5 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			return (byte)(input ^ GetByte());
 		}
-
-		private static uint RotateRight(uint x, int bits)
-		{
-			return (x >> bits) | (x << -bits);
-		}
 	}
 }
diff --git a/crypto/test/src/test/CipherStreamTest.cs b/crypto/test/src/test/CipherStreamTest.cs
index f7115e254..d51234649 100644
--- a/crypto/test/src/test/CipherStreamTest.cs
+++ b/crypto/test/src/test/CipherStreamTest.cs
@@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Tests
 			+ "F9E460BC65EF95DA58F740B7D1DBB0AA");
 
 		private static readonly byte[] HCIN = new byte[64];
-		private static readonly byte[] HCIV = new byte[32];
+		private static readonly byte[] HCIV = new byte[16];
 
 		private static readonly byte[] HCK256A = new byte[32];
 		private static readonly byte[] HC256A = Hex.Decode(