diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-05-29 17:34:36 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-05-29 17:34:36 +0700 |
commit | 3e1cd145fc0c700ea267dc4e30e6f0ebd99f9c04 (patch) | |
tree | 1dacd33f47bb0fe7195d9c09ba87a3e177bf643c | |
parent | Correct the error message (diff) | |
download | BouncyCastle.NET-ed25519-3e1cd145fc0c700ea267dc4e30e6f0ebd99f9c04.tar.xz |
HC128Engine: require exactly 128 bits of IV
-rw-r--r-- | crypto/Readme.html | 1 | ||||
-rw-r--r-- | crypto/src/crypto/engines/HC128Engine.cs | 91 | ||||
-rw-r--r-- | crypto/src/crypto/engines/HC256Engine.cs | 112 | ||||
-rw-r--r-- | crypto/test/src/test/CipherStreamTest.cs | 2 |
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( |