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(
|