From 118d174d4ebf68f6a9a2e8ea8e74ad9a60541907 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Thu, 29 Sep 2022 20:19:44 +0700 Subject: Grain128Aead fixes --- crypto/src/crypto/engines/Grain128AEADEngine.cs | 202 +++++++++++------------- crypto/test/src/crypto/test/Grain128AeadTest.cs | 59 +++---- 2 files changed, 112 insertions(+), 149 deletions(-) diff --git a/crypto/src/crypto/engines/Grain128AEADEngine.cs b/crypto/src/crypto/engines/Grain128AEADEngine.cs index 19d780362..8dca6a6d8 100644 --- a/crypto/src/crypto/engines/Grain128AEADEngine.cs +++ b/crypto/src/crypto/engines/Grain128AEADEngine.cs @@ -1,13 +1,14 @@ using System; using System.IO; + using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; namespace Org.BouncyCastle.Crypto.Engines { - public class Grain128AeadEngine: IAeadCipher + public sealed class Grain128AeadEngine + : IAeadCipher { - /** * Constants */ @@ -32,7 +33,6 @@ namespace Org.BouncyCastle.Crypto.Engines private byte[] mac; - public string AlgorithmName => "Grain-128AEAD"; /** @@ -48,49 +48,32 @@ namespace Org.BouncyCastle.Crypto.Engines * Grain encryption and decryption is completely symmetrical, so the * 'forEncryption' is irrelevant. */ - if (!(param is ParametersWithIV)) - { - throw new ArgumentException( - "Grain-128AEAD Init parameters must include an IV"); - } - - ParametersWithIV ivParams = (ParametersWithIV)param; + if (!(param is ParametersWithIV ivParams)) + throw new ArgumentException("Grain-128AEAD Init parameters must include an IV"); - byte[] - iv = ivParams.GetIV(); + byte[] iv = ivParams.GetIV(); if (iv == null || iv.Length != 12) - { - throw new ArgumentException( - "Grain-128AEAD requires exactly 12 bytes of IV"); - } + throw new ArgumentException("Grain-128AEAD requires exactly 12 bytes of IV"); - if (!(ivParams.Parameters is KeyParameter)) - { - throw new ArgumentException( - "Grain-128AEAD Init parameters must include a key"); - } + if (!(ivParams.Parameters is KeyParameter key)) + throw new ArgumentException("Grain-128AEAD Init parameters must include a key"); - KeyParameter key = (KeyParameter)ivParams.Parameters; byte[] keyBytes = key.GetKey(); if (keyBytes.Length != 16) - { - throw new ArgumentException( - "Grain-128AEAD key must be 128 bits long"); - } + throw new ArgumentException("Grain-128AEAD key must be 128 bits long"); + /** * Initialize variables. */ - workingIV = new byte[key.GetKey().Length]; - workingKey = new byte[key.GetKey().Length]; + workingIV = new byte[keyBytes.Length]; + workingKey = keyBytes; lfsr = new uint[STATE_SIZE]; nfsr = new uint[STATE_SIZE]; authAcc = new uint[2]; authSr = new uint[2]; - Array.Copy(iv, 0, workingIV, 0, iv.Length); - Array.Copy(key.GetKey(), 0, workingKey, 0, key.GetKey().Length); Reset(); } @@ -233,12 +216,10 @@ namespace Org.BouncyCastle.Crypto.Engines */ private uint[] Shift(uint[] array, uint val) { - array[0] = (array[0] >> 1) | (array[1] << 31); array[1] = (array[1] >> 1) | (array[2] << 31); array[2] = (array[2] >> 1) | (array[3] << 31); array[3] = (array[3] >> 1) | (val << 31); - return array; } @@ -274,51 +255,43 @@ namespace Org.BouncyCastle.Crypto.Engines } } - public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, - int outOff) + public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff) { + Check.DataLength(input, inOff, len, "input buffer too short"); + Check.OutputLength(output, outOff, len, "output buffer too short"); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return ProcessBytes(input.AsSpan(inOff, len), output.AsSpan(outOff)); +#else if (!initialised) - { throw new ArgumentException(AlgorithmName + " not initialised"); - } + if (!aadFinished) { DoProcessAADBytes(aadData.GetBuffer(), 0, (int)aadData.Length); aadFinished = true; } - - if ((inOff + len) > input.Length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + len) > output.Length) - { - throw new OutputLengthException("output buffer too short"); - } GetKeyStream(input, inOff, len, output, outOff); return len; +#endif } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public int ProcessBytes(ReadOnlySpan input, Span output) { + Check.OutputLength(output, input.Length, "output buffer too short"); + if (!initialised) - { throw new ArgumentException(AlgorithmName + " not initialised"); - } + if (!aadFinished) { DoProcessAADBytes(aadData.GetBuffer(), 0, (int)aadData.Length); aadFinished = true; } - if (input.Length > output.Length) - { - throw new OutputLengthException("output buffer too short"); - } - GetKeyStream(input.ToArray(), 0, input.Length, output.ToArray(), 0); + GetKeyStream(input, output); return input.Length; } #endif @@ -334,10 +307,49 @@ namespace Org.BouncyCastle.Crypto.Engines InitGrain(); } - private byte[] GetKeyStream(byte[] input, int inOff, int len, byte[] ciphertext, int outOff) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void GetKeyStream(ReadOnlySpan input, Span output) + { + int len = input.Length; + int mCnt = 0, acCnt = 0, cCnt = 0; + byte[] plaintext = new byte[len]; + for (int i = 0; i < len; ++i) + { + plaintext[i] = (byte)ReverseByte(input[i]); + } + for (int i = 0; i < len; ++i) + { + byte cc = 0; + for (int j = 0; j < 16; ++j) + { + outputZ = GetOutput(); + nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1); + lfsr = Shift(lfsr, (GetOutputLFSR()) & 1); + if (isEven) + { + cc |= (byte)(((((plaintext[mCnt >> 3]) >> (7 - (mCnt & 7))) & 1) ^ outputZ) << (cCnt & 7)); + mCnt++; + cCnt++; + isEven = false; + } + else + { + if ((plaintext[acCnt >> 3] & (1 << (7 - (acCnt & 7)))) != 0) + { + Accumulate(); + } + AuthShift(outputZ); + acCnt++; + isEven = true; + } + } + output[i] = cc; + } + } +#else + private void GetKeyStream(byte[] input, int inOff, int len, byte[] ciphertext, int outOff) { int mCnt = 0, acCnt = 0, cCnt = 0; - byte cc; byte[] plaintext = new byte[len]; for (int i = 0; i < len; ++i) { @@ -345,7 +357,7 @@ namespace Org.BouncyCastle.Crypto.Engines } for (int i = 0; i < len; ++i) { - cc = 0; + byte cc = 0; for (int j = 0; j < 16; ++j) { outputZ = GetOutput(); @@ -372,68 +384,49 @@ namespace Org.BouncyCastle.Crypto.Engines } ciphertext[outOff + i] = cc; } - //outputZ = GetOutput(); - //nfsr = Shift(nfsr, (GetOutputNFSR() ^ lfsr[0]) & 1); - //lfsr = Shift(lfsr, (GetOutputLFSR()) & 1); - //Accumulate(); - //cCnt = len + outOff;//acc_idx - //for (int i = 0; i < 2; ++i) - //{ - // for (int j = 0; j < 4; ++j) - // { - // ciphertext[cCnt] = (byte)((authAcc[i] >> (j << 3)) & 0xff); - // cCnt++; - // } - //} - - return ciphertext; } - +#endif public byte ReturnByte(byte input) { if (!initialised) - { - throw new ArgumentException(AlgorithmName - + " not initialised"); - } - byte[] plaintext = new byte[1]; - plaintext[0] = input; + throw new ArgumentException(AlgorithmName + " not initialised"); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + Span plaintext = stackalloc byte[1]{ input }; + Span ciphertext = stackalloc byte[1]; + GetKeyStream(plaintext, ciphertext); + return ciphertext[0]; +#else + byte[] plaintext = new byte[1]{ input }; byte[] ciphertext = new byte[1]; - return GetKeyStream(plaintext, 0, 1, ciphertext, 0)[0]; + GetKeyStream(plaintext, 0, 1, ciphertext, 0); + return ciphertext[0]; +#endif } - public void ProcessAadByte(byte input) { if (aadFinished) - { throw new ArgumentException("associated data must be added before plaintext/ciphertext"); - } - aadData.Write(new byte[] { input }, 0, 1); + aadData.WriteByte(input); } public void ProcessAadBytes(byte[] input, int inOff, int len) { -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - ProcessAadBytes(input.AsSpan(inOff, len)); -#else if (aadFinished) - { throw new ArgumentException("associated data must be added before plaintext/ciphertext"); - } + aadData.Write(input, inOff, len); -#endif } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public void ProcessAadBytes(ReadOnlySpan input) { if (aadFinished) - { throw new ArgumentException("associated data must be added before plaintext/ciphertext"); - } + aadData.Write(input); } #endif @@ -450,17 +443,15 @@ namespace Org.BouncyCastle.Crypto.Engines authSr[1] = (authSr[1] >> 1) | (val << 31); } - public int ProcessByte(byte input, byte[] output, int outOff) { - return ProcessBytes(new byte[] { input }, 0, 1, output, outOff); + return ProcessBytes(new byte[]{ input }, 0, 1, output, outOff); } - #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public int ProcessByte(byte input, Span output) { - return ProcessBytes(new byte[] { input }.AsSpan(), output); + return ProcessBytes(stackalloc byte[1]{ input }, output); } #endif @@ -468,7 +459,6 @@ namespace Org.BouncyCastle.Crypto.Engines { byte[] ader; int aderlen; - //encodeDer if (len < 128) { ader = new byte[1 + len]; @@ -491,7 +481,7 @@ namespace Org.BouncyCastle.Crypto.Engines { ader[1 + aderlen + i] = (byte)ReverseByte(input[inOff + i]); } - byte adval; + int adCnt = 0; for (int i = 0; i < ader.Length; ++i) { @@ -502,7 +492,7 @@ namespace Org.BouncyCastle.Crypto.Engines lfsr = Shift(lfsr, (GetOutputLFSR()) & 1); if ((j & 1) == 1) { - adval = (byte)(ader[adCnt >> 3] & (1 << (7 - (adCnt & 7)))); + byte adval = (byte)(ader[adCnt >> 3] & (1 << (7 - (adCnt & 7)))); if (adval != 0) { Accumulate(); @@ -512,24 +502,18 @@ namespace Org.BouncyCastle.Crypto.Engines } } } - - } private int LenLength(int v) { if ((v & 0xff) == v) - { return 1; - } + if ((v & 0xffff) == v) - { return 2; - } + if ((v & 0xffffff) == v) - { return 3; - } return 4; } @@ -599,7 +583,7 @@ namespace Org.BouncyCastle.Crypto.Engines } } - Array.Copy(mac, 0, output.ToArray(), 0, mac.Length); + mac.CopyTo(output); try { @@ -612,18 +596,16 @@ namespace Org.BouncyCastle.Crypto.Engines } #endif - public byte[] GetMac() + public byte[] GetMac() { return mac; } - public int GetUpdateOutputSize(int len) { return len; } - public int GetOutputSize(int len) { return len + 8; diff --git a/crypto/test/src/crypto/test/Grain128AeadTest.cs b/crypto/test/src/crypto/test/Grain128AeadTest.cs index 253adfdbf..4f4df5af3 100644 --- a/crypto/test/src/crypto/test/Grain128AeadTest.cs +++ b/crypto/test/src/crypto/test/Grain128AeadTest.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.IO; + using NUnit.Framework; + using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Utilities; @@ -11,29 +13,13 @@ using Org.BouncyCastle.Utilities.Test; namespace Org.BouncyCastle.Crypto.Tests { [TestFixture] - public class Grain128AeadTest : SimpleTest + public class Grain128AeadTest { - public override string Name - { - get { return "Grain-128Aead"; } - } - [Test] - public override void PerformTest() - { - testVectors(); - testSplitUpdate(); - testLongAead(); - testExceptions(); - } - - - private void testVectors() + public void TestVectors() { Grain128AeadEngine grain = new Grain128AeadEngine(); - ICipherParameters param; var buf = new Dictionary(); - //TestSampler sampler = new TestSampler(); using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.LWC_AEAD_KAT_128_96.txt"))) { string line; @@ -46,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Tests data = line.Split(' '); if (data.Length == 1) { - param = new ParametersWithIV(new KeyParameter(Hex.Decode(map["Key"])), Hex.Decode(map["Nonce"])); + var param = new ParametersWithIV(new KeyParameter(Hex.Decode(map["Key"])), Hex.Decode(map["Nonce"])); grain.Init(true, param); adByte = Hex.Decode(map["AD"]); grain.ProcessAadBytes(adByte, 0, adByte.Length); @@ -68,13 +54,13 @@ namespace Org.BouncyCastle.Crypto.Tests { map[data[0].Trim()] = ""; } - } } } } - private void testSplitUpdate() + [Test] + public void TestSplitUpdate() { byte[] Key = Hex.Decode("000102030405060708090A0B0C0D0E0F"); byte[] Nonce = Hex.Decode("000102030405060708090A0B"); @@ -102,12 +88,12 @@ namespace Org.BouncyCastle.Crypto.Tests grain.ProcessBytes(PT, 0, 10, rv, 0); try { - grain.ProcessAadByte((byte)0x01); + grain.ProcessAadByte(0x01); Assert.Fail("no exception"); } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext")); + Assert.IsTrue(e.Message.Contains("associated data must be added before plaintext/ciphertext")); } try @@ -117,16 +103,12 @@ namespace Org.BouncyCastle.Crypto.Tests } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext")); + Assert.IsTrue(e.Message.Contains("associated data must be added before plaintext/ciphertext")); } } - private bool Contains(string message, string sub) - { - return message.IndexOf(sub) >= 0; - } - - private void testLongAead() + [Test] + public void TestLongAead() { byte[] Key = Hex.Decode("000102030405060708090A0B0C0D0E0F"); byte[] Nonce = Hex.Decode("000102030405060708090A0B"); @@ -153,12 +135,12 @@ namespace Org.BouncyCastle.Crypto.Tests grain.ProcessBytes(PT, 0, 10, rv, 0); try { - grain.ProcessAadByte((byte)0x01); + grain.ProcessAadByte(0x01); Assert.Fail("no exception"); } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext")); + Assert.IsTrue(e.Message.Contains("associated data must be added before plaintext/ciphertext")); } try @@ -168,11 +150,12 @@ namespace Org.BouncyCastle.Crypto.Tests } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "associated data must be added before plaintext/ciphertext")); + Assert.IsTrue(e.Message.Contains("associated data must be added before plaintext/ciphertext")); } } - private void testExceptions() + [Test] + public void TestExceptions() { try @@ -184,7 +167,7 @@ namespace Org.BouncyCastle.Crypto.Tests } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "Grain-128AEAD Init parameters must include an IV")); + Assert.IsTrue(e.Message.Contains("Grain-128AEAD Init parameters must include an IV")); } try @@ -196,7 +179,7 @@ namespace Org.BouncyCastle.Crypto.Tests } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "Grain-128AEAD requires exactly 12 bytes of IV")); + Assert.IsTrue(e.Message.Contains("Grain-128AEAD requires exactly 12 bytes of IV")); } try @@ -208,10 +191,8 @@ namespace Org.BouncyCastle.Crypto.Tests } catch (ArgumentException e) { - Assert.IsTrue(Contains(e.Message, "Grain-128AEAD key must be 128 bits long")); + Assert.IsTrue(e.Message.Contains("Grain-128AEAD key must be 128 bits long")); } } - } } - -- cgit 1.4.1