diff options
-rw-r--r-- | crypto/src/crypto/engines/ElephantEngine.cs | 556 | ||||
-rw-r--r-- | crypto/src/crypto/engines/ISAPEngine.cs | 1035 | ||||
-rw-r--r-- | crypto/src/crypto/engines/PhotonBeetleEngine.cs | 441 | ||||
-rw-r--r-- | crypto/src/crypto/engines/SparkleEngine.cs | 580 | ||||
-rw-r--r-- | crypto/src/crypto/engines/XoodyakEngine.cs | 431 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/ElephantTest.cs | 408 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/ISAPTest.cs | 486 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/PhotonBeetleTest.cs | 468 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/SparkleTest.cs | 484 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/XoodyakTest.cs | 459 |
10 files changed, 0 insertions, 5348 deletions
diff --git a/crypto/src/crypto/engines/ElephantEngine.cs b/crypto/src/crypto/engines/ElephantEngine.cs deleted file mode 100644 index 89d2ca6be..000000000 --- a/crypto/src/crypto/engines/ElephantEngine.cs +++ /dev/null @@ -1,556 +0,0 @@ -using System; -using System.Drawing; -using System.IO; - -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math.Raw; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Engines -{ - /** - * Elephant AEAD v2, based on the current round 3 submission, https://www.esat.kuleuven.be/cosic/elephant/ - * Reference C implementation: https://github.com/TimBeyne/Elephant - * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/elephant-spec-final.pdf - */ - public class ElephantEngine - // TODO IAeadCipher only - : IAeadBlockCipher - { - public enum ElephantParameters - { - elephant160, - elephant176, - elephant200 - } - - private bool forEncryption = true; // Safe output sizes before initialization - private readonly string algorithmName; - private ElephantParameters parameters; - private int BLOCK_SIZE; - private int nBits; - private int nSBox; - private int nRounds; - private byte lfsrIV; - private byte[] npub; - private byte[] expanded_key; - private byte[] tag; - private byte CRYPTO_KEYBYTES = 16; - private byte CRYPTO_NPUBBYTES = 12; - private byte CRYPTO_ABYTES; - private bool initialised; - private MemoryStream aadData = new MemoryStream(); - private MemoryStream message = new MemoryStream(); - - private readonly byte[] sBoxLayer = { - (byte)0xee, (byte)0xed, (byte)0xeb, (byte)0xe0, (byte)0xe2, (byte)0xe1, (byte)0xe4, (byte)0xef, (byte)0xe7, (byte)0xea, (byte)0xe8, (byte)0xe5, (byte)0xe9, (byte)0xec, (byte)0xe3, (byte)0xe6, - (byte)0xde, (byte)0xdd, (byte)0xdb, (byte)0xd0, (byte)0xd2, (byte)0xd1, (byte)0xd4, (byte)0xdf, (byte)0xd7, (byte)0xda, (byte)0xd8, (byte)0xd5, (byte)0xd9, (byte)0xdc, (byte)0xd3, (byte)0xd6, - (byte)0xbe, (byte)0xbd, (byte)0xbb, (byte)0xb0, (byte)0xb2, (byte)0xb1, (byte)0xb4, (byte)0xbf, (byte)0xb7, (byte)0xba, (byte)0xb8, (byte)0xb5, (byte)0xb9, (byte)0xbc, (byte)0xb3, (byte)0xb6, - (byte)0x0e, (byte)0x0d, (byte)0x0b, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x04, (byte)0x0f, (byte)0x07, (byte)0x0a, (byte)0x08, (byte)0x05, (byte)0x09, (byte)0x0c, (byte)0x03, (byte)0x06, - (byte)0x2e, (byte)0x2d, (byte)0x2b, (byte)0x20, (byte)0x22, (byte)0x21, (byte)0x24, (byte)0x2f, (byte)0x27, (byte)0x2a, (byte)0x28, (byte)0x25, (byte)0x29, (byte)0x2c, (byte)0x23, (byte)0x26, - (byte)0x1e, (byte)0x1d, (byte)0x1b, (byte)0x10, (byte)0x12, (byte)0x11, (byte)0x14, (byte)0x1f, (byte)0x17, (byte)0x1a, (byte)0x18, (byte)0x15, (byte)0x19, (byte)0x1c, (byte)0x13, (byte)0x16, - (byte)0x4e, (byte)0x4d, (byte)0x4b, (byte)0x40, (byte)0x42, (byte)0x41, (byte)0x44, (byte)0x4f, (byte)0x47, (byte)0x4a, (byte)0x48, (byte)0x45, (byte)0x49, (byte)0x4c, (byte)0x43, (byte)0x46, - (byte)0xfe, (byte)0xfd, (byte)0xfb, (byte)0xf0, (byte)0xf2, (byte)0xf1, (byte)0xf4, (byte)0xff, (byte)0xf7, (byte)0xfa, (byte)0xf8, (byte)0xf5, (byte)0xf9, (byte)0xfc, (byte)0xf3, (byte)0xf6, - (byte)0x7e, (byte)0x7d, (byte)0x7b, (byte)0x70, (byte)0x72, (byte)0x71, (byte)0x74, (byte)0x7f, (byte)0x77, (byte)0x7a, (byte)0x78, (byte)0x75, (byte)0x79, (byte)0x7c, (byte)0x73, (byte)0x76, - (byte)0xae, (byte)0xad, (byte)0xab, (byte)0xa0, (byte)0xa2, (byte)0xa1, (byte)0xa4, (byte)0xaf, (byte)0xa7, (byte)0xaa, (byte)0xa8, (byte)0xa5, (byte)0xa9, (byte)0xac, (byte)0xa3, (byte)0xa6, - (byte)0x8e, (byte)0x8d, (byte)0x8b, (byte)0x80, (byte)0x82, (byte)0x81, (byte)0x84, (byte)0x8f, (byte)0x87, (byte)0x8a, (byte)0x88, (byte)0x85, (byte)0x89, (byte)0x8c, (byte)0x83, (byte)0x86, - (byte)0x5e, (byte)0x5d, (byte)0x5b, (byte)0x50, (byte)0x52, (byte)0x51, (byte)0x54, (byte)0x5f, (byte)0x57, (byte)0x5a, (byte)0x58, (byte)0x55, (byte)0x59, (byte)0x5c, (byte)0x53, (byte)0x56, - (byte)0x9e, (byte)0x9d, (byte)0x9b, (byte)0x90, (byte)0x92, (byte)0x91, (byte)0x94, (byte)0x9f, (byte)0x97, (byte)0x9a, (byte)0x98, (byte)0x95, (byte)0x99, (byte)0x9c, (byte)0x93, (byte)0x96, - (byte)0xce, (byte)0xcd, (byte)0xcb, (byte)0xc0, (byte)0xc2, (byte)0xc1, (byte)0xc4, (byte)0xcf, (byte)0xc7, (byte)0xca, (byte)0xc8, (byte)0xc5, (byte)0xc9, (byte)0xcc, (byte)0xc3, (byte)0xc6, - (byte)0x3e, (byte)0x3d, (byte)0x3b, (byte)0x30, (byte)0x32, (byte)0x31, (byte)0x34, (byte)0x3f, (byte)0x37, (byte)0x3a, (byte)0x38, (byte)0x35, (byte)0x39, (byte)0x3c, (byte)0x33, (byte)0x36, - (byte)0x6e, (byte)0x6d, (byte)0x6b, (byte)0x60, (byte)0x62, (byte)0x61, (byte)0x64, (byte)0x6f, (byte)0x67, (byte)0x6a, (byte)0x68, (byte)0x65, (byte)0x69, (byte)0x6c, (byte)0x63, (byte)0x66 - }; - - private readonly byte[] KeccakRoundConstants = { - (byte)0x01, (byte)0x82, (byte)0x8a, (byte)0x00, (byte)0x8b, (byte)0x01, (byte)0x81, (byte)0x09, (byte)0x8a, - (byte)0x88, (byte)0x09, (byte)0x0a, (byte)0x8b, (byte)0x8b, (byte)0x89, (byte)0x03, (byte)0x02, (byte)0x80 - }; - - private readonly int[] KeccakRhoOffsets = { 0, 1, 6, 4, 3, 4, 4, 6, 7, 4, 3, 2, 3, 1, 7, 1, 5, 7, 5, 0, 2, 2, 5, 0, 6 }; - - public ElephantEngine(ElephantParameters parameters) - { - switch (parameters) - { - case ElephantParameters.elephant160: - BLOCK_SIZE = 20; - nBits = 160; - nSBox = 20; - nRounds = 80; - lfsrIV = 0x75; - CRYPTO_ABYTES = 8; - algorithmName = "Elephant 160 AEAD"; - break; - case ElephantParameters.elephant176: - BLOCK_SIZE = 22; - nBits = 176; - nSBox = 22; - nRounds = 90; - lfsrIV = 0x45; - CRYPTO_ABYTES = 8; - algorithmName = "Elephant 176 AEAD"; - break; - case ElephantParameters.elephant200: - BLOCK_SIZE = 25; - nRounds = 18; - CRYPTO_ABYTES = 16; - algorithmName = "Elephant 200 AEAD"; - break; - default: - throw new ArgumentException("Invalid parameter settings for Elephant"); - } - this.parameters = parameters; - initialised = false; - reset(false); - } - - private void permutation(byte[] state) - { - switch (parameters) - { - case ElephantParameters.elephant160: - case ElephantParameters.elephant176: - byte IV = lfsrIV; - byte[] tmp = new byte[nSBox]; - for (int i = 0; i < nRounds; i++) - { - /* Add counter values */ - state[0] ^= IV; - state[nSBox - 1] ^= (byte)(((IV & 0x01) << 7) | ((IV & 0x02) << 5) | ((IV & 0x04) << 3) | ((IV & 0x08) - << 1) | ((IV & 0x10) >> 1) | ((IV & 0x20) >> 3) | ((IV & 0x40) >> 5) | ((IV & 0x80) >> 7)); - IV = (byte)(((IV << 1) | (((0x40 & IV) >> 6) ^ ((0x20 & IV) >> 5))) & 0x7f); - /* sBoxLayer layer */ - for (int j = 0; j < nSBox; j++) - { - state[j] = sBoxLayer[(state[j] & 0xFF)]; - } - /* pLayer */ - int PermutedBitNo; - Arrays.Fill(tmp, (byte)0); - for (int j = 0; j < nSBox; j++) - { - for (int k = 0; k < 8; k++) - { - PermutedBitNo = (j << 3) + k; - if (PermutedBitNo != nBits - 1) - { - PermutedBitNo = ((PermutedBitNo * nBits) >> 2) % (nBits - 1); - } - tmp[PermutedBitNo >> 3] ^= (byte)((((state[j] & 0xFF) >> k) & 0x1) << (PermutedBitNo & 7)); - } - } - Array.Copy(tmp, 0, state, 0, nSBox); - } - break; - case ElephantParameters.elephant200: - for (int i = 0; i < nRounds; i++) - { - KeccakP200Round(state, i); - } - break; - } - } - - private byte rotl(byte b) - { - return (byte)(((b & 0xFF) << 1) | ((b & 0xFF) >> 7)); - } - - private byte ROL8(byte a, int offset) - { - return (byte)((offset != 0) ? (((a & 0xFF) << offset) ^ ((a & 0xFF) >> (8 - offset))) : a); - } - - private int index(int x, int y) - { - return x + y * 5; - } - - private void KeccakP200Round(byte[] state, int indexRound) - { - int x, y; - byte[] tempA = new byte[25]; - //theta - for (x = 0; x < 5; x++) - { - for (y = 0; y < 5; y++) - { - tempA[x] ^= state[index(x, y)]; - } - } - for (x = 0; x < 5; x++) - { - tempA[x + 5] = (byte)(ROL8(tempA[(x + 1) % 5], 1) ^ tempA[(x + 4) % 5]); - } - for (x = 0; x < 5; x++) - { - for (y = 0; y < 5; y++) - { - state[index(x, y)] ^= tempA[x + 5]; - } - } - //rho - for (x = 0; x < 5; x++) - { - for (y = 0; y < 5; y++) - { - tempA[index(x, y)] = ROL8(state[index(x, y)], KeccakRhoOffsets[index(x, y)]); - } - } - //pi - for (x = 0; x < 5; x++) - { - for (y = 0; y < 5; y++) - { - state[index(y, (2 * x + 3 * y) % 5)] = tempA[index(x, y)]; - } - } - //chi - for (y = 0; y < 5; y++) - { - for (x = 0; x < 5; x++) - { - tempA[x] = (byte)(state[index(x, y)] ^ ((~state[index((x + 1) % 5, y)]) & state[index((x + 2) % 5, y)])); - } - for (x = 0; x < 5; x++) - { - state[index(x, y)] = tempA[x]; - } - } - //iota - state[index(0, 0)] ^= KeccakRoundConstants[indexRound]; - } - - - // State should be BLOCK_SIZE bytes long - // Note: input may be equal to output - private void lfsr_step(byte[] output, byte[] input) - { - switch (parameters) - { - case ElephantParameters.elephant160: - output[BLOCK_SIZE - 1] = (byte)((((input[0] & 0xFF) << 3) | ((input[0] & 0xFF) >> 5)) ^ - ((input[3] & 0xFF) << 7) ^ ((input[13] & 0xFF) >> 7)); - break; - case ElephantParameters.elephant176: - output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ ((input[3] & 0xFF) << 7) ^ ((input[19] & 0xFF) >> 7)); - break; - case ElephantParameters.elephant200: - output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ rotl(input[2]) ^ (input[13] << 1)); - break; - } - Array.Copy(input, 1, output, 0, BLOCK_SIZE - 1); - } - - // Write the ith assocated data block to "output". - // The nonce is prepended and padding is added as required. - // adlen is the length of the associated data in bytes - private void get_ad_block(byte[] output, byte[] ad, int adlen, byte[] npub, int i) - { - int len = 0; - // First block contains nonce - // Remark: nonce may not be longer then BLOCK_SIZE - if (i == 0) - { - Array.Copy(npub, 0, output, 0, CRYPTO_NPUBBYTES); - len += CRYPTO_NPUBBYTES; - } - int block_offset = i * BLOCK_SIZE - ((i != 0) ? 1 : 0) * CRYPTO_NPUBBYTES; - // If adlen is divisible by BLOCK_SIZE, add an additional padding block - if (i != 0 && block_offset == adlen) - { - Arrays.Fill(output, 0, BLOCK_SIZE, (byte)0); - output[0] = 0x01; - return; - } - int r_outlen = BLOCK_SIZE - len; - int r_adlen = adlen - block_offset; - // Fill with associated data if available - if (r_outlen <= r_adlen) - { // enough AD - Array.Copy(ad, block_offset, output, len, r_outlen); - } - else - { // not enough AD, need to pad - if (r_adlen > 0) // ad might be nullptr - { - Array.Copy(ad, block_offset, output, len, r_adlen); - } - Arrays.Fill(output, len + r_adlen, len + r_outlen, (byte)0); - output[len + r_adlen] = 0x01; - } - } - - // Return the ith ciphertext block. - // clen is the length of the ciphertext in bytes - private void get_c_block(byte[] output, byte[] c, int cOff, int clen, int i) - { - int block_offset = i * BLOCK_SIZE; - // If clen is divisible by BLOCK_SIZE, add an additional padding block - if (block_offset == clen) - { - Arrays.Fill(output, 0, BLOCK_SIZE, (byte)0); - output[0] = 0x01; - return; - } - int r_clen = clen - block_offset; - // Fill with ciphertext if available - if (BLOCK_SIZE <= r_clen) - { // enough ciphertext - Array.Copy(c, cOff + block_offset, output, 0, BLOCK_SIZE); - } - else - { // not enough ciphertext, need to pad - if (r_clen > 0) // c might be nullptr - { - Array.Copy(c, cOff + block_offset, output, 0, r_clen); - } - Arrays.Fill(output, r_clen, BLOCK_SIZE, (byte)0); - output[r_clen] = 0x01; - } - } - - public void Init(bool forEncryption, ICipherParameters param) - { - this.forEncryption = forEncryption; - - if (!(param is ParametersWithIV ivParams)) - throw new ArgumentException("Elephant init parameters must include an IV"); - - npub = ivParams.GetIV(); - - if (npub == null || npub.Length != 12) - throw new ArgumentException("Elephant requires exactly 12 bytes of IV"); - - if (!(ivParams.Parameters is KeyParameter key)) - throw new ArgumentException("Elephant init parameters must include a key"); - - byte[] k = key.GetKey(); - if (k.Length != 16) - throw new ArgumentException("Elephant key must be 128 bits long"); - - // Storage for the expanded key L - expanded_key = new byte[BLOCK_SIZE]; - Array.Copy(k, 0, expanded_key, 0, CRYPTO_KEYBYTES); - permutation(expanded_key); - initialised = true; - reset(false); - } - - - public string AlgorithmName => algorithmName; - - public IBlockCipher UnderlyingCipher => throw new NotImplementedException(); - - public void ProcessAadByte(byte input) - { - aadData.WriteByte(input); - } - - public void ProcessAadBytes(byte[] inBytes, int inOff, int len) - { - Check.DataLength(inBytes, inOff, len, "input buffer too short"); - - aadData.Write(inBytes, inOff, len); - } - - public int ProcessByte(byte input, byte[] outBytes, int outOff) - { - message.Write(new byte[]{ input }, 0, 1); - return 0; - } - - public int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff) - { - Check.DataLength(inBytes, inOff, len, "input buffer too short"); - - message.Write(inBytes, inOff, len); - return 0; - } - - public int DoFinal(byte[] output, int outOff) - { - if (!initialised) - throw new ArgumentException("Need to call Init function before encryption/decryption"); - - int mlen = (int)message.Length - (forEncryption ? 0 : CRYPTO_ABYTES); - if ((forEncryption && mlen + outOff + CRYPTO_ABYTES > output.Length) || - (!forEncryption && mlen + outOff - CRYPTO_ABYTES > output.Length)) - { - throw new OutputLengthException("output buffer is too short"); - } - byte[] tag_buffer = new byte[BLOCK_SIZE]; - byte[] m = message.GetBuffer(); - byte[] ad = aadData.GetBuffer(); - int adlen = (int)aadData.Length; - int nblocks_c = 1 + mlen / BLOCK_SIZE; - int nblocks_m = (mlen % BLOCK_SIZE) != 0 ? nblocks_c : nblocks_c - 1; - int nblocks_ad = 1 + (CRYPTO_NPUBBYTES + adlen) / BLOCK_SIZE; - int nb_it = System.Math.Max(nblocks_c + 1, nblocks_ad - 1); - // Buffers for storing previous, current and next mask - byte[] previous_mask = new byte[BLOCK_SIZE]; - byte[] current_mask = new byte[BLOCK_SIZE]; - byte[] next_mask = new byte[BLOCK_SIZE]; - Array.Copy(expanded_key, 0, current_mask, 0, BLOCK_SIZE); - // Buffer to store current ciphertext/AD block - byte[] buffer = new byte[BLOCK_SIZE]; - // Tag buffer and initialization of tag to first AD block - get_ad_block(tag_buffer, ad, adlen, npub, 0); - int offset = 0; - for (int i = 0; i < nb_it; ++i) - { - // Compute mask for the next message - lfsr_step(next_mask, current_mask); - if (i < nblocks_m) - { - // Compute ciphertext block - Array.Copy(npub, 0, buffer, 0, CRYPTO_NPUBBYTES); - Arrays.Fill(buffer, CRYPTO_NPUBBYTES, BLOCK_SIZE, (byte)0); - Bytes.XorTo(BLOCK_SIZE, current_mask, buffer); - Bytes.XorTo(BLOCK_SIZE, next_mask, buffer); - permutation(buffer); - Bytes.XorTo(BLOCK_SIZE, current_mask, buffer); - Bytes.XorTo(BLOCK_SIZE, next_mask, buffer); - int r_size = (i == nblocks_m - 1) ? mlen - offset : BLOCK_SIZE; - Bytes.Xor(r_size, m, offset, buffer, 0, output, outOff + offset); - } - if (i > 0 && i <= nblocks_c) - { - // Compute tag for ciphertext block - if (forEncryption) - { - get_c_block(buffer, output, outOff, mlen, i - 1); - } - else - { - get_c_block(buffer, m, 0, mlen, i - 1); - } - Bytes.XorTo(BLOCK_SIZE, previous_mask, buffer); - Bytes.XorTo(BLOCK_SIZE, next_mask, buffer); - permutation(buffer); - Bytes.XorTo(BLOCK_SIZE, previous_mask, buffer); - Bytes.XorTo(BLOCK_SIZE, next_mask, buffer); - Bytes.XorTo(BLOCK_SIZE, buffer, tag_buffer); - } - // If there is any AD left, compute tag for AD block - if (i + 1 < nblocks_ad) - { - get_ad_block(buffer, ad, adlen, npub, i + 1); - Bytes.XorTo(BLOCK_SIZE, next_mask, buffer); - permutation(buffer); - Bytes.XorTo(BLOCK_SIZE, next_mask, buffer); - Bytes.XorTo(BLOCK_SIZE, buffer, tag_buffer); - } - // Cyclically shift the mask buffers - // Value of next_mask will be computed in the next iteration - byte[] temp = previous_mask; - previous_mask = current_mask; - current_mask = next_mask; - next_mask = temp; - offset += BLOCK_SIZE; - } - outOff += mlen; - tag = new byte[CRYPTO_ABYTES]; - Bytes.XorTo(BLOCK_SIZE, expanded_key, tag_buffer); - permutation(tag_buffer); - Bytes.XorTo(BLOCK_SIZE, expanded_key, tag_buffer); - if (forEncryption) - { - Array.Copy(tag_buffer, 0, tag, 0, CRYPTO_ABYTES); - Array.Copy(tag, 0, output, outOff, tag.Length); - mlen += CRYPTO_ABYTES; - } - else - { - if (!Arrays.FixedTimeEquals(CRYPTO_ABYTES, tag_buffer, 0, m, mlen)) - throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed"); - } - reset(false); - return mlen; - } - - public byte[] GetMac() - { - return tag; - } - - public int GetUpdateOutputSize(int len) - { - // TODO - return len; - } - - public int GetOutputSize(int len) - { - // TODO - return len + CRYPTO_ABYTES; - } - - public void Reset() - { - reset(true); - } - - private void reset(bool clearMac) - { - if (clearMac) - { - tag = null; - } - aadData.SetLength(0); - message.SetLength(0); - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public void ProcessAadBytes(ReadOnlySpan<byte> input) - { - aadData.Write(input); - } - - public int ProcessByte(byte input, Span<byte> output) - { - message.WriteByte(input); - return 0; - } - - public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output) - { - message.Write(input); - return 0; - } - - public int DoFinal(Span<byte> output) - { - byte[] rv; - if (forEncryption) - { - rv = new byte[message.Length + CRYPTO_ABYTES]; - } - else - { - rv = new byte[message.Length - CRYPTO_ABYTES]; - } - int len = DoFinal(rv, 0); - rv.AsSpan(0, len).CopyTo(output); - return rv.Length; - - } -#endif - - public int GetKeyBytesSize() - { - return CRYPTO_KEYBYTES; - } - - public int GetIVBytesSize() - { - return CRYPTO_NPUBBYTES; - } - - public int GetBlockSize() - { - return BLOCK_SIZE; - } - } -} diff --git a/crypto/src/crypto/engines/ISAPEngine.cs b/crypto/src/crypto/engines/ISAPEngine.cs deleted file mode 100644 index 17c679439..000000000 --- a/crypto/src/crypto/engines/ISAPEngine.cs +++ /dev/null @@ -1,1035 +0,0 @@ -using System; -using System.Drawing; -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 -{ - /** - * ISAP AEAD v2, https://isap.iaik.tugraz.at/ - * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/constist-round/updated-spec-doc/isap-spec-const.pdf - * <p> - * ISAP AEAD v2 with reference to C Reference Impl from: https://github.com/isap-lwc/isap-code-package - * </p> - */ - public sealed class IsapEngine - : IAeadCipher - { - public enum IsapType - { - ISAP_A_128A, - ISAP_K_128A, - ISAP_A_128, - ISAP_K_128 - } - - private const int CRYPTO_KEYBYTES = 16; - private const int CRYPTO_NPUBBYTES = 16; - private const int ISAP_STATE_SZ = 40; - - private string algorithmName; - private bool forEncryption = true; // Safe output sizes before initialization - private bool initialised; - private byte[] mac; - private MemoryStream aadData = new MemoryStream(); - private MemoryStream message = new MemoryStream(); - private MemoryStream outputStream = new MemoryStream(); - private ISAP_AEAD ISAPAEAD; - private int ISAP_rH; - private int ISAP_rH_SZ; - - public IsapEngine(IsapType isapType) - { - switch (isapType) - { - case IsapType.ISAP_A_128A: - ISAPAEAD = new ISAPAEAD_A_128A(); - ISAP_rH = 64; - algorithmName = "ISAP-A-128A AEAD"; - break; - case IsapType.ISAP_K_128A: - ISAPAEAD = new ISAPAEAD_K_128A(); - ISAP_rH = 144; - algorithmName = "ISAP-K-128A AEAD"; - break; - case IsapType.ISAP_A_128: - ISAPAEAD = new ISAPAEAD_A_128(); - ISAP_rH = 64; - algorithmName = "ISAP-A-128 AEAD"; - break; - case IsapType.ISAP_K_128: - ISAPAEAD = new ISAPAEAD_K_128(); - ISAP_rH = 144; - algorithmName = "ISAP-K-128 AEAD"; - break; - } - ISAP_rH_SZ = (ISAP_rH + 7) >> 3; - } - - public int GetKeyBytesSize() - { - return CRYPTO_KEYBYTES; - } - - public int GetIVBytesSize() - { - return CRYPTO_NPUBBYTES; - } - - public string AlgorithmName => algorithmName; - - private abstract class ISAP_AEAD - { - protected byte[] k; - protected byte[] npub; - protected int ISAP_rH; - protected int ISAP_rH_SZ; - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public abstract void isap_enc(ReadOnlySpan<byte> m, Span<byte> c); -#else - public abstract void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff); -#endif - - public abstract void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ); - - public abstract void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff); - - public abstract void reset(); - } - - private abstract class ISAPAEAD_A : ISAP_AEAD - { - protected ulong[] k64; - protected ulong[] npub64; - protected ulong ISAP_IV1_64; - protected ulong ISAP_IV2_64; - protected ulong ISAP_IV3_64; - protected ulong x0, x1, x2, x3, x4; - - public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ) - { - this.k = k; - this.npub = npub; - this.ISAP_rH = ISAP_rH; - this.ISAP_rH_SZ = ISAP_rH_SZ; - npub64 = new ulong[(npub.Length + 7) / 8]; - Pack.BE_To_UInt64(npub, 0, npub64, 0, npub64.Length); - k64 = new ulong[(k.Length + 7) / 8]; - Pack.BE_To_UInt64(k, 0, k64, 0, k64.Length); - reset(); - } - - protected abstract void PX1(); - - protected abstract void PX2(); - - protected void ABSORB_MAC(byte[] src, int len) - { - int off = 0; - while (len >= 8) - { - x0 ^= Pack.BE_To_UInt64(src, off); - off += 8; - len -= 8; - P12(); - } - if (len > 0) - { - x0 ^= Pack.BE_To_UInt64_High(src, off, len); - } - x0 ^= 0x8000000000000000UL >> (len << 3); - P12(); - } - - public override void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff) - { - // Init State - x0 = npub64[0]; - x1 = npub64[1]; - x2 = ISAP_IV1_64; - x3 = x4 = 0; - P12(); - ABSORB_MAC(ad, adlen); - // Domain seperation - x4 ^= 1L; - ABSORB_MAC(c, clen); - // Derive K* - Pack.UInt64_To_BE(x0, tag, 0); - Pack.UInt64_To_BE(x1, tag, 8); - ulong tmp_x2 = x2, tmp_x3 = x3, tmp_x4 = x4; - isap_rk(ISAP_IV2_64, tag, CRYPTO_KEYBYTES); - x2 = tmp_x2; - x3 = tmp_x3; - x4 = tmp_x4; - // Squeeze tag - P12(); - Pack.UInt64_To_BE(x0, tag, tagOff); - Pack.UInt64_To_BE(x1, tag, tagOff + 8); - } - - public void isap_rk(ulong iv64, byte[] y, int ylen) - { - // Init state - x0 = k64[0]; - x1 = k64[1]; - x2 = iv64; - x3 = x4 = 0; - P12(); - // Absorb Y - for (int i = 0; i < (ylen << 3) - 1; i++) - { - x0 ^= (((((ulong)y[i >> 3] >> (7 - (i & 7))) & 0x01UL) << 7) & 0xFFUL) << 56; - PX2(); - } - x0 ^= (((y[ylen - 1]) & 0x01UL) << 7) << 56; - P12(); - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public override void isap_enc(ReadOnlySpan<byte> m, Span<byte> c) - { - while (m.Length >= 8) - { - ulong t = Pack.BE_To_UInt64(m); - t ^= x0; - Pack.UInt64_To_BE(t, c); - m = m[8..]; - c = c[8..]; - PX1(); - } - if (!m.IsEmpty) - { - ulong t = Pack.BE_To_UInt64_High(m); - t ^= x0; - Pack.UInt64_To_BE_High(t, c[..m.Length]); - } - } -#else - public override void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff) - { - while (mlen >= 8) - { - ulong t = Pack.BE_To_UInt64(m, mOff); - t ^= x0; - Pack.UInt64_To_BE(t, c, cOff); - mOff += 8; - mlen -= 8; - cOff += 8; - PX1(); - } - if (mlen > 0) - { - ulong t = Pack.BE_To_UInt64_High(m, mOff, mlen); - t ^= x0; - Pack.UInt64_To_BE_High(t, c, cOff, mlen); - } - } -#endif - - public override void reset() - { - // Init state - isap_rk(ISAP_IV3_64, npub, CRYPTO_NPUBBYTES); - x3 = npub64[0]; - x4 = npub64[1]; - PX1(); - } - -#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - protected 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); - } - - public void P12() - { - ROUND(0xf0); - ROUND(0xe1); - ROUND(0xd2); - ROUND(0xc3); - ROUND(0xb4); - ROUND(0xa5); - P6(); - } - - protected void P6() - { - ROUND(0x96); - ROUND(0x87); - ROUND(0x78); - ROUND(0x69); - ROUND(0x5a); - ROUND(0x4b); - } - } - - private class ISAPAEAD_A_128A : ISAPAEAD_A - { - public ISAPAEAD_A_128A() - { - ISAP_IV1_64 = 108156764297430540UL; - ISAP_IV2_64 = 180214358335358476UL; - ISAP_IV3_64 = 252271952373286412UL; - } - - protected override void PX1() - { - P6(); - } - - protected override void PX2() - { - ROUND(0x4b); - } - } - - private class ISAPAEAD_A_128 : ISAPAEAD_A - { - public ISAPAEAD_A_128() - { - ISAP_IV1_64 = 108156764298152972L; - ISAP_IV2_64 = 180214358336080908L; - ISAP_IV3_64 = 252271952374008844L; - } - - protected override void PX1() - { - P12(); - } - - protected override void PX2() - { - P12(); - } - } - - private abstract class ISAPAEAD_K : ISAP_AEAD - { - const int ISAP_STATE_SZ_CRYPTO_NPUBBYTES = ISAP_STATE_SZ - CRYPTO_NPUBBYTES; - protected ushort[] ISAP_IV1_16; - protected ushort[] ISAP_IV2_16; - protected ushort[] ISAP_IV3_16; - protected ushort[] k16; - protected ushort[] iv16; - private readonly int[] KeccakF400RoundConstants = { - 0x0001, 0x8082, 0x808a, 0x8000, 0x808b, 0x0001, 0x8081, 0x8009, 0x008a, 0x0088, 0x8009, 0x000a, 0x808b, - 0x008b, 0x8089, 0x8003, 0x8002, 0x0080, 0x800a, 0x000a }; - protected ushort[] SX = new ushort[25]; - protected ushort[] E = new ushort[25]; - protected ushort[] C = new ushort[5]; - - public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ) - { - this.k = k; - this.npub = npub; - this.ISAP_rH = ISAP_rH; - this.ISAP_rH_SZ = ISAP_rH_SZ; - k16 = new ushort[k.Length >> 1]; - Pack.LE_To_UInt16(k, 0, k16); - iv16 = new ushort[npub.Length >> 1]; - Pack.LE_To_UInt16(npub, 0, iv16); - reset(); - } - - public override void reset() - { - // Init state - SX = new ushort[25]; - E = new ushort[25]; - C = new ushort[5]; - isap_rk(ISAP_IV3_16, npub, CRYPTO_NPUBBYTES, SX, ISAP_STATE_SZ_CRYPTO_NPUBBYTES, C); - Array.Copy(iv16, 0, SX, 17, 8); - PermuteRoundsKX(SX, E, C); - } - - protected abstract void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C); - - protected abstract void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C); - - protected abstract void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C); - - protected void ABSORB_MAC(ushort[] SX, byte[] src, int len, ushort[] E, ushort[] C) - { - int rem_bytes = len; - int idx = 0; - while (rem_bytes > ISAP_rH_SZ) - { - byteToushortXor(src, SX, ISAP_rH_SZ >> 1); - idx += ISAP_rH_SZ; - rem_bytes -= ISAP_rH_SZ; - PermuteRoundsHX(SX, E, C); - } - if (rem_bytes == ISAP_rH_SZ) - { - byteToushortXor(src, SX, ISAP_rH_SZ >> 1); - PermuteRoundsHX(SX, E, C); - SX[0] ^= 0x80; - PermuteRoundsHX(SX, E, C); - } - else - { - for (int i = 0; i < rem_bytes; i++) - { - SX[i >> 1] ^= (ushort)((src[idx++] & 0xFFU) << ((i & 1) << 3)); - } - SX[rem_bytes >> 1] ^= (ushort)(0x80U << ((rem_bytes & 1) << 3)); - PermuteRoundsHX(SX, E, C); - } - } - - public void isap_rk(ushort[] iv16, byte[] y, int ylen, ushort[] out16, int outlen, ushort[] C) - { - // Init state - ushort[] SX = new ushort[25]; - ushort[] E = new ushort[25]; - Array.Copy(k16, 0, SX, 0, 8); - Array.Copy(iv16, 0, SX, 8, 4); - PermuteRoundsKX(SX, E, C); - // Absorb all bits of Y - for (int i = 0; i < (ylen << 3) - 1; i++) - { - SX[0] ^= (ushort)(((y[i >> 3] >> (7 - (i & 7))) & 0x01) << 7); - PermuteRoundsBX(SX, E, C); - } - SX[0] ^= (ushort)(((y[ylen - 1]) & 0x01) << 7); - PermuteRoundsKX(SX, E, C); - // Extract K* - Array.Copy(SX, 0, out16, 0, outlen == ISAP_STATE_SZ_CRYPTO_NPUBBYTES ? 17 : 8); - } - - public override void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff) - { - SX = new ushort[25]; - // Init state - Array.Copy(iv16, 0, SX, 0, 8); - Array.Copy(ISAP_IV1_16, 0, SX, 8, 4); - PermuteRoundsHX(SX, E, C); - // Absorb AD - ABSORB_MAC(SX, ad, adlen, E, C); - // Domain seperation - SX[24] ^= 0x0100; - // Absorb C - ABSORB_MAC(SX, c, clen, E, C); - // Derive K* - Pack.UInt16_To_LE(SX, 0, 8, tag, tagOff); - isap_rk(ISAP_IV2_16, tag, CRYPTO_KEYBYTES, SX, CRYPTO_KEYBYTES, C); - // Squeeze tag - PermuteRoundsHX(SX, E, C); - Pack.UInt16_To_LE(SX, 0, 8, tag, tagOff); - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public override void isap_enc(ReadOnlySpan<byte> m, Span<byte> c) - { - int off = 0, len = m.Length; - - // Squeeze key stream - while (len >= ISAP_rH_SZ) - { - // Squeeze full lane and continue - for (int i = 0; i < ISAP_rH_SZ; ++i) - { - c[off] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[off]); - ++off; - } - len -= ISAP_rH_SZ; - PermuteRoundsKX(SX, E, C); - } - // Squeeze partial lane and stop - for (int i = 0; i < len; ++i) - { - c[off] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[off]); - ++off; - } - } -#else - public override void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff) - { - // Squeeze key stream - while (mlen >= ISAP_rH_SZ) - { - // Squeeze full lane and continue - for (int i = 0; i < ISAP_rH_SZ; ++i) - { - c[cOff++] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[mOff++]); - } - mlen -= ISAP_rH_SZ; - PermuteRoundsKX(SX, E, C); - } - // Squeeze partial lane and stop - for (int i = 0; i < mlen; ++i) - { - c[cOff++] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[mOff++]); - } - } -#endif - - private void byteToushortXor(byte[] input, ushort[] output, int outLen) - { - for (int i = 0; i < outLen; ++i) - { - output[i] ^= Pack.LE_To_UInt16(input, (i << 1)); - } - } - - protected void rounds12X(ushort[] SX, ushort[] E, ushort[] C) - { - prepareThetaX(SX, C); - rounds_8_18(SX, E, C); - } - - protected void rounds_4_18(ushort[] SX, ushort[] E, ushort[] C) - { - thetaRhoPiChiIotaPrepareTheta(4, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(5, E, SX, C); - thetaRhoPiChiIotaPrepareTheta(6, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(7, E, SX, C); - rounds_8_18(SX, E, C); - } - - protected void rounds_8_18(ushort[] SX, ushort[] E, ushort[] C) - { - thetaRhoPiChiIotaPrepareTheta(8, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(9, E, SX, C); - thetaRhoPiChiIotaPrepareTheta(10, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(11, E, SX, C); - rounds_12_18(SX, E, C); - } - - protected void rounds_12_18(ushort[] SX, ushort[] E, ushort[] C) - { - thetaRhoPiChiIotaPrepareTheta(12, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(13, E, SX, C); - thetaRhoPiChiIotaPrepareTheta(14, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(15, E, SX, C); - thetaRhoPiChiIotaPrepareTheta(16, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(17, E, SX, C); - thetaRhoPiChiIotaPrepareTheta(18, SX, E, C); - thetaRhoPiChiIota(E, SX, C); - } - - protected void prepareThetaX(ushort[] SX, ushort[] C) - { - C[0] = (ushort)(SX[0] ^ SX[5] ^ SX[10] ^ SX[15] ^ SX[20]); - C[1] = (ushort)(SX[1] ^ SX[6] ^ SX[11] ^ SX[16] ^ SX[21]); - C[2] = (ushort)(SX[2] ^ SX[7] ^ SX[12] ^ SX[17] ^ SX[22]); - C[3] = (ushort)(SX[3] ^ SX[8] ^ SX[13] ^ SX[18] ^ SX[23]); - C[4] = (ushort)(SX[4] ^ SX[9] ^ SX[14] ^ SX[19] ^ SX[24]); - } - - protected void thetaRhoPiChiIotaPrepareTheta(int i, ushort[] A, ushort[] E, ushort[] C) - { - ushort Da = (ushort)(C[4] ^ Shorts.RotateLeft(C[1], 1)); - ushort De = (ushort)(C[0] ^ Shorts.RotateLeft(C[2], 1)); - ushort Di = (ushort)(C[1] ^ Shorts.RotateLeft(C[3], 1)); - ushort Do = (ushort)(C[2] ^ Shorts.RotateLeft(C[4], 1)); - ushort Du = (ushort)(C[3] ^ Shorts.RotateLeft(C[0], 1)); - - ushort Ba = A[0] ^= Da; - A[6] ^= De; - ushort Be = Shorts.RotateLeft(A[6], 12); - A[12] ^= Di; - ushort Bi = Shorts.RotateLeft(A[12], 11); - A[18] ^= Do; - ushort Bo = Shorts.RotateLeft(A[18], 5); - A[24] ^= Du; - ushort Bu = Shorts.RotateLeft(A[24], 14); - C[0] = E[0] = (ushort)(Ba ^ ((~Be) & Bi) ^ KeccakF400RoundConstants[i]); - C[1] = E[1] = (ushort)(Be ^ ((~Bi) & Bo)); - C[2] = E[2] = (ushort)(Bi ^ ((~Bo) & Bu)); - C[3] = E[3] = (ushort)(Bo ^ ((~Bu) & Ba)); - C[4] = E[4] = (ushort)(Bu ^ ((~Ba) & Be)); - - A[3] ^= Do; - Ba = Shorts.RotateLeft(A[3], 12); - A[9] ^= Du; - Be = Shorts.RotateLeft(A[9], 4); - A[10] ^= Da; - Bi = Shorts.RotateLeft(A[10], 3); - A[16] ^= De; - Bo = Shorts.RotateLeft(A[16], 13); - A[22] ^= Di; - Bu = Shorts.RotateLeft(A[22], 13); - E[5] = (ushort)(Ba ^ ((~Be) & Bi)); - C[0] ^= E[5]; - E[6] = (ushort)(Be ^ ((~Bi) & Bo)); - C[1] ^= E[6]; - E[7] = (ushort)(Bi ^ ((~Bo) & Bu)); - C[2] ^= E[7]; - E[8] = (ushort)(Bo ^ ((~Bu) & Ba)); - C[3] ^= E[8]; - E[9] = (ushort)(Bu ^ ((~Ba) & Be)); - C[4] ^= E[9]; - - A[1] ^= De; - Ba = Shorts.RotateLeft(A[1], 1); - A[7] ^= Di; - Be = Shorts.RotateLeft(A[7], 6); - A[13] ^= Do; - Bi = Shorts.RotateLeft(A[13], 9); - A[19] ^= Du; - Bo = Shorts.RotateLeft(A[19], 8); - A[20] ^= Da; - Bu = Shorts.RotateLeft(A[20], 2); - E[10] = (ushort)(Ba ^ ((~Be) & Bi)); - C[0] ^= E[10]; - E[11] = (ushort)(Be ^ ((~Bi) & Bo)); - C[1] ^= E[11]; - E[12] = (ushort)(Bi ^ ((~Bo) & Bu)); - C[2] ^= E[12]; - E[13] = (ushort)(Bo ^ ((~Bu) & Ba)); - C[3] ^= E[13]; - E[14] = (ushort)(Bu ^ ((~Ba) & Be)); - C[4] ^= E[14]; - - A[4] ^= Du; - Ba = Shorts.RotateLeft(A[4], 11); - A[5] ^= Da; - Be = Shorts.RotateLeft(A[5], 4); - A[11] ^= De; - Bi = Shorts.RotateLeft(A[11], 10); - A[17] ^= Di; - Bo = Shorts.RotateLeft(A[17], 15); - A[23] ^= Do; - Bu = Shorts.RotateLeft(A[23], 8); - E[15] = (ushort)(Ba ^ ((~Be) & Bi)); - C[0] ^= E[15]; - E[16] = (ushort)(Be ^ ((~Bi) & Bo)); - C[1] ^= E[16]; - E[17] = (ushort)(Bi ^ ((~Bo) & Bu)); - C[2] ^= E[17]; - E[18] = (ushort)(Bo ^ ((~Bu) & Ba)); - C[3] ^= E[18]; - E[19] = (ushort)(Bu ^ ((~Ba) & Be)); - C[4] ^= E[19]; - - A[2] ^= Di; - Ba = Shorts.RotateLeft(A[2], 14); - A[8] ^= Do; - Be = Shorts.RotateLeft(A[8], 7); - A[14] ^= Du; - Bi = Shorts.RotateLeft(A[14], 7); - A[15] ^= Da; - Bo = Shorts.RotateLeft(A[15], 9); - A[21] ^= De; - Bu = Shorts.RotateLeft(A[21], 2); - E[20] = (ushort)(Ba ^ ((~Be) & Bi)); - C[0] ^= E[20]; - E[21] = (ushort)(Be ^ ((~Bi) & Bo)); - C[1] ^= E[21]; - E[22] = (ushort)(Bi ^ ((~Bo) & Bu)); - C[2] ^= E[22]; - E[23] = (ushort)(Bo ^ ((~Bu) & Ba)); - C[3] ^= E[23]; - E[24] = (ushort)(Bu ^ ((~Ba) & Be)); - C[4] ^= E[24]; - } - - protected void thetaRhoPiChiIota(ushort[] A, ushort[] E, ushort[] C) - { - ushort Da = (ushort)(C[4] ^ Shorts.RotateLeft(C[1], 1)); - ushort De = (ushort)(C[0] ^ Shorts.RotateLeft(C[2], 1)); - ushort Di = (ushort)(C[1] ^ Shorts.RotateLeft(C[3], 1)); - ushort Do = (ushort)(C[2] ^ Shorts.RotateLeft(C[4], 1)); - ushort Du = (ushort)(C[3] ^ Shorts.RotateLeft(C[0], 1)); - - ushort Ba = A[0] ^= Da; - A[6] ^= De; - ushort Be = Shorts.RotateLeft(A[6], 12); - A[12] ^= Di; - ushort Bi = Shorts.RotateLeft(A[12], 11); - A[18] ^= Do; - ushort Bo = Shorts.RotateLeft(A[18], 5); - A[24] ^= Du; - ushort Bu = Shorts.RotateLeft(A[24], 14); - E[0] = (ushort)(Ba ^ ((~Be) & Bi) ^ KeccakF400RoundConstants[19]); - E[1] = (ushort)(Be ^ ((~Bi) & Bo)); - E[2] = (ushort)(Bi ^ ((~Bo) & Bu)); - E[3] = (ushort)(Bo ^ ((~Bu) & Ba)); - E[4] = (ushort)(Bu ^ ((~Ba) & Be)); - - A[3] ^= Do; - Ba = Shorts.RotateLeft(A[3], 12); - A[9] ^= Du; - Be = Shorts.RotateLeft(A[9], 4); - A[10] ^= Da; - Bi = Shorts.RotateLeft(A[10], 3); - A[16] ^= De; - Bo = Shorts.RotateLeft(A[16], 13); - A[22] ^= Di; - Bu = Shorts.RotateLeft(A[22], 13); - E[5] = (ushort)(Ba ^ ((~Be) & Bi)); - E[6] = (ushort)(Be ^ ((~Bi) & Bo)); - E[7] = (ushort)(Bi ^ ((~Bo) & Bu)); - E[8] = (ushort)(Bo ^ ((~Bu) & Ba)); - E[9] = (ushort)(Bu ^ ((~Ba) & Be)); - - A[1] ^= De; - Ba = Shorts.RotateLeft(A[1], 1); - A[7] ^= Di; - Be = Shorts.RotateLeft(A[7], 6); - A[13] ^= Do; - Bi = Shorts.RotateLeft(A[13], 9); - A[19] ^= Du; - Bo = Shorts.RotateLeft(A[19], 8); - A[20] ^= Da; - Bu = Shorts.RotateLeft(A[20], 2); - E[10] = (ushort)(Ba ^ ((~Be) & Bi)); - E[11] = (ushort)(Be ^ ((~Bi) & Bo)); - E[12] = (ushort)(Bi ^ ((~Bo) & Bu)); - E[13] = (ushort)(Bo ^ ((~Bu) & Ba)); - E[14] = (ushort)(Bu ^ ((~Ba) & Be)); - - A[4] ^= Du; - Ba = Shorts.RotateLeft(A[4], 11); - A[5] ^= Da; - Be = Shorts.RotateLeft(A[5], 4); - A[11] ^= De; - Bi = Shorts.RotateLeft(A[11], 10); - A[17] ^= Di; - Bo = Shorts.RotateLeft(A[17], 15); - A[23] ^= Do; - Bu = Shorts.RotateLeft(A[23], 8); - E[15] = (ushort)(Ba ^ ((~Be) & Bi)); - E[16] = (ushort)(Be ^ ((~Bi) & Bo)); - E[17] = (ushort)(Bi ^ ((~Bo) & Bu)); - E[18] = (ushort)(Bo ^ ((~Bu) & Ba)); - E[19] = (ushort)(Bu ^ ((~Ba) & Be)); - - A[2] ^= Di; - Ba = Shorts.RotateLeft(A[2], 14); - A[8] ^= Do; - Be = Shorts.RotateLeft(A[8], 7); - A[14] ^= Du; - Bi = Shorts.RotateLeft(A[14], 7); - A[15] ^= Da; - Bo = Shorts.RotateLeft(A[15], 9); - A[21] ^= De; - Bu = Shorts.RotateLeft(A[21], 2); - E[20] = (ushort)(Ba ^ ((~Be) & Bi)); - E[21] = (ushort)(Be ^ ((~Bi) & Bo)); - E[22] = (ushort)(Bi ^ ((~Bo) & Bu)); - E[23] = (ushort)(Bo ^ ((~Bu) & Ba)); - E[24] = (ushort)(Bu ^ ((~Ba) & Be)); - } - } - - private class ISAPAEAD_K_128A : ISAPAEAD_K - { - public ISAPAEAD_K_128A() - { - ISAP_IV1_16 = new ushort[]{ 32769, 400, 272, 2056 }; - ISAP_IV2_16 = new ushort[]{ 32770, 400, 272, 2056 }; - ISAP_IV3_16 = new ushort[]{ 32771, 400, 272, 2056 }; - } - - protected override void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C) - { - prepareThetaX(SX, C); - rounds_4_18(SX, E, C); - } - - protected override void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C) - { - prepareThetaX(SX, C); - rounds_12_18(SX, E, C); - } - - protected override void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C) - { - prepareThetaX(SX, C); - thetaRhoPiChiIotaPrepareTheta(19, SX, E, C); - Array.Copy(E, 0, SX, 0, E.Length); - } - } - - private class ISAPAEAD_K_128 - : ISAPAEAD_K - { - public ISAPAEAD_K_128() - { - ISAP_IV1_16 = new ushort[]{ 32769, 400, 3092, 3084 }; - ISAP_IV2_16 = new ushort[]{ 32770, 400, 3092, 3084 }; - ISAP_IV3_16 = new ushort[]{ 32771, 400, 3092, 3084 }; - } - - protected override void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C) - { - prepareThetaX(SX, C); - thetaRhoPiChiIotaPrepareTheta(0, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(1, E, SX, C); - thetaRhoPiChiIotaPrepareTheta(2, SX, E, C); - thetaRhoPiChiIotaPrepareTheta(3, E, SX, C); - rounds_4_18(SX, E, C); - } - - protected override void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C) - { - rounds12X(SX, E, C); - } - - protected override void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C) - { - rounds12X(SX, E, C); - } - } - - public void Init(bool forEncryption, ICipherParameters param) - { - this.forEncryption = forEncryption; - if (!(param is ParametersWithIV withIV)) - throw new ArgumentException("ISAP AEAD init parameters must include an IV"); - - byte[] iv = withIV.GetIV(); - if (iv == null || iv.Length != 16) - throw new ArgumentException("ISAP AEAD requires exactly 12 bytes of IV"); - - if (!(withIV.Parameters is KeyParameter key)) - throw new ArgumentException("ISAP AEAD init parameters must include a key"); - - byte[] keyBytes = key.GetKey(); - if (keyBytes.Length != 16) - throw new ArgumentException("ISAP AEAD key must be 128 bits ulong"); - - /* - * Initialize variables. - */ - initialised = true; - ISAPAEAD.init(keyBytes, iv, ISAP_rH, ISAP_rH_SZ); - Reset(); - } - - public void ProcessAadByte(byte input) - { - aadData.WriteByte(input); - } - - public void ProcessAadBytes(byte[] inBytes, int inOff, int len) - { - Check.DataLength(inBytes, inOff, len, "input buffer too short"); - - aadData.Write(inBytes, inOff, len); - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public void ProcessAadBytes(ReadOnlySpan<byte> input) - { - 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<byte> output) - { - Span<byte> singleByte = stackalloc byte[1]{ input }; - - return ProcessBytes(singleByte, output); - } -#endif - - public int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff) - { - 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); - - if (forEncryption) - { - int msgLen = Convert.ToInt32(message.Length); - if (msgLen >= ISAP_rH_SZ) - { - int outLen = msgLen / ISAP_rH_SZ * ISAP_rH_SZ; - Check.OutputLength(outBytes, outOff, outLen, "output buffer is too short"); - byte[] enc_input = message.GetBuffer(); - ISAPAEAD.isap_enc(enc_input, 0, outLen, outBytes, outOff); - outputStream.Write(outBytes, outOff, outLen); - int enc_input_len = msgLen; - message.SetLength(0); - message.Write(enc_input, outLen, enc_input_len - outLen); - return outLen; - } - } - return 0; -#endif - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output) - { - if (!initialised) - throw new ArgumentException("Need to call Init function before encryption/decryption"); - - message.Write(input); - - if (forEncryption) - { - int msgLen = Convert.ToInt32(message.Length); - if (msgLen >= ISAP_rH_SZ) - { - int outLen = msgLen / ISAP_rH_SZ * ISAP_rH_SZ; - Check.OutputLength(output, outLen, "output buffer is too short"); - byte[] enc_input = message.GetBuffer(); - ISAPAEAD.isap_enc(enc_input.AsSpan(0, outLen), output); - outputStream.Write(output[..outLen]); - int enc_input_len = msgLen; - message.SetLength(0); - message.Write(enc_input, outLen, enc_input_len - outLen); - return outLen; - } - } - return 0; - } -#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 to call Init before encryption/decryption"); - - byte[] aad = aadData.GetBuffer(); - byte[] msg = message.GetBuffer(); - - int aadLen = Convert.ToInt32(aadData.Length); - int msgLen = Convert.ToInt32(message.Length); - int outLen; - if (forEncryption) - { - outLen = msgLen + 16; - Check.OutputLength(outBytes, outOff, outLen, "output buffer is too short"); - ISAPAEAD.isap_enc(msg, 0, msgLen, outBytes, outOff); - outputStream.Write(outBytes, outOff, msgLen); - outOff += msgLen; - byte[] c = outputStream.GetBuffer(); - mac = new byte[16]; - ISAPAEAD.isap_mac(aad, aadLen, c, Convert.ToInt32(outputStream.Length), mac, 0); - Array.Copy(mac, 0, outBytes, outOff, 16); - } - else - { - outLen = msgLen - 16; - Check.OutputLength(outBytes, outOff, outLen, "output buffer is too short"); - mac = new byte[16]; - ISAPAEAD.isap_mac(aad, aadLen, msg, outLen, mac, 0); - ISAPAEAD.reset(); - if (!Arrays.FixedTimeEquals(16, mac, 0, msg, outLen)) - throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed"); - - ISAPAEAD.isap_enc(msg, 0, outLen, outBytes, outOff); - } - return outLen; -#endif - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public int DoFinal(Span<byte> output) - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - byte[] aad = aadData.GetBuffer(); - byte[] msg = message.GetBuffer(); - - int aadLen = Convert.ToInt32(aadData.Length); - int msgLen = Convert.ToInt32(message.Length); - int outLen; - if (forEncryption) - { - outLen = msgLen + 16; - Check.OutputLength(output, outLen, "output buffer is too short"); - ISAPAEAD.isap_enc(msg.AsSpan(0, msgLen), output); - outputStream.Write(output[..msgLen]); - output = output[msgLen..]; - byte[] c = outputStream.GetBuffer(); - mac = new byte[16]; - ISAPAEAD.isap_mac(aad, aadLen, c, Convert.ToInt32(outputStream.Length), mac, 0); - mac.CopyTo(output); - } - else - { - outLen = msgLen - 16; - Check.OutputLength(output, outLen, "output buffer is too short"); - mac = new byte[16]; - ISAPAEAD.isap_mac(aad, aadLen, msg, outLen, mac, 0); - ISAPAEAD.reset(); - if (!Arrays.FixedTimeEquals(16, mac, 0, msg, outLen)) - throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed"); - - ISAPAEAD.isap_enc(msg.AsSpan(0, outLen), output); - } - return outLen; - } -#endif - - public byte[] GetMac() - { - return mac; - } - - public int GetUpdateOutputSize(int len) - { - if (!forEncryption) - return 0; - - int totalData = Convert.ToInt32(message.Length + len); - return totalData - totalData % ISAP_rH_SZ; - } - - public int GetOutputSize(int len) - { - int totalData = Convert.ToInt32(message.Length + len); - - if (forEncryption) - return totalData + 16; - - return System.Math.Max(0, totalData - 16); - } - - public void Reset() - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - aadData.SetLength(0); - ISAPAEAD.reset(); - message.SetLength(0); - outputStream.SetLength(0); - } - } -} diff --git a/crypto/src/crypto/engines/PhotonBeetleEngine.cs b/crypto/src/crypto/engines/PhotonBeetleEngine.cs deleted file mode 100644 index 5d96213a1..000000000 --- a/crypto/src/crypto/engines/PhotonBeetleEngine.cs +++ /dev/null @@ -1,441 +0,0 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Engines -{ - /** - * Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/ - * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/readonlyist-round/updated-spec-doc/photon-beetle-spec-readonly.pdf - * <p> - * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software - * </p> - */ - public sealed class PhotonBeetleEngine - // TODO IAeadCipher only - : IAeadBlockCipher - { - public enum PhotonBeetleParameters - { - pb32, - pb128 - } - - private bool input_empty; - private bool forEncryption = true; // Safe output sizes before initialization - private bool initialised; - private byte[] K; - private byte[] N; - private byte[] state; - private byte[][] state_2d; - private byte[] A; - private byte[] T; - private MemoryStream aadData = new MemoryStream(); - private MemoryStream message = new MemoryStream(); - private readonly int CRYPTO_KEYBYTES = 16; - private readonly int CRYPTO_NPUBBYTES = 16; - private readonly int RATE_INBYTES; - private readonly int RATE_INBYTES_HALF; - private int STATE_INBYTES; - private int TAG_INBYTES = 16; - private int LAST_THREE_BITS_OFFSET; - private int ROUND = 12; - private int D = 8; - private int Dq = 3; - private int Dr = 7; - private int DSquare = 64; - private int S = 4; - private int S_1 = 3; - private byte[][] RC = { - new byte[]{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10}, - new byte[]{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11}, - new byte[]{2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9}, - new byte[]{6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13}, - new byte[]{14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5}, - new byte[]{15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4}, - new byte[]{13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6}, - new byte[]{9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2} - }; - private byte[][] MixColMatrix = { - new byte[]{2, 4, 2, 11, 2, 8, 5, 6}, - new byte[]{12, 9, 8, 13, 7, 7, 5, 2}, - new byte[]{4, 4, 13, 13, 9, 4, 13, 9}, - new byte[]{1, 6, 5, 1, 12, 13, 15, 14}, - new byte[]{15, 12, 9, 13, 14, 5, 14, 13}, - new byte[]{9, 14, 5, 15, 4, 12, 9, 6}, - new byte[]{12, 2, 2, 10, 3, 1, 1, 14}, - new byte[]{15, 1, 13, 10, 5, 10, 2, 3} - }; - - private byte[] sbox = { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 }; - public PhotonBeetleEngine(PhotonBeetleParameters pbp) - { - int CAPACITY_INBITS = 0, RATE_INBITS = 0; - switch (pbp) - { - case PhotonBeetleParameters.pb32: - RATE_INBITS = 32; - CAPACITY_INBITS = 224; - break; - case PhotonBeetleParameters.pb128: - RATE_INBITS = 128; - CAPACITY_INBITS = 128; - break; - } - RATE_INBYTES = (RATE_INBITS + 7) >> 3; - RATE_INBYTES_HALF = RATE_INBYTES >> 1; - int STATE_INBITS = RATE_INBITS + CAPACITY_INBITS; - STATE_INBYTES = (STATE_INBITS + 7) >> 3; - LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3); - initialised = false; - } - - public string AlgorithmName => "Photon-Beetle AEAD"; - - // TODO - public IBlockCipher UnderlyingCipher => throw new NotImplementedException(); - - public byte[] GetMac() - { - return T; - } - - public int GetOutputSize(int len) - { - // TODO - return len + TAG_INBYTES; - } - - public int GetUpdateOutputSize(int len) - { - // TODO - return len; - } - - public void Init(bool forEncryption, ICipherParameters parameters) - { - this.forEncryption = forEncryption; - - if (!(parameters is ParametersWithIV ivParams)) - throw new ArgumentException("Photon-Beetle AEAD init parameters must include an IV"); - - N = ivParams.GetIV(); - if (N == null || N.Length != CRYPTO_NPUBBYTES) - throw new ArgumentException("Photon-Beetle AEAD requires exactly 16 bytes of IV"); - - if (!(ivParams.Parameters is KeyParameter key)) - throw new ArgumentException("Photon-Beetle AEAD init parameters must include a key"); - - K = key.GetKey(); - if (K.Length != CRYPTO_KEYBYTES) - throw new ArgumentException("Photon-Beetle AEAD key must be 128 bits long"); - - state = new byte[STATE_INBYTES]; - state_2d = new byte[D][]; - for (int i = 0; i < D; ++i) - { - state_2d[i] = new byte[D]; - } - T = new byte[TAG_INBYTES]; - initialised = true; - reset(false); - } - - public void ProcessAadByte(byte input) - { - aadData.WriteByte(input); - } - - public void ProcessAadBytes(byte[] inBytes, int inOff, int len) - { - Check.DataLength(inBytes, inOff, len, "input buffer too short"); - - aadData.Write(inBytes, inOff, len); - } - - public int ProcessByte(byte input, byte[] outBytes, int outOff) - { - message.WriteByte(input); - return 0; - } - - public int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff) - { - Check.DataLength(inBytes, inOff, len, "input buffer too short"); - - message.Write(inBytes, inOff, len); - return 0; - } - - public void Reset() - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - reset(true); - } - - private void reset(bool clearMac) - { - if (clearMac) - { - T = null; - } - input_empty = true; - aadData.SetLength(0); - message.SetLength(0); - Array.Copy(K, 0, state, 0, K.Length); - Array.Copy(N, 0, state, K.Length, N.Length); - } - - void PHOTON_Permutation() - { - int i, j, k, l; - for (i = 0; i < DSquare; i++) - { - state_2d[i >> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >> (4 * (i & 1))) & 0xf); - } - for (int round = 0; round < ROUND; round++) - { - //AddKey - for (i = 0; i < D; i++) - { - state_2d[i][0] ^= RC[i][round]; - } - //SubCell - for (i = 0; i < D; i++) - { - for (j = 0; j < D; j++) - { - state_2d[i][j] = sbox[state_2d[i][j]]; - } - } - //ShiftRow - for (i = 1; i < D; i++) - { - Array.Copy(state_2d[i], 0, state, 0, D); - Array.Copy(state, i, state_2d[i], 0, D - i); - Array.Copy(state, 0, state_2d[i], D - i, i); - } - //MixColumn - for (j = 0; j < D; j++) - { - for (i = 0; i < D; i++) - { - byte sum = 0; - for (k = 0; k < D; k++) - { - int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j]; - for (l = 0; l < S; l++) - { - if (((b >> l) & 1) != 0) - { - ret ^= x; - } - if (((x >> S_1) & 1) != 0) - { - x <<= 1; - x ^= 0x3; - } - else - { - x <<= 1; - } - } - sum ^= (byte)(ret & 15); - } - state[i] = sum; - } - for (i = 0; i < D; i++) - { - state_2d[i][j] = state[i]; - } - } - } - for (i = 0; i < DSquare; i += 2) - { - state[i >> 1] = (byte)(((state_2d[i >> Dq][i & Dr] & 0xf)) | ((state_2d[i >> Dq][(i + 1) & Dr] & 0xf) << 4)); - } - } - - private byte select(bool condition1, bool condition2, byte option3, byte option4) - { - if (condition1 && condition2) - { - return 1; - } - if (condition1) - { - return 2; - } - if (condition2) - { - return option3; - } - return option4; - } - - void rhoohr(byte[] ciphertext, int offset, byte[] plaintext, int inOff, int DBlen_inbytes) - { - byte[] OuterState_part1_ROTR1 = state_2d[0]; - int i, loop_end = System.Math.Min(DBlen_inbytes, RATE_INBYTES_HALF); - for (i = 0; i < RATE_INBYTES_HALF - 1; i++) - { - OuterState_part1_ROTR1[i] = (byte)(((state[i] & 0xFF) >> 1) | ((state[(i + 1)] & 1) << 7)); - } - OuterState_part1_ROTR1[RATE_INBYTES_HALF - 1] = (byte)(((state[i] & 0xFF) >> 1) | ((state[0] & 1) << 7)); - i = 0; - while (i < loop_end) - { - ciphertext[i + offset] = (byte)(state[i + RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]); - } - while (i < DBlen_inbytes) - { - ciphertext[i + offset] = (byte)(OuterState_part1_ROTR1[i - RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]); - } - if (forEncryption) - { - Bytes.XorTo(DBlen_inbytes, plaintext, inOff, state, 0); - } - else - { - Bytes.XorTo(DBlen_inbytes, ciphertext, inOff, state, 0); - } - } - - public int DoFinal(byte[] output, int outOff) - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - int len = (int)message.Length - (forEncryption ? 0 : TAG_INBYTES); - if ((forEncryption && len + TAG_INBYTES + outOff > output.Length) || - (!forEncryption && len + outOff > output.Length)) - { - throw new OutputLengthException("output buffer too short"); - } - byte[] input = message.GetBuffer(); - int inOff = 0; - A = aadData.GetBuffer(); - int adlen = (int)aadData.Length, i; - if (adlen != 0 || len != 0) - { - input_empty = false; - } - byte c0 = select((len != 0), ((adlen % RATE_INBYTES) == 0), (byte)3, (byte)4); - byte c1 = select((adlen != 0), ((len % RATE_INBYTES) == 0), (byte)5, (byte)6); - int Dlen_inblocks, LastDBlocklen; - if (adlen != 0) - { - Dlen_inblocks = (adlen + RATE_INBYTES - 1) / RATE_INBYTES; - for (i = 0; i < Dlen_inblocks - 1; i++) - { - PHOTON_Permutation(); - Bytes.XorTo(RATE_INBYTES, A, i * RATE_INBYTES, state, 0); - } - PHOTON_Permutation(); - LastDBlocklen = adlen - i * RATE_INBYTES; - Bytes.XorTo(LastDBlocklen, A, i * RATE_INBYTES, state, 0); - if (LastDBlocklen < RATE_INBYTES) - { - state[LastDBlocklen] ^= 0x01; // ozs - } - state[STATE_INBYTES - 1] ^= (byte)(c0 << LAST_THREE_BITS_OFFSET); - } - if (len != 0) - { - Dlen_inblocks = (len + RATE_INBYTES - 1) / RATE_INBYTES; - for (i = 0; i < Dlen_inblocks - 1; i++) - { - PHOTON_Permutation(); - rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, RATE_INBYTES); - } - PHOTON_Permutation(); - LastDBlocklen = len - i * RATE_INBYTES; - rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, LastDBlocklen); - if (LastDBlocklen < RATE_INBYTES) - { - state[LastDBlocklen] ^= 0x01; // ozs - } - state[STATE_INBYTES - 1] ^= (byte)(c1 << LAST_THREE_BITS_OFFSET); - } - outOff += len; - if (input_empty) - { - state[STATE_INBYTES - 1] ^= (byte)(1 << LAST_THREE_BITS_OFFSET); - } - PHOTON_Permutation(); - T = new byte[TAG_INBYTES]; - Array.Copy(state, 0, T, 0, TAG_INBYTES); - if (forEncryption) - { - Array.Copy(T, 0, output, outOff, TAG_INBYTES); - len += TAG_INBYTES; - } - else - { - if (!Arrays.FixedTimeEquals(TAG_INBYTES, T, 0, input, len)) - throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed"); - } - reset(false); - return len; - } - - public int GetBlockSize() - { - return RATE_INBYTES; - } - - public int GetKeyBytesSize() - { - return CRYPTO_KEYBYTES; - } - - public int GetIVBytesSize() - { - return CRYPTO_NPUBBYTES; - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public void ProcessAadBytes(ReadOnlySpan<byte> input) - { - aadData.Write(input); - } - - public int ProcessByte(byte input, Span<byte> 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<byte> input, Span<byte> 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<byte> output) - { - byte[] rv; - if (forEncryption) - { - rv = new byte[message.Length + 16]; - } - else - { - rv = new byte[message.Length - 16]; - } - int len = DoFinal(rv, 0); - rv.AsSpan(0, len).CopyTo(output); - return rv.Length; - } -#endif - } -} diff --git a/crypto/src/crypto/engines/SparkleEngine.cs b/crypto/src/crypto/engines/SparkleEngine.cs deleted file mode 100644 index 7d8c28f8e..000000000 --- a/crypto/src/crypto/engines/SparkleEngine.cs +++ /dev/null @@ -1,580 +0,0 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Utilities; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Engines -{ - /// <summary>Sparkle v1.2, based on the current round 3 submission, https://sparkle-lwc.github.io/ .</summary> - /// <remarks> - /// Reference C implementation: https://github.com/cryptolu/sparkle.<br/> - /// Specification: - /// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/sparkle-spec-final.pdf . - /// </remarks> - public sealed class SparkleEngine - // TODO IAeadCipher only - : IAeadBlockCipher - { - public enum SparkleParameters - { - SCHWAEMM128_128, - SCHWAEMM256_128, - SCHWAEMM192_192, - SCHWAEMM256_256 - } - - private string algorithmName; - private bool forEncryption = true; // Safe output sizes before initialization - private readonly uint[] state; - private readonly uint[] k; - private readonly uint[] npub; - private byte[] tag; - private bool initialised; - private bool encrypted; - private bool aadFinished; - private readonly MemoryStream aadData = new MemoryStream(); - private readonly MemoryStream message = new MemoryStream(); - private readonly int SCHWAEMM_KEY_LEN; - private readonly int SCHWAEMM_NONCE_LEN; - private readonly int SPARKLE_STEPS_SLIM; - private readonly int SPARKLE_STEPS_BIG; - private readonly int KEY_BYTES; - private readonly int KEY_WORDS; - private readonly int TAG_WORDS; - private readonly int TAG_BYTES; - private readonly int STATE_BRANS; - private readonly int STATE_WORDS; - private readonly int RATE_WORDS; - private readonly int RATE_BYTES; - private readonly int CAP_WORDS; - private readonly uint _A0; - private readonly uint _A1; - private readonly uint _M2; - private readonly uint _M3; - - public SparkleEngine(SparkleParameters sparkleParameters) - { - int SPARKLE_STATE; - int SCHWAEMM_TAG_LEN; - int SPARKLE_CAPACITY; - switch (sparkleParameters) - { - case SparkleParameters.SCHWAEMM128_128: - SCHWAEMM_KEY_LEN = 128; - SCHWAEMM_NONCE_LEN = 128; - SCHWAEMM_TAG_LEN = 128; - SPARKLE_STATE = 256; - SPARKLE_CAPACITY = 128; - SPARKLE_STEPS_SLIM = 7; - SPARKLE_STEPS_BIG = 10; - algorithmName = "SCHWAEMM128-128"; - break; - case SparkleParameters.SCHWAEMM256_128: - SCHWAEMM_KEY_LEN = 128; - SCHWAEMM_NONCE_LEN = 256; - SCHWAEMM_TAG_LEN = 128; - SPARKLE_STATE = 384; - SPARKLE_CAPACITY = 128; - SPARKLE_STEPS_SLIM = 7; - SPARKLE_STEPS_BIG = 11; - algorithmName = "SCHWAEMM256-128"; - break; - case SparkleParameters.SCHWAEMM192_192: - SCHWAEMM_KEY_LEN = 192; - SCHWAEMM_NONCE_LEN = 192; - SCHWAEMM_TAG_LEN = 192; - SPARKLE_STATE = 384; - SPARKLE_CAPACITY = 192; - SPARKLE_STEPS_SLIM = 7; - SPARKLE_STEPS_BIG = 11; - algorithmName = "SCHWAEMM192-192"; - break; - case SparkleParameters.SCHWAEMM256_256: - SCHWAEMM_KEY_LEN = 256; - SCHWAEMM_NONCE_LEN = 256; - SCHWAEMM_TAG_LEN = 256; - SPARKLE_STATE = 512; - SPARKLE_CAPACITY = 256; - SPARKLE_STEPS_SLIM = 8; - SPARKLE_STEPS_BIG = 12; - algorithmName = "SCHWAEMM256-256"; - break; - default: - throw new ArgumentException("Invalid definition of SCHWAEMM instance"); - } - KEY_WORDS = SCHWAEMM_KEY_LEN >> 5; - KEY_BYTES = SCHWAEMM_KEY_LEN >> 3; - TAG_WORDS = SCHWAEMM_TAG_LEN >> 5; - TAG_BYTES = SCHWAEMM_TAG_LEN >> 3; - STATE_BRANS = SPARKLE_STATE >> 6; - STATE_WORDS = SPARKLE_STATE >> 5; - RATE_WORDS = SCHWAEMM_NONCE_LEN >> 5; - RATE_BYTES = SCHWAEMM_NONCE_LEN >> 3; - int CAP_BRANS = SPARKLE_CAPACITY >> 6; - CAP_WORDS = SPARKLE_CAPACITY >> 5; - _A0 = ((((1u << CAP_BRANS))) << 24); - _A1 = (((1u ^ (1u << CAP_BRANS))) << 24); - _M2 = (((2u ^ (1u << CAP_BRANS))) << 24); - _M3 = (((3u ^ (1u << CAP_BRANS))) << 24); - state = new uint[STATE_WORDS]; - tag = new byte[TAG_BYTES]; - k = new uint[KEY_WORDS]; - npub = new uint[RATE_WORDS]; - initialised = false; - } - - private uint ELL(uint x) - { - return Integers.RotateRight(x ^ (x << 16), 16); - } - - private static readonly uint[] RCON = {0xB7E15162, 0xBF715880, 0x38B4DA56, 0x324E7738, 0xBB1185EB, 0x4F7C7B57, - 0xCFBFA1C8, 0xC2B3293D}; - - void sparkle_opt(uint[] state, int brans, int steps) - { - uint i, j, rc, tmpx, tmpy, x0, y0; - for (i = 0; i < steps; i++) - { - // Add round ant - state[1] ^= RCON[i & 7]; - state[3] ^= i; - // ARXBOX layer - for (j = 0; j < 2 * brans; j += 2) - { - rc = RCON[j >> 1]; - state[j] += Integers.RotateRight(state[j + 1], 31); - state[j + 1] ^= Integers.RotateRight(state[j], 24); - state[j] ^= rc; - state[j] += Integers.RotateRight(state[j + 1], 17); - state[j + 1] ^= Integers.RotateRight(state[j], 17); - state[j] ^= rc; - state[j] += state[j + 1]; - state[j + 1] ^= Integers.RotateRight(state[j], 31); - state[j] ^= rc; - state[j] += Integers.RotateRight(state[j + 1], 24); - state[j + 1] ^= Integers.RotateRight(state[j], 16); - state[j] ^= rc; - } - // Linear layer - tmpx = x0 = state[0]; - tmpy = y0 = state[1]; - for (j = 2; j < brans; j += 2) - { - tmpx ^= state[j]; - tmpy ^= state[j + 1]; - } - tmpx = ELL(tmpx); - tmpy = ELL(tmpy); - for (j = 2; j < brans; j += 2) - { - state[j - 2] = state[j + brans] ^ state[j] ^ tmpy; - state[j + brans] = state[j]; - state[j - 1] = state[j + brans + 1] ^ state[j + 1] ^ tmpx; - state[j + brans + 1] = state[j + 1]; - } - state[brans - 2] = state[brans] ^ x0 ^ tmpy; - state[brans] = x0; - state[brans - 1] = state[brans + 1] ^ y0 ^ tmpx; - state[brans + 1] = y0; - } - } - - private int CAP_INDEX(int i) - { - if (RATE_WORDS > CAP_WORDS) - { - return i & (CAP_WORDS - 1); - } - return i; - } - - // The ProcessAssocData function absorbs the associated data, which becomes - // only authenticated but not encrypted, into the state (in blocks of size - // RATE_BYTES). Note that this function MUST NOT be called when the length of - // the associated data is 0. - void ProcessAssocData(uint[] state) - { - int inlen = (int)aadData.Length; - if (aadFinished || inlen == 0) - { - return; - } - aadFinished = true; - byte[] input = aadData.GetBuffer(); - // Main Authentication Loop - int inOff = 0, i, j; - uint tmp; - uint[] in32 = Pack.LE_To_UInt32(input, inOff, input.Length >> 2); - while (inlen > RATE_BYTES) - { - // combined Rho and rate-whitening operation - // Rho and rate-whitening for the authentication of associated data. The third - // parameter indicates whether the uint8_t-pointer 'in' is properly aligned to - // permit casting to a int-pointer. If this is the case then array 'in' is - // processed directly, otherwise it is first copied to an aligned buffer. - for (i = 0, j = RATE_WORDS / 2; i < RATE_WORDS / 2; i++, j++) - { - tmp = state[i]; - state[i] = state[j] ^ in32[i + (inOff >> 2)] ^ state[RATE_WORDS + i]; - state[j] ^= tmp ^ in32[j + (inOff >> 2)] ^ state[RATE_WORDS + CAP_INDEX(j)]; - } - // execute SPARKLE with slim number of steps - sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_SLIM); - inlen -= RATE_BYTES; - inOff += RATE_BYTES; - } - // Authentication of Last Block - // addition of ant A0 or A1 to the state - state[STATE_WORDS - 1] ^= ((inlen < RATE_BYTES) ? _A0 : _A1); - // combined Rho and rate-whitening (incl. padding) - // Rho and rate-whitening for the authentication of the last associated-data - // block. Since this last block may require padding, it is always copied to a buffer. - uint[] buffer = new uint[RATE_WORDS]; - for (i = 0; i < inlen; ++i) - { - buffer[i >> 2] |= (uint)input[inOff++] << ((i & 3) << 3); - } - if (inlen < RATE_BYTES) - { // padding - buffer[i >> 2] |= 0x80u << ((i & 3) << 3); - } - for (i = 0, j = RATE_WORDS / 2; i < RATE_WORDS / 2; i++, j++) - { - tmp = state[i]; - state[i] = state[j] ^ buffer[i] ^ state[RATE_WORDS + i]; - state[j] ^= tmp ^ buffer[j] ^ state[RATE_WORDS + CAP_INDEX(j)]; - } - // execute SPARKLE with big number of steps - sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_BIG); - } - - // The ProcessPlainText function encrypts the plaintext (input blocks of size - // RATE_BYTES) and generates the respective ciphertext. The uint8_t-array 'input' - // contains the plaintext and the ciphertext is written to uint8_t-array 'output' - // ('input' and 'output' can be the same array, i.e. they can have the same start - // address). Note that this function MUST NOT be called when the length of the - // plaintext is 0. - private int ProcessPlainText(uint[] state, byte[] output, byte[] input, int inOff, int inlen) - { - // Main Encryption Loop - int outOff = 0, i, j; - uint tmp1, tmp2; - uint[] in32 = Pack.LE_To_UInt32(input, inOff, input.Length >> 2); - uint[] out32 = new uint[output.Length >> 2]; - int rv = 0; - while (inlen > RATE_BYTES) - { - // combined Rho and rate-whitening operation - // Rho and rate-whitening for the encryption of plaintext. The third parameter - // indicates whether the uint8_t-pointers 'input' and 'output' are properly aligned - // to permit casting to int-pointers. If this is the case then array 'input' - // and 'output' are processed directly, otherwise 'input' is copied to an aligned buffer. - for (i = 0, j = RATE_WORDS / 2; i < RATE_WORDS / 2; i++, j++) - { - tmp1 = state[i]; - tmp2 = state[j]; - if (forEncryption) - { - state[i] = state[j] ^ in32[i + (inOff >> 2)] ^ state[RATE_WORDS + i]; - state[j] ^= tmp1 ^ in32[j + (inOff >> 2)] ^ state[RATE_WORDS + CAP_INDEX(j)]; - } - else - { - state[i] ^= state[j] ^ in32[i + (inOff >> 2)] ^ state[RATE_WORDS + i]; - state[j] = tmp1 ^ in32[j + (inOff >> 2)] ^ state[RATE_WORDS + CAP_INDEX(j)]; - } - out32[i] = in32[i] ^ tmp1; - out32[j] = in32[j] ^ tmp2; - } - Pack.UInt32_To_LE(out32, 0, RATE_WORDS, output, outOff); - // execute SPARKLE with slim number of steps - sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_SLIM); - inlen -= RATE_BYTES; - outOff += RATE_BYTES; - inOff += RATE_BYTES; - rv += RATE_BYTES; - encrypted = true; - } - return rv; - } - - public void Init(bool forEncryption, ICipherParameters param) - { - this.forEncryption = forEncryption; - if (!(param is ParametersWithIV ivParams)) - throw new ArgumentException(algorithmName + " init parameters must include an IV"); - - byte[] iv = ivParams.GetIV(); - if (iv == null || iv.Length != SCHWAEMM_NONCE_LEN >> 3) - throw new ArgumentException(algorithmName + " requires exactly 16 bytes of IV"); - - Pack.LE_To_UInt32(iv, 0, npub, 0, RATE_WORDS); - - if (!(ivParams.Parameters is KeyParameter key)) - throw new ArgumentException(algorithmName + " init parameters must include a key"); - - byte[] key8 = key.GetKey(); - if (key8.Length != SCHWAEMM_KEY_LEN >> 3) - throw new ArgumentException(algorithmName + " key must be 128 bits long"); - - Pack.LE_To_UInt32(key8, 0, k, 0, KEY_WORDS); - initialised = true; - reset(false); - } - - public void ProcessAadByte(byte input) - { - if (encrypted) - { - throw new ArgumentException(algorithmName + ": AAD cannot be added after reading a full block(" + - GetBlockSize() + " bytes) of input for " + (forEncryption ? "encryption" : "decryption")); - } - - aadData.WriteByte(input); - } - - public void ProcessAadBytes(byte[] input, int inOff, int len) - { - if (encrypted) - { - throw new ArgumentException(algorithmName + ": AAD cannot be added after reading a full block(" + - GetBlockSize() + " bytes) of input for " + (forEncryption ? "encryption" : "decryption")); - } - - Check.DataLength(input, inOff, len, "input buffer too short"); - - aadData.Write(input, inOff, len); - } - - public int ProcessByte(byte input, byte[] output, int outOff) - { - return ProcessBytes(new byte[]{ input }, 0, 1, output, outOff); - } - - public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff) - { - if (!initialised) - throw new ArgumentException(algorithmName + " Need call init function before encryption/decryption"); - - Check.DataLength(input, inOff, len, "input buffer too short"); - - message.Write(input, inOff, len); - - int msgLen = Convert.ToInt32(message.Length); - - len = 0; - if ((forEncryption && msgLen > GetBlockSize()) || - (!forEncryption && msgLen - TAG_BYTES > GetBlockSize())) - { - len = msgLen - (forEncryption ? 0 : TAG_BYTES); - Check.OutputLength(output, outOff, len / RATE_BYTES * RATE_BYTES, "output buffer is too short"); - byte[] m = message.GetBuffer(); - ProcessAssocData(state); - if (len != 0) - { - len = ProcessPlainText(state, output, m, 0, len); - } - message.SetLength(0); - // TODO Sketchy writing back to the buffer after setting length to 0 - message.Write(m, len, msgLen - len); - } - return len; - } - - public int DoFinal(byte[] output, int outOff) - { - if (!initialised) - throw new ArgumentException(algorithmName + " needs to call Init before DoFinal"); - - int inlen = Convert.ToInt32(message.Length) - (forEncryption ? 0 : TAG_BYTES); - if ((forEncryption && inlen + TAG_BYTES + outOff > output.Length) || - (!forEncryption && inlen + outOff > output.Length)) - { - throw new OutputLengthException("output buffer is too short"); - } - ProcessAssocData(state); - int i, j; - uint tmp1, tmp2; - byte[] input = message.GetBuffer(); - int inOff = 0; - if (encrypted || inlen != 0) - { - // Encryption of Last Block - // addition of ant M2 or M3 to the state - state[STATE_WORDS - 1] ^= ((inlen < RATE_BYTES) ? _M2 : _M3); - // combined Rho and rate-whitening (incl. padding) - // Rho and rate-whitening for the encryption of the last plaintext block. Since - // this last block may require padding, it is always copied to a buffer. - uint[] buffer = new uint[RATE_WORDS]; - for (i = 0; i < inlen; ++i) - { - buffer[i >> 2] |= (input[inOff++] & 0xffu) << ((i & 3) << 3); - } - if (inlen < RATE_BYTES) - { - if (!forEncryption) - { - int tmp = (i & 3) << 3; - buffer[i >> 2] |= (state[i >> 2] >> tmp) << tmp; - tmp = (i >> 2) + 1; - Array.Copy(state, tmp, buffer, tmp, RATE_WORDS - tmp); - } - buffer[i >> 2] ^= 0x80u << ((i & 3) << 3); - } - for (i = 0, j = RATE_WORDS / 2; i < RATE_WORDS / 2; i++, j++) - { - tmp1 = state[i]; - tmp2 = state[j]; - if (forEncryption) - { - state[i] = state[j] ^ buffer[i] ^ state[RATE_WORDS + i]; - state[j] ^= tmp1 ^ buffer[j] ^ state[RATE_WORDS + CAP_INDEX(j)]; - } - else - { - state[i] ^= state[j] ^ buffer[i] ^ state[RATE_WORDS + i]; - state[j] = tmp1 ^ buffer[j] ^ state[RATE_WORDS + CAP_INDEX(j)]; - } - buffer[i] ^= tmp1; - buffer[j] ^= tmp2; - } - for (i = 0; i < inlen; ++i) - { - output[outOff++] = (byte)(buffer[i >> 2] >> ((i & 3) << 3)); - } - // execute SPARKLE with big number of steps - sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_BIG); - } - // add key to the capacity-part of the state - for (i = 0; i < KEY_WORDS; i++) - { - state[RATE_WORDS + i] ^= k[i]; - } - tag = new byte[TAG_BYTES]; - Pack.UInt32_To_LE(state, RATE_WORDS, TAG_WORDS, tag, 0); - if (forEncryption) - { - Array.Copy(tag, 0, output, outOff, TAG_BYTES); - inlen += TAG_BYTES; - } - else - { - if (!Arrays.FixedTimeEquals(TAG_BYTES, tag, 0, input, inlen)) - throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed"); - } - reset(false); - return inlen; - } - - public byte[] GetMac() - { - return tag; - } - - public int GetUpdateOutputSize(int len) - { - // TODO - return len; - } - - public int GetOutputSize(int len) - { - // TODO - return len + TAG_BYTES; - } - - public void Reset() - { - if (!initialised) - throw new ArgumentException(algorithmName + " needs to call Init before Reset"); - - reset(true); - } - - private void reset(bool clearMac) - { - if (clearMac) - { - tag = null; - } - // The Initialize function loads nonce and key into the state and executes the - // SPARKLE permutation with the big number of steps. - // load nonce into the rate-part of the state - Array.Copy(npub, 0, state, 0, RATE_WORDS); - // load key into the capacity-part of the sate - Array.Copy(k, 0, state, RATE_WORDS, KEY_WORDS); - // execute SPARKLE with big number of steps - sparkle_opt(state, STATE_BRANS, SPARKLE_STEPS_BIG); - aadData.SetLength(0); - message.SetLength(0); - encrypted = false; - aadFinished = false; - } - public string AlgorithmName => algorithmName; - - public IBlockCipher UnderlyingCipher => throw new NotImplementedException(); - - public int GetBlockSize() - { - return RATE_BYTES; - } - - - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public void ProcessAadBytes(ReadOnlySpan<byte> input) - { - aadData.Write(input); - } - - public int ProcessByte(byte input, Span<byte> 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<byte> input, Span<byte> 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<byte> output) - { - byte[] rv; - if (forEncryption) - { - rv = new byte[message.Length + TAG_BYTES]; - } - else - { - rv = new byte[message.Length - TAG_BYTES]; - } - int len = DoFinal(rv, 0); - rv.AsSpan(0, len).CopyTo(output); - return rv.Length; - - } -#endif - - public int GetKeyBytesSize() - { - return KEY_BYTES; - } - - public int GetIVBytesSize() - { - return RATE_BYTES; - } - } -} - diff --git a/crypto/src/crypto/engines/XoodyakEngine.cs b/crypto/src/crypto/engines/XoodyakEngine.cs deleted file mode 100644 index 2eb563525..000000000 --- a/crypto/src/crypto/engines/XoodyakEngine.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Utilities; -using Org.BouncyCastle.Utilities; - -namespace Org.BouncyCastle.Crypto.Engines -{ - /** - * Xoodyak v1, https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/xoodyak-spec-final.pdf - * <p> - * Xoodyak with reference to C Reference Impl from: https://github.com/XKCP/XKCP - * </p> - */ - public sealed class XoodyakEngine - // TODO IAeadCipher only - : IAeadBlockCipher - { - private enum MODE - { - ModeHash, - ModeKeyed - } - - private const int Rkin = 44; - - private static readonly uint[] RC = { 0x00000058U, 0x00000038U, 0x000003C0U, 0x000000D0U, 0x00000120U, - 0x00000014U, 0x00000060U, 0x0000002CU, 0x00000380U, 0x000000F0U, 0x000001A0U, 0x00000012U }; - - private bool forEncryption = true; // Safe output sizes before initialization - private byte[] state; - private int phase; - private MODE mode; - private int Rabsorb; - private const int f_bPrime = 48; - private const int Rkout = 24; - private byte[] K; - private byte[] iv; - private const int PhaseDown = 1; - private const int PhaseUp = 2; - private const int NLANES = 12; - private const int NROWS = 3; - private const int NCOLUMS = 4; - private const int MAXROUNDS = 12; - private const int TAGLEN = 16; - private byte[] tag; - private bool aadFinished; - private bool encrypted; - private bool initialised = false; - - private MemoryStream aadData = new MemoryStream(); - private MemoryStream message = new MemoryStream(); - - public string AlgorithmName => "Xoodak AEAD"; - - public IBlockCipher UnderlyingCipher => throw new NotImplementedException(); - - public void Init(bool forEncryption, ICipherParameters parameters) - { - this.forEncryption = forEncryption; - - if (!(parameters is ParametersWithIV ivParams)) - throw new ArgumentException("Xoodyak init parameters must include an IV"); - - iv = ivParams.GetIV(); - if (iv == null || iv.Length != 16) - throw new ArgumentException("Xoodyak requires exactly 16 bytes of IV"); - - if (!(ivParams.Parameters is KeyParameter key)) - throw new ArgumentException("Xoodyak init parameters must include a key"); - - K = key.GetKey(); - if (K.Length != 16) - throw new ArgumentException("Xoodyak key must be 128 bits long"); - - state = new byte[48]; - tag = new byte[TAGLEN]; - initialised = true; - reset(false); - } - - public void ProcessAadByte(byte input) - { - if (aadFinished) - { - throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() + - " bytes) of input for " + (forEncryption ? "encryption" : "decryption")); - } - - aadData.WriteByte(input); - } - - public void ProcessAadBytes(byte[] input, int inOff, int len) - { - if (aadFinished) - { - throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() + - " bytes) of input for " + (forEncryption ? "encryption" : "decryption")); - } - - Check.DataLength(input, inOff, len, "input buffer too short"); - - aadData.Write(input, inOff, len); - } - - public int ProcessByte(byte input, byte[] outBytes, int outOff) - { - return ProcessBytes(new byte[]{ input }, 0, 1, outBytes, outOff); - } - - private void processAAD() - { - if (!aadFinished) - { - byte[] ad = aadData.GetBuffer(); - AbsorbAny(ad, 0, (int)aadData.Length, Rabsorb, 0x03); - aadFinished = true; - } - } - - public int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff) - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - if (mode != MODE.ModeKeyed) - throw new ArgumentException("Xoodyak has not been initialised"); - - Check.DataLength(inBytes, inOff, len, "input buffer too short"); - - message.Write(inBytes, inOff, len); - int blockLen = (int)message.Length - (forEncryption ? 0 : TAGLEN); - if (blockLen >= GetBlockSize()) - { - byte[] blocks = message.GetBuffer(); - len = blockLen / GetBlockSize() * GetBlockSize(); - Check.OutputLength(outBytes, outOff, len, "output buffer is too short"); - processAAD(); - encrypt(blocks, 0, len, outBytes, outOff); - int messageLen = (int)message.Length; - message.SetLength(0); - message.Write(blocks, len, messageLen - len); - return len; - } - return 0; - } - - private int encrypt(byte[] input, int inOff, int len, byte[] output, int outOff) - { - int IOLen = len; - int splitLen; - byte[] P = new byte[Rkout]; - uint Cu = encrypted ? 0u : 0x80u; - while (IOLen != 0 || !encrypted) - { - splitLen = System.Math.Min(IOLen, Rkout); /* use Rkout instead of Rsqueeze, this function is only called in keyed mode */ - if (forEncryption) - { - Array.Copy(input, inOff, P, 0, splitLen); - } - Up(null, 0, Cu); /* Up without extract */ - /* Extract from Up and Add */ - for (int i = 0; i < splitLen; i++) - { - output[outOff + i] = (byte)(input[inOff++] ^ state[i]); - } - if (forEncryption) - { - Down(P, 0, splitLen, 0x00); - } - else - { - Down(output, outOff, splitLen, 0x00); - } - Cu = 0x00; - outOff += splitLen; - IOLen -= splitLen; - encrypted = true; - } - return len; - } - - - public int DoFinal(byte[] outBytes, int outOff) - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - byte[] blocks = message.GetBuffer(); - int len = (int)message.Length; - if ((forEncryption && len + TAGLEN + outOff > outBytes.Length) || - (!forEncryption && len - TAGLEN + outOff > outBytes.Length)) - { - throw new OutputLengthException("output buffer too short"); - } - processAAD(); - int rv = 0; - if (forEncryption) - { - encrypt(blocks, 0, len, outBytes, outOff); - outOff += len; - tag = new byte[TAGLEN]; - Up(tag, TAGLEN, 0x40); - Array.Copy(tag, 0, outBytes, outOff, TAGLEN); - rv = len + TAGLEN; - } - else - { - int inOff = len - TAGLEN; - rv = inOff; - encrypt(blocks, 0, inOff, outBytes, outOff); - tag = new byte[TAGLEN]; - Up(tag, TAGLEN, 0x40); - - if (!Arrays.FixedTimeEquals(TAGLEN, tag, 0, blocks, inOff)) - throw new InvalidCipherTextException("mac check in " + AlgorithmName + " failed"); - } - reset(false); - return rv; - } - - public byte[] GetMac() - { - return tag; - } - - public int GetUpdateOutputSize(int len) - { - // TODO - return len; - } - - public int GetOutputSize(int len) - { - // TODO - return len + TAGLEN; - } - - public void Reset() - { - if (!initialised) - throw new ArgumentException("Need to call Init before encryption/decryption"); - - reset(true); - } - - private void reset(bool clearMac) - { - if (clearMac) - { - tag = null; - } - Arrays.Fill(state, (byte)0); - aadFinished = false; - encrypted = false; - phase = PhaseUp; - message.SetLength(0); - aadData.SetLength(0); - //Absorb key - int KLen = K.Length; - int IDLen = iv.Length; - byte[] KID = new byte[Rkin]; - mode = MODE.ModeKeyed; - Rabsorb = Rkin; - Array.Copy(K, 0, KID, 0, KLen); - Array.Copy(iv, 0, KID, KLen, IDLen); - KID[KLen + IDLen] = (byte)IDLen; - AbsorbAny(KID, 0, KLen + IDLen + 1, Rabsorb, 0x02); - } - - private void AbsorbAny(byte[] X, int Xoff, int XLen, int r, uint Cd) - { - int splitLen; - do - { - if (phase != PhaseUp) - { - Up(null, 0, 0); - } - splitLen = System.Math.Min(XLen, r); - Down(X, Xoff, splitLen, Cd); - Cd = 0; - Xoff += splitLen; - XLen -= splitLen; - } - while (XLen != 0); - } - - private void Up(byte[] Yi, int YiLen, uint Cu) - { - if (mode != MODE.ModeHash) - { - state[f_bPrime - 1] ^= (byte)Cu; - } - uint[] a = new uint[NLANES]; - Pack.LE_To_UInt32(state, 0, a, 0, a.Length); - uint x, y; - uint[] b = new uint[NLANES]; - uint[] p = new uint[NCOLUMS]; - uint[] e = new uint[NCOLUMS]; - for (int i = 0; i < MAXROUNDS; ++i) - { - /* Theta: Column Parity Mixer */ - for (x = 0; x < NCOLUMS; ++x) - { - p[x] = a[index(x, 0)] ^ a[index(x, 1)] ^ a[index(x, 2)]; - } - for (x = 0; x < NCOLUMS; ++x) - { - y = p[(x + 3) & 3]; - e[x] = ROTL32(y, 5) ^ ROTL32(y, 14); - } - for (x = 0; x < NCOLUMS; ++x) - { - for (y = 0; y < NROWS; ++y) - { - a[index(x, y)] ^= e[x]; - } - } - /* Rho-west: plane shift */ - for (x = 0; x < NCOLUMS; ++x) - { - b[index(x, 0)] = a[index(x, 0)]; - b[index(x, 1)] = a[index(x + 3, 1)]; - b[index(x, 2)] = ROTL32(a[index(x, 2)], 11); - } - /* Iota: round ant */ - b[0] ^= RC[i]; - /* Chi: non linear layer */ - for (x = 0; x < NCOLUMS; ++x) - { - for (y = 0; y < NROWS; ++y) - { - a[index(x, y)] = b[index(x, y)] ^ (~b[index(x, y + 1)] & b[index(x, y + 2)]); - } - } - /* Rho-east: plane shift */ - for (x = 0; x < NCOLUMS; ++x) - { - b[index(x, 0)] = a[index(x, 0)]; - b[index(x, 1)] = ROTL32(a[index(x, 1)], 1); - b[index(x, 2)] = ROTL32(a[index(x + 2, 2)], 8); - } - Array.Copy(b, 0, a, 0, NLANES); - } - Pack.UInt32_To_LE(a, 0, a.Length, state, 0); - phase = PhaseUp; - if (Yi != null) - { - Array.Copy(state, 0, Yi, 0, YiLen); - } - } - - void Down(byte[] Xi, int XiOff, int XiLen, uint Cd) - { - for (int i = 0; i < XiLen; i++) - { - state[i] ^= Xi[XiOff++]; - } - state[XiLen] ^= 0x01; - state[f_bPrime - 1] ^= (byte)((mode == MODE.ModeHash) ? (Cd & 0x01) : Cd); - phase = PhaseDown; - } - - private uint index(uint x, uint y) - { - return (((y % NROWS) * NCOLUMS) + ((x) % NCOLUMS)); - } - - private uint ROTL32(uint a, int offset) - { - return (a << (offset & 31)) ^ (a >> ((32 - (offset)) & 31)); - } - - public int GetBlockSize() - { - return Rkout; - } - - public int GetKeyBytesSize() - { - return 16; - } - - public int GetIVBytesSize() - { - return 16; - } - -#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public void ProcessAadBytes(ReadOnlySpan<byte> input) - { - aadData.Write(input); - } - - public int ProcessByte(byte input, Span<byte> 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<byte> input, Span<byte> 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<byte> output) - { - byte[] rv; - if (forEncryption) - { - rv = new byte[message.Length + 16]; - } - else - { - rv = new byte[message.Length - 16]; - } - int len = DoFinal(rv, 0); - rv.AsSpan(0, len).CopyTo(output); - return rv.Length; - } -#endif - } -} diff --git a/crypto/test/src/crypto/test/ElephantTest.cs b/crypto/test/src/crypto/test/ElephantTest.cs deleted file mode 100644 index 7e7e131ab..000000000 --- a/crypto/test/src/crypto/test/ElephantTest.cs +++ /dev/null @@ -1,408 +0,0 @@ -using System; -using System.Collections.Generic; -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; -using Org.BouncyCastle.Utilities.Test; - -namespace Org.BouncyCastle.Crypto.Tests -{ - public class ElephantTest - : SimpleTest - { - public override string Name => "Elephant"; - - [Test] - public override void PerformTest() - { - ImplTestVectors(ElephantEngine.ElephantParameters.elephant160, "v160"); - ImplTestVectors(ElephantEngine.ElephantParameters.elephant176, "v176"); - ImplTestVectors(ElephantEngine.ElephantParameters.elephant200, "v200"); - ElephantEngine elephantEngine = new ElephantEngine(ElephantEngine.ElephantParameters.elephant160); - ImplTestExceptions(elephantEngine, elephantEngine.GetKeyBytesSize(), elephantEngine.GetIVBytesSize(), elephantEngine.GetBlockSize()); - ImplTestParameters(elephantEngine, 16, 12, 8, 20); - elephantEngine = new ElephantEngine(ElephantEngine.ElephantParameters.elephant176); - ImplTestExceptions(elephantEngine, elephantEngine.GetKeyBytesSize(), elephantEngine.GetIVBytesSize(), elephantEngine.GetBlockSize()); - ImplTestParameters(elephantEngine, 16, 12, 8, 22); - elephantEngine = new ElephantEngine(ElephantEngine.ElephantParameters.elephant200); - ImplTestExceptions(elephantEngine, elephantEngine.GetKeyBytesSize(), elephantEngine.GetIVBytesSize(), elephantEngine.GetBlockSize()); - ImplTestParameters(elephantEngine, 16, 12, 16, 25); - } - - private void ImplTestVectors(ElephantEngine.ElephantParameters pbp, String filename) - { - ElephantEngine Elephant = new ElephantEngine(pbp); - ICipherParameters param; - var buf = new Dictionary<string, string>(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.elephant." + filename + "_LWC_AEAD_KAT_128_96.txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - 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(); - - param = new ParametersWithIV(new KeyParameter(key), nonce); - Elephant.Init(true, param); - Elephant.ProcessAadBytes(ad, 0, ad.Length); - byte[] rv = new byte[Elephant.GetOutputSize(pt.Length)]; - int len = Elephant.ProcessBytes(pt, 0, pt.Length, rv, 0); - Elephant.DoFinal(rv, len); - Assert.True(Arrays.AreEqual(rv, ct)); - Elephant.Reset(); - Elephant.Init(false, param); - //Decrypt - Elephant.ProcessAadBytes(ad, 0, ad.Length); - rv = new byte[pt.Length + 16]; - len = Elephant.ProcessBytes(ct, 0, ct.Length, rv, 0); - Elephant.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)); - Elephant.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestExceptions(ElephantEngine elephantEngine, int keysize, int ivsize, int blocksize) - { - byte[] k = new byte[keysize]; - byte[] iv = new byte[ivsize]; - byte[] m = new byte[0]; - byte[] c1 = new byte[elephantEngine.GetOutputSize(m.Length)]; - var param = new ParametersWithIV(new KeyParameter(k), iv); - //try - //{ - // aeadBlockCipher.ProcessBytes(m, 0, m.Length, c1, 0); - // Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before ProcessBytes"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - - //try - //{ - // aeadBlockCipher.ProcessByte((byte)0, c1, 0); - // Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before ProcessByte"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - - //try - //{ - // aeadBlockCipher.Reset(); - // Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before Reset"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - - try - { - elephantEngine.DoFinal(c1, m.Length); - Assert.Fail(elephantEngine.AlgorithmName + " needs to be initialized before DoFinal"); - } - catch (ArgumentException) - { - //expected - } - - try - { - elephantEngine.GetMac(); - elephantEngine.GetOutputSize(0); - elephantEngine.GetUpdateOutputSize(0); - } - catch (ArgumentException) - { - //expected - Assert.Fail(elephantEngine.AlgorithmName + " functions can be called before initialization"); - } - Random rand = new Random(); - int randomNum; - while ((randomNum = rand.Next(100)) == keysize) ; - byte[] k1 = new byte[randomNum]; - while ((randomNum = rand.Next(100)) == ivsize) ; - byte[] iv1 = new byte[randomNum]; - try - { - elephantEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv)); - Assert.Fail(elephantEngine.AlgorithmName + " k size does not match"); - } - catch (ArgumentException) - { - //expected - } - try - { - elephantEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); - Assert.Fail(elephantEngine.AlgorithmName + "iv size does not match"); - } - catch (ArgumentException) - { - //expected - } - - - elephantEngine.Init(true, param); - try - { - elephantEngine.DoFinal(c1, m.Length); - } - catch (Exception) - { - Assert.Fail(elephantEngine.AlgorithmName + " allows no input for AAD and plaintext"); - } - byte[] mac2 = elephantEngine.GetMac(); - if (mac2 == null) - { - Assert.Fail("mac should not be empty after dofinal"); - } - if (!Arrays.AreEqual(mac2, c1)) - { - Assert.Fail("mac should be equal when calling dofinal and getMac"); - } - elephantEngine.ProcessAadByte((byte)0); - byte[] mac1 = new byte[elephantEngine.GetOutputSize(0)]; - elephantEngine.DoFinal(mac1, 0); - if (Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should not match"); - } - //aeadBlockCipher.Reset(); - //aeadBlockCipher.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], 0); - //try - //{ - // aeadBlockCipher.ProcessAadByte((byte)0); - // Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - //try - //{ - // aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 0, 1); - // Assert.Fail("ProcessAadByte(s) cannot be called once only"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - - elephantEngine.Reset(); - try - { - elephantEngine.ProcessAadBytes(new byte[] { 0 }, 1, 1); - Assert.Fail("input for ProcessAadBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - elephantEngine.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0); - Assert.Fail("input for ProcessBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - //try - //{ - // aeadBlockCipher.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], blocksize >> 1); - // Assert.Fail("output for ProcessBytes is too short"); - //} - //catch (OutputLengthException) - //{ - // //expected - //} - try - { - elephantEngine.DoFinal(new byte[2], 2); - Assert.Fail("output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - - mac1 = new byte[elephantEngine.GetOutputSize(0)]; - mac2 = new byte[elephantEngine.GetOutputSize(0)]; - elephantEngine.Reset(); - elephantEngine.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2); - elephantEngine.DoFinal(mac1, 0); - elephantEngine.Reset(); - elephantEngine.ProcessAadByte((byte)0); - elephantEngine.ProcessAadByte((byte)0); - elephantEngine.DoFinal(mac2, 0); - if (!Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should match for the same AAD with different ways of inputting"); - } - - byte[] c2 = new byte[elephantEngine.GetOutputSize(10)]; - byte[] c3 = new byte[elephantEngine.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]; - elephantEngine.Reset(); - elephantEngine.ProcessAadBytes(aad2, 0, aad2.Length); - int offset = elephantEngine.ProcessBytes(m2, 0, m2.Length, c2, 0); - elephantEngine.DoFinal(c2, offset); - elephantEngine.Reset(); - elephantEngine.ProcessAadBytes(aad3, 1, aad2.Length); - offset = elephantEngine.ProcessBytes(m3, 1, m2.Length, c3, 1); - elephantEngine.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"); - } - elephantEngine.Reset(); - elephantEngine.Init(false, param); - elephantEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = elephantEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - elephantEngine.DoFinal(m4, offset); - if (!Arrays.AreEqual(m2, m4)) - { - Assert.Fail("The encryption and decryption does not recover the plaintext"); - } - Console.WriteLine(elephantEngine.AlgorithmName + " test Exceptions pass"); - c2[c2.Length - 1] ^= 1; - elephantEngine.Reset(); - elephantEngine.Init(false, param); - elephantEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = elephantEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - try - { - elephantEngine.DoFinal(m4, offset); - Assert.Fail("The decryption should fail"); - } - catch (InvalidCipherTextException) - { - //expected; - } - 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[elephantEngine.GetOutputSize(m7.Length)]; - byte[] c8 = new byte[c7.Length]; - byte[] c9 = new byte[c7.Length]; - elephantEngine.Init(true, param); - elephantEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = elephantEngine.ProcessBytes(m7, 0, m7.Length, c7, 0); - elephantEngine.DoFinal(c7, offset); - elephantEngine.Reset(); - elephantEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = elephantEngine.ProcessBytes(m7, 0, blocksize, c8, 0); - offset += elephantEngine.ProcessBytes(m7, blocksize, m7.Length - blocksize, c8, offset); - elephantEngine.DoFinal(c8, offset); - elephantEngine.Reset(); - int split = rand.Next(blocksize * 2); - elephantEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = elephantEngine.ProcessBytes(m7, 0, split, c9, 0); - offset += elephantEngine.ProcessBytes(m7, split, m7.Length - split, c9, offset); - elephantEngine.DoFinal(c9, offset); - if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9)) - { - Assert.Fail("Splitting input of plaintext should output the same ciphertext"); - } -#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span<byte> c4_1 = new byte[c2.Length]; - Span<byte> c4_2 = new byte[c2.Length]; - ReadOnlySpan<byte> m5 = new ReadOnlySpan<byte>(m2); - ReadOnlySpan<byte> aad4 = new ReadOnlySpan<byte>(aad2); - elephantEngine.Init(true, param); - elephantEngine.ProcessAadBytes(aad4); - offset = elephantEngine.ProcessBytes(m5, c4_1); - elephantEngine.DoFinal(c4_2); - byte[] c5 = new byte[c2.Length]; - c4_1[..offset].CopyTo(c5); - c4_2[..(c5.Length - offset)].CopyTo(c5.AsSpan(offset)); - if (!Arrays.AreEqual(c2, c5)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } - elephantEngine.Reset(); - elephantEngine.Init(false, param); - Span<byte> m6_1 = new byte[m2.Length]; - Span<byte> m6_2 = new byte[m2.Length]; - ReadOnlySpan<byte> c6 = new ReadOnlySpan<byte>(c2); - elephantEngine.ProcessAadBytes(aad4); - offset = elephantEngine.ProcessBytes(c6, m6_1); - elephantEngine.DoFinal(m6_2); - byte[] m6 = new byte[m2.Length]; - m6_1[..offset].CopyTo(m6); - m6_2[..(m6.Length - offset)].CopyTo(m6.AsSpan(offset)); - if (!Arrays.AreEqual(m2, m6)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } -#endif - - } - - private void ImplTestParameters(ElephantEngine Elephant, int keySize, int ivSize, int macSize, int blockSize) - { - if (Elephant.GetKeyBytesSize() != keySize) - { - Assert.Fail("key bytes of " + Elephant.AlgorithmName + " is not correct"); - } - if (Elephant.GetIVBytesSize() != ivSize) - { - Assert.Fail("iv bytes of " + Elephant.AlgorithmName + " is not correct"); - } - if (Elephant.GetOutputSize(0) != macSize) - { - Assert.Fail("mac bytes of " + Elephant.AlgorithmName + " is not correct"); - } - if (Elephant.GetBlockSize() != blockSize) - { - Assert.Fail("block size of " + Elephant.AlgorithmName + " is not correct"); - } - Console.WriteLine(Elephant.AlgorithmName + " test Parameters pass"); - } - - } -} - diff --git a/crypto/test/src/crypto/test/ISAPTest.cs b/crypto/test/src/crypto/test/ISAPTest.cs deleted file mode 100644 index 38cf7c633..000000000 --- a/crypto/test/src/crypto/test/ISAPTest.cs +++ /dev/null @@ -1,486 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using NUnit.Framework; - -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; -using Org.BouncyCastle.Utilities.Test; - -namespace Org.BouncyCastle.Crypto.Tests -{ - [TestFixture] - public class IsapTest - : SimpleTest - { - public override string Name => "ISAP"; - - [Test] - public override void PerformTest() - { - IsapEngine isapEngine = new IsapEngine(IsapEngine.IsapType.ISAP_K_128A); - ImplTestExceptions(isapEngine); - ImplTestParameters(isapEngine, 16, 16, 16); - isapEngine = new IsapEngine(IsapEngine.IsapType.ISAP_K_128); - ImplTestExceptions(isapEngine); - ImplTestParameters(isapEngine, 16, 16, 16); - isapEngine = new IsapEngine(IsapEngine.IsapType.ISAP_A_128A); - ImplTestExceptions(isapEngine); - ImplTestParameters(isapEngine, 16, 16, 16); - isapEngine = new IsapEngine(IsapEngine.IsapType.ISAP_A_128); - ImplTestExceptions(isapEngine); - ImplTestParameters(isapEngine, 16, 16, 16); - ImplTestExceptions(new IsapDigest(), 32); - ImplTestVectors("isapa128av20", IsapEngine.IsapType.ISAP_A_128A); - ImplTestVectors("isapa128v20", IsapEngine.IsapType.ISAP_A_128); - ImplTestVectors("isapk128av20", IsapEngine.IsapType.ISAP_K_128A); - ImplTestVectors("isapk128v20", IsapEngine.IsapType.ISAP_K_128); - ImplTestVectors(); - } - - private void ImplTestVectors(string filename, IsapEngine.IsapType isapType) - { - Random random = new Random(); - IsapEngine isapEngine = new IsapEngine(isapType); - var buf = new Dictionary<string, string>(); - //TestSampler sampler = new TestSampler(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.isap." + filename + "_LWC_AEAD_KAT_128_128.txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - 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 - { - isapEngine.Init(true, parameters); - - var rv = new byte[isapEngine.GetOutputSize(pt.Length)]; - random.NextBytes(rv); // should overwrite any existing data - - isapEngine.ProcessAadBytes(ad, 0, ad.Length); - int len = isapEngine.ProcessBytes(pt, 0, pt.Length, rv, 0); - len += isapEngine.DoFinal(rv, len); - - Assert.True(Arrays.AreEqual(rv, 0, len, ct, 0, ct.Length)); - } - - // Decrypt - { - isapEngine.Init(false, parameters); - - var rv = new byte[isapEngine.GetOutputSize(ct.Length)]; - random.NextBytes(rv); // should overwrite any existing data - - isapEngine.ProcessAadBytes(ad, 0, ad.Length); - int len = isapEngine.ProcessBytes(ct, 0, ct.Length, rv, 0); - len += isapEngine.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 void ImplTestVectors() - { - IsapDigest isap = new IsapDigest(); - var buf = new Dictionary<string, string>(); - //TestSampler sampler = new TestSampler(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.isap.LWC_HASH_KAT_256.txt"))) - { - string line; - string[] data; - byte[] ptByte; - Dictionary<string, string> map = new Dictionary<string, string>(); - while ((line = src.ReadLine()) != null) - { - data = line.Split(' '); - if (data.Length == 1) - { - ptByte = Hex.Decode(map["Msg"]); - isap.BlockUpdate(ptByte, 0, ptByte.Length); - byte[] hash = new byte[32]; - isap.DoFinal(hash, 0); - Assert.True(Arrays.AreEqual(hash, Hex.Decode(map["MD"]))); - map.Clear(); - isap.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestExceptions(IsapEngine isapEngine) - { - int keySize = isapEngine.GetKeyBytesSize(), ivSize = isapEngine.GetIVBytesSize(); - int offset; - byte[] k = new byte[keySize]; - byte[] iv = new byte[ivSize]; - byte[] m = Array.Empty<byte>(); - ICipherParameters param = new ParametersWithIV(new KeyParameter(k), iv); - try - { - isapEngine.ProcessBytes(m, 0, m.Length, null, 0); - Assert.Fail(isapEngine.AlgorithmName + " need to be initialized before ProcessBytes"); - } - catch (ArgumentException) - { - //expected - } - - try - { - isapEngine.ProcessByte((byte)0, null, 0); - Assert.Fail(isapEngine.AlgorithmName + " need to be initialized before ProcessByte"); - } - catch (ArgumentException) - { - //expected - } - - try - { - isapEngine.Reset(); - Assert.Fail(isapEngine.AlgorithmName + " need to be initialized before Reset"); - } - catch (ArgumentException) - { - //expected - } - - try - { - isapEngine.DoFinal(null, m.Length); - Assert.Fail(isapEngine.AlgorithmName + " need to be initialized before DoFinal"); - } - catch (ArgumentException) - { - //expected - } - - try - { - isapEngine.GetMac(); - isapEngine.GetOutputSize(0); - isapEngine.GetUpdateOutputSize(0); - } - catch (ArgumentException) - { - Assert.Fail(isapEngine.AlgorithmName + " functions can be called before initialization"); - } - Random rand = new Random(); - int randomNum; - while ((randomNum = rand.Next(100)) == keySize) ; - byte[] k1 = new byte[randomNum]; - while ((randomNum = rand.Next(100)) == ivSize) ; - byte[] iv1 = new byte[randomNum]; - try - { - isapEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv)); - Assert.Fail(isapEngine.AlgorithmName + " k size does not match"); - } - catch (ArgumentException) - { - //expected - } - try - { - isapEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); - Assert.Fail(isapEngine.AlgorithmName + "iv size does not match"); - } - catch (ArgumentException) - { - //expected - } - - isapEngine.Init(true, param); - byte[] c1 = new byte[isapEngine.GetOutputSize(m.Length)]; - try - { - isapEngine.DoFinal(c1, m.Length); - } - catch (Exception) - { - Assert.Fail(isapEngine.AlgorithmName + " allows no input for AAD and plaintext"); - } - byte[] mac2 = isapEngine.GetMac(); - if (mac2 == null) - { - Assert.Fail("mac should not be empty after Dofinal"); - } - if (!Arrays.AreEqual(mac2, c1)) - { - Assert.Fail("mac should be equal when calling Dofinal and GetMac"); - } - isapEngine.ProcessAadByte(0x00); - byte[] mac1 = new byte[isapEngine.GetOutputSize(0)]; - isapEngine.DoFinal(mac1, 0); - if (Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should not match"); - } - isapEngine.Reset(); - isapEngine.ProcessBytes(new byte[16], 0, 16, new byte[16], 0); - //try - //{ - // aeadBlockCipher.ProcessAadByte((byte)0); - // Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption"); - //} - //catch (ArgumentException) - //{ - // //expected - //} - //try - //{ - // aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 0, 1); - // Assert.Fail("ProcessAadByte(s) cannot be called once only"); - //} - //catch (ArgumentException) - //{ - // //expected - //} - - isapEngine.Reset(); - try - { - isapEngine.ProcessAadBytes(new byte[] { 0 }, 1, 1); - Assert.Fail("input for ProcessAadBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - isapEngine.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0); - Assert.Fail("input for ProcessBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - int inputSize = rand.Next(32, 64); - int outputSize = isapEngine.GetUpdateOutputSize(inputSize); - isapEngine.ProcessBytes(new byte[inputSize], 0, inputSize, new byte[outputSize], 1); - Assert.Fail("output for ProcessBytes is too short"); - } - catch (OutputLengthException) - { - //expected - } - try - { - isapEngine.DoFinal(new byte[2], 2); - Assert.Fail("output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - - mac1 = new byte[isapEngine.GetOutputSize(0)]; - mac2 = new byte[isapEngine.GetOutputSize(0)]; - isapEngine.Reset(); - isapEngine.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2); - isapEngine.DoFinal(mac1, 0); - isapEngine.Reset(); - isapEngine.ProcessAadByte((byte)0); - isapEngine.ProcessAadByte((byte)0); - isapEngine.DoFinal(mac2, 0); - if (!Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should match for the same AAD with different ways of inputting"); - } - - byte[] c2 = new byte[isapEngine.GetOutputSize(10)]; - byte[] c3 = new byte[isapEngine.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]; - isapEngine.Reset(); - isapEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = isapEngine.ProcessBytes(m2, 0, m2.Length, c2, 0); - isapEngine.DoFinal(c2, offset); - isapEngine.Reset(); - isapEngine.ProcessAadBytes(aad3, 1, aad2.Length); - offset = isapEngine.ProcessBytes(m3, 1, m2.Length, c3, 1); - isapEngine.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"); - } - isapEngine.Reset(); - isapEngine.Init(false, param); - isapEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = isapEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - offset += isapEngine.DoFinal(m4, offset); - if (!Arrays.AreEqual(m2, m4)) - { - Assert.Fail("The encryption and decryption does not recover the plaintext"); - } - c2[c2.Length - 1] ^= 1; - isapEngine.Reset(); - isapEngine.Init(false, param); - isapEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = isapEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - try - { - offset += isapEngine.DoFinal(m4, offset); - Assert.Fail("The decryption should fail"); - } - catch (InvalidCipherTextException) - { - //expected; - } - c2[c2.Length - 1] ^= 1; - - byte[] m7 = new byte[32 + rand.Next(32)]; - rand.NextBytes(m7); - - isapEngine.Init(true, param); - byte[] c7 = new byte[isapEngine.GetOutputSize(m7.Length)]; - byte[] c8 = new byte[c7.Length]; - byte[] c9 = new byte[c7.Length]; - isapEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = isapEngine.ProcessBytes(m7, 0, m7.Length, c7, 0); - offset += isapEngine.DoFinal(c7, offset); - isapEngine.Reset(); - isapEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = isapEngine.ProcessBytes(m7, 0, m7.Length / 2, c8, 0); - offset += isapEngine.ProcessBytes(m7, m7.Length / 2, m7.Length - m7.Length / 2, c8, offset); - offset += isapEngine.DoFinal(c8, offset); - isapEngine.Reset(); - int split = rand.Next(1, m7.Length); - isapEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = isapEngine.ProcessBytes(m7, 0, split, c9, 0); - offset += isapEngine.ProcessBytes(m7, split, m7.Length - split, c9, offset); - isapEngine.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<T>, 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 - Span<byte> c4_1 = new byte[c2.Length]; - Span<byte> c4_2 = new byte[c2.Length]; - ReadOnlySpan<byte> m5 = new ReadOnlySpan<byte>(m2); - ReadOnlySpan<byte> aad4 = new ReadOnlySpan<byte>(aad2); - isapEngine.Init(true, param); - isapEngine.ProcessAadBytes(aad4); - offset = isapEngine.ProcessBytes(m5, c4_1); - isapEngine.DoFinal(c4_2); - byte[] c5 = new byte[c2.Length]; - c4_1[..offset].CopyTo(c5); - c4_2[..(c5.Length - offset)].CopyTo(c5.AsSpan(offset)); - if (!Arrays.AreEqual(c2, c5)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } - isapEngine.Reset(); - isapEngine.Init(false, param); - Span<byte> m6_1 = new byte[m2.Length]; - Span<byte> m6_2 = new byte[m2.Length]; - ReadOnlySpan<byte> c6 = new ReadOnlySpan<byte>(c2); - isapEngine.ProcessAadBytes(aad4); - offset = isapEngine.ProcessBytes(c6, m6_1); - isapEngine.DoFinal(m6_2); - byte[] m6 = new byte[m2.Length]; - m6_1[..offset].CopyTo(m6); - m6_2[..(m6.Length - offset)].CopyTo(m6.AsSpan(offset)); - if (!Arrays.AreEqual(m2, m6)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } -#endif - } - - private void ImplTestParameters(IsapEngine isapEngine, int keySize, int ivSize, int macSize) - { - Assert.AreEqual(keySize, isapEngine.GetKeyBytesSize(), - "key bytes of " + isapEngine.AlgorithmName + " is not correct"); - Assert.AreEqual(ivSize, isapEngine.GetIVBytesSize(), - "iv bytes of " + isapEngine.AlgorithmName + " is not correct"); - - var parameters = new ParametersWithIV(new KeyParameter(new byte[keySize]), new byte[ivSize]); - - isapEngine.Init(true, parameters); - Assert.AreEqual(macSize, isapEngine.GetOutputSize(0), - "GetOutputSize of " + isapEngine.AlgorithmName + " is incorrect for encryption"); - - isapEngine.Init(false, parameters); - Assert.AreEqual(0, isapEngine.GetOutputSize(macSize), - "GetOutputSize of " + isapEngine.AlgorithmName + " is incorrect for decryption"); - } - - private void ImplTestExceptions(IsapDigest isapDigest, int digestSize) - { - Assert.AreEqual(digestSize, isapDigest.GetDigestSize(), - isapDigest.AlgorithmName + ": digest size is not correct"); - - try - { - isapDigest.BlockUpdate(new byte[1], 1, 1); - Assert.Fail(isapDigest.AlgorithmName + ": input for BlockUpdate is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - isapDigest.DoFinal(new byte[isapDigest.GetDigestSize() - 1], 2); - Assert.Fail(isapDigest.AlgorithmName + ": output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - } - } -} diff --git a/crypto/test/src/crypto/test/PhotonBeetleTest.cs b/crypto/test/src/crypto/test/PhotonBeetleTest.cs deleted file mode 100644 index b9a648f17..000000000 --- a/crypto/test/src/crypto/test/PhotonBeetleTest.cs +++ /dev/null @@ -1,468 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using NUnit.Framework; - -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; -using Org.BouncyCastle.Utilities.Test; - -namespace Org.BouncyCastle.Crypto.Tests -{ - [TestFixture] - public class PhotonBeetleTest - : SimpleTest - { - public override string Name => "Photon-Beetle"; - - [Test] - public override void PerformTest() - { - ImplTestVectors("v32", PhotonBeetleEngine.PhotonBeetleParameters.pb32); - ImplTestVectors("v128", PhotonBeetleEngine.PhotonBeetleParameters.pb128); - ImplTestVectors(); - PhotonBeetleEngine photonBeetleEngine = new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32); - ImplTestExceptions(photonBeetleEngine, photonBeetleEngine.GetKeyBytesSize(), photonBeetleEngine.GetIVBytesSize(), photonBeetleEngine.GetBlockSize()); - ImplTestParameters(photonBeetleEngine, 16, 16, 16, 4); - photonBeetleEngine = new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128); - ImplTestExceptions(photonBeetleEngine, photonBeetleEngine.GetKeyBytesSize(), photonBeetleEngine.GetIVBytesSize(), photonBeetleEngine.GetBlockSize()); - ImplTestParameters(photonBeetleEngine, 16, 16, 16, 16); - ImplTestExceptions(new PhotonBeetleDigest(), 32); - } - - private void ImplTestVectors(String filename, PhotonBeetleEngine.PhotonBeetleParameters PhotonBeetleType) - { - PhotonBeetleEngine PhotonBeetle = new PhotonBeetleEngine(PhotonBeetleType); - var buf = new Dictionary<string, string>(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.photonbeetle." + filename + "_LWC_AEAD_KAT_128_128.txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - 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 param = new ParametersWithIV(new KeyParameter(key), nonce); - PhotonBeetle.Init(true, param); - PhotonBeetle.ProcessAadBytes(ad, 0, ad.Length); - byte[] rv = new byte[PhotonBeetle.GetOutputSize(pt.Length)]; - int len = PhotonBeetle.ProcessBytes(pt, 0, pt.Length, rv, 0); - PhotonBeetle.DoFinal(rv, len); - Assert.True(Arrays.AreEqual(rv, ct)); - PhotonBeetle.Reset(); - PhotonBeetle.Init(false, param); - //Decrypt - PhotonBeetle.ProcessAadBytes(ad, 0, ad.Length); - rv = new byte[pt.Length + 16]; - len = PhotonBeetle.ProcessBytes(ct, 0, ct.Length, rv, 0); - PhotonBeetle.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)); - PhotonBeetle.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestVectors() - { - PhotonBeetleDigest PhotonBeetle = new PhotonBeetleDigest(); - var buf = new Dictionary<string, string>(); - //TestSampler sampler = new TestSampler(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.photonbeetle.LWC_HASH_KAT_256.txt"))) - { - string line; - string[] data; - byte[] ptByte; - Dictionary<string, string> map = new Dictionary<string, string>(); - while ((line = src.ReadLine()) != null) - { - data = line.Split(' '); - if (data.Length == 1) - { - ptByte = Hex.Decode(map["Msg"]); - PhotonBeetle.BlockUpdate(ptByte, 0, ptByte.Length); - byte[] hash = new byte[32]; - PhotonBeetle.DoFinal(hash, 0); - Assert.True(Arrays.AreEqual(hash, Hex.Decode(map["MD"]))); - map.Clear(); - PhotonBeetle.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestExceptions(IAeadBlockCipher aeadBlockCipher, int keysize, int ivsize, int blocksize) - { - ICipherParameters param; - 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); - //try - //{ - // aeadBlockCipher.ProcessBytes(m, 0, m.Length, c1, 0); - // Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before ProcessBytes"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - - //try - //{ - // aeadBlockCipher.ProcessByte((byte)0, c1, 0); - // Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before ProcessByte"); - //} - //catch (ArgumentException e) - //{ - // //expected - //} - - try - { - aeadBlockCipher.Reset(); - Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before Reset"); - } - catch (ArgumentException) - { - //expected - } - - try - { - aeadBlockCipher.DoFinal(c1, m.Length); - Assert.Fail(aeadBlockCipher.AlgorithmName + " needs to be initialized before DoFinal"); - } - catch (ArgumentException) - { - //expected - } - - try - { - aeadBlockCipher.GetMac(); - aeadBlockCipher.GetOutputSize(0); - aeadBlockCipher.GetUpdateOutputSize(0); - } - catch (ArgumentException) - { - //expected - Assert.Fail(aeadBlockCipher.AlgorithmName + " functions can be called before initialization"); - } - Random rand = new Random(); - int randomNum; - while ((randomNum = rand.Next(100)) == keysize) ; - byte[] k1 = new byte[randomNum]; - 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"); - } - catch (ArgumentException) - { - //expected - } - try - { - aeadBlockCipher.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); - Assert.Fail(aeadBlockCipher.AlgorithmName + "iv size does not match"); - } - catch (ArgumentException) - { - //expected - } - - - aeadBlockCipher.Init(true, param); - try - { - aeadBlockCipher.DoFinal(c1, m.Length); - } - catch (Exception) - { - Assert.Fail(aeadBlockCipher.AlgorithmName + " allows no input for AAD and plaintext"); - } - byte[] mac2 = aeadBlockCipher.GetMac(); - if (mac2 == null) - { - Assert.Fail("mac should not be empty after DoFinal"); - } - if (!Arrays.AreEqual(mac2, c1)) - { - 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); - if (Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should not match"); - } - //aeadBlockCipher.Reset(); - //aeadBlockCipher.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], 0); - //try - //{ - // aeadBlockCipher.ProcessAadByte((byte)0); - // Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption"); - //} - //catch (ArgumentException) - //{ - // //expected - //} - //try - //{ - // aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 0, 1); - // Assert.Fail("ProcessAadByte(s) cannot be called once only"); - //} - //catch (ArgumentException) - //{ - // //expected - //} - - aeadBlockCipher.Reset(); - try - { - aeadBlockCipher.ProcessAadBytes(new byte[] { 0 }, 1, 1); - Assert.Fail("input for ProcessAadBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - aeadBlockCipher.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0); - Assert.Fail("input for ProcessBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - //try - //{ - // aeadBlockCipher.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], blocksize >> 1); - // Assert.Fail("output for ProcessBytes is too short"); - //} - //catch (OutputLengthException) - //{ - // //expected - //} - try - { - aeadBlockCipher.DoFinal(new byte[2], 2); - Assert.Fail("output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //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); - if (!Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should match for the same AAD with different ways of inputting"); - } - - byte[] c2 = new byte[aeadBlockCipher.GetOutputSize(10)]; - byte[] c3 = new byte[aeadBlockCipher.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); - 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); - if (!Arrays.AreEqual(m2, m4)) - { - Assert.Fail("The encryption and decryption does not recover the plaintext"); - } - 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); - try - { - aeadBlockCipher.DoFinal(m4, offset); - Assert.Fail("The decryption should fail"); - } - catch (InvalidCipherTextException) - { - //expected; - } - 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[] 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); - if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9)) - { - Assert.Fail("Splitting input of plaintext should output the same ciphertext"); - } -#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span<byte> c4_1 = new byte[c2.Length]; - Span<byte> c4_2 = new byte[c2.Length]; - ReadOnlySpan<byte> m5 = new ReadOnlySpan<byte>(m2); - ReadOnlySpan<byte> aad4 = new ReadOnlySpan<byte>(aad2); - aeadBlockCipher.Init(true, param); - aeadBlockCipher.ProcessAadBytes(aad4); - offset = aeadBlockCipher.ProcessBytes(m5, c4_1); - aeadBlockCipher.DoFinal(c4_2); - byte[] c5 = new byte[c2.Length]; - c4_1[..offset].CopyTo(c5); - c4_2[..(c5.Length - offset)].CopyTo(c5.AsSpan(offset)); - if (!Arrays.AreEqual(c2, c5)) - { - 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); - Span<byte> m6_1 = new byte[m2.Length]; - Span<byte> m6_2 = new byte[m2.Length]; - ReadOnlySpan<byte> c6 = new ReadOnlySpan<byte>(c2); - aeadBlockCipher.ProcessAadBytes(aad4); - offset = aeadBlockCipher.ProcessBytes(c6, m6_1); - aeadBlockCipher.DoFinal(m6_2); - byte[] m6 = new byte[m2.Length]; - m6_1[..offset].CopyTo(m6); - m6_2[..(m6.Length - offset)].CopyTo(m6.AsSpan(offset)); - if (!Arrays.AreEqual(m2, m6)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } -#endif - } - - private void ImplTestParameters(PhotonBeetleEngine photonBeetleEngine, int keySize, int ivSize, int macSize, int blockSize) - { - if (photonBeetleEngine.GetKeyBytesSize() != keySize) - { - Assert.Fail("key bytes of " + photonBeetleEngine.AlgorithmName + " is not correct"); - } - if (photonBeetleEngine.GetIVBytesSize() != ivSize) - { - Assert.Fail("iv bytes of " + photonBeetleEngine.AlgorithmName + " is not correct"); - } - if (photonBeetleEngine.GetOutputSize(0) != macSize) - { - Assert.Fail("mac bytes of " + photonBeetleEngine.AlgorithmName + " is not correct"); - } - if (photonBeetleEngine.GetBlockSize() != blockSize) - { - Assert.Fail("block size of " + photonBeetleEngine.AlgorithmName + " is not correct"); - } - } - - private void ImplTestExceptions(PhotonBeetleDigest photonBeetleDigest, int digestSize) - { - Assert.AreEqual(digestSize, photonBeetleDigest.GetDigestSize(), - photonBeetleDigest.AlgorithmName + ": digest size is not correct"); - - try - { - photonBeetleDigest.BlockUpdate(new byte[1], 1, 1); - Assert.Fail(photonBeetleDigest.AlgorithmName + ": input for BlockUpdate is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - photonBeetleDigest.DoFinal(new byte[digestSize - 1], 2); - Assert.Fail(photonBeetleDigest.AlgorithmName + ": output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - } - } -} diff --git a/crypto/test/src/crypto/test/SparkleTest.cs b/crypto/test/src/crypto/test/SparkleTest.cs deleted file mode 100644 index ea4520226..000000000 --- a/crypto/test/src/crypto/test/SparkleTest.cs +++ /dev/null @@ -1,484 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using NUnit.Framework; - -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; -using Org.BouncyCastle.Utilities.Test; - -namespace Org.BouncyCastle.Crypto.Tests -{ - [TestFixture] - public class SparkleTest - : SimpleTest - { - public override string Name => "Sparkle"; - - [Test] - public override void PerformTest() - { - SparkleEngine sparkleEngine = new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM128_128); - ImplTestExceptions(sparkleEngine); - ImplTestParameters(sparkleEngine, 16, 16, 16, 16); - sparkleEngine = new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM192_192); - ImplTestExceptions(sparkleEngine); - ImplTestParameters(sparkleEngine, 24, 24, 24, 24); - sparkleEngine = new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_128); - ImplTestExceptions(sparkleEngine); - ImplTestParameters(sparkleEngine, 16, 32, 16, 32); - sparkleEngine = new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_256); - ImplTestExceptions(sparkleEngine); - ImplTestParameters(sparkleEngine, 32, 32, 32, 32); - ImplTestExceptions(new SparkleDigest(SparkleDigest.SparkleParameters.ESCH256), 32); - ImplTestExceptions(new SparkleDigest(SparkleDigest.SparkleParameters.ESCH384), 48); - ImplTestVectors("128_128", SparkleEngine.SparkleParameters.SCHWAEMM128_128); - ImplTestVectors("192_192", SparkleEngine.SparkleParameters.SCHWAEMM192_192); - ImplTestVectors("128_256", SparkleEngine.SparkleParameters.SCHWAEMM256_128); - ImplTestVectors("256_256", SparkleEngine.SparkleParameters.SCHWAEMM256_256); - ImplTestVectors("256", SparkleDigest.SparkleParameters.ESCH256); - ImplTestVectors("384", SparkleDigest.SparkleParameters.ESCH384); - } - - private void ImplTestVectors(string filename, SparkleEngine.SparkleParameters SparkleType) - { - SparkleEngine Sparkle = new SparkleEngine(SparkleType); - ICipherParameters param; - var buf = new Dictionary<string, string>(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.sparkle.LWC_AEAD_KAT_" + filename + ".txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - string line; - while ((line = src.ReadLine()) != null) - { - var data = line.Split(' '); - if (data.Length == 1) - { - //if (!map["Count"].Equals("562")) - //{ - // 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); - Sparkle.Init(true, param); - Sparkle.ProcessAadBytes(ad, 0, ad.Length); - byte[] rv = new byte[Sparkle.GetOutputSize(pt.Length)]; - int len = Sparkle.ProcessBytes(pt, 0, pt.Length, rv, 0); - Sparkle.DoFinal(rv, len); - Assert.True(Arrays.AreEqual(rv, ct)); - Sparkle.Reset(); - Sparkle.Init(false, param); - //Decrypt - Sparkle.ProcessAadBytes(ad, 0, ad.Length); - rv = new byte[pt.Length + 16]; - len = Sparkle.ProcessBytes(ct, 0, ct.Length, rv, 0); - Sparkle.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)); - map.Clear(); - Sparkle.Reset(); - - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestVectors(String filename, SparkleDigest.SparkleParameters SparkleType) - { - SparkleDigest Sparkle = new SparkleDigest(SparkleType); - var buf = new Dictionary<string, string>(); - //TestSampler sampler = new TestSampler(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.sparkle.LWC_HASH_KAT_" + filename + ".txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - string line; - while ((line = src.ReadLine()) != null) - { - var data = line.Split(' '); - if (data.Length == 1) - { - var ptByte = Hex.Decode(map["Msg"]); - Sparkle.BlockUpdate(ptByte, 0, ptByte.Length); - byte[] hash = new byte[Sparkle.GetDigestSize()]; - Sparkle.DoFinal(hash, 0); - Assert.True(Arrays.AreEqual(hash, Hex.Decode(map["MD"]))); - map.Clear(); - Sparkle.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestExceptions(SparkleEngine sparkleEngine) - { - int blocksize = sparkleEngine.GetBlockSize(); - int keysize = sparkleEngine.GetKeyBytesSize(), ivsize = sparkleEngine.GetIVBytesSize(); - byte[] k = new byte[keysize]; - byte[] iv = new byte[ivsize]; - byte[] m = new byte[0]; - byte[] c1 = new byte[sparkleEngine.GetOutputSize(m.Length)]; - var param = new ParametersWithIV(new KeyParameter(k), iv); - try - { - sparkleEngine.ProcessBytes(m, 0, m.Length, c1, 0); - Assert.Fail(sparkleEngine.AlgorithmName + " needs to be initialized before ProcessBytes"); - } - catch (ArgumentException) - { - //expected - } - - try - { - sparkleEngine.ProcessByte((byte)0, c1, 0); - Assert.Fail(sparkleEngine.AlgorithmName + " needs to be initialized before ProcessByte"); - } - catch (ArgumentException) - { - //expected - } - - try - { - sparkleEngine.Reset(); - Assert.Fail(sparkleEngine.AlgorithmName + " needs to be initialized before Reset"); - } - catch (ArgumentException) - { - //expected - } - - try - { - sparkleEngine.DoFinal(c1, m.Length); - Assert.Fail(sparkleEngine.AlgorithmName + " needs to be initialized before DoFinal"); - } - catch (ArgumentException) - { - //expected - } - - try - { - sparkleEngine.GetMac(); - sparkleEngine.GetOutputSize(0); - sparkleEngine.GetUpdateOutputSize(0); - } - catch (ArgumentException) - { - //expected - Assert.Fail(sparkleEngine.AlgorithmName + " functions can be called before initialization"); - } - Random rand = new Random(); - int randomNum; - while ((randomNum = rand.Next(100)) == keysize) ; - byte[] k1 = new byte[randomNum]; - while ((randomNum = rand.Next(100)) == ivsize) ; - byte[] iv1 = new byte[randomNum]; - try - { - sparkleEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv)); - Assert.Fail(sparkleEngine.AlgorithmName + " k size does not match"); - } - catch (ArgumentException) - { - //expected - } - try - { - sparkleEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); - Assert.Fail(sparkleEngine.AlgorithmName + "iv size does not match"); - } - catch (ArgumentException) - { - //expected - } - - - sparkleEngine.Init(true, param); - try - { - sparkleEngine.DoFinal(c1, m.Length); - } - catch (Exception) - { - Assert.Fail(sparkleEngine.AlgorithmName + " allows no input for AAD and plaintext"); - } - byte[] mac2 = sparkleEngine.GetMac(); - if (mac2 == null) - { - Assert.Fail("mac should not be empty after DoFinal"); - } - if (!Arrays.AreEqual(mac2, c1)) - { - Assert.Fail("mac should be equal when calling DoFinal and GetMac"); - } - sparkleEngine.ProcessAadByte((byte)0); - byte[] mac1 = new byte[sparkleEngine.GetOutputSize(0)]; - sparkleEngine.DoFinal(mac1, 0); - if (Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should not match"); - } - sparkleEngine.Reset(); - sparkleEngine.ProcessBytes(new byte[blocksize+1], 0, blocksize+1, new byte[blocksize+1], 0); - try - { - sparkleEngine.ProcessAadByte((byte)0); - Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption"); - } - catch (ArgumentException) - { - //expected - } - try - { - sparkleEngine.ProcessAadBytes(new byte[] { 0 }, 0, 1); - Assert.Fail("ProcessAadByte(s) cannot be called once only"); - } - catch (ArgumentException) - { - //expected - } - - sparkleEngine.Reset(); - try - { - sparkleEngine.ProcessAadBytes(new byte[] { 0 }, 1, 1); - Assert.Fail("input for ProcessAadBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - sparkleEngine.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0); - Assert.Fail("input for ProcessBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - sparkleEngine.ProcessBytes(new byte[blocksize+1], 0, blocksize+1, new byte[blocksize+1], blocksize >> 1); - Assert.Fail("output for ProcessBytes is too short"); - } - catch (OutputLengthException) - { - //expected - } - try - { - sparkleEngine.DoFinal(new byte[2], 2); - Assert.Fail("output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - - mac1 = new byte[sparkleEngine.GetOutputSize(0)]; - mac2 = new byte[sparkleEngine.GetOutputSize(0)]; - sparkleEngine.Reset(); - sparkleEngine.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2); - sparkleEngine.DoFinal(mac1, 0); - sparkleEngine.Reset(); - sparkleEngine.ProcessAadByte((byte)0); - sparkleEngine.ProcessAadByte((byte)0); - sparkleEngine.DoFinal(mac2, 0); - if (!Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should match for the same AAD with different ways of inputting"); - } - - byte[] c2 = new byte[sparkleEngine.GetOutputSize(10)]; - byte[] c3 = new byte[sparkleEngine.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]; - sparkleEngine.Reset(); - sparkleEngine.ProcessAadBytes(aad2, 0, aad2.Length); - int offset = sparkleEngine.ProcessBytes(m2, 0, m2.Length, c2, 0); - sparkleEngine.DoFinal(c2, offset); - sparkleEngine.Reset(); - sparkleEngine.ProcessAadBytes(aad3, 1, aad2.Length); - offset = sparkleEngine.ProcessBytes(m3, 1, m2.Length, c3, 1); - sparkleEngine.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"); - } - sparkleEngine.Reset(); - sparkleEngine.Init(false, param); - sparkleEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = sparkleEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - sparkleEngine.DoFinal(m4, offset); - if (!Arrays.AreEqual(m2, m4)) - { - Assert.Fail("The encryption and decryption does not recover the plaintext"); - } - c2[c2.Length - 1] ^= 1; - sparkleEngine.Reset(); - sparkleEngine.Init(false, param); - sparkleEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = sparkleEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - try - { - sparkleEngine.DoFinal(m4, offset); - Assert.Fail("The decryption should fail"); - } - catch (InvalidCipherTextException) - { - //expected; - } - 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[sparkleEngine.GetOutputSize(m7.Length)]; - byte[] c8 = new byte[c7.Length]; - byte[] c9 = new byte[c7.Length]; - sparkleEngine.Init(true, param); - sparkleEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = sparkleEngine.ProcessBytes(m7, 0, m7.Length, c7, 0); - sparkleEngine.DoFinal(c7, offset); - sparkleEngine.Reset(); - sparkleEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = sparkleEngine.ProcessBytes(m7, 0, blocksize, c8, 0); - offset += sparkleEngine.ProcessBytes(m7, blocksize, m7.Length - blocksize, c8, offset); - sparkleEngine.DoFinal(c8, offset); - sparkleEngine.Reset(); - int split = rand.Next(blocksize * 2); - sparkleEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = sparkleEngine.ProcessBytes(m7, 0, split, c9, 0); - offset += sparkleEngine.ProcessBytes(m7, split, m7.Length - split, c9, offset); - sparkleEngine.DoFinal(c9, offset); - if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9)) - { - Assert.Fail("Splitting input of plaintext should output the same ciphertext"); - } -#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span<byte> c4_1 = new byte[c2.Length]; - Span<byte> c4_2 = new byte[c2.Length]; - ReadOnlySpan<byte> m5 = new ReadOnlySpan<byte>(m2); - ReadOnlySpan<byte> aad4 = new ReadOnlySpan<byte>(aad2); - sparkleEngine.Init(true, param); - sparkleEngine.ProcessAadBytes(aad4); - offset = sparkleEngine.ProcessBytes(m5, c4_1); - sparkleEngine.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); - if (!Arrays.AreEqual(c2, c5)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } - sparkleEngine.Reset(); - sparkleEngine.Init(false, param); - Span<byte> m6_1 = new byte[m2.Length]; - Span<byte> m6_2 = new byte[m2.Length]; - ReadOnlySpan<byte> c6 = new ReadOnlySpan<byte>(c2); - sparkleEngine.ProcessAadBytes(aad4); - offset = sparkleEngine.ProcessBytes(c6, m6_1); - sparkleEngine.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); - if (!Arrays.AreEqual(m2, m6)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } -#endif - } - - private void ImplTestParameters(SparkleEngine sparkleEngine, int keySize, int ivSize, int macSize, int blockSize) - { - if (sparkleEngine.GetKeyBytesSize() != keySize) - { - Assert.Fail("key bytes of " + sparkleEngine.AlgorithmName + " is not correct"); - } - if (sparkleEngine.GetIVBytesSize() != ivSize) - { - Assert.Fail("iv bytes of " + sparkleEngine.AlgorithmName + " is not correct"); - } - if (sparkleEngine.GetOutputSize(0) != macSize) - { - Assert.Fail("mac bytes of " + sparkleEngine.AlgorithmName + " is not correct"); - } - if (sparkleEngine.GetBlockSize() != blockSize) - { - Assert.Fail("block size of " + sparkleEngine.AlgorithmName + " is not correct"); - } - } - - private void ImplTestExceptions(SparkleDigest sparkleDigest, int digestsize) - { - if (sparkleDigest.GetDigestSize() != digestsize) - { - Assert.Fail(sparkleDigest.AlgorithmName + ": digest size is not correct"); - } - - try - { - sparkleDigest.BlockUpdate(new byte[1], 1, 1); - Assert.Fail(sparkleDigest.AlgorithmName + ": input for BlockUpdate is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - sparkleDigest.DoFinal(new byte[sparkleDigest.GetDigestSize() - 1], 2); - Assert.Fail(sparkleDigest.AlgorithmName + ": output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - } - } -} diff --git a/crypto/test/src/crypto/test/XoodyakTest.cs b/crypto/test/src/crypto/test/XoodyakTest.cs deleted file mode 100644 index 5cbff7a41..000000000 --- a/crypto/test/src/crypto/test/XoodyakTest.cs +++ /dev/null @@ -1,459 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -using NUnit.Framework; - -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Utilities.Encoders; -using Org.BouncyCastle.Utilities.Test; - -namespace Org.BouncyCastle.Crypto.Tests -{ - [TestFixture] - public class XoodyakTest - : SimpleTest - { - public override string Name => "Xoodyak"; - - [Test] - public override void PerformTest() - { - ImplTestVectorsHash(); - ImplTestVectors(); - XoodyakEngine xoodyakEngine = new XoodyakEngine(); - ImplTestExceptions(xoodyakEngine, xoodyakEngine.GetKeyBytesSize(), xoodyakEngine.GetIVBytesSize(), xoodyakEngine.GetBlockSize()); - ImplTestParameters(xoodyakEngine, 16, 16, 16, 24); - ImplTestExceptions(new XoodyakDigest(), 32); - } - - private void ImplTestVectors() - { - XoodyakEngine xoodyak = new XoodyakEngine(); - var buf = new Dictionary<string, string>(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.xoodyak.LWC_AEAD_KAT_128_128.txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - 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 param = new ParametersWithIV(new KeyParameter(key), nonce); - xoodyak.Init(true, param); - xoodyak.ProcessAadBytes(ad, 0, ad.Length); - byte[] rv = new byte[xoodyak.GetOutputSize(pt.Length)]; - int len = xoodyak.ProcessBytes(pt, 0, pt.Length, rv, 0); - xoodyak.DoFinal(rv, len); - Assert.True(Arrays.AreEqual(rv, ct)); - xoodyak.Reset(); - xoodyak.Init(false, param); - //Decrypt - xoodyak.ProcessAadBytes(ad, 0, ad.Length); - rv = new byte[pt.Length + 16]; - len = xoodyak.ProcessBytes(ct, 0, ct.Length, rv, 0); - xoodyak.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)); - xoodyak.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - } - } - } - } - private void ImplTestVectorsHash() - { - XoodyakDigest xoodyak = new XoodyakDigest(); - var buf = new Dictionary<string, string>(); - //TestSampler sampler = new TestSampler(); - using (var src = new StreamReader(SimpleTest.GetTestDataAsStream("crypto.xoodyak.LWC_HASH_KAT_256.txt"))) - { - Dictionary<string, string> map = new Dictionary<string, string>(); - string line; - while ((line = src.ReadLine()) != null) - { - var data = line.Split(' '); - if (data.Length == 1) - { - var ptByte = Hex.Decode(map["Msg"]); - xoodyak.BlockUpdate(ptByte, 0, ptByte.Length); - byte[] hash = new byte[32]; - xoodyak.DoFinal(hash, 0); - Assert.True(Arrays.AreEqual(hash, Hex.Decode(map["MD"]))); - map.Clear(); - xoodyak.Reset(); - } - else - { - if (data.Length >= 3) - { - map[data[0].Trim()] = data[2].Trim(); - } - else - { - map[data[0].Trim()] = ""; - } - - } - } - } - } - - private void ImplTestExceptions(XoodyakEngine xoodyakEngine, int keysize, int ivsize, int blocksize) - { - byte[] k = new byte[keysize]; - byte[] iv = new byte[ivsize]; - byte[] m = new byte[0]; - byte[] c1 = new byte[xoodyakEngine.GetOutputSize(m.Length)]; - var param = new ParametersWithIV(new KeyParameter(k), iv); - try - { - xoodyakEngine.ProcessBytes(m, 0, m.Length, c1, 0); - Assert.Fail(xoodyakEngine.AlgorithmName + " needs to be initialized before ProcessBytes"); - } - catch (ArgumentException) - { - //expected - } - - try - { - xoodyakEngine.ProcessByte((byte)0, c1, 0); - Assert.Fail(xoodyakEngine.AlgorithmName + " needs to be initialized before ProcessByte"); - } - catch (ArgumentException) - { - //expected - } - - try - { - xoodyakEngine.Reset(); - Assert.Fail(xoodyakEngine.AlgorithmName + " needs to be initialized before Reset"); - } - catch (ArgumentException) - { - //expected - } - - try - { - xoodyakEngine.DoFinal(c1, m.Length); - Assert.Fail(xoodyakEngine.AlgorithmName + " needs to be initialized before DoFinal"); - } - catch (ArgumentException) - { - //expected - } - - try - { - xoodyakEngine.GetMac(); - xoodyakEngine.GetOutputSize(0); - xoodyakEngine.GetUpdateOutputSize(0); - } - catch (ArgumentException) - { - //expected - Assert.Fail(xoodyakEngine.AlgorithmName + " functions can be called before initialization"); - } - Random rand = new Random(); - int randomNum; - while ((randomNum = rand.Next(100)) == keysize) ; - byte[] k1 = new byte[randomNum]; - while ((randomNum = rand.Next(100)) == ivsize) ; - byte[] iv1 = new byte[randomNum]; - try - { - xoodyakEngine.Init(true, new ParametersWithIV(new KeyParameter(k1), iv)); - Assert.Fail(xoodyakEngine.AlgorithmName + " k size does not match"); - } - catch (ArgumentException) - { - //expected - } - try - { - xoodyakEngine.Init(true, new ParametersWithIV(new KeyParameter(k), iv1)); - Assert.Fail(xoodyakEngine.AlgorithmName + "iv size does not match"); - } - catch (ArgumentException) - { - //expected - } - - - xoodyakEngine.Init(true, param); - try - { - xoodyakEngine.DoFinal(c1, m.Length); - } - catch (Exception) - { - Assert.Fail(xoodyakEngine.AlgorithmName + " allows no input for AAD and plaintext"); - } - byte[] mac2 = xoodyakEngine.GetMac(); - if (mac2 == null) - { - Assert.Fail("mac should not be empty after DoFinal"); - } - if (!Arrays.AreEqual(mac2, c1)) - { - Assert.Fail("mac should be equal when calling DoFinal and GetMac"); - } - xoodyakEngine.ProcessAadByte((byte)0); - byte[] mac1 = new byte[xoodyakEngine.GetOutputSize(0)]; - xoodyakEngine.DoFinal(mac1, 0); - if (Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should not match"); - } - xoodyakEngine.Reset(); - xoodyakEngine.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], 0); - try - { - xoodyakEngine.ProcessAadByte((byte)0); - Assert.Fail("ProcessAadByte(s) cannot be called after encryption/decryption"); - } - catch (ArgumentException) - { - //expected - } - try - { - xoodyakEngine.ProcessAadBytes(new byte[] { 0 }, 0, 1); - Assert.Fail("ProcessAadByte(s) cannot be called once only"); - } - catch (ArgumentException) - { - //expected - } - - xoodyakEngine.Reset(); - try - { - xoodyakEngine.ProcessAadBytes(new byte[] { 0 }, 1, 1); - Assert.Fail("input for ProcessAadBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - xoodyakEngine.ProcessBytes(new byte[] { 0 }, 1, 1, c1, 0); - Assert.Fail("input for ProcessBytes is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - xoodyakEngine.ProcessBytes(new byte[blocksize], 0, blocksize, new byte[blocksize], blocksize >> 1); - Assert.Fail("output for ProcessBytes is too short"); - } - catch (OutputLengthException) - { - //expected - } - try - { - xoodyakEngine.DoFinal(new byte[2], 2); - Assert.Fail("output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - - mac1 = new byte[xoodyakEngine.GetOutputSize(0)]; - mac2 = new byte[xoodyakEngine.GetOutputSize(0)]; - xoodyakEngine.Reset(); - xoodyakEngine.ProcessAadBytes(new byte[] { 0, 0 }, 0, 2); - xoodyakEngine.DoFinal(mac1, 0); - xoodyakEngine.Reset(); - xoodyakEngine.ProcessAadByte((byte)0); - xoodyakEngine.ProcessAadByte((byte)0); - xoodyakEngine.DoFinal(mac2, 0); - if (!Arrays.AreEqual(mac1, mac2)) - { - Assert.Fail("mac should match for the same AAD with different ways of inputting"); - } - - byte[] c2 = new byte[xoodyakEngine.GetOutputSize(10)]; - byte[] c3 = new byte[xoodyakEngine.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]; - xoodyakEngine.Reset(); - xoodyakEngine.ProcessAadBytes(aad2, 0, aad2.Length); - int offset = xoodyakEngine.ProcessBytes(m2, 0, m2.Length, c2, 0); - xoodyakEngine.DoFinal(c2, offset); - xoodyakEngine.Reset(); - xoodyakEngine.ProcessAadBytes(aad3, 1, aad2.Length); - offset = xoodyakEngine.ProcessBytes(m3, 1, m2.Length, c3, 1); - xoodyakEngine.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"); - } - xoodyakEngine.Reset(); - xoodyakEngine.Init(false, param); - xoodyakEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = xoodyakEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - xoodyakEngine.DoFinal(m4, offset); - if (!Arrays.AreEqual(m2, m4)) - { - Assert.Fail("The encryption and decryption does not recover the plaintext"); - } - c2[c2.Length - 1] ^= 1; - xoodyakEngine.Reset(); - xoodyakEngine.Init(false, param); - xoodyakEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = xoodyakEngine.ProcessBytes(c2, 0, c2.Length, m4, 0); - try - { - xoodyakEngine.DoFinal(m4, offset); - Assert.Fail("The decryption should fail"); - } - catch (InvalidCipherTextException) - { - //expected; - } - 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[xoodyakEngine.GetOutputSize(m7.Length)]; - byte[] c8 = new byte[c7.Length]; - byte[] c9 = new byte[c7.Length]; - xoodyakEngine.Init(true, param); - xoodyakEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = xoodyakEngine.ProcessBytes(m7, 0, m7.Length, c7, 0); - xoodyakEngine.DoFinal(c7, offset); - xoodyakEngine.Reset(); - xoodyakEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = xoodyakEngine.ProcessBytes(m7, 0, blocksize, c8, 0); - offset += xoodyakEngine.ProcessBytes(m7, blocksize, m7.Length - blocksize, c8, offset); - xoodyakEngine.DoFinal(c8, offset); - xoodyakEngine.Reset(); - int split = rand.Next(blocksize * 2); - xoodyakEngine.ProcessAadBytes(aad2, 0, aad2.Length); - offset = xoodyakEngine.ProcessBytes(m7, 0, split, c9, 0); - offset += xoodyakEngine.ProcessBytes(m7, split, m7.Length - split, c9, offset); - xoodyakEngine.DoFinal(c9, offset); - if (!Arrays.AreEqual(c7, c8) || !Arrays.AreEqual(c7, c9)) - { - Assert.Fail("Splitting input of plaintext should output the same ciphertext"); - } -#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER - Span<byte> c4_1 = new byte[c2.Length]; - Span<byte> c4_2 = new byte[c2.Length]; - ReadOnlySpan<byte> m5 = new ReadOnlySpan<byte>(m2); - ReadOnlySpan<byte> aad4 = new ReadOnlySpan<byte>(aad2); - xoodyakEngine.Init(true, param); - xoodyakEngine.ProcessAadBytes(aad4); - offset = xoodyakEngine.ProcessBytes(m5, c4_1); - xoodyakEngine.DoFinal(c4_2); - byte[] c5 = new byte[c2.Length]; - c4_1[..offset].CopyTo(c5); - c4_2[..(c5.Length - offset)].CopyTo(c5.AsSpan(offset)); - if (!Arrays.AreEqual(c2, c5)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } - xoodyakEngine.Reset(); - xoodyakEngine.Init(false, param); - Span<byte> m6_1 = new byte[m2.Length]; - Span<byte> m6_2 = new byte[m2.Length]; - ReadOnlySpan<byte> c6 = new ReadOnlySpan<byte>(c2); - xoodyakEngine.ProcessAadBytes(aad4); - offset = xoodyakEngine.ProcessBytes(c6, m6_1); - xoodyakEngine.DoFinal(m6_2); - byte[] m6 = new byte[m2.Length]; - m6_1[..offset].CopyTo(m6); - m6_2[..(m6.Length - offset)].CopyTo(m6.AsSpan(offset)); - if (!Arrays.AreEqual(m2, m6)) - { - Assert.Fail("mac should match for the same AAD and message with different offset for both input and output"); - } -#endif - - } - - private void ImplTestParameters(XoodyakEngine xoodyak, int keySize, int ivSize, int macSize, int blockSize) - { - if (xoodyak.GetKeyBytesSize() != keySize) - { - Assert.Fail("key bytes of " + xoodyak.AlgorithmName + " is not correct"); - } - if (xoodyak.GetIVBytesSize() != ivSize) - { - Assert.Fail("iv bytes of " + xoodyak.AlgorithmName + " is not correct"); - } - if (xoodyak.GetOutputSize(0) != macSize) - { - Assert.Fail("mac bytes of " + xoodyak.AlgorithmName + " is not correct"); - } - if (xoodyak.GetBlockSize() != blockSize) - { - Assert.Fail("block size of " + xoodyak.AlgorithmName + " is not correct"); - } - } - - private void ImplTestExceptions(XoodyakDigest xoodyakDigest, int digestSize) - { - Assert.AreEqual(digestSize, xoodyakDigest.GetDigestSize(), - xoodyakDigest.AlgorithmName + ": digest size is not correct"); - - try - { - xoodyakDigest.BlockUpdate(new byte[1], 1, 1); - Assert.Fail(xoodyakDigest.AlgorithmName + ": input for BlockUpdate is too short"); - } - catch (DataLengthException) - { - //expected - } - try - { - xoodyakDigest.DoFinal(new byte[xoodyakDigest.GetDigestSize() - 1], 2); - Assert.Fail(xoodyakDigest.AlgorithmName + ": output for DoFinal is too short"); - } - catch (OutputLengthException) - { - //expected - } - } - } -} |