From d5865255abae4b260a7e3191cc0d591c403eb6fa Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 8 Feb 2023 19:33:39 +0700
Subject: Refactor AsconEngine
---
crypto/src/crypto/engines/AsconEngine.cs | 976 ++++++++++++++++++-------------
crypto/test/src/crypto/test/AsconTest.cs | 337 +++++------
2 files changed, 721 insertions(+), 592 deletions(-)
diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs
index 281c4b0df..6f70ee43b 100644
--- a/crypto/src/crypto/engines/AsconEngine.cs
+++ b/crypto/src/crypto/engines/AsconEngine.cs
@@ -1,8 +1,13 @@
using System;
using System.IO;
+#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
+using System.Runtime.CompilerServices;
+#endif
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines
{
@@ -13,8 +18,8 @@ namespace Org.BouncyCastle.Crypto.Engines
* ASCON AEAD v1.2 with reference to C Reference Impl from: https://github.com/ascon/ascon-c
*
*/
- public class AsconEngine
- : IAeadBlockCipher
+ public sealed class AsconEngine
+ : IAeadCipher
{
public enum AsconParameters
{
@@ -46,9 +51,7 @@ namespace Org.BouncyCastle.Crypto.Engines
private ulong x2;
private ulong x3;
private ulong x4;
- private String algorithmName;
-
- public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+ private string algorithmName;
public string AlgorithmName => algorithmName;
@@ -57,136 +60,301 @@ namespace Org.BouncyCastle.Crypto.Engines
this.asconParameters = asconParameters;
switch (asconParameters)
{
- case AsconParameters.ascon80pq:
- CRYPTO_KEYBYTES = 20;
- CRYPTO_ABYTES = 16;
- ASCON_AEAD_RATE = 8;
- ASCON_IV = 0xa0400c0600000000UL;
- algorithmName = "Ascon-80pq AEAD";
- break;
- case AsconParameters.ascon128a:
- CRYPTO_KEYBYTES = 16;
- CRYPTO_ABYTES = 16;
- ASCON_AEAD_RATE = 16;
- ASCON_IV = 0x80800c0800000000UL;
- algorithmName = "Ascon-128a AEAD";
- break;
- case AsconParameters.ascon128:
- CRYPTO_KEYBYTES = 16;
- CRYPTO_ABYTES = 16;
- ASCON_AEAD_RATE = 8;
- ASCON_IV = 0x80400c0600000000UL;
- algorithmName = "Ascon-128 AEAD";
- break;
- default:
- throw new ArgumentException("invalid parameter setting for ASCON AEAD");
+ case AsconParameters.ascon80pq:
+ CRYPTO_KEYBYTES = 20;
+ CRYPTO_ABYTES = 16;
+ ASCON_AEAD_RATE = 8;
+ ASCON_IV = 0xa0400c0600000000UL;
+ algorithmName = "Ascon-80pq AEAD";
+ break;
+ case AsconParameters.ascon128a:
+ CRYPTO_KEYBYTES = 16;
+ CRYPTO_ABYTES = 16;
+ ASCON_AEAD_RATE = 16;
+ ASCON_IV = 0x80800c0800000000UL;
+ algorithmName = "Ascon-128a AEAD";
+ break;
+ case AsconParameters.ascon128:
+ CRYPTO_KEYBYTES = 16;
+ CRYPTO_ABYTES = 16;
+ ASCON_AEAD_RATE = 8;
+ ASCON_IV = 0x80400c0600000000UL;
+ algorithmName = "Ascon-128 AEAD";
+ break;
+ default:
+ throw new ArgumentException("invalid parameter setting for ASCON AEAD");
}
nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
initialised = false;
}
- private ulong U64BIG(ulong x)
+ public int GetKeyBytesSize()
{
- return (((0x00000000000000FFUL & x) << 56) |
- ((0x000000000000FF00UL & x) << 40) |
- ((0x0000000000FF0000UL & x) << 24) |
- ((0x00000000FF000000UL & x) << 8) |
- ((0x000000FF00000000UL & x) >> 8) |
- ((0x0000FF0000000000UL & x) >> 24) |
- ((0x00FF000000000000UL & x) >> 40) |
- ((0xFF00000000000000UL & x) >> 56));
+ return CRYPTO_KEYBYTES;
}
- private ulong ROR(ulong x, int n)
+ public int GetIVBytesSize()
{
- return x >> n | x << (64 - n);
+ return CRYPTO_ABYTES;
}
- private ulong KEYROT(ulong lo2hi, ulong hi2lo)
+ public void Init(bool forEncryption, ICipherParameters parameters)
{
- return lo2hi << 32 | hi2lo >> 32;
+ this.forEncryption = forEncryption;
+ if (!(parameters is ParametersWithIV withIV))
+ throw new ArgumentException("ASCON Init parameters must include an IV");
+
+ byte[] npub = withIV.GetIV();
+ if (npub == null || npub.Length != CRYPTO_ABYTES)
+ throw new ArgumentException(asconParameters + " requires exactly " + CRYPTO_ABYTES + " bytes of IV");
+
+ if (!(withIV.Parameters is KeyParameter key))
+ throw new ArgumentException("ASCON Init parameters must include a key");
+
+ byte[] k = key.GetKey();
+ if (k.Length != CRYPTO_KEYBYTES)
+ throw new ArgumentException(asconParameters + " key must be " + CRYPTO_KEYBYTES + " bytes long");
+
+ N0 = Pack.BE_To_UInt64(npub, 0);
+ N1 = Pack.BE_To_UInt64(npub, 8);
+ if (CRYPTO_KEYBYTES == 16)
+ {
+ K1 = Pack.BE_To_UInt64(k, 0);
+ K2 = Pack.BE_To_UInt64(k, 8);
+ }
+ else if (CRYPTO_KEYBYTES == 20)
+ {
+ K0 = Pack.BE_To_UInt32(k, 0);
+ K1 = Pack.BE_To_UInt64(k, 4);
+ K2 = Pack.BE_To_UInt64(k, 12);
+ }
+ initialised = true;
+ /*Mask-Gen*/
+ Reset(false);
}
- private ulong PAD(int i)
+ public void ProcessAadByte(byte input)
{
- return 0x80UL << (56 - (i << 3));
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+
+ aadData.WriteByte(input);
}
- private ulong MASK(int n)
+ public void ProcessAadBytes(byte[] inBytes, int inOff, int len)
{
- /* undefined for n == 0 */
- return ~0UL >> (64 - (n << 3));
+ if (aadFinished)
+ {
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ }
+
+ Check.DataLength(inBytes, inOff, len, "input buffer too short");
+
+ aadData.Write(inBytes, inOff, len);
}
- private ulong LOAD(byte[] bytes, int inOff, int n)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void ProcessAadBytes(ReadOnlySpan input)
{
- ulong x = 0;
- int len = System.Math.Min(8, bytes.Length - inOff);
- for (int i = 0; i < len; ++i)
+ if (aadFinished)
{
- x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+ throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+ " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
}
- return U64BIG(x & MASK(n));
+
+ aadData.Write(input);
+ }
+#endif
+
+ public int ProcessByte(byte input, byte[] outBytes, int outOff)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessByte(input, Spans.FromNullable(outBytes, outOff));
+#else
+ return ProcessBytes(new byte[]{ input }, 0, 1, outBytes, outOff);
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessByte(byte input, Span output)
+ {
+ Span singleByte = stackalloc byte[1]{ input };
+
+ return ProcessBytes(singleByte, output);
}
+#endif
- private void STORE(byte[] bytes, int inOff, ulong w, int n)
+ public int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
{
- ulong x = 0;
- for (int i = 0; i < n; ++i)
+ Check.DataLength(inBytes, inOff, len, "input buffer too short");
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
+#else
+ if (!initialised)
+ throw new ArgumentException("Need to call Init function before encryption/decryption");
+
+ message.Write(inBytes, inOff, len);
+ int rv = ProcessBytes(outBytes, outOff);
+ encrypted = true;
+ return rv;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessBytes(ReadOnlySpan input, Span output)
+ {
+ if (!initialised)
+ throw new ArgumentException("Need to call Init function before encryption/decryption");
+
+ message.Write(input);
+ int rv = ProcessBytes(output);
+ encrypted = true;
+ return rv;
+ }
+#endif
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(outBytes.AsSpan(outOff));
+#else
+ if (!initialised)
+ throw new ArgumentException("Need call init function before encryption/decryption");
+
+ if (!aadFinished)
+ {
+ ProcessAad();
+ }
+ if (!encrypted)
+ {
+ ProcessBytes(Array.Empty(), 0, 0, Array.Empty(), 0);
+ }
+ byte[] input = message.GetBuffer();
+ int len = Convert.ToInt32(message.Length);
+ if (forEncryption)
{
- x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+ Check.OutputLength(outBytes, outOff, len + CRYPTO_ABYTES, "output buffer too short");
}
- x &= ~MASK(n);
- x |= U64BIG(w);
- for (int i = 0; i < n; ++i)
+ else
{
- bytes[i + inOff] = (byte)(x >> (i << 3));
+ Check.OutputLength(outBytes, outOff, len - CRYPTO_ABYTES, "output buffer too short");
}
+ if (forEncryption)
+ {
+ ascon_final(outBytes, outOff, input, 0, len);
+ /* set tag */
+ mac = new byte[16];
+ Pack.UInt64_To_BE(x3, mac, 0);
+ Pack.UInt64_To_BE(x4, mac, 8);
+ Array.Copy(mac, 0, outBytes, len + outOff, 16);
+ Reset(false);
+ return len + CRYPTO_ABYTES;
+ }
+ else
+ {
+ len -= CRYPTO_ABYTES;
+ ascon_final(outBytes, outOff, input, 0, len);
+ x3 ^= Pack.BE_To_UInt64(input, len);
+ x4 ^= Pack.BE_To_UInt64(input, len + 8);
+ ulong result = x3 | x4;
+ Reset(true);
+
+ if (result != 0UL)
+ throw new ArgumentException("Mac does not match");
+
+ return len;
+ }
+#endif
}
- private ulong LOADBYTES(byte[] bytes, int inOff, int n)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span output)
{
- ulong x = 0;
- for (int i = 0; i < n; ++i)
+ if (!initialised)
+ throw new ArgumentException("Need call init function before encryption/decryption");
+
+ if (!aadFinished)
+ {
+ ProcessAad();
+ }
+ if (!encrypted)
+ {
+ ProcessBytes(Array.Empty(), 0, 0, Array.Empty(), 0);
+ }
+ byte[] input = message.GetBuffer();
+ int len = Convert.ToInt32(message.Length);
+ if (forEncryption)
+ {
+ Check.OutputLength(output, len + CRYPTO_ABYTES, "output buffer too short");
+ }
+ else
+ {
+ Check.OutputLength(output, len - CRYPTO_ABYTES, "output buffer too short");
+ }
+ if (forEncryption)
+ {
+ ascon_final(output, input.AsSpan(0, len));
+ /* set tag */
+ mac = new byte[CRYPTO_ABYTES];
+ Pack.UInt64_To_BE(x3, mac, 0);
+ Pack.UInt64_To_BE(x4, mac, 8);
+ mac.AsSpan(0, CRYPTO_ABYTES).CopyTo(output[len..]);
+ Reset(false);
+ return len + CRYPTO_ABYTES;
+ }
+ else
{
- x |= (bytes[i + inOff] & 0xFFUL) << ((7 - i) << 3);
+ len -= CRYPTO_ABYTES;
+ ascon_final(output, input.AsSpan(0, len));
+ x3 ^= Pack.BE_To_UInt64(input, len);
+ x4 ^= Pack.BE_To_UInt64(input, len + 8);
+ ulong result = x3 | x4;
+ Reset(true);
+
+ if (result != 0UL)
+ throw new ArgumentException("Mac does not match");
+
+ return len;
}
- return x;
}
+#endif
- private void STOREBYTES(byte[] bytes, int inOff, ulong w, int n)
+ public byte[] GetMac()
{
- for (int i = 0; i < n; ++i)
- {
- bytes[i + inOff] = (byte)(w >> ((7 - i) << 3));
- }
+ return mac;
+ }
+
+ public int GetUpdateOutputSize(int len)
+ {
+ return len;
}
- private void ROUND(ulong C)
+ public int GetOutputSize(int len)
{
- ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
- ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
- ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
- ulong t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
- ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
- x0 = t0 ^ ROR(t0, 19) ^ ROR(t0, 28);
- x1 = t1 ^ ROR(t1, 39) ^ ROR(t1, 61);
- x2 = ~(t2 ^ ROR(t2, 1) ^ ROR(t2, 6));
- x3 = t3 ^ ROR(t3, 10) ^ ROR(t3, 17);
- x4 = t4 ^ ROR(t4, 7) ^ ROR(t4, 41);
+ return len + CRYPTO_ABYTES;
+ }
+
+ public void Reset()
+ {
+ Reset(true);
}
private void P(int nr)
{
- if (nr == 12)
- {
- ROUND(0xf0UL);
- ROUND(0xe1UL);
- ROUND(0xd2UL);
- ROUND(0xc3UL);
- }
if (nr >= 8)
{
+ if (nr == 12)
+ {
+ ROUND(0xf0UL);
+ ROUND(0xe1UL);
+ ROUND(0xd2UL);
+ ROUND(0xc3UL);
+ }
ROUND(0xb4UL);
ROUND(0xa5UL);
}
@@ -198,6 +366,39 @@ namespace Org.BouncyCastle.Crypto.Engines
ROUND(0x4bUL);
}
+#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ private void ROUND(ulong c)
+ {
+ ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ c ^ (x1 & (x0 ^ x2 ^ x4 ^ c));
+ ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ c ^ ((x1 ^ x2 ^ c) & (x1 ^ x3));
+ ulong t2 = x1 ^ x2 ^ x4 ^ c ^ (x3 & x4);
+ ulong t3 = x0 ^ x1 ^ x2 ^ c ^ ((~x0) & (x3 ^ x4));
+ ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+ x0 = t0 ^ Longs.RotateRight(t0, 19) ^ Longs.RotateRight(t0, 28);
+ x1 = t1 ^ Longs.RotateRight(t1, 39) ^ Longs.RotateRight(t1, 61);
+ x2 = ~(t2 ^ Longs.RotateRight(t2, 1) ^ Longs.RotateRight(t2, 6));
+ x3 = t3 ^ Longs.RotateRight(t3, 10) ^ Longs.RotateRight(t3, 17);
+ x4 = t4 ^ Longs.RotateRight(t4, 7) ^ Longs.RotateRight(t4, 41);
+ }
+
+ private void ProcessAad()
+ {
+ if (!aadFinished)
+ {
+ byte[] ad = aadData.GetBuffer();
+ int adlen = Convert.ToInt32(aadData.Length);
+ /* perform ascon computation */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ascon_adata(ad.AsSpan(0, adlen));
+#else
+ ascon_adata(ad, 0, adlen);
+#endif
+ aadFinished = true;
+ }
+ }
+
private void ascon_aeadinit()
{
/* initialize */
@@ -219,40 +420,72 @@ namespace Org.BouncyCastle.Crypto.Engines
x4 ^= K2;
}
- private void ascon_adata(byte[] ad, int adOff, int adlen)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int ProcessBytes(Span output)
{
- if (adlen != 0)
+ int len_orig = Convert.ToInt32(message.Length);
+ int len = 0;
+ if (forEncryption)
+ {
+ if (len_orig >= ASCON_AEAD_RATE)
+ {
+ ProcessAad();
+ byte[] input = message.GetBuffer();
+ len = (len_orig / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+ Check.OutputLength(output, len, "output buffer is too short");
+ ascon_encrypt(output, input.AsSpan(0, len));
+ message.SetLength(0);
+ message.Write(input, len, len_orig - len);
+ }
+ }
+ else
+ {
+ if (len_orig - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
+ {
+ ProcessAad();
+ byte[] input = message.GetBuffer();
+ len = ((len_orig - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+ Check.OutputLength(output, len, "output buffer is too short");
+ ascon_decrypt(output, input.AsSpan(0, len));
+ message.SetLength(0);
+ message.Write(input, len, len_orig - len);
+ }
+ }
+ return len;
+ }
+
+ private void ascon_adata(ReadOnlySpan aad)
+ {
+ if (!aad.IsEmpty)
{
/* full associated data blocks */
- while (adlen >= ASCON_AEAD_RATE)
+ while (aad.Length >= ASCON_AEAD_RATE)
{
- x0 ^= LOAD(ad, adOff, 8);
+ x0 ^= Pack.BE_To_UInt64(aad);
if (ASCON_AEAD_RATE == 16)
{
- x1 ^= LOAD(ad, adOff + 8, 8);
+ x1 ^= Pack.BE_To_UInt64(aad[8..]);
}
P(nr);
- adOff += ASCON_AEAD_RATE;
- adlen -= ASCON_AEAD_RATE;
+ aad = aad[ASCON_AEAD_RATE..];
}
- /* readonly associated data block */
- if (ASCON_AEAD_RATE == 16 && adlen >= 8)
+ /* final associated data block */
+ if (ASCON_AEAD_RATE == 16 && aad.Length >= 8)
{
- x0 ^= LOAD(ad, adOff, 8);
- adOff += 8;
- adlen -= 8;
- x1 ^= PAD(adlen);
- if (adlen != 0)
+ x0 ^= Pack.BE_To_UInt64(aad);
+ aad = aad[8..];
+ x1 ^= PAD(aad.Length);
+ if (!aad.IsEmpty)
{
- x1 ^= LOAD(ad, adOff, adlen);
+ x1 ^= Pack.BE_To_UInt64_High(aad);
}
}
else
{
- x0 ^= PAD(adlen);
- if (adlen != 0)
+ x0 ^= PAD(aad.Length);
+ if (!aad.IsEmpty)
{
- x0 ^= LOAD(ad, adOff, adlen);
+ x0 ^= Pack.BE_To_UInt64_High(aad);
}
}
P(nr);
@@ -261,115 +494,104 @@ namespace Org.BouncyCastle.Crypto.Engines
x4 ^= 1UL;
}
- private void ascon_encrypt(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+ private void ascon_encrypt(Span c, ReadOnlySpan m)
{
/* full plaintext blocks */
- while (mlen >= ASCON_AEAD_RATE)
+ while (m.Length >= ASCON_AEAD_RATE)
{
- x0 ^= LOAD(m, mOff, 8);
- STORE(c, cOff, x0, 8);
+ x0 ^= Pack.BE_To_UInt64(m);
+ Pack.UInt64_To_BE(x0, c);
if (ASCON_AEAD_RATE == 16)
{
- x1 ^= LOAD(m, mOff + 8, 8);
- STORE(c, cOff + 8, x1, 8);
+ x1 ^= Pack.BE_To_UInt64(m[8..]);
+ Pack.UInt64_To_BE(x1, c[8..]);
}
P(nr);
- mOff += ASCON_AEAD_RATE;
- cOff += ASCON_AEAD_RATE;
- mlen -= ASCON_AEAD_RATE;
+ m = m[ASCON_AEAD_RATE..];
+ c = c[ASCON_AEAD_RATE..];
}
}
- private void ascon_decrypt(byte[] m, int mOff, byte[] c, int cOff, int clen)
+ private void ascon_decrypt(Span m, ReadOnlySpan c)
{
/* full ciphertext blocks */
- while (clen >= ASCON_AEAD_RATE)
+ while (c.Length >= ASCON_AEAD_RATE)
{
- ulong cx = LOAD(c, cOff, 8);
+ ulong cx = Pack.BE_To_UInt64(c);
x0 ^= cx;
- STORE(m, mOff, x0, 8);
+ Pack.UInt64_To_BE(x0, m);
x0 = cx;
if (ASCON_AEAD_RATE == 16)
{
- cx = LOAD(c, cOff + 8, 8);
+ cx = Pack.BE_To_UInt64(c[8..]);
x1 ^= cx;
- STORE(m, mOff + 8, x1, 8);
+ Pack.UInt64_To_BE(x1, m[8..]);
x1 = cx;
}
P(nr);
- mOff += ASCON_AEAD_RATE;
- cOff += ASCON_AEAD_RATE;
- clen -= ASCON_AEAD_RATE;
+ c = c[ASCON_AEAD_RATE..];
+ m = m[ASCON_AEAD_RATE..];
}
}
- private ulong CLEAR(ulong w, int n)
- {
- /* undefined for n == 0 */
- ulong mask = 0x00ffffffffffffffUL >> (n * 8 - 8);
- return w & mask;
- }
-
- private void ascon_final(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+ private void ascon_final(Span output, ReadOnlySpan input)
{
if (forEncryption)
{
/* final plaintext block */
- if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+ if (ASCON_AEAD_RATE == 16 && input.Length >= 8)
{
- x0 ^= LOAD(m, mOff, 8);
- STORE(c, cOff, x0, 8);
- mOff += 8;
- cOff += 8;
- mlen -= 8;
- x1 ^= PAD(mlen);
- if (mlen != 0)
+ x0 ^= Pack.BE_To_UInt64(input);
+ Pack.UInt64_To_BE(x0, output);
+ input = input[8..];
+ output = output[8..];
+ x1 ^= PAD(input.Length);
+ if (!input.IsEmpty)
{
- x1 ^= LOAD(m, mOff, mlen);
- STORE(c, cOff, x1, mlen);
+ x1 ^= Pack.BE_To_UInt64_High(input);
+ Pack.UInt64_To_BE_High(x1, output[..input.Length]);
}
}
else
{
- x0 ^= PAD(mlen);
- if (mlen != 0)
+ x0 ^= PAD(input.Length);
+ if (!input.IsEmpty)
{
- x0 ^= LOAD(m, mOff, mlen);
- STORE(c, cOff, x0, mlen);
+ x0 ^= Pack.BE_To_UInt64_High(input);
+ Pack.UInt64_To_BE_High(x0, output[..input.Length]);
}
}
}
else
{
/* final ciphertext block */
- if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+ if (ASCON_AEAD_RATE == 16 && input.Length >= 8)
{
- ulong cx = LOAD(m, mOff, 8);
+ ulong cx = Pack.BE_To_UInt64(input);
x0 ^= cx;
- STORE(c, cOff, x0, 8);
+ Pack.UInt64_To_BE(x0, output);
x0 = cx;
- mOff += 8;
- cOff += 8;
- mlen -= 8;
- x1 ^= PAD(mlen);
- if (mlen != 0)
+ input = input[8..];
+ output = output[8..];
+ x1 ^= PAD(input.Length);
+ if (!input.IsEmpty)
{
- cx = LOAD(m, mOff, mlen);
+ cx = Pack.BE_To_UInt64_High(input);
x1 ^= cx;
- STORE(c, cOff, x1, mlen);
- x1 = CLEAR(x1, mlen);
+ Pack.UInt64_To_BE_High(x1, output[..input.Length]);
+ x1 &= ulong.MaxValue >> (input.Length << 3);
x1 ^= cx;
}
}
else
{
- x0 ^= PAD(mlen);
- if (mlen != 0)
+ x0 ^= PAD(input.Length);
+ if (!input.IsEmpty)
{
- ulong cx = LOAD(m, mOff, mlen);
+ ulong cx = Pack.BE_To_UInt64_High(input);
x0 ^= cx;
- STORE(c, cOff, x0, mlen);
- x0 = CLEAR(x0, mlen);
+ Pack.UInt64_To_BE_High(x0, output[..input.Length]);
+ x0 &= ulong.MaxValue >> (input.Length << 3);
x0 ^= cx;
}
}
@@ -377,247 +599,234 @@ namespace Org.BouncyCastle.Crypto.Engines
/* finalize */
switch (asconParameters)
{
- case AsconParameters.ascon128:
- x1 ^= K1;
- x2 ^= K2;
- break;
- case AsconParameters.ascon128a:
- x2 ^= K1;
- x3 ^= K2;
- break;
- case AsconParameters.ascon80pq:
- x1 ^= KEYROT(K0, K1);
- x2 ^= KEYROT(K1, K2);
- x3 ^= KEYROT(K2, 0UL);
- break;
+ case AsconParameters.ascon128:
+ x1 ^= K1;
+ x2 ^= K2;
+ break;
+ case AsconParameters.ascon128a:
+ x2 ^= K1;
+ x3 ^= K2;
+ break;
+ case AsconParameters.ascon80pq:
+ x1 ^= (K0 << 32 | K1 >> 32);
+ x2 ^= (K1 << 32 | K2 >> 32);
+ x3 ^= K2 << 32;
+ break;
}
P(12);
x3 ^= K1;
x4 ^= K2;
}
-
- public void Init(bool forEncryption, ICipherParameters param)
+#else
+ private int ProcessBytes(byte[] output, int outOff)
{
- this.forEncryption = forEncryption;
- if (!(param is ParametersWithIV))
- {
- throw new ArgumentException(
- "ASCON init parameters must include an IV");
- }
- ParametersWithIV ivParams = (ParametersWithIV)param;
- byte[] npub = ivParams.GetIV();
- if (npub == null || npub.Length != CRYPTO_ABYTES)
- {
- throw new ArgumentException(asconParameters + " requires exactly " + CRYPTO_ABYTES + " bytes of IV");
- }
- if (!(ivParams.Parameters is KeyParameter))
- {
- throw new ArgumentException(
- "ASCON init parameters must include a key");
- }
- KeyParameter key = (KeyParameter)ivParams.Parameters;
- byte[] k = key.GetKey();
- if (k.Length != CRYPTO_KEYBYTES)
- {
- throw new ArgumentException(asconParameters + " key must be " + CRYPTO_KEYBYTES + " bytes long");
- }
- N0 = LOAD(npub, 0, 8);
- N1 = LOAD(npub, 8, 8);
- if (CRYPTO_KEYBYTES == 16)
- {
- K1 = LOAD(k, 0, 8);
- K2 = LOAD(k, 8, 8);
- }
- else if (CRYPTO_KEYBYTES == 20)
+ int len_orig = Convert.ToInt32(message.Length);
+ int len = 0;
+ if (forEncryption)
{
- K0 = KEYROT(0, LOADBYTES(k, 0, 4));
- K1 = LOADBYTES(k, 4, 8);
- K2 = LOADBYTES(k, 12, 8);
+ if (len_orig >= ASCON_AEAD_RATE)
+ {
+ ProcessAad();
+ byte[] input = message.GetBuffer();
+ len = (len_orig / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+ Check.OutputLength(output, outOff, len, "output buffer is too short");
+ ascon_encrypt(output, outOff, input, 0, len);
+ message.SetLength(0);
+ message.Write(input, len, len_orig - len);
+ }
}
- initialised = true;
- /*Mask-Gen*/
- reset(false);
- }
-
- public void ProcessAadByte(byte input)
- {
- if (aadFinished)
+ else
{
- throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
- " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+ if (len_orig - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
+ {
+ ProcessAad();
+ byte[] input = message.GetBuffer();
+ len = ((len_orig - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+ Check.OutputLength(output, outOff, len, "output buffer is too short");
+ ascon_decrypt(output, outOff, input, 0, len);
+ message.SetLength(0);
+ message.Write(input, len, len_orig - len);
+ }
}
- aadData.Write(new byte[] { input }, 0, 1);
+ return len;
}
-
- public void ProcessAadBytes(byte[] input, int inOff, int len)
+ private void ascon_adata(byte[] ad, int adOff, int adlen)
{
- if (aadFinished)
- {
- throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
- " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
- }
- if ((inOff + len) > input.Length)
+ if (adlen != 0)
{
- throw new DataLengthException("input buffer too short");
+ /* full associated data blocks */
+ while (adlen >= ASCON_AEAD_RATE)
+ {
+ x0 ^= Pack.BE_To_UInt64(ad, adOff);
+ if (ASCON_AEAD_RATE == 16)
+ {
+ x1 ^= Pack.BE_To_UInt64(ad, adOff + 8);
+ }
+ P(nr);
+ adOff += ASCON_AEAD_RATE;
+ adlen -= ASCON_AEAD_RATE;
+ }
+ /* final associated data block */
+ if (ASCON_AEAD_RATE == 16 && adlen >= 8)
+ {
+ x0 ^= Pack.BE_To_UInt64(ad, adOff);
+ adOff += 8;
+ adlen -= 8;
+ x1 ^= PAD(adlen);
+ if (adlen != 0)
+ {
+ x1 ^= Pack.BE_To_UInt64_High(ad, adOff, adlen);
+ }
+ }
+ else
+ {
+ x0 ^= PAD(adlen);
+ if (adlen != 0)
+ {
+ x0 ^= Pack.BE_To_UInt64_High(ad, adOff, adlen);
+ }
+ }
+ P(nr);
}
- aadData.Write(input, inOff, len);
- }
-
-
- public int ProcessByte(byte input, byte[] output, int outOff)
- {
- return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+ /* domain separation */
+ x4 ^= 1UL;
}
-
- public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ private void ascon_encrypt(byte[] c, int cOff, byte[] m, int mOff, int mlen)
{
- if (!initialised)
- {
- throw new ArgumentException("Need call init function before encryption/decryption");
- }
- if ((inOff + len) > input.Length)
+ /* full plaintext blocks */
+ while (mlen >= ASCON_AEAD_RATE)
{
- throw new DataLengthException("input buffer too short");
+ x0 ^= Pack.BE_To_UInt64(m, mOff);
+ Pack.UInt64_To_BE(x0, c, cOff);
+ if (ASCON_AEAD_RATE == 16)
+ {
+ x1 ^= Pack.BE_To_UInt64(m, mOff + 8);
+ Pack.UInt64_To_BE(x1, c, cOff + 8);
+ }
+ P(nr);
+ mOff += ASCON_AEAD_RATE;
+ cOff += ASCON_AEAD_RATE;
+ mlen -= ASCON_AEAD_RATE;
}
- message.Write(input, inOff, len);
- int rv = processBytes(output, outOff);
- encrypted = true;
- return rv;
}
- private void processAAD()
+ private void ascon_decrypt(byte[] m, int mOff, byte[] c, int cOff, int clen)
{
- if (!aadFinished)
+ /* full ciphertext blocks */
+ while (clen >= ASCON_AEAD_RATE)
{
- byte[] ad = aadData.GetBuffer();
- int adlen = (int)aadData.Length;
- /* perform ascon computation */
- ascon_adata(ad, 0, adlen);
- aadFinished = true;
+ ulong cx = Pack.BE_To_UInt64(c, cOff);
+ x0 ^= cx;
+ Pack.UInt64_To_BE(x0, m, mOff);
+ x0 = cx;
+ if (ASCON_AEAD_RATE == 16)
+ {
+ cx = Pack.BE_To_UInt64(c, cOff + 8);
+ x1 ^= cx;
+ Pack.UInt64_To_BE(x1, m, mOff + 8);
+ x1 = cx;
+ }
+ P(nr);
+ mOff += ASCON_AEAD_RATE;
+ cOff += ASCON_AEAD_RATE;
+ clen -= ASCON_AEAD_RATE;
}
}
- private int processBytes(byte[] output, int outOff)
+ private void ascon_final(byte[] c, int cOff, byte[] m, int mOff, int mlen)
{
- int len = 0;
if (forEncryption)
{
- if ((int)message.Length >= ASCON_AEAD_RATE)
+ /* final plaintext block */
+ if (ASCON_AEAD_RATE == 16 && mlen >= 8)
{
- processAAD();
- byte[] input = message.GetBuffer();
- len = ((int)message.Length / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
- if (len + outOff > output.Length)
+ x0 ^= Pack.BE_To_UInt64(m, mOff);
+ Pack.UInt64_To_BE(x0, c, cOff);
+ mOff += 8;
+ cOff += 8;
+ mlen -= 8;
+ x1 ^= PAD(mlen);
+ if (mlen != 0)
{
- throw new OutputLengthException("output buffer is too short");
+ x1 ^= Pack.BE_To_UInt64_High(m, mOff, mlen);
+ Pack.UInt64_To_BE_High(x1, c, cOff, mlen);
}
- ascon_encrypt(output, outOff, input, 0, len);
- int len_orig = (int)message.Length;
- message.SetLength(0);
- message.Write(input, len, len_orig - len);
}
- }
- else
- {
- if ((int)message.Length - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
+ else
{
- processAAD();
- byte[] input = message.GetBuffer();
- len = (((int)message.Length - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
- if (len + outOff > output.Length)
+ x0 ^= PAD(mlen);
+ if (mlen != 0)
{
- throw new OutputLengthException("output buffer is too short");
+ x0 ^= Pack.BE_To_UInt64_High(m, mOff, mlen);
+ Pack.UInt64_To_BE_High(x0, c, cOff, mlen);
}
- ascon_decrypt(output, outOff, input, 0, len);
- int len_orig = (int)message.Length;
- message.SetLength(0);
- message.Write(input, len, len_orig - len);
}
}
- return len;
- }
-
- public int DoFinal(byte[] output, int outOff)
- {
- if (!initialised)
- {
- throw new ArgumentException("Need call init function before encryption/decryption");
- }
- if (!aadFinished)
- {
- processAAD();
- }
- if (!encrypted)
- {
- ProcessBytes(new byte[] { }, 0, 0, new byte[] { }, 0);
- }
- byte[] input = message.GetBuffer();
- int len = (int)message.Length;
- if ((forEncryption && outOff + len + CRYPTO_ABYTES > output.Length) ||
- (!forEncryption && outOff + len - CRYPTO_ABYTES > output.Length))
- {
- throw new OutputLengthException("output buffer too short");
- }
- if (forEncryption)
- {
- ascon_final(output, outOff, input, 0, len);
- /* set tag */
- mac = new byte[16];
- STOREBYTES(mac, 0, x3, 8);
- STOREBYTES(mac, 8, x4, 8);
- Array.Copy(mac, 0, output, len + outOff, 16);
- reset(false);
- return len + CRYPTO_ABYTES;
- }
else
{
- len -= CRYPTO_ABYTES;
- ascon_final(output, outOff, input, 0, len);
- x3 ^= LOADBYTES(input, len, 8);
- x4 ^= LOADBYTES(input, len + 8, 8);
- ulong result = x3 | x4;
- result |= result >> 32;
- result |= result >> 16;
- result |= result >> 8;
- reset(true);
- if ((((((int)(result & 0xffUL) - 1) >> 8) & 1) - 1) != 0)
+ /* final ciphertext block */
+ if (ASCON_AEAD_RATE == 16 && mlen >= 8)
{
- throw new ArgumentException("Mac does not match");
+ ulong cx = Pack.BE_To_UInt64(m, mOff);
+ x0 ^= cx;
+ Pack.UInt64_To_BE(x0, c, cOff);
+ x0 = cx;
+ mOff += 8;
+ cOff += 8;
+ mlen -= 8;
+ x1 ^= PAD(mlen);
+ if (mlen != 0)
+ {
+ cx = Pack.BE_To_UInt64_High(m, mOff, mlen);
+ x1 ^= cx;
+ Pack.UInt64_To_BE_High(x1, c, cOff, mlen);
+ x1 &= ulong.MaxValue >> (mlen << 3);
+ x1 ^= cx;
+ }
+ }
+ else
+ {
+ x0 ^= PAD(mlen);
+ if (mlen != 0)
+ {
+ ulong cx = Pack.BE_To_UInt64_High(m, mOff, mlen);
+ x0 ^= cx;
+ Pack.UInt64_To_BE_High(x0, c, cOff, mlen);
+ x0 &= ulong.MaxValue >> (mlen << 3);
+ x0 ^= cx;
+ }
}
- return len;
}
+ /* finalize */
+ switch (asconParameters)
+ {
+ case AsconParameters.ascon128:
+ x1 ^= K1;
+ x2 ^= K2;
+ break;
+ case AsconParameters.ascon128a:
+ x2 ^= K1;
+ x3 ^= K2;
+ break;
+ case AsconParameters.ascon80pq:
+ x1 ^= (K0 << 32 | K1 >> 32);
+ x2 ^= (K1 << 32 | K2 >> 32);
+ x3 ^= K2 << 32;
+ break;
+ }
+ P(12);
+ x3 ^= K1;
+ x4 ^= K2;
}
+#endif
-
- public byte[] GetMac()
- {
- return mac;
- }
-
-
- public int GetUpdateOutputSize(int len)
- {
- return len;
- }
-
- public int GetOutputSize(int len)
- {
- return len + CRYPTO_ABYTES;
- }
-
- public void Reset()
- {
- reset(true);
- }
-
- private void reset(bool clearMac)
+ private void Reset(bool clearMac)
{
if (!initialised)
- {
throw new ArgumentException("Need call init function before encryption/decryption");
- }
+
x0 = x1 = x2 = x3 = x4 = 0;
ascon_aeadinit();
aadData.SetLength(0);
@@ -630,64 +839,9 @@ namespace Org.BouncyCastle.Crypto.Engines
}
}
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- public void ProcessAadBytes(ReadOnlySpan input)
+ private static ulong PAD(int i)
{
- if (aadFinished)
- {
- throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
- " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
- }
- aadData.Write(input);
- }
-
- public int ProcessByte(byte input, Span output)
- {
- byte[] rv = new byte[1];
- int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
- rv.AsSpan(0, len).CopyTo(output);
- return len;
- }
-
- public int ProcessBytes(ReadOnlySpan input, Span output)
- {
- byte[] rv = new byte[input.Length];
- int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
- rv.AsSpan(0, len).CopyTo(output);
- return len;
- }
-
- public int DoFinal(Span output)
- {
- byte[] rv;
- if (forEncryption)
- {
- rv = new byte[message.Length + 16];
- }
- else
- {
- rv = new byte[message.Length];
- }
- int len = DoFinal(rv, 0);
- rv.AsSpan(0, len).CopyTo(output);
- return rv.Length;
- }
-#endif
- public int GetBlockSize()
- {
- return ASCON_AEAD_RATE;
- }
-
- public int GetKeyBytesSize()
- {
- return CRYPTO_KEYBYTES;
- }
-
- public int GetIVBytesSize()
- {
- return CRYPTO_ABYTES;
+ return 0x8000000000000000UL >> (i << 3);
}
}
}
-
-
diff --git a/crypto/test/src/crypto/test/AsconTest.cs b/crypto/test/src/crypto/test/AsconTest.cs
index 837dc413b..eca949471 100644
--- a/crypto/test/src/crypto/test/AsconTest.cs
+++ b/crypto/test/src/crypto/test/AsconTest.cs
@@ -5,7 +5,6 @@ using System.IO;
using NUnit.Framework;
using Org.BouncyCastle.Crypto.Engines;
-using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
@@ -14,87 +13,82 @@ using Org.BouncyCastle.Utilities.Test;
namespace Org.BouncyCastle.Crypto.Tests
{
[TestFixture]
- public class AsconTest : SimpleTest
+ public class AsconTest
+ : SimpleTest
{
- public override string Name
- {
- get { return "ASCON AEAD"; }
- }
+ public override string Name => "ASCON AEAD";
[Test]
public override void PerformTest()
{
- AsconEngine Ascon = new AsconEngine(AsconEngine.AsconParameters.ascon80pq);
- testExceptions(Ascon, Ascon.GetKeyBytesSize(), Ascon.GetIVBytesSize(), Ascon.GetBlockSize());
- testParameters(Ascon, 20, 16, 16, 8);
- Ascon = new AsconEngine(AsconEngine.AsconParameters.ascon128a);
- testExceptions(Ascon, Ascon.GetKeyBytesSize(), Ascon.GetIVBytesSize(), Ascon.GetBlockSize());
- testParameters(Ascon, 16, 16, 16, 16);
- Ascon = new AsconEngine(AsconEngine.AsconParameters.ascon128);
- testExceptions(Ascon, Ascon.GetKeyBytesSize(), Ascon.GetIVBytesSize(), Ascon.GetBlockSize());
- testParameters(Ascon, 16, 16, 16, 8);
- testVectors(AsconEngine.AsconParameters.ascon80pq, "160_128");
- testVectors(AsconEngine.AsconParameters.ascon128a, "128_128_a");
- testVectors(AsconEngine.AsconParameters.ascon128, "128_128");
+ 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);
+
+ 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 testVectors(AsconEngine.AsconParameters asconParameters, string filename)
+ private void ImplTestVectors(AsconEngine.AsconParameters asconParameters, string filename)
{
+ Random random = new Random();
AsconEngine Ascon = new AsconEngine(asconParameters);
- ICipherParameters param;
var buf = new Dictionary();
//TestSampler sampler = new TestSampler();
using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.ascon.LWC_AEAD_KAT_" + filename + ".txt")))
{
- string line;
- string[] data;
- byte[] rv;
Dictionary map = new Dictionary();
+ string line;
while ((line = src.ReadLine()) != null)
{
- data = line.Split(' ');
+ var data = line.Split(' ');
if (data.Length == 1)
{
- //if (!map["Count"].Equals("265"))
- //{
- // continue;
- //}
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"]);
- param = new ParametersWithIV(new KeyParameter(key), nonce);
- Ascon.Init(true, param);
- Ascon.ProcessAadBytes(ad, 0, ad.Length);
- rv = new byte[Ascon.GetOutputSize(pt.Length)];
- int len = Ascon.ProcessBytes(pt, 0, pt.Length, rv, 0);
- //byte[] mac = new byte[16];
- Ascon.DoFinal(rv, len);
- //foreach(byte b in Hex.Decode(map["CT"]))
- //{
- // Console.Write(b.ToString("X2"));
- //}
- //Console.WriteLine();
- //foreach (byte b in Arrays.Concatenate(rv, mac))
- //{
- // Console.Write(b.ToString("X2"));
- //}
- //Console.WriteLine();
- Assert.True(Arrays.AreEqual(rv, ct));
- Ascon.Reset();
- Ascon.Init(false, param);
- //Decrypt
- Ascon.ProcessAadBytes(ad, 0, ad.Length);
- rv = new byte[pt.Length + 16];
- len = Ascon.ProcessBytes(ct, 0, ct.Length, rv, 0);
- Ascon.DoFinal(rv, len);
- byte[] pt_recovered = new byte[pt.Length];
- Array.Copy(rv, 0, pt_recovered, 0, pt.Length);
- Assert.True(Arrays.AreEqual(pt, pt_recovered));
- //Console.WriteLine(map["Count"] + " pass");
map.Clear();
+ var param = new ParametersWithIV(new KeyParameter(key), nonce);
+
+ // Encrypt
+ {
+ Ascon.Init(true, param);
+
+ var rv = new byte[Ascon.GetOutputSize(pt.Length)];
+ random.NextBytes(rv); // should overwrite any existing data
+
+ Ascon.ProcessAadBytes(ad, 0, ad.Length);
+ int len = Ascon.ProcessBytes(pt, 0, pt.Length, rv, 0);
+ len += Ascon.DoFinal(rv, len);
+
+ Assert.True(Arrays.AreEqual(rv, 0, len, ct, 0, ct.Length));
+ }
+
+ // Decrypt
+ {
+ Ascon.Init(false, param);
+
+ var rv = new byte[Ascon.GetOutputSize(ct.Length)];
+ random.NextBytes(rv); // should overwrite any existing data
+
+ Ascon.ProcessAadBytes(ad, 0, ad.Length);
+ int len = Ascon.ProcessBytes(ct, 0, ct.Length, rv, 0);
+ len += Ascon.DoFinal(rv, len);
+
+ Assert.True(Arrays.AreEqual(rv, 0, len, pt, 0, pt.Length));
+ }
}
else
{
@@ -106,27 +100,23 @@ namespace Org.BouncyCastle.Crypto.Tests
{
map[data[0].Trim()] = "";
}
-
}
}
}
- Console.WriteLine("Ascon AEAD pass");
}
-
- private void testExceptions(IAeadBlockCipher aeadBlockCipher, int keysize, int ivsize, int blocksize)
-
+ private void ImplTestExceptions(AsconEngine asconEngine)
{
- ICipherParameters param;
- byte[] k = new byte[keysize];
- byte[] iv = new byte[ivsize];
+ int keySize = asconEngine.GetKeyBytesSize(), ivSize = asconEngine.GetIVBytesSize();
+ byte[] k = new byte[keySize];
+ byte[] iv = new byte[ivSize];
byte[] m = new byte[0];
- byte[] c1 = new byte[aeadBlockCipher.GetOutputSize(m.Length)];
- param = new ParametersWithIV(new KeyParameter(k), iv);
+ byte[] c1 = new byte[asconEngine.GetOutputSize(m.Length)];
+ var param = new ParametersWithIV(new KeyParameter(k), iv);
try
{
- aeadBlockCipher.ProcessBytes(m, 0, m.Length, c1, 0);
- Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before ProcessBytes");
+ asconEngine.ProcessBytes(m, 0, m.Length, c1, 0);
+ Assert.Fail(asconEngine.AlgorithmName + " need to be initialed before ProcessBytes");
}
catch (ArgumentException)
{
@@ -135,8 +125,8 @@ namespace Org.BouncyCastle.Crypto.Tests
try
{
- aeadBlockCipher.ProcessByte((byte)0, c1, 0);
- Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before ProcessByte");
+ asconEngine.ProcessByte((byte)0, c1, 0);
+ Assert.Fail(asconEngine.AlgorithmName + " need to be initialed before ProcessByte");
}
catch (ArgumentException)
{
@@ -145,8 +135,8 @@ namespace Org.BouncyCastle.Crypto.Tests
try
{
- aeadBlockCipher.Reset();
- Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before reset");
+ asconEngine.Reset();
+ Assert.Fail(asconEngine.AlgorithmName + " need to be initialed before reset");
}
catch (ArgumentException)
{
@@ -155,8 +145,8 @@ namespace Org.BouncyCastle.Crypto.Tests
try
{
- aeadBlockCipher.DoFinal(c1, m.Length);
- Assert.Fail(aeadBlockCipher.AlgorithmName + " need to be initialed before dofinal");
+ asconEngine.DoFinal(c1, m.Length);
+ Assert.Fail(asconEngine.AlgorithmName + " need to be initialed before dofinal");
}
catch (ArgumentException)
{
@@ -165,25 +155,26 @@ namespace Org.BouncyCastle.Crypto.Tests
try
{
- aeadBlockCipher.GetMac();
- aeadBlockCipher.GetOutputSize(0);
- aeadBlockCipher.GetUpdateOutputSize(0);
+ asconEngine.GetMac();
+ asconEngine.GetOutputSize(0);
+ asconEngine.GetUpdateOutputSize(0);
}
catch (ArgumentException)
{
//expected
- Assert.Fail(aeadBlockCipher.AlgorithmName + " functions can be called before initialisation");
+ Assert.Fail(asconEngine.AlgorithmName + " functions can be called before initialisation");
}
+
Random rand = new Random();
int randomNum;
- while ((randomNum = rand.Next(100)) == keysize) ;
+ while ((randomNum = rand.Next(100)) == keySize) ;
byte[] k1 = new byte[randomNum];
- while ((randomNum = rand.Next(100)) == ivsize) ;
+ while ((randomNum = rand.Next(100)) == ivSize) ;
byte[] iv1 = new byte[randomNum];
try
{
- aeadBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(k1), iv));
- Assert.Fail(aeadBlockCipher.AlgorithmName + " k size does not match");
+ asconEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv));
+ Assert.Fail(asconEngine.AlgorithmName + " k size does not match");
}
catch (ArgumentException)
{
@@ -191,25 +182,24 @@ namespace Org.BouncyCastle.Crypto.Tests
}
try
{
- aeadBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(k), iv1));
- Assert.Fail(aeadBlockCipher.AlgorithmName + "iv size does not match");
+ asconEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1));
+ Assert.Fail(asconEngine.AlgorithmName + "iv size does not match");
}
catch (ArgumentException)
{
//expected
}
-
- aeadBlockCipher.Init(true, param);
+ asconEngine.Init(true, param);
try
{
- aeadBlockCipher.DoFinal(c1, m.Length);
+ asconEngine.DoFinal(c1, m.Length);
}
catch (Exception)
{
- Assert.Fail(aeadBlockCipher.AlgorithmName + " allows no input for AAD and plaintext");
+ Assert.Fail(asconEngine.AlgorithmName + " allows no input for AAD and plaintext");
}
- byte[] mac2 = aeadBlockCipher.GetMac();
+ byte[] mac2 = asconEngine.GetMac();
if (mac2 == null)
{
Assert.Fail("mac should not be empty after dofinal");
@@ -218,18 +208,18 @@ namespace Org.BouncyCastle.Crypto.Tests
{
Assert.Fail("mac should be equal when calling dofinal and getMac");
}
- aeadBlockCipher.ProcessAadByte((byte)0);
- byte[] mac1 = new byte[aeadBlockCipher.GetOutputSize(0)];
- aeadBlockCipher.DoFinal(mac1, 0);
+ asconEngine.ProcessAadByte((byte)0);
+ byte[] mac1 = new byte[asconEngine.GetOutputSize(0)];
+ asconEngine.DoFinal(mac1, 0);
if (Arrays.AreEqual(mac1, mac2))
{
Assert.Fail("mac should not match");
}
- aeadBlockCipher.Reset();
- aeadBlockCipher.ProcessBytes(new byte[16], 0, 16, new byte[16], 0);
+ asconEngine.Reset();
+ asconEngine.ProcessBytes(new byte[16], 0, 16, new byte[16], 0);
try
{
- aeadBlockCipher.ProcessAadByte((byte)0);
+ asconEngine.ProcessAadByte((byte)0);
Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption");
}
catch (ArgumentException)
@@ -238,7 +228,7 @@ namespace Org.BouncyCastle.Crypto.Tests
}
try
{
- aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 0, 1);
+ asconEngine.ProcessAadBytes(new byte[] { 0 }, 0, 1);
Assert.Fail("ProcessAadByte(s) cannot be called once only");
}
catch (ArgumentException)
@@ -246,10 +236,10 @@ namespace Org.BouncyCastle.Crypto.Tests
//expected
}
- aeadBlockCipher.Reset();
+ asconEngine.Reset();
try
{
- aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 1, 1);
+ asconEngine.ProcessAadBytes(new byte[] { 0 }, 1, 1);
Assert.Fail("input for ProcessAadBytes is too short");
}
catch (DataLengthException)
@@ -258,7 +248,7 @@ namespace Org.BouncyCastle.Crypto.Tests
}
try
{
- aeadBlockCipher.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0);
+ asconEngine.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0);
Assert.Fail("input for ProcessBytes is too short");
}
catch (DataLengthException)
@@ -267,7 +257,7 @@ namespace Org.BouncyCastle.Crypto.Tests
}
try
{
- aeadBlockCipher.ProcessBytes(new byte[16], 0, 16, new byte[16], 8);
+ asconEngine.ProcessBytes(new byte[16], 0, 16, new byte[16], 8);
Assert.Fail("output for ProcessBytes is too short");
}
catch (OutputLengthException)
@@ -276,7 +266,7 @@ namespace Org.BouncyCastle.Crypto.Tests
}
try
{
- aeadBlockCipher.DoFinal(new byte[2], 2);
+ asconEngine.DoFinal(new byte[2], 2);
Assert.Fail("output for dofinal is too short");
}
catch (DataLengthException)
@@ -284,59 +274,58 @@ namespace Org.BouncyCastle.Crypto.Tests
//expected
}
- mac1 = new byte[aeadBlockCipher.GetOutputSize(0)];
- mac2 = new byte[aeadBlockCipher.GetOutputSize(0)];
- aeadBlockCipher.Reset();
- aeadBlockCipher.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2);
- aeadBlockCipher.DoFinal(mac1, 0);
- aeadBlockCipher.Reset();
- aeadBlockCipher.ProcessAadByte((byte)0);
- aeadBlockCipher.ProcessAadByte((byte)0);
- aeadBlockCipher.DoFinal(mac2, 0);
+ mac1 = new byte[asconEngine.GetOutputSize(0)];
+ mac2 = new byte[asconEngine.GetOutputSize(0)];
+ asconEngine.Reset();
+ asconEngine.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2);
+ asconEngine.DoFinal(mac1, 0);
+ asconEngine.Reset();
+ asconEngine.ProcessAadByte((byte)0);
+ asconEngine.ProcessAadByte((byte)0);
+ asconEngine.DoFinal(mac2, 0);
if (!Arrays.AreEqual(mac1, mac2))
{
Assert.Fail("mac should match for the same AAD with different ways of inputing");
}
- byte[] c2 = new byte[aeadBlockCipher.GetOutputSize(10)];
- byte[] c3 = new byte[aeadBlockCipher.GetOutputSize(10) + 2];
+ byte[] c2 = new byte[asconEngine.GetOutputSize(10)];
+ byte[] c3 = new byte[asconEngine.GetOutputSize(10) + 2];
byte[] aad2 = { 0, 1, 2, 3, 4 };
byte[] aad3 = { 0, 0, 1, 2, 3, 4, 5 };
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];
- aeadBlockCipher.Reset();
- aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
- int offset = aeadBlockCipher.ProcessBytes(m2, 0, m2.Length, c2, 0);
- aeadBlockCipher.DoFinal(c2, offset);
- aeadBlockCipher.Reset();
- aeadBlockCipher.ProcessAadBytes(aad3, 1, aad2.Length);
- offset = aeadBlockCipher.ProcessBytes(m3, 1, m2.Length, c3, 1);
- aeadBlockCipher.DoFinal(c3, offset + 1);
+ asconEngine.Reset();
+ asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
+ int offset = asconEngine.ProcessBytes(m2, 0, m2.Length, c2, 0);
+ asconEngine.DoFinal(c2, offset);
+ asconEngine.Reset();
+ asconEngine.ProcessAadBytes(aad3, 1, aad2.Length);
+ offset = asconEngine.ProcessBytes(m3, 1, m2.Length, c3, 1);
+ asconEngine.DoFinal(c3, offset + 1);
byte[] c3_partial = new byte[c2.Length];
Array.Copy(c3, 1, c3_partial, 0, c2.Length);
if (!Arrays.AreEqual(c2, c3_partial))
{
Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
}
- aeadBlockCipher.Reset();
- aeadBlockCipher.Init(false, param);
- aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
- offset = aeadBlockCipher.ProcessBytes(c2, 0, c2.Length, m4, 0);
- aeadBlockCipher.DoFinal(m4, offset);
+ asconEngine.Reset();
+ asconEngine.Init(false, param);
+ asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0);
+ asconEngine.DoFinal(m4, offset);
if (!Arrays.AreEqual(m2, m4))
{
Assert.Fail("The encryption and decryption does not recover the plaintext");
}
- Console.WriteLine(aeadBlockCipher.AlgorithmName + " test Exceptions pass");
c2[c2.Length - 1] ^= 1;
- aeadBlockCipher.Reset();
- aeadBlockCipher.Init(false, param);
- aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
- offset = aeadBlockCipher.ProcessBytes(c2, 0, c2.Length, m4, 0);
+ asconEngine.Reset();
+ asconEngine.Init(false, param);
+ asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = asconEngine.ProcessBytes(c2, 0, c2.Length, m4, 0);
try
{
- aeadBlockCipher.DoFinal(m4, offset);
+ asconEngine.DoFinal(m4, offset);
Assert.Fail("The decryption should fail");
}
catch (ArgumentException)
@@ -345,29 +334,26 @@ namespace Org.BouncyCastle.Crypto.Tests
}
c2[c2.Length - 1] ^= 1;
- byte[] m7 = new byte[blocksize * 2];
- for (int i = 0; i < m7.Length; ++i)
- {
- m7[i] = (byte)rand.Next();
- }
- byte[] c7 = new byte[aeadBlockCipher.GetOutputSize(m7.Length)];
+ byte[] m7 = new byte[32 + rand.Next(16)];
+ rand.NextBytes(m7);
+
+ byte[] c7 = new byte[asconEngine.GetOutputSize(m7.Length)];
byte[] c8 = new byte[c7.Length];
byte[] c9 = new byte[c7.Length];
- aeadBlockCipher.Init(true, param);
- aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
- offset = aeadBlockCipher.ProcessBytes(m7, 0, m7.Length, c7, 0);
- aeadBlockCipher.DoFinal(c7, offset);
- aeadBlockCipher.Reset();
- aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
- offset = aeadBlockCipher.ProcessBytes(m7, 0, blocksize, c8, 0);
- offset += aeadBlockCipher.ProcessBytes(m7, blocksize, m7.Length - blocksize, c8, offset);
- aeadBlockCipher.DoFinal(c8, offset);
- aeadBlockCipher.Reset();
- int split = rand.Next(blocksize * 2);
- aeadBlockCipher.ProcessAadBytes(aad2, 0, aad2.Length);
- offset = aeadBlockCipher.ProcessBytes(m7, 0, split, c9, 0);
- offset += aeadBlockCipher.ProcessBytes(m7, split, m7.Length - split, c9, offset);
- aeadBlockCipher.DoFinal(c9, offset);
+ asconEngine.Init(true, param);
+ asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = asconEngine.ProcessBytes(m7, 0, m7.Length, c7, 0);
+ asconEngine.DoFinal(c7, offset);
+ asconEngine.Reset();
+ asconEngine.ProcessAadBytes(aad2, 0, aad2.Length);
+ offset = asconEngine.ProcessBytes(m7, 0, m7.Length, c8, 0);
+ offset += asconEngine.DoFinal(c8, offset);
+ asconEngine.Reset();
+ 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);
+ asconEngine.DoFinal(c9, offset);
if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9))
{
Assert.Fail("Splitting input of plaintext should output the same ciphertext");
@@ -379,10 +365,10 @@ namespace Org.BouncyCastle.Crypto.Tests
Span c4_2 = new byte[c2.Length];
ReadOnlySpan m5 = new ReadOnlySpan(m2);
ReadOnlySpan aad4 = new ReadOnlySpan(aad2);
- aeadBlockCipher.Init(true, param);
- aeadBlockCipher.ProcessAadBytes(aad4);
- offset = aeadBlockCipher.ProcessBytes(m5, c4_1);
- aeadBlockCipher.DoFinal(c4_2);
+ asconEngine.Init(true, param);
+ asconEngine.ProcessAadBytes(aad4);
+ offset = asconEngine.ProcessBytes(m5, c4_1);
+ asconEngine.DoFinal(c4_2);
byte[] c5 = new byte[c2.Length];
Array.Copy(c4_1.ToArray(), 0, c5, 0, offset);
Array.Copy(c4_2.ToArray(), 0, c5, offset, c5.Length - offset);
@@ -390,14 +376,14 @@ namespace Org.BouncyCastle.Crypto.Tests
{
Assert.Fail("mac should match for the same AAD and message with different offset for both input and output");
}
- aeadBlockCipher.Reset();
- aeadBlockCipher.Init(false, param);
+ asconEngine.Reset();
+ asconEngine.Init(false, param);
Span m6_1 = new byte[m2.Length];
Span m6_2 = new byte[m2.Length];
ReadOnlySpan c6 = new ReadOnlySpan(c2);
- aeadBlockCipher.ProcessAadBytes(aad4);
- offset = aeadBlockCipher.ProcessBytes(c6, m6_1);
- aeadBlockCipher.DoFinal(m6_2);
+ asconEngine.ProcessAadBytes(aad4);
+ offset = asconEngine.ProcessBytes(c6, m6_1);
+ asconEngine.DoFinal(m6_2);
byte[] m6 = new byte[m2.Length];
Array.Copy(m6_1.ToArray(), 0, m6, 0, offset);
Array.Copy(m6_2.ToArray(), 0, m6, offset, m6.Length - offset);
@@ -408,25 +394,14 @@ namespace Org.BouncyCastle.Crypto.Tests
#endif
}
- private void testParameters(AsconEngine ascon, int keySize, int ivSize, int macSize, int blockSize)
+ private void ImplTestParameters(AsconEngine asconEngine, int keySize, int ivSize, int macSize)
{
- if (ascon.GetKeyBytesSize() != keySize)
- {
- Assert.Fail("key bytes of " + ascon.AlgorithmName + " is not correct");
- }
- if (ascon.GetIVBytesSize() != ivSize)
- {
- Assert.Fail("iv bytes of " + ascon.AlgorithmName + " is not correct");
- }
- if (ascon.GetOutputSize(0) != macSize)
- {
- Assert.Fail("mac bytes of " + ascon.AlgorithmName + " is not correct");
- }
- if (ascon.GetBlockSize() != blockSize)
- {
- Assert.Fail("block size of " + ascon.AlgorithmName + " is not correct");
- }
- Console.WriteLine(ascon.AlgorithmName + " test Parameters pass");
+ 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");
+ Assert.AreEqual(macSize, asconEngine.GetOutputSize(0),
+ "mac bytes of " + asconEngine.AlgorithmName + " is not correct");
}
}
-}
\ No newline at end of file
+}
--
cgit 1.4.1