From 8e23b0e1a4e8394bc68e2de9e6bb636a7aeef059 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 26 Apr 2023 20:05:40 +0700 Subject: Refactor AsconTest --- crypto/src/crypto/engines/AsconEngine.cs | 13 +- crypto/test/src/crypto/test/AsconTest.cs | 823 +++++++++++++++++++++---------- 2 files changed, 557 insertions(+), 279 deletions(-) diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs index 4bda8a02a..fc38764d1 100644 --- a/crypto/src/crypto/engines/AsconEngine.cs +++ b/crypto/src/crypto/engines/AsconEngine.cs @@ -99,15 +99,9 @@ namespace Org.BouncyCastle.Crypto.Engines m_buf = new byte[m_bufferSizeDecrypt]; } - public int GetKeyBytesSize() - { - return CRYPTO_KEYBYTES; - } + public int GetKeyBytesSize() => CRYPTO_KEYBYTES; - public int GetIVBytesSize() - { - return CRYPTO_ABYTES; - } + public int GetIVBytesSize() => CRYPTO_ABYTES; public string AlgorithmName => algorithmName; @@ -1060,6 +1054,9 @@ namespace Org.BouncyCastle.Crypto.Engines } } +#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif private static ulong PAD(int i) { return 0x8000000000000000UL >> (i << 3); diff --git a/crypto/test/src/crypto/test/AsconTest.cs b/crypto/test/src/crypto/test/AsconTest.cs index 313f7d45e..eabf7e043 100644 --- a/crypto/test/src/crypto/test/AsconTest.cs +++ b/crypto/test/src/crypto/test/AsconTest.cs @@ -15,164 +15,347 @@ namespace Org.BouncyCastle.Crypto.Tests { [TestFixture] public class AsconTest - : SimpleTest { - public override string Name => "ASCON"; + [Test, Explicit] + public void BenchDigest_AsconHash() + { + ImplBenchDigest(AsconDigest.AsconParameters.AsconHash); + } + + [Test, Explicit] + public void BenchDigest_AsconHashA() + { + ImplBenchDigest(AsconDigest.AsconParameters.AsconHashA); + } + + [Test, Explicit] + public void BenchEngineAuth_ascon128() + { + ImplBenchEngineAuth(AsconEngine.AsconParameters.ascon128); + } + + [Test, Explicit] + public void BenchEngineAuth_ascon128a() + { + ImplBenchEngineAuth(AsconEngine.AsconParameters.ascon128a); + } + + [Test, Explicit] + public void BenchEngineAuth_ascon80pq() + { + ImplBenchEngineAuth(AsconEngine.AsconParameters.ascon80pq); + } + + [Test, Explicit] + public void BenchEngineDecrypt_ascon128() + { + ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128, false); + } + + [Test, Explicit] + public void BenchEngineDecrypt_ascon128a() + { + ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128a, false); + } [Test, Explicit] - public void BenchAuth80pq() + public void BenchEngineDecrypt_ascon80pq() + { + ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon80pq, false); + } + + [Test, Explicit] + public void BenchEngineEncrypt_ascon128() + { + ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128, true); + } + + [Test, Explicit] + public void BenchEngineEncrypt_ascon128a() + { + ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon128a, true); + } + + [Test, Explicit] + public void BenchEngineEncrypt_ascon80pq() + { + ImplBenchEngineCrypt(AsconEngine.AsconParameters.ascon80pq, true); + } + + [Test, Explicit] + public void BenchXof_AsconXof() + { + ImplBenchXof(AsconXof.AsconParameters.AsconXof); + } + + [Test, Explicit] + public void BenchXof_AsconXofA() + { + ImplBenchXof(AsconXof.AsconParameters.AsconXofA); + } + + [Test] + public void TestExceptionsDigest_AsconHash() + { + ImplTestExceptionsDigest(AsconDigest.AsconParameters.AsconHash); + } + + [Test] + public void TestExceptionsDigest_AsconHashA() + { + ImplTestExceptionsDigest(AsconDigest.AsconParameters.AsconHashA); + } + + [Test] + public void TestExceptionsEngine_ascon128() + { + ImplTestExceptionsEngine(AsconEngine.AsconParameters.ascon128); + } + + [Test] + public void TestExceptionsEngine_ascon128a() + { + ImplTestExceptionsEngine(AsconEngine.AsconParameters.ascon128a); + } + + [Test] + public void TestExceptionsEngine_ascon80pq() + { + ImplTestExceptionsEngine(AsconEngine.AsconParameters.ascon80pq); + } + + [Test] + public void TestExceptionsXof_AsconXof() + { + ImplTestExceptionsXof(AsconXof.AsconParameters.AsconXof); + } + + [Test] + public void TestExceptionsXof_AsconXofA() + { + ImplTestExceptionsXof(AsconXof.AsconParameters.AsconXofA); + } + + [Test] + public void TestParametersDigest_AsconHash() + { + ImplTestParametersDigest(AsconDigest.AsconParameters.AsconHash, 32); + } + + [Test] + public void TestParametersDigest_AsconHashA() + { + ImplTestParametersDigest(AsconDigest.AsconParameters.AsconHashA, 32); + } + + [Test] + public void TestParametersEngine_ascon128() + { + ImplTestParametersEngine(AsconEngine.AsconParameters.ascon128, 16, 16, 16); + } + + [Test] + public void TestParametersEngine_ascon128a() + { + ImplTestParametersEngine(AsconEngine.AsconParameters.ascon128a, 16, 16, 16); + } + + [Test] + public void TestParametersEngine_ascon80pq() + { + ImplTestParametersEngine(AsconEngine.AsconParameters.ascon80pq, 20, 16, 16); + } + + [Test] + public void TestParametersXof_AsconXof() + { + ImplTestParametersXof(AsconXof.AsconParameters.AsconXof, 32); + } + + [Test] + public void TestParametersXof_AsconXofA() + { + ImplTestParametersXof(AsconXof.AsconParameters.AsconXofA, 32); + } + + [Test] + public void TestVectorsDigest_AsconHash() + { + ImplTestVectorsDigest(AsconDigest.AsconParameters.AsconHash, "asconhash"); + } + + [Test] + public void TestVectorsDigest_AsconHashA() + { + ImplTestVectorsDigest(AsconDigest.AsconParameters.AsconHashA, "asconhasha"); + } + + [Test] + public void TestVectorsEngine_ascon128() + { + ImplTestVectorsEngine(AsconEngine.AsconParameters.ascon128, "128_128"); + } + + [Test] + public void TestVectorsEngine_ascon128a() + { + ImplTestVectorsEngine(AsconEngine.AsconParameters.ascon128a, "128_128_a"); + } + + [Test] + public void TestVectorsEngine_ascon80pq() + { + ImplTestVectorsEngine(AsconEngine.AsconParameters.ascon80pq, "160_128"); + } + + [Test] + public void TestVectorsXof_AsconXof() { - var parameters = new AeadParameters(new KeyParameter(new byte[20]), 128, new byte[16], null); - var engine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq); - engine.Init(false, parameters); + ImplTestVectorsXof(AsconXof.AsconParameters.AsconXof, "asconxof"); + } + + [Test] + public void TestVectorsXof_AsconXofA() + { + ImplTestVectorsXof(AsconXof.AsconParameters.AsconXofA, "asconxofa"); + } + + private static AsconDigest CreateDigest(AsconDigest.AsconParameters asconParameters) + { + return new AsconDigest(asconParameters); + } + + private static AsconEngine CreateEngine(AsconEngine.AsconParameters asconParameters) + { + return new AsconEngine(asconParameters); + } + + private static AsconXof CreateXof(AsconXof.AsconParameters asconParameters) + { + return new AsconXof(asconParameters); + } + + private static void ImplBenchDigest(AsconDigest.AsconParameters asconParameters) + { + var ascon = CreateDigest(asconParameters); byte[] data = new byte[1024]; - for (int i = 0; i < 1024 * 1024; ++i) + for (int i = 0; i < 1024; ++i) { -#if NET6_0_OR_GREATER - engine.ProcessAadBytes(data.AsSpan(0, 1024)); + for (int j = 0; j < 1024; ++j) + { + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ascon.BlockUpdate(data); +#else + ascon.BlockUpdate(data, 0, 1024); +#endif + } + + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ascon.DoFinal(data); #else - engine.ProcessAadBytes(data, 0, 1024); + ascon.DoFinal(data, 0); #endif } } - [Test, Explicit] - public void BenchDecrypt80pq() + private static void ImplBenchEngineAuth(AsconEngine.AsconParameters asconParameters) { - var parameters = new AeadParameters(new KeyParameter(new byte[20]), 128, new byte[16], null); - var engine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq); - engine.Init(false, parameters); + var ascon = CreateEngine(asconParameters); + InitEngine(ascon, true); byte[] data = new byte[1024]; for (int i = 0; i < 1024 * 1024; ++i) { -#if NET6_0_OR_GREATER - engine.ProcessBytes(data.AsSpan(0, 1024), data); + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ascon.ProcessAadBytes(data); #else - engine.ProcessBytes(data, 0, 1024, data, 0); + ascon.ProcessAadBytes(data, 0, 1024); #endif } } - [Test, Explicit] - public void BenchEncrypt80pq() + private static void ImplBenchEngineCrypt(AsconEngine.AsconParameters asconParameters, bool forEncryption) { - var parameters = new AeadParameters(new KeyParameter(new byte[20]), 128, new byte[16], null); - var engine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq); - engine.Init(true, parameters); + var ascon = CreateEngine(asconParameters); + InitEngine(ascon, forEncryption); - byte[] data = new byte[engine.GetUpdateOutputSize(1024)]; + byte[] data = new byte[1024 + 64]; for (int i = 0; i < 1024 * 1024; ++i) { -#if NET6_0_OR_GREATER - engine.ProcessBytes(data.AsSpan(0, 1024), data); + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ascon.ProcessBytes(data.AsSpan(0, 1024), data); #else - engine.ProcessBytes(data, 0, 1024, data, 0); + ascon.ProcessBytes(data, 0, 1024, data, 0); #endif } } - [Test] - public override void PerformTest() + private static void ImplBenchXof(AsconXof.AsconParameters asconParameters) { - ImplTestVectorsHash(AsconDigest.AsconParameters.AsconHashA, "asconhasha"); - ImplTestVectorsHash(AsconDigest.AsconParameters.AsconHash, "asconhash"); - ImplTestVectorsXof(AsconXof.AsconParameters.AsconXof, "asconxof"); - ImplTestVectorsXof(AsconXof.AsconParameters.AsconXofA, "asconxofa"); - - ImplTestExceptions(new AsconDigest(AsconDigest.AsconParameters.AsconHashA), 32); - ImplTestExceptions(new AsconDigest(AsconDigest.AsconParameters.AsconHash), 32); - ImplTestExceptions(new AsconXof(AsconXof.AsconParameters.AsconXof), 32); - ImplTestExceptions(new AsconXof(AsconXof.AsconParameters.AsconXofA), 32); - - AsconEngine asconEngine = new AsconEngine(AsconEngine.AsconParameters.ascon80pq); - ImplTestExceptions(asconEngine); - ImplTestParameters(asconEngine, 20, 16, 16); - - asconEngine = new AsconEngine(AsconEngine.AsconParameters.ascon128a); - ImplTestExceptions(asconEngine); - ImplTestParameters(asconEngine, 16, 16, 16); + var ascon = CreateXof(asconParameters); - asconEngine = new AsconEngine(AsconEngine.AsconParameters.ascon128); - ImplTestExceptions(asconEngine); - ImplTestParameters(asconEngine, 16, 16, 16); - - ImplTestVectors(AsconEngine.AsconParameters.ascon80pq, "160_128"); - ImplTestVectors(AsconEngine.AsconParameters.ascon128a, "128_128_a"); - ImplTestVectors(AsconEngine.AsconParameters.ascon128, "128_128"); - } - - private void ImplTestVectors(AsconEngine.AsconParameters asconParameters, string filename) - { - Random random = new Random(); - AsconEngine asconEngine = new AsconEngine(asconParameters); - var buf = new Dictionary(); - //TestSampler sampler = new TestSampler(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.ascon.LWC_AEAD_KAT_" + filename + ".txt"))) + byte[] data = new byte[1024]; + for (int i = 0; i < 1024; ++i) { - Dictionary map = new Dictionary(); - string line; - while ((line = src.ReadLine()) != null) + for (int j = 0; j < 1024; ++j) { - var data = line.Split(' '); - if (data.Length == 1) - { - byte[] key = Hex.Decode(map["Key"]); - byte[] nonce = Hex.Decode(map["Nonce"]); - byte[] ad = Hex.Decode(map["AD"]); - byte[] pt = Hex.Decode(map["PT"]); - byte[] ct = Hex.Decode(map["CT"]); - map.Clear(); - - var parameters = new ParametersWithIV(new KeyParameter(key), nonce); - - // Encrypt - { - asconEngine.Init(true, parameters); - - var rv = new byte[asconEngine.GetOutputSize(pt.Length)]; - random.NextBytes(rv); // should overwrite any existing data - - asconEngine.ProcessAadBytes(ad, 0, ad.Length); - int len = asconEngine.ProcessBytes(pt, 0, pt.Length, rv, 0); - len += asconEngine.DoFinal(rv, len); - - Assert.True(Arrays.AreEqual(rv, 0, len, ct, 0, ct.Length)); - } + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ascon.BlockUpdate(data); +#else + ascon.BlockUpdate(data, 0, 1024); +#endif + } - // Decrypt - { - asconEngine.Init(false, parameters); + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ascon.OutputFinal(data); +#else + ascon.OutputFinal(data, 0, data.Length); +#endif + } + } - var rv = new byte[asconEngine.GetOutputSize(ct.Length)]; - random.NextBytes(rv); // should overwrite any existing data + private static void ImplTestExceptionsDigest(AsconDigest.AsconParameters asconParameters) + { + var ascon = new AsconDigest(asconParameters); - asconEngine.ProcessAadBytes(ad, 0, ad.Length); - int len = asconEngine.ProcessBytes(ct, 0, ct.Length, rv, 0); - len += asconEngine.DoFinal(rv, len); + try + { + ascon.BlockUpdate(new byte[1], 1, 1); + Assert.Fail(ascon.AlgorithmName + ": input for BlockUpdate is too short"); + } + catch (DataLengthException) + { + //expected + } - Assert.True(Arrays.AreEqual(rv, 0, len, pt, 0, pt.Length)); - } - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - } - } + try + { + ascon.DoFinal(new byte[ascon.GetDigestSize() - 1], 2); + Assert.Fail(ascon.AlgorithmName + ": output for DoFinal is too short"); + } + catch (OutputLengthException) + { + //expected } } - private void ImplTestExceptions(AsconEngine asconEngine) + private void ImplTestExceptionsEngine(AsconEngine.AsconParameters asconParameters) { - int keySize = asconEngine.GetKeyBytesSize(), ivSize = asconEngine.GetIVBytesSize(); + var ascon = CreateEngine(asconParameters); + int keySize = ascon.GetKeyBytesSize(), ivSize = ascon.GetIVBytesSize(); int offset; byte[] k = new byte[keySize]; byte[] iv = new byte[ivSize]; @@ -180,8 +363,8 @@ namespace Org.BouncyCastle.Crypto.Tests var param = new ParametersWithIV(new KeyParameter(k), iv); try { - asconEngine.ProcessBytes(m, 0, m.Length, null, 0); - Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before ProcessBytes"); + ascon.ProcessBytes(m, 0, m.Length, null, 0); + Assert.Fail(ascon.AlgorithmName + " needs to be initialized before ProcessBytes"); } catch (InvalidOperationException) { @@ -190,8 +373,8 @@ namespace Org.BouncyCastle.Crypto.Tests try { - asconEngine.ProcessByte(0x00, null, 0); - Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before ProcessByte"); + ascon.ProcessByte(0x00, null, 0); + Assert.Fail(ascon.AlgorithmName + " needs to be initialized before ProcessByte"); } catch (InvalidOperationException) { @@ -200,8 +383,8 @@ namespace Org.BouncyCastle.Crypto.Tests try { - asconEngine.Reset(); - Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before Reset"); + ascon.Reset(); + Assert.Fail(ascon.AlgorithmName + " needs to be initialized before Reset"); } catch (InvalidOperationException) { @@ -210,8 +393,8 @@ namespace Org.BouncyCastle.Crypto.Tests try { - asconEngine.DoFinal(null, m.Length); - Assert.Fail(asconEngine.AlgorithmName + " needs to be initialized before DoFinal"); + ascon.DoFinal(null, m.Length); + Assert.Fail(ascon.AlgorithmName + " needs to be initialized before DoFinal"); } catch (InvalidOperationException) { @@ -220,14 +403,14 @@ namespace Org.BouncyCastle.Crypto.Tests try { - asconEngine.GetMac(); - asconEngine.GetOutputSize(0); - asconEngine.GetUpdateOutputSize(0); + ascon.GetMac(); + ascon.GetOutputSize(0); + ascon.GetUpdateOutputSize(0); } catch (InvalidOperationException) { //expected - Assert.Fail(asconEngine.AlgorithmName + " functions can be called before initialization"); + Assert.Fail(ascon.AlgorithmName + " functions can be called before initialization"); } Random rand = new Random(); @@ -238,8 +421,8 @@ namespace Org.BouncyCastle.Crypto.Tests byte[] iv1 = new byte[randomNum]; try { - asconEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv)); - Assert.Fail(asconEngine.AlgorithmName + " k size does not match"); + ascon.Init(true, new ParametersWithIV(new KeyParameter(k1), iv)); + Assert.Fail(ascon.AlgorithmName + " k size does not match"); } catch (ArgumentException) { @@ -247,25 +430,25 @@ namespace Org.BouncyCastle.Crypto.Tests } try { - asconEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); - Assert.Fail(asconEngine.AlgorithmName + "iv size does not match"); + ascon.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); + Assert.Fail(ascon.AlgorithmName + "iv size does not match"); } catch (ArgumentException) { //expected } - asconEngine.Init(true, param); - byte[] c1 = new byte[asconEngine.GetOutputSize(m.Length)]; + ascon.Init(true, param); + byte[] c1 = new byte[ascon.GetOutputSize(m.Length)]; try { - asconEngine.DoFinal(c1, m.Length); + ascon.DoFinal(c1, m.Length); } catch (Exception) { - Assert.Fail(asconEngine.AlgorithmName + " allows no input for AAD and plaintext"); + Assert.Fail(ascon.AlgorithmName + " allows no input for AAD and plaintext"); } - byte[] mac2 = asconEngine.GetMac(); + byte[] mac2 = ascon.GetMac(); if (mac2 == null) { Assert.Fail("mac should not be empty after DoFinal"); @@ -276,21 +459,21 @@ namespace Org.BouncyCastle.Crypto.Tests } // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessAadByte(0x00); - byte[] mac1 = new byte[asconEngine.GetOutputSize(0)]; - asconEngine.DoFinal(mac1, 0); + ascon.Init(true, param); + ascon.ProcessAadByte(0x00); + byte[] mac1 = new byte[ascon.GetOutputSize(0)]; + ascon.DoFinal(mac1, 0); if (Arrays.AreEqual(mac1, mac2)) { Assert.Fail("mac should not match"); } // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessByte(0, null, 0); + ascon.Init(true, param); + ascon.ProcessByte(0, null, 0); try { - asconEngine.ProcessAadByte(0x00); + ascon.ProcessAadByte(0x00); Assert.Fail("ProcessAadByte cannot be called after encryption/decryption"); } catch (InvalidOperationException) @@ -299,7 +482,7 @@ namespace Org.BouncyCastle.Crypto.Tests } try { - asconEngine.ProcessAadBytes(new byte[1], 0, 1); + ascon.ProcessAadBytes(new byte[1], 0, 1); Assert.Fail("ProcessAadBytes cannot be called after encryption/decryption"); } catch (InvalidOperationException) @@ -308,10 +491,10 @@ namespace Org.BouncyCastle.Crypto.Tests } // TODO Maybe use a different IV for this - asconEngine.Init(true, param); + ascon.Init(true, param); try { - asconEngine.ProcessAadBytes(new byte[1], 1, 1); + ascon.ProcessAadBytes(new byte[1], 1, 1); Assert.Fail("input for ProcessAadBytes is too short"); } catch (DataLengthException) @@ -320,28 +503,16 @@ namespace Org.BouncyCastle.Crypto.Tests } try { - asconEngine.ProcessBytes(new byte[1], 1, 1, c1, 0); + ascon.ProcessBytes(new byte[1], 1, 1, c1, 0); Assert.Fail("input for ProcessBytes is too short"); } catch (DataLengthException) { //expected } - - try - { - int inputSize = rand.Next(32, 64); - int outputSize = asconEngine.GetUpdateOutputSize(inputSize); - asconEngine.ProcessBytes(new byte[inputSize], 0, inputSize, new byte[outputSize], 1); - Assert.Fail("output for ProcessBytes is too short"); - } - catch (OutputLengthException) - { - //expected - } try { - asconEngine.DoFinal(new byte[2], 2); + ascon.DoFinal(new byte[2], 2); Assert.Fail("output for DoFinal is too short"); } catch (OutputLengthException) @@ -349,19 +520,22 @@ namespace Org.BouncyCastle.Crypto.Tests //expected } - mac1 = new byte[asconEngine.GetOutputSize(0)]; - mac2 = new byte[asconEngine.GetOutputSize(0)]; + ImplTestExceptionsGetUpdateOutputSize(ascon, false, param, 100); + ImplTestExceptionsGetUpdateOutputSize(ascon, true, param, 100); + + mac1 = new byte[ascon.GetOutputSize(0)]; + mac2 = new byte[ascon.GetOutputSize(0)]; // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessAadBytes(new byte[2], 0, 2); - asconEngine.DoFinal(mac1, 0); + ascon.Init(true, param); + ascon.ProcessAadBytes(new byte[2], 0, 2); + ascon.DoFinal(mac1, 0); // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessAadByte(0x00); - asconEngine.ProcessAadByte(0x00); - asconEngine.DoFinal(mac2, 0); + ascon.Init(true, param); + ascon.ProcessAadByte(0x00); + ascon.ProcessAadByte(0x00); + ascon.DoFinal(mac2, 0); if (!Arrays.AreEqual(mac1, mac2)) { @@ -373,20 +547,20 @@ namespace Org.BouncyCastle.Crypto.Tests byte[] m2 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; byte[] m3 = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; byte[] m4 = new byte[m2.Length]; - byte[] c2 = new byte[asconEngine.GetOutputSize(m2.Length)]; - byte[] c3 = new byte[asconEngine.GetOutputSize(m3.Length)]; + byte[] c2 = new byte[ascon.GetOutputSize(m2.Length)]; + byte[] c3 = new byte[ascon.GetOutputSize(m3.Length)]; // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = asconEngine.ProcessBytes(m2, 0, m2.Length, c2, 0); - asconEngine.DoFinal(c2, offset); + ascon.Init(true, param); + ascon.ProcessAadBytes(aad2, 0, aad2.Length); + offset = ascon.ProcessBytes(m2, 0, m2.Length, c2, 0); + ascon.DoFinal(c2, offset); // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessAadBytes(aad3, 1, aad2.Length); - offset = asconEngine.ProcessBytes(m3, 1, m2.Length, c3, 1); - asconEngine.DoFinal(c3, offset + 1); + ascon.Init(true, param); + ascon.ProcessAadBytes(aad3, 1, aad2.Length); + offset = ascon.ProcessBytes(m3, 1, m2.Length, c3, 1); + ascon.DoFinal(c3, offset + 1); byte[] c3_partial = new byte[c2.Length]; Array.Copy(c3, 1, c3_partial, 0, c2.Length); @@ -395,10 +569,10 @@ namespace Org.BouncyCastle.Crypto.Tests Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); } - asconEngine.Init(false, param); - asconEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - asconEngine.DoFinal(m4, offset); + ascon.Init(false, param); + ascon.ProcessAadBytes(aad2, 0, aad2.Length); + offset = ascon.ProcessBytes(c2, 0, c2.Length, m4, 0); + ascon.DoFinal(m4, offset); if (!Arrays.AreEqual(m2, m4)) { Assert.Fail("The encryption and decryption does not recover the plaintext"); @@ -406,11 +580,11 @@ namespace Org.BouncyCastle.Crypto.Tests c2[c2.Length - 1] ^= 1; - asconEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); + ascon.ProcessAadBytes(aad2, 0, aad2.Length); + offset = ascon.ProcessBytes(c2, 0, c2.Length, m4, 0); try { - asconEngine.DoFinal(m4, offset); + ascon.DoFinal(m4, offset); Assert.Fail("The decryption should fail"); } catch (InvalidCipherTextException) @@ -423,51 +597,52 @@ namespace Org.BouncyCastle.Crypto.Tests rand.NextBytes(m7); // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - byte[] c7 = new byte[asconEngine.GetOutputSize(m7.Length)]; + ascon.Init(true, param); + byte[] c7 = new byte[ascon.GetOutputSize(m7.Length)]; byte[] c8 = new byte[c7.Length]; byte[] c9 = new byte[c7.Length]; - asconEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = asconEngine.ProcessBytes(m7, 0, m7.Length, c7, 0); - offset += asconEngine.DoFinal(c7, offset); + ascon.ProcessAadBytes(aad2, 0, aad2.Length); + offset = ascon.ProcessBytes(m7, 0, m7.Length, c7, 0); + offset += ascon.DoFinal(c7, offset); // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - asconEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = asconEngine.ProcessBytes(m7, 0, m7.Length / 2, c8, 0); - offset += asconEngine.ProcessBytes(m7, m7.Length / 2, m7.Length - m7.Length / 2, c8, offset); - offset += asconEngine.DoFinal(c8, offset); + ascon.Init(true, param); + ascon.ProcessAadBytes(aad2, 0, aad2.Length); + offset = ascon.ProcessBytes(m7, 0, m7.Length / 2, c8, 0); + offset += ascon.ProcessBytes(m7, m7.Length / 2, m7.Length - m7.Length / 2, c8, offset); + offset += ascon.DoFinal(c8, offset); // TODO Maybe use a different IV for this - asconEngine.Init(true, param); + ascon.Init(true, param); int split = rand.Next(1, m7.Length); - asconEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = asconEngine.ProcessBytes(m7, 0, split, c9, 0); - offset += asconEngine.ProcessBytes(m7, split, m7.Length - split, c9, offset); - offset += asconEngine.DoFinal(c9, offset); + ascon.ProcessAadBytes(aad2, 0, aad2.Length); + offset = ascon.ProcessBytes(m7, 0, split, c9, 0); + offset += ascon.ProcessBytes(m7, split, m7.Length - split, c9, offset); + offset += ascon.DoFinal(c9, offset); if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9)) { Assert.Fail("Splitting input of plaintext should output the same ciphertext"); } + // NOTE: .NET Core 3.1 has Span, but is tested against our .NET Standard 2.0 assembly. - //#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER +//#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER #if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER // TODO Maybe use a different IV for this - asconEngine.Init(true, param); - Span c4 = new byte[asconEngine.GetOutputSize(m2.Length)]; - asconEngine.ProcessAadBytes(aad2); - offset = asconEngine.ProcessBytes(m2, c4); - offset += asconEngine.DoFinal(c4[offset..]); + ascon.Init(true, param); + Span c4 = new byte[ascon.GetOutputSize(m2.Length)]; + ascon.ProcessAadBytes(aad2); + offset = ascon.ProcessBytes(m2, c4); + offset += ascon.DoFinal(c4[offset..]); if (!c4[..offset].SequenceEqual(c2)) { Assert.Fail("Encryption should match for the same AAD and message with/without Span-based API"); } - asconEngine.Init(false, param); + ascon.Init(false, param); Span m6 = new byte[m2.Length]; - asconEngine.ProcessAadBytes(aad2); - offset = asconEngine.ProcessBytes(c2, m6); - offset += asconEngine.DoFinal(m6[offset..]); + ascon.ProcessAadBytes(aad2); + offset = ascon.ProcessBytes(c2, m6); + offset += ascon.DoFinal(m6[offset..]); if (!m6[..offset].SequenceEqual(m2)) { Assert.Fail("Decryption should match for the same AAD and message with/without Span-based API"); @@ -475,27 +650,106 @@ namespace Org.BouncyCastle.Crypto.Tests #endif } - private void ImplTestParameters(AsconEngine asconEngine, int keySize, int ivSize, int macSize) + private static void ImplTestExceptionsGetUpdateOutputSize(AsconEngine ascon, bool forEncryption, + ICipherParameters parameters, int maxInputSize) + { + // TODO Maybe use a different IV for this + ascon.Init(forEncryption, parameters); + + int maxOutputSize = ascon.GetUpdateOutputSize(maxInputSize); + + byte[] input = new byte[maxInputSize]; + byte[] output = new byte[maxOutputSize]; + + for (int inputSize = 0; inputSize <= maxInputSize; ++inputSize) + { + // TODO Maybe use a different IV for this + ascon.Init(forEncryption, parameters); + + int outputSize = ascon.GetUpdateOutputSize(inputSize); + if (outputSize > 0) + { + try + { + ascon.ProcessBytes(input, 0, inputSize, output, maxOutputSize - outputSize + 1); + Assert.Fail("output for ProcessBytes is too short"); + } + catch (OutputLengthException) + { + //expected + } + } + else + { + ascon.ProcessBytes(input, 0, inputSize, null, 0); + } + } + } + + private static void ImplTestExceptionsXof(AsconXof.AsconParameters asconParameters) + { + var ascon = CreateXof(asconParameters); + + try + { + ascon.BlockUpdate(new byte[1], 1, 1); + Assert.Fail(ascon.AlgorithmName + ": input for BlockUpdate is too short"); + } + catch (DataLengthException) + { + //expected + } + + try + { + ascon.DoFinal(new byte[ascon.GetDigestSize() - 1], 2); + Assert.Fail(ascon.AlgorithmName + ": output for DoFinal is too short"); + } + catch (OutputLengthException) + { + //expected + } + } + + private static void ImplTestParametersDigest(AsconDigest.AsconParameters asconParameters, int digestSize) + { + var ascon = CreateDigest(asconParameters); + + Assert.AreEqual(digestSize, ascon.GetDigestSize(), ascon.AlgorithmName + ": digest size is not correct"); + } + + private static void ImplTestParametersEngine(AsconEngine.AsconParameters asconParameters, int keySize, + int ivSize, int macSize) { - Assert.AreEqual(keySize, asconEngine.GetKeyBytesSize(), - "key bytes of " + asconEngine.AlgorithmName + " is not correct"); - Assert.AreEqual(ivSize, asconEngine.GetIVBytesSize(), - "iv bytes of " + asconEngine.AlgorithmName + " is not correct"); + var ascon = CreateEngine(asconParameters); + + Assert.AreEqual(keySize, ascon.GetKeyBytesSize(), + "key bytes of " + ascon.AlgorithmName + " is not correct"); + Assert.AreEqual(ivSize, ascon.GetIVBytesSize(), + "iv bytes of " + ascon.AlgorithmName + " is not correct"); var parameters = new ParametersWithIV(new KeyParameter(new byte[keySize]), new byte[ivSize]); + ascon.Init(true, parameters); - asconEngine.Init(true, parameters); - Assert.AreEqual(macSize, asconEngine.GetOutputSize(0), - "GetOutputSize of " + asconEngine.AlgorithmName + " is incorrect for encryption"); + Assert.AreEqual(macSize, ascon.GetOutputSize(0), + "GetOutputSize of " + ascon.AlgorithmName + " is incorrect for encryption"); - asconEngine.Init(false, parameters); - Assert.AreEqual(0, asconEngine.GetOutputSize(macSize), - "GetOutputSize of " + asconEngine.AlgorithmName + " is incorrect for decryption"); + ascon.Init(false, parameters); + Assert.AreEqual(0, ascon.GetOutputSize(macSize), + "GetOutputSize of " + ascon.AlgorithmName + " is incorrect for decryption"); } - private void ImplTestVectorsHash(AsconDigest.AsconParameters asconParameters, string filename) + private static void ImplTestParametersXof(AsconXof.AsconParameters asconParameters, int digestSize) { - AsconDigest ascon = new AsconDigest(asconParameters); + var ascon = CreateXof(asconParameters); + + Assert.AreEqual(digestSize, ascon.GetDigestSize(), + ascon.AlgorithmName + ": digest size is not correct"); + } + + private static void ImplTestVectorsDigest(AsconDigest.AsconParameters asconParameters, string filename) + { + var ascon = CreateDigest(asconParameters); var map = new Dictionary(); using (var src = new StreamReader( SimpleTest.GetTestDataAsStream("crypto.ascon." + filename + "_LWC_HASH_KAT_256.txt"))) @@ -530,7 +784,74 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void ImplTestVectorsXof(AsconXof.AsconParameters asconParameters, string filename) + private static void ImplTestVectorsEngine(AsconEngine.AsconParameters asconParameters, string filename) + { + Random random = new Random(); + var asconEngine = CreateEngine(asconParameters); + var buf = new Dictionary(); + //TestSampler sampler = new TestSampler(); + using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.ascon.LWC_AEAD_KAT_" + filename + ".txt"))) + { + Dictionary map = new Dictionary(); + string line; + while ((line = src.ReadLine()) != null) + { + var data = line.Split(' '); + if (data.Length == 1) + { + byte[] key = Hex.Decode(map["Key"]); + byte[] nonce = Hex.Decode(map["Nonce"]); + byte[] ad = Hex.Decode(map["AD"]); + byte[] pt = Hex.Decode(map["PT"]); + byte[] ct = Hex.Decode(map["CT"]); + map.Clear(); + + var parameters = new ParametersWithIV(new KeyParameter(key), nonce); + + // Encrypt + { + asconEngine.Init(true, parameters); + + var rv = new byte[asconEngine.GetOutputSize(pt.Length)]; + random.NextBytes(rv); // should overwrite any existing data + + asconEngine.ProcessAadBytes(ad, 0, ad.Length); + int len = asconEngine.ProcessBytes(pt, 0, pt.Length, rv, 0); + len += asconEngine.DoFinal(rv, len); + + Assert.True(Arrays.AreEqual(rv, 0, len, ct, 0, ct.Length)); + } + + // Decrypt + { + asconEngine.Init(false, parameters); + + var rv = new byte[asconEngine.GetOutputSize(ct.Length)]; + random.NextBytes(rv); // should overwrite any existing data + + asconEngine.ProcessAadBytes(ad, 0, ad.Length); + int len = asconEngine.ProcessBytes(ct, 0, ct.Length, rv, 0); + len += asconEngine.DoFinal(rv, len); + + Assert.True(Arrays.AreEqual(rv, 0, len, pt, 0, pt.Length)); + } + } + else + { + if (data.Length >= 3) + { + map[data[0].Trim()] = data[2].Trim(); + } + else + { + map[data[0].Trim()] = ""; + } + } + } + } + } + + private static void ImplTestVectorsXof(AsconXof.AsconParameters asconParameters, string filename) { AsconXof ascon = new AsconXof(asconParameters); var buf = new Dictionary(); @@ -568,54 +889,14 @@ namespace Org.BouncyCastle.Crypto.Tests } } - private void ImplTestExceptions(AsconDigest asconDigest, int digestSize) + private static void InitEngine(AsconEngine ascon, bool forEncryption) { - Assert.AreEqual(digestSize, asconDigest.GetDigestSize(), - asconDigest.AlgorithmName + ": digest size is not correct"); + int keySize = ascon.GetKeyBytesSize(); + int ivSize = ascon.GetIVBytesSize(); + int macSize = ivSize * 8; - try - { - asconDigest.BlockUpdate(new byte[1], 1, 1); - Assert.Fail(asconDigest.AlgorithmName + ": input for BlockUpdate is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - asconDigest.DoFinal(new byte[digestSize - 1], 2); - Assert.Fail(asconDigest.AlgorithmName + ": output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - } - - private void ImplTestExceptions(AsconXof asconXof, int digestSize) - { - Assert.AreEqual(digestSize, asconXof.GetDigestSize(), - asconXof.AlgorithmName + ": digest size is not correct"); - - try - { - asconXof.BlockUpdate(new byte[1], 1, 1); - Assert.Fail(asconXof.AlgorithmName + ": input for BlockUpdate is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - asconXof.DoFinal(new byte[digestSize - 1], 2); - Assert.Fail(asconXof.AlgorithmName + ": output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } + var parameters = new AeadParameters(new KeyParameter(new byte[keySize]), macSize, new byte[ivSize], null); + ascon.Init(forEncryption, parameters); } } } -- cgit 1.4.1