diff options
author | David Hook <dgh@cryptoworkshop.com> | 2022-07-13 06:26:36 +1000 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2022-07-13 06:26:36 +1000 |
commit | c990f6a071a7b09d7d4750542817bf1d74186268 (patch) | |
tree | 5c2e0e8b941c2bdb2b3f53d6a9f52b9c7aa34621 | |
parent | Detached picnic signature (diff) | |
download | BouncyCastle.NET-ed25519-c990f6a071a7b09d7d4750542817bf1d74186268.tar.xz |
initial Haraka install
-rw-r--r-- | crypto/src/crypto/digests/Haraka256Digest.cs | 160 | ||||
-rw-r--r-- | crypto/src/crypto/digests/Haraka512Digest.cs | 221 | ||||
-rw-r--r-- | crypto/src/crypto/digests/HarakaBase.cs | 152 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/Haraka256DigestTest.cs | 196 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/Haraka512DigestTest.cs | 192 |
5 files changed, 921 insertions, 0 deletions
diff --git a/crypto/src/crypto/digests/Haraka256Digest.cs b/crypto/src/crypto/digests/Haraka256Digest.cs new file mode 100644 index 000000000..b5b230e27 --- /dev/null +++ b/crypto/src/crypto/digests/Haraka256Digest.cs @@ -0,0 +1,160 @@ +using System; + + +namespace Org.BouncyCastle.Crypto.Digests +{ + public class Haraka256Digest : HarakaBase + { + private static readonly byte[][] RC = new byte[][]{ + new byte[]{(byte)0x06, (byte)0x84, (byte)0x70, (byte)0x4c, (byte)0xe6, (byte)0x20, (byte)0xc0, (byte)0x0a, (byte)0xb2, (byte)0xc5, (byte)0xfe, (byte)0xf0, (byte)0x75, (byte)0x81, (byte)0x7b, (byte)0x9d}, + new byte[]{(byte)0x8b, (byte)0x66, (byte)0xb4, (byte)0xe1, (byte)0x88, (byte)0xf3, (byte)0xa0, (byte)0x6b, (byte)0x64, (byte)0x0f, (byte)0x6b, (byte)0xa4, (byte)0x2f, (byte)0x08, (byte)0xf7, (byte)0x17}, + new byte[]{(byte)0x34, (byte)0x02, (byte)0xde, (byte)0x2d, (byte)0x53, (byte)0xf2, (byte)0x84, (byte)0x98, (byte)0xcf, (byte)0x02, (byte)0x9d, (byte)0x60, (byte)0x9f, (byte)0x02, (byte)0x91, (byte)0x14}, + new byte[]{(byte)0x0e, (byte)0xd6, (byte)0xea, (byte)0xe6, (byte)0x2e, (byte)0x7b, (byte)0x4f, (byte)0x08, (byte)0xbb, (byte)0xf3, (byte)0xbc, (byte)0xaf, (byte)0xfd, (byte)0x5b, (byte)0x4f, (byte)0x79}, + new byte[]{(byte)0xcb, (byte)0xcf, (byte)0xb0, (byte)0xcb, (byte)0x48, (byte)0x72, (byte)0x44, (byte)0x8b, (byte)0x79, (byte)0xee, (byte)0xcd, (byte)0x1c, (byte)0xbe, (byte)0x39, (byte)0x70, (byte)0x44}, + new byte[]{(byte)0x7e, (byte)0xea, (byte)0xcd, (byte)0xee, (byte)0x6e, (byte)0x90, (byte)0x32, (byte)0xb7, (byte)0x8d, (byte)0x53, (byte)0x35, (byte)0xed, (byte)0x2b, (byte)0x8a, (byte)0x05, (byte)0x7b}, + new byte[]{(byte)0x67, (byte)0xc2, (byte)0x8f, (byte)0x43, (byte)0x5e, (byte)0x2e, (byte)0x7c, (byte)0xd0, (byte)0xe2, (byte)0x41, (byte)0x27, (byte)0x61, (byte)0xda, (byte)0x4f, (byte)0xef, (byte)0x1b}, + new byte[]{(byte)0x29, (byte)0x24, (byte)0xd9, (byte)0xb0, (byte)0xaf, (byte)0xca, (byte)0xcc, (byte)0x07, (byte)0x67, (byte)0x5f, (byte)0xfd, (byte)0xe2, (byte)0x1f, (byte)0xc7, (byte)0x0b, (byte)0x3b}, + new byte[]{(byte)0xab, (byte)0x4d, (byte)0x63, (byte)0xf1, (byte)0xe6, (byte)0x86, (byte)0x7f, (byte)0xe9, (byte)0xec, (byte)0xdb, (byte)0x8f, (byte)0xca, (byte)0xb9, (byte)0xd4, (byte)0x65, (byte)0xee}, + new byte[]{(byte)0x1c, (byte)0x30, (byte)0xbf, (byte)0x84, (byte)0xd4, (byte)0xb7, (byte)0xcd, (byte)0x64, (byte)0x5b, (byte)0x2a, (byte)0x40, (byte)0x4f, (byte)0xad, (byte)0x03, (byte)0x7e, (byte)0x33}, + new byte[]{(byte)0xb2, (byte)0xcc, (byte)0x0b, (byte)0xb9, (byte)0x94, (byte)0x17, (byte)0x23, (byte)0xbf, (byte)0x69, (byte)0x02, (byte)0x8b, (byte)0x2e, (byte)0x8d, (byte)0xf6, (byte)0x98, (byte)0x00}, + new byte[]{(byte)0xfa, (byte)0x04, (byte)0x78, (byte)0xa6, (byte)0xde, (byte)0x6f, (byte)0x55, (byte)0x72, (byte)0x4a, (byte)0xaa, (byte)0x9e, (byte)0xc8, (byte)0x5c, (byte)0x9d, (byte)0x2d, (byte)0x8a}, + new byte[]{(byte)0xdf, (byte)0xb4, (byte)0x9f, (byte)0x2b, (byte)0x6b, (byte)0x77, (byte)0x2a, (byte)0x12, (byte)0x0e, (byte)0xfa, (byte)0x4f, (byte)0x2e, (byte)0x29, (byte)0x12, (byte)0x9f, (byte)0xd4}, + new byte[]{(byte)0x1e, (byte)0xa1, (byte)0x03, (byte)0x44, (byte)0xf4, (byte)0x49, (byte)0xa2, (byte)0x36, (byte)0x32, (byte)0xd6, (byte)0x11, (byte)0xae, (byte)0xbb, (byte)0x6a, (byte)0x12, (byte)0xee}, + new byte[]{(byte)0xaf, (byte)0x04, (byte)0x49, (byte)0x88, (byte)0x4b, (byte)0x05, (byte)0x00, (byte)0x84, (byte)0x5f, (byte)0x96, (byte)0x00, (byte)0xc9, (byte)0x9c, (byte)0xa8, (byte)0xec, (byte)0xa6}, + new byte[]{(byte)0x21, (byte)0x02, (byte)0x5e, (byte)0xd8, (byte)0x9d, (byte)0x19, (byte)0x9c, (byte)0x4f, (byte)0x78, (byte)0xa2, (byte)0xc7, (byte)0xe3, (byte)0x27, (byte)0xe5, (byte)0x93, (byte)0xec}, + new byte[]{(byte)0xbf, (byte)0x3a, (byte)0xaa, (byte)0xf8, (byte)0xa7, (byte)0x59, (byte)0xc9, (byte)0xb7, (byte)0xb9, (byte)0x28, (byte)0x2e, (byte)0xcd, (byte)0x82, (byte)0xd4, (byte)0x01, (byte)0x73}, + new byte[]{(byte)0x62, (byte)0x60, (byte)0x70, (byte)0x0d, (byte)0x61, (byte)0x86, (byte)0xb0, (byte)0x17, (byte)0x37, (byte)0xf2, (byte)0xef, (byte)0xd9, (byte)0x10, (byte)0x30, (byte)0x7d, (byte)0x6b}, + new byte[]{(byte)0x5a, (byte)0xca, (byte)0x45, (byte)0xc2, (byte)0x21, (byte)0x30, (byte)0x04, (byte)0x43, (byte)0x81, (byte)0xc2, (byte)0x91, (byte)0x53, (byte)0xf6, (byte)0xfc, (byte)0x9a, (byte)0xc6}, + new byte[]{(byte)0x92, (byte)0x23, (byte)0x97, (byte)0x3c, (byte)0x22, (byte)0x6b, (byte)0x68, (byte)0xbb, (byte)0x2c, (byte)0xaf, (byte)0x92, (byte)0xe8, (byte)0x36, (byte)0xd1, (byte)0x94, (byte)0x3a} + }; + private readonly byte[] buffer; + private int off; + private void mix256(byte[][] s1, byte[][] s2) + { + Array.Copy(s1[0], 0, s2[0], 0, 4); + Array.Copy(s1[1], 0, s2[0], 4, 4); + Array.Copy(s1[0], 4, s2[0], 8, 4); + Array.Copy(s1[1], 4, s2[0], 12, 4); + + Array.Copy(s1[0], 8, s2[1], 0, 4); + Array.Copy(s1[1], 8, s2[1], 4, 4); + Array.Copy(s1[0], 12, s2[1], 8, 4); + Array.Copy(s1[1], 12, s2[1], 12, 4); + } + + private int haraka256256(byte[] msg, byte[] output, int outOff) + { + byte[][] s1 = new byte[2][]; + s1[0] = new byte[16]; + s1[1] = new byte[16]; + byte[][] s2 = new byte[2][]; + s2[0] = new byte[16]; + s2[1] = new byte[16]; + + Array.Copy(msg, 0, s1[0], 0, 16); + Array.Copy(msg, 16, s1[1], 0, 16); + + s1[0] = aesEnc(s1[0], RC[0]); + s1[1] = aesEnc(s1[1], RC[1]); + s1[0] = aesEnc(s1[0], RC[2]); + s1[1] = aesEnc(s1[1], RC[3]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[4]); + s1[1] = aesEnc(s2[1], RC[5]); + s1[0] = aesEnc(s1[0], RC[6]); + s1[1] = aesEnc(s1[1], RC[7]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[8]); + s1[1] = aesEnc(s2[1], RC[9]); + s1[0] = aesEnc(s1[0], RC[10]); + s1[1] = aesEnc(s1[1], RC[11]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[12]); + s1[1] = aesEnc(s2[1], RC[13]); + s1[0] = aesEnc(s1[0], RC[14]); + s1[1] = aesEnc(s1[1], RC[15]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[16]); + s1[1] = aesEnc(s2[1], RC[17]); + s1[0] = aesEnc(s1[0], RC[18]); + s1[1] = aesEnc(s1[1], RC[19]); + mix256(s1, s2); + + s1[0] = Xor(s2[0], msg, 0); + s1[1] = Xor(s2[1], msg, 16); + + Array.Copy(s1[0], 0, output, outOff, 16); + Array.Copy(s1[1], 0, output, outOff + 16, 16); + + return DIGEST_SIZE; + } + + + + public Haraka256Digest() + { + this.buffer = new byte[32]; + } + + public Haraka256Digest(Haraka256Digest digest) + { + this.buffer = (byte[]) digest.buffer.Clone(); + this.off = digest.off; + } + + public string getAlgorithmName() + { + return "Haraka-256"; + } + + public override void Update(byte input) + { + if (off + 1 > 32) + { + throw new ArgumentException("total input cannot be more than 32 bytes"); + } + + buffer[off++] = input; + } + + public void Update(byte[] input, int inOff, int len) + { + if (off + len > 32) + { + throw new ArgumentException("total input cannot be more than 32 bytes"); + } + + Array.Copy(input, inOff, buffer, off, len); + off += len; + } + + public override int DoFinal(byte[] output, int outOff) + { + if (off != 32) + { + throw new ArgumentException("input must be exactly 32 bytes"); + } + + if (output.Length - outOff < 32) + { + throw new ArgumentException("output too short to receive digest"); + } + + int rv = haraka256256(buffer, output, outOff); + + Reset(); + + return rv; + } + + public override void Reset() + { + off = 0; + Array.Clear(buffer, 0, 32); + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/digests/Haraka512Digest.cs b/crypto/src/crypto/digests/Haraka512Digest.cs new file mode 100644 index 000000000..ce48c81bc --- /dev/null +++ b/crypto/src/crypto/digests/Haraka512Digest.cs @@ -0,0 +1,221 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Digests +{ + public class Haraka512Digest : HarakaBase + { + private static readonly byte[][] RC = new byte[][]{ + new byte[]{(byte)0x06, (byte)0x84, (byte)0x70, (byte)0x4c, (byte)0xe6, (byte)0x20, (byte)0xc0, (byte)0x0a, (byte)0xb2, (byte)0xc5, (byte)0xfe, (byte)0xf0, (byte)0x75, (byte)0x81, (byte)0x7b, (byte)0x9d}, + new byte[]{(byte)0x8b, (byte)0x66, (byte)0xb4, (byte)0xe1, (byte)0x88, (byte)0xf3, (byte)0xa0, (byte)0x6b, (byte)0x64, (byte)0x0f, (byte)0x6b, (byte)0xa4, (byte)0x2f, (byte)0x08, (byte)0xf7, (byte)0x17}, + new byte[]{(byte)0x34, (byte)0x02, (byte)0xde, (byte)0x2d, (byte)0x53, (byte)0xf2, (byte)0x84, (byte)0x98, (byte)0xcf, (byte)0x02, (byte)0x9d, (byte)0x60, (byte)0x9f, (byte)0x02, (byte)0x91, (byte)0x14}, + new byte[]{(byte)0x0e, (byte)0xd6, (byte)0xea, (byte)0xe6, (byte)0x2e, (byte)0x7b, (byte)0x4f, (byte)0x08, (byte)0xbb, (byte)0xf3, (byte)0xbc, (byte)0xaf, (byte)0xfd, (byte)0x5b, (byte)0x4f, (byte)0x79}, + new byte[]{(byte)0xcb, (byte)0xcf, (byte)0xb0, (byte)0xcb, (byte)0x48, (byte)0x72, (byte)0x44, (byte)0x8b, (byte)0x79, (byte)0xee, (byte)0xcd, (byte)0x1c, (byte)0xbe, (byte)0x39, (byte)0x70, (byte)0x44}, + new byte[]{(byte)0x7e, (byte)0xea, (byte)0xcd, (byte)0xee, (byte)0x6e, (byte)0x90, (byte)0x32, (byte)0xb7, (byte)0x8d, (byte)0x53, (byte)0x35, (byte)0xed, (byte)0x2b, (byte)0x8a, (byte)0x05, (byte)0x7b}, + new byte[]{(byte)0x67, (byte)0xc2, (byte)0x8f, (byte)0x43, (byte)0x5e, (byte)0x2e, (byte)0x7c, (byte)0xd0, (byte)0xe2, (byte)0x41, (byte)0x27, (byte)0x61, (byte)0xda, (byte)0x4f, (byte)0xef, (byte)0x1b}, + new byte[]{(byte)0x29, (byte)0x24, (byte)0xd9, (byte)0xb0, (byte)0xaf, (byte)0xca, (byte)0xcc, (byte)0x07, (byte)0x67, (byte)0x5f, (byte)0xfd, (byte)0xe2, (byte)0x1f, (byte)0xc7, (byte)0x0b, (byte)0x3b}, + new byte[]{(byte)0xab, (byte)0x4d, (byte)0x63, (byte)0xf1, (byte)0xe6, (byte)0x86, (byte)0x7f, (byte)0xe9, (byte)0xec, (byte)0xdb, (byte)0x8f, (byte)0xca, (byte)0xb9, (byte)0xd4, (byte)0x65, (byte)0xee}, + new byte[]{(byte)0x1c, (byte)0x30, (byte)0xbf, (byte)0x84, (byte)0xd4, (byte)0xb7, (byte)0xcd, (byte)0x64, (byte)0x5b, (byte)0x2a, (byte)0x40, (byte)0x4f, (byte)0xad, (byte)0x03, (byte)0x7e, (byte)0x33}, + new byte[]{(byte)0xb2, (byte)0xcc, (byte)0x0b, (byte)0xb9, (byte)0x94, (byte)0x17, (byte)0x23, (byte)0xbf, (byte)0x69, (byte)0x02, (byte)0x8b, (byte)0x2e, (byte)0x8d, (byte)0xf6, (byte)0x98, (byte)0x00}, + new byte[]{(byte)0xfa, (byte)0x04, (byte)0x78, (byte)0xa6, (byte)0xde, (byte)0x6f, (byte)0x55, (byte)0x72, (byte)0x4a, (byte)0xaa, (byte)0x9e, (byte)0xc8, (byte)0x5c, (byte)0x9d, (byte)0x2d, (byte)0x8a}, + new byte[]{(byte)0xdf, (byte)0xb4, (byte)0x9f, (byte)0x2b, (byte)0x6b, (byte)0x77, (byte)0x2a, (byte)0x12, (byte)0x0e, (byte)0xfa, (byte)0x4f, (byte)0x2e, (byte)0x29, (byte)0x12, (byte)0x9f, (byte)0xd4}, + new byte[]{(byte)0x1e, (byte)0xa1, (byte)0x03, (byte)0x44, (byte)0xf4, (byte)0x49, (byte)0xa2, (byte)0x36, (byte)0x32, (byte)0xd6, (byte)0x11, (byte)0xae, (byte)0xbb, (byte)0x6a, (byte)0x12, (byte)0xee}, + new byte[]{(byte)0xaf, (byte)0x04, (byte)0x49, (byte)0x88, (byte)0x4b, (byte)0x05, (byte)0x00, (byte)0x84, (byte)0x5f, (byte)0x96, (byte)0x00, (byte)0xc9, (byte)0x9c, (byte)0xa8, (byte)0xec, (byte)0xa6}, + new byte[]{(byte)0x21, (byte)0x02, (byte)0x5e, (byte)0xd8, (byte)0x9d, (byte)0x19, (byte)0x9c, (byte)0x4f, (byte)0x78, (byte)0xa2, (byte)0xc7, (byte)0xe3, (byte)0x27, (byte)0xe5, (byte)0x93, (byte)0xec}, + new byte[]{(byte)0xbf, (byte)0x3a, (byte)0xaa, (byte)0xf8, (byte)0xa7, (byte)0x59, (byte)0xc9, (byte)0xb7, (byte)0xb9, (byte)0x28, (byte)0x2e, (byte)0xcd, (byte)0x82, (byte)0xd4, (byte)0x01, (byte)0x73}, + new byte[]{(byte)0x62, (byte)0x60, (byte)0x70, (byte)0x0d, (byte)0x61, (byte)0x86, (byte)0xb0, (byte)0x17, (byte)0x37, (byte)0xf2, (byte)0xef, (byte)0xd9, (byte)0x10, (byte)0x30, (byte)0x7d, (byte)0x6b}, + new byte[]{(byte)0x5a, (byte)0xca, (byte)0x45, (byte)0xc2, (byte)0x21, (byte)0x30, (byte)0x04, (byte)0x43, (byte)0x81, (byte)0xc2, (byte)0x91, (byte)0x53, (byte)0xf6, (byte)0xfc, (byte)0x9a, (byte)0xc6}, + new byte[]{(byte)0x92, (byte)0x23, (byte)0x97, (byte)0x3c, (byte)0x22, (byte)0x6b, (byte)0x68, (byte)0xbb, (byte)0x2c, (byte)0xaf, (byte)0x92, (byte)0xe8, (byte)0x36, (byte)0xd1, (byte)0x94, (byte)0x3a}, + new byte[]{(byte)0xd3, (byte)0xbf, (byte)0x92, (byte)0x38, (byte)0x22, (byte)0x58, (byte)0x86, (byte)0xeb, (byte)0x6c, (byte)0xba, (byte)0xb9, (byte)0x58, (byte)0xe5, (byte)0x10, (byte)0x71, (byte)0xb4}, + new byte[]{(byte)0xdb, (byte)0x86, (byte)0x3c, (byte)0xe5, (byte)0xae, (byte)0xf0, (byte)0xc6, (byte)0x77, (byte)0x93, (byte)0x3d, (byte)0xfd, (byte)0xdd, (byte)0x24, (byte)0xe1, (byte)0x12, (byte)0x8d}, + new byte[]{(byte)0xbb, (byte)0x60, (byte)0x62, (byte)0x68, (byte)0xff, (byte)0xeb, (byte)0xa0, (byte)0x9c, (byte)0x83, (byte)0xe4, (byte)0x8d, (byte)0xe3, (byte)0xcb, (byte)0x22, (byte)0x12, (byte)0xb1}, + new byte[]{(byte)0x73, (byte)0x4b, (byte)0xd3, (byte)0xdc, (byte)0xe2, (byte)0xe4, (byte)0xd1, (byte)0x9c, (byte)0x2d, (byte)0xb9, (byte)0x1a, (byte)0x4e, (byte)0xc7, (byte)0x2b, (byte)0xf7, (byte)0x7d}, + new byte[]{(byte)0x43, (byte)0xbb, (byte)0x47, (byte)0xc3, (byte)0x61, (byte)0x30, (byte)0x1b, (byte)0x43, (byte)0x4b, (byte)0x14, (byte)0x15, (byte)0xc4, (byte)0x2c, (byte)0xb3, (byte)0x92, (byte)0x4e}, + new byte[]{(byte)0xdb, (byte)0xa7, (byte)0x75, (byte)0xa8, (byte)0xe7, (byte)0x07, (byte)0xef, (byte)0xf6, (byte)0x03, (byte)0xb2, (byte)0x31, (byte)0xdd, (byte)0x16, (byte)0xeb, (byte)0x68, (byte)0x99}, + new byte[]{(byte)0x6d, (byte)0xf3, (byte)0x61, (byte)0x4b, (byte)0x3c, (byte)0x75, (byte)0x59, (byte)0x77, (byte)0x8e, (byte)0x5e, (byte)0x23, (byte)0x02, (byte)0x7e, (byte)0xca, (byte)0x47, (byte)0x2c}, + new byte[]{(byte)0xcd, (byte)0xa7, (byte)0x5a, (byte)0x17, (byte)0xd6, (byte)0xde, (byte)0x7d, (byte)0x77, (byte)0x6d, (byte)0x1b, (byte)0xe5, (byte)0xb9, (byte)0xb8, (byte)0x86, (byte)0x17, (byte)0xf9}, + new byte[]{(byte)0xec, (byte)0x6b, (byte)0x43, (byte)0xf0, (byte)0x6b, (byte)0xa8, (byte)0xe9, (byte)0xaa, (byte)0x9d, (byte)0x6c, (byte)0x06, (byte)0x9d, (byte)0xa9, (byte)0x46, (byte)0xee, (byte)0x5d}, + new byte[]{(byte)0xcb, (byte)0x1e, (byte)0x69, (byte)0x50, (byte)0xf9, (byte)0x57, (byte)0x33, (byte)0x2b, (byte)0xa2, (byte)0x53, (byte)0x11, (byte)0x59, (byte)0x3b, (byte)0xf3, (byte)0x27, (byte)0xc1}, + new byte[]{(byte)0x2c, (byte)0xee, (byte)0x0c, (byte)0x75, (byte)0x00, (byte)0xda, (byte)0x61, (byte)0x9c, (byte)0xe4, (byte)0xed, (byte)0x03, (byte)0x53, (byte)0x60, (byte)0x0e, (byte)0xd0, (byte)0xd9}, + new byte[]{(byte)0xf0, (byte)0xb1, (byte)0xa5, (byte)0xa1, (byte)0x96, (byte)0xe9, (byte)0x0c, (byte)0xab, (byte)0x80, (byte)0xbb, (byte)0xba, (byte)0xbc, (byte)0x63, (byte)0xa4, (byte)0xa3, (byte)0x50}, + new byte[]{(byte)0xae, (byte)0x3d, (byte)0xb1, (byte)0x02, (byte)0x5e, (byte)0x96, (byte)0x29, (byte)0x88, (byte)0xab, (byte)0x0d, (byte)0xde, (byte)0x30, (byte)0x93, (byte)0x8d, (byte)0xca, (byte)0x39}, + new byte[]{(byte)0x17, (byte)0xbb, (byte)0x8f, (byte)0x38, (byte)0xd5, (byte)0x54, (byte)0xa4, (byte)0x0b, (byte)0x88, (byte)0x14, (byte)0xf3, (byte)0xa8, (byte)0x2e, (byte)0x75, (byte)0xb4, (byte)0x42}, + new byte[]{(byte)0x34, (byte)0xbb, (byte)0x8a, (byte)0x5b, (byte)0x5f, (byte)0x42, (byte)0x7f, (byte)0xd7, (byte)0xae, (byte)0xb6, (byte)0xb7, (byte)0x79, (byte)0x36, (byte)0x0a, (byte)0x16, (byte)0xf6}, + new byte[]{(byte)0x26, (byte)0xf6, (byte)0x52, (byte)0x41, (byte)0xcb, (byte)0xe5, (byte)0x54, (byte)0x38, (byte)0x43, (byte)0xce, (byte)0x59, (byte)0x18, (byte)0xff, (byte)0xba, (byte)0xaf, (byte)0xde}, + new byte[]{(byte)0x4c, (byte)0xe9, (byte)0x9a, (byte)0x54, (byte)0xb9, (byte)0xf3, (byte)0x02, (byte)0x6a, (byte)0xa2, (byte)0xca, (byte)0x9c, (byte)0xf7, (byte)0x83, (byte)0x9e, (byte)0xc9, (byte)0x78}, + new byte[]{(byte)0xae, (byte)0x51, (byte)0xa5, (byte)0x1a, (byte)0x1b, (byte)0xdf, (byte)0xf7, (byte)0xbe, (byte)0x40, (byte)0xc0, (byte)0x6e, (byte)0x28, (byte)0x22, (byte)0x90, (byte)0x12, (byte)0x35}, + new byte[]{(byte)0xa0, (byte)0xc1, (byte)0x61, (byte)0x3c, (byte)0xba, (byte)0x7e, (byte)0xd2, (byte)0x2b, (byte)0xc1, (byte)0x73, (byte)0xbc, (byte)0x0f, (byte)0x48, (byte)0xa6, (byte)0x59, (byte)0xcf}, + new byte[]{(byte)0x75, (byte)0x6a, (byte)0xcc, (byte)0x03, (byte)0x02, (byte)0x28, (byte)0x82, (byte)0x88, (byte)0x4a, (byte)0xd6, (byte)0xbd, (byte)0xfd, (byte)0xe9, (byte)0xc5, (byte)0x9d, (byte)0xa1} + }; + + private readonly byte[] buffer; + private int off; + + public Haraka512Digest() + { + this.buffer = new byte[64]; + } + + public Haraka512Digest(Haraka512Digest digest) + { + this.buffer = (byte[])digest.buffer.Clone(); + this.off = digest.off; + } + + private void Mix512(byte[][] s1, byte[][] s2) + { + Array.Copy(s1[0], 12, s2[0], 0, 4); + Array.Copy(s1[2], 12, s2[0], 4, 4); + Array.Copy(s1[1], 12, s2[0], 8, 4); + Array.Copy(s1[3], 12, s2[0], 12, 4); + + Array.Copy(s1[2], 0, s2[1], 0, 4); + Array.Copy(s1[0], 0, s2[1], 4, 4); + Array.Copy(s1[3], 0, s2[1], 8, 4); + Array.Copy(s1[1], 0, s2[1], 12, 4); + + Array.Copy(s1[2], 4, s2[2], 0, 4); + Array.Copy(s1[0], 4, s2[2], 4, 4); + Array.Copy(s1[3], 4, s2[2], 8, 4); + Array.Copy(s1[1], 4, s2[2], 12, 4); + + Array.Copy(s1[0], 8, s2[3], 0, 4); + Array.Copy(s1[2], 8, s2[3], 4, 4); + Array.Copy(s1[1], 8, s2[3], 8, 4); + Array.Copy(s1[3], 8, s2[3], 12, 4); + } + + private int Haraka512256(byte[] msg, byte[] output, int outOff) + { + byte[][] s1 = new byte[4][]; + s1[0] = new byte[16]; + s1[1] = new byte[16]; + s1[2] = new byte[16]; + s1[3] = new byte[16]; + byte[][] s2 = new byte[4][]; + s2[0] = new byte[16]; + s2[1] = new byte[16]; + s2[2] = new byte[16]; + s2[3] = new byte[16]; + + //-- Unrolled version of above. + + Array.Copy(msg, 0, s1[0], 0, 16); + Array.Copy(msg, 16, s1[1], 0, 16); + Array.Copy(msg, 32, s1[2], 0, 16); + Array.Copy(msg, 48, s1[3], 0, 16); + + s1[0] = aesEnc(s1[0], RC[0]); + s1[1] = aesEnc(s1[1], RC[1]); + s1[2] = aesEnc(s1[2], RC[2]); + s1[3] = aesEnc(s1[3], RC[3]); + s1[0] = aesEnc(s1[0], RC[4]); + s1[1] = aesEnc(s1[1], RC[5]); + s1[2] = aesEnc(s1[2], RC[6]); + s1[3] = aesEnc(s1[3], RC[7]); + Mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[8]); + s1[1] = aesEnc(s2[1], RC[9]); + s1[2] = aesEnc(s2[2], RC[10]); + s1[3] = aesEnc(s2[3], RC[11]); + s1[0] = aesEnc(s1[0], RC[12]); + s1[1] = aesEnc(s1[1], RC[13]); + s1[2] = aesEnc(s1[2], RC[14]); + s1[3] = aesEnc(s1[3], RC[15]); + Mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[16]); + s1[1] = aesEnc(s2[1], RC[17]); + s1[2] = aesEnc(s2[2], RC[18]); + s1[3] = aesEnc(s2[3], RC[19]); + s1[0] = aesEnc(s1[0], RC[20]); + s1[1] = aesEnc(s1[1], RC[21]); + s1[2] = aesEnc(s1[2], RC[22]); + s1[3] = aesEnc(s1[3], RC[23]); + Mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[24]); + s1[1] = aesEnc(s2[1], RC[25]); + s1[2] = aesEnc(s2[2], RC[26]); + s1[3] = aesEnc(s2[3], RC[27]); + s1[0] = aesEnc(s1[0], RC[28]); + s1[1] = aesEnc(s1[1], RC[29]); + s1[2] = aesEnc(s1[2], RC[30]); + s1[3] = aesEnc(s1[3], RC[31]); + Mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[32]); + s1[1] = aesEnc(s2[1], RC[33]); + s1[2] = aesEnc(s2[2], RC[34]); + s1[3] = aesEnc(s2[3], RC[35]); + s1[0] = aesEnc(s1[0], RC[36]); + s1[1] = aesEnc(s1[1], RC[37]); + s1[2] = aesEnc(s1[2], RC[38]); + s1[3] = aesEnc(s1[3], RC[39]); + Mix512(s1, s2); + + s1[0] = Xor(s2[0], msg, 0); + s1[1] = Xor(s2[1], msg, 16); + s1[2] = Xor(s2[2], msg, 32); + s1[3] = Xor(s2[3], msg, 48); + + Array.Copy(s1[0], 8, output, outOff, 8); + Array.Copy(s1[1], 8, output, outOff + 8, 8); + Array.Copy(s1[2], 0, output, outOff + 16, 8); + Array.Copy(s1[3], 0, output, outOff + 24, 8); + + return DIGEST_SIZE; + } + + public string GetAlgorithmName() + { + return "Haraka-512"; + } + + public override void Update(byte input) + { + if (off + 1 > 64) + { + throw new ArgumentException("total input cannot be more than 64 bytes"); + } + + buffer[off++] = input; + } + + public void Update(byte[] input, int inOff, int len) + { + if (off + len > 64) + { + throw new ArgumentException("total input cannot be more than 64 bytes"); + } + + Array.Copy(input, inOff, buffer, off, len); + off += len; + } + + public override int DoFinal(byte[] output, int outOff) + { + if (off != 64) + { + throw new ArgumentException("input must be exactly 64 bytes"); + } + + if (output.Length - outOff < 32) + { + throw new ArgumentException("output too short to receive digest"); + } + + int rv = Haraka512256(buffer, output, outOff); + + Reset(); + + return rv; + } + + public override void Reset() + { + off = 0; + Array.Clear(buffer, 0, 64); + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/digests/HarakaBase.cs b/crypto/src/crypto/digests/HarakaBase.cs new file mode 100644 index 000000000..ef74204e9 --- /dev/null +++ b/crypto/src/crypto/digests/HarakaBase.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Org.BouncyCastle.Crypto.Digests +{ + public abstract class HarakaBase : IDigest + { + protected static readonly int DIGEST_SIZE = 32; + + protected static readonly byte[,] S = { + {(byte)0x63, (byte)0x7c, (byte)0x77, (byte)0x7b, (byte)0xf2, (byte)0x6b, (byte)0x6f, (byte)0xc5, (byte)0x30, (byte)0x01, (byte)0x67, (byte)0x2b, (byte)0xfe, (byte)0xd7, (byte)0xab, (byte)0x76}, + {(byte)0xca, (byte)0x82, (byte)0xc9, (byte)0x7d, (byte)0xfa, (byte)0x59, (byte)0x47, (byte)0xf0, (byte)0xad, (byte)0xd4, (byte)0xa2, (byte)0xaf, (byte)0x9c, (byte)0xa4, (byte)0x72, (byte)0xc0}, + {(byte)0xb7, (byte)0xfd, (byte)0x93, (byte)0x26, (byte)0x36, (byte)0x3f, (byte)0xf7, (byte)0xcc, (byte)0x34, (byte)0xa5, (byte)0xe5, (byte)0xf1, (byte)0x71, (byte)0xd8, (byte)0x31, (byte)0x15}, + {(byte)0x04, (byte)0xc7, (byte)0x23, (byte)0xc3, (byte)0x18, (byte)0x96, (byte)0x05, (byte)0x9a, (byte)0x07, (byte)0x12, (byte)0x80, (byte)0xe2, (byte)0xeb, (byte)0x27, (byte)0xb2, (byte)0x75}, + {(byte)0x09, (byte)0x83, (byte)0x2c, (byte)0x1a, (byte)0x1b, (byte)0x6e, (byte)0x5a, (byte)0xa0, (byte)0x52, (byte)0x3b, (byte)0xd6, (byte)0xb3, (byte)0x29, (byte)0xe3, (byte)0x2f, (byte)0x84}, + {(byte)0x53, (byte)0xd1, (byte)0x00, (byte)0xed, (byte)0x20, (byte)0xfc, (byte)0xb1, (byte)0x5b, (byte)0x6a, (byte)0xcb, (byte)0xbe, (byte)0x39, (byte)0x4a, (byte)0x4c, (byte)0x58, (byte)0xcf}, + {(byte)0xd0, (byte)0xef, (byte)0xaa, (byte)0xfb, (byte)0x43, (byte)0x4d, (byte)0x33, (byte)0x85, (byte)0x45, (byte)0xf9, (byte)0x02, (byte)0x7f, (byte)0x50, (byte)0x3c, (byte)0x9f, (byte)0xa8}, + {(byte)0x51, (byte)0xa3, (byte)0x40, (byte)0x8f, (byte)0x92, (byte)0x9d, (byte)0x38, (byte)0xf5, (byte)0xbc, (byte)0xb6, (byte)0xda, (byte)0x21, (byte)0x10, (byte)0xff, (byte)0xf3, (byte)0xd2}, + {(byte)0xcd, (byte)0x0c, (byte)0x13, (byte)0xec, (byte)0x5f, (byte)0x97, (byte)0x44, (byte)0x17, (byte)0xc4, (byte)0xa7, (byte)0x7e, (byte)0x3d, (byte)0x64, (byte)0x5d, (byte)0x19, (byte)0x73}, + {(byte)0x60, (byte)0x81, (byte)0x4f, (byte)0xdc, (byte)0x22, (byte)0x2a, (byte)0x90, (byte)0x88, (byte)0x46, (byte)0xee, (byte)0xb8, (byte)0x14, (byte)0xde, (byte)0x5e, (byte)0x0b, (byte)0xdb}, + {(byte)0xe0, (byte)0x32, (byte)0x3a, (byte)0x0a, (byte)0x49, (byte)0x06, (byte)0x24, (byte)0x5c, (byte)0xc2, (byte)0xd3, (byte)0xac, (byte)0x62, (byte)0x91, (byte)0x95, (byte)0xe4, (byte)0x79}, + {(byte)0xe7, (byte)0xc8, (byte)0x37, (byte)0x6d, (byte)0x8d, (byte)0xd5, (byte)0x4e, (byte)0xa9, (byte)0x6c, (byte)0x56, (byte)0xf4, (byte)0xea, (byte)0x65, (byte)0x7a, (byte)0xae, (byte)0x08}, + {(byte)0xba, (byte)0x78, (byte)0x25, (byte)0x2e, (byte)0x1c, (byte)0xa6, (byte)0xb4, (byte)0xc6, (byte)0xe8, (byte)0xdd, (byte)0x74, (byte)0x1f, (byte)0x4b, (byte)0xbd, (byte)0x8b, (byte)0x8a}, + {(byte)0x70, (byte)0x3e, (byte)0xb5, (byte)0x66, (byte)0x48, (byte)0x03, (byte)0xf6, (byte)0x0e, (byte)0x61, (byte)0x35, (byte)0x57, (byte)0xb9, (byte)0x86, (byte)0xc1, (byte)0x1d, (byte)0x9e}, + {(byte)0xe1, (byte)0xf8, (byte)0x98, (byte)0x11, (byte)0x69, (byte)0xd9, (byte)0x8e, (byte)0x94, (byte)0x9b, (byte)0x1e, (byte)0x87, (byte)0xe9, (byte)0xce, (byte)0x55, (byte)0x28, (byte)0xdf}, + {(byte)0x8c, (byte)0xa1, (byte)0x89, (byte)0x0d, (byte)0xbf, (byte)0xe6, (byte)0x42, (byte)0x68, (byte)0x41, (byte)0x99, (byte)0x2d, (byte)0x0f, (byte)0xb0, (byte)0x54, (byte)0xbb, (byte)0x16}}; + + public string AlgorithmName + { + get { return "Haraka Base"; } + } + + static byte sBox(byte x) + { + return S[(uint)(((x & 0xFF) >> 4)),x & 0xF]; + } + + static byte[] subBytes(byte[] s) + { + byte[] output = new byte[s.Length]; + for(int i = 0; i < 16; ++i) + { + output[i] = sBox(s[i]); + } + return output; + } + + static byte[] shiftRows(byte[] s) + { + return new byte[]{ + s[0], s[5], s[10], s[15], + s[4], s[9], s[14], s[3], + s[8], s[13], s[2], s[7], + s[12], s[1], s[6], s[11] + }; + } + + protected static byte[] aesEnc(byte[] s, byte[] rk) + { + s = subBytes(s); + s = shiftRows(s); + s = mixColumns(s); + xorReverse(s, rk); + return s; + } + + static byte xTime(byte x) + { + if ((x >> 7) > 0) + { + return (byte)(((x << 1) ^ 0x1b) & 0xff); + } + else + { + return (byte)((x << 1) & 0xff); + } + } + + + static void xorReverse(byte[] x, byte[] y) + { + x[0] = (byte)(x[0] ^ y[15]); + x[1] = (byte)(x[1] ^ y[14]); + x[2] = (byte)(x[2] ^ y[13]); + x[3] = (byte)(x[3] ^ y[12]); + x[4] = (byte)(x[4] ^ y[11]); + x[5] = (byte)(x[5] ^ y[10]); + x[6] = (byte)(x[6] ^ y[9]); + x[7] = (byte)(x[7] ^ y[8]); + x[8] = (byte)(x[8] ^ y[7]); + x[9] = (byte)(x[9] ^ y[6]); + x[10] = (byte)(x[10] ^ y[5]); + x[11] = (byte)(x[11] ^ y[4]); + x[12] = (byte)(x[12] ^ y[3]); + x[13] = (byte)(x[13] ^ y[2]); + x[14] = (byte)(x[14] ^ y[1]); + x[15] = (byte)(x[15] ^ y[0]); + } + + + protected static byte[] Xor(byte[] x, byte[] y, int yStart) + { + byte[] output = new byte[16]; + for (int i = 0; i < output.Length; i++) + { + output[i] = (byte)(x[i] ^ y[yStart++]); + } + return output; + } + + + static private byte[] mixColumns(byte[] s) + { + byte[] output = new byte[s.Length]; + int j = 0, i4; + for (int i = 0; i < 4; i++) + { + i4 = i << 2; + output[j++] = (byte)(xTime(s[i4]) ^ xTime(s[i4 + 1]) ^ s[i4 + 1] ^ s[i4 + 2] ^ s[i4 + 3]); + output[j++] = (byte)(s[i4] ^ xTime(s[i4 + 1]) ^ xTime(s[i4 + 2]) ^ s[i4 + 2] ^ s[i4 + 3]); + output[j++] = (byte)(s[i4] ^ s[i4 + 1] ^ xTime(s[i4 + 2]) ^ xTime(s[i4 + 3]) ^ s[i4 + 3]); + output[j++] = (byte)(xTime(s[i4]) ^ s[i4] ^ s[i4 + 1] ^ s[i4 + 2] ^ xTime(s[i4 + 3])); + } + + return output; + } + + public int GetDigestSize() + { + return DIGEST_SIZE; + } + + public int GetByteLength() + { + throw new NotImplementedException(); + } + + public abstract void Update(byte input); + + + public void BlockUpdate(byte[] input, int inOff, int length) + { + throw new NotImplementedException(); + } + + public abstract int DoFinal(byte[] output, int outOff); + + public abstract void Reset(); + + } +} diff --git a/crypto/test/src/crypto/test/Haraka256DigestTest.cs b/crypto/test/src/crypto/test/Haraka256DigestTest.cs new file mode 100644 index 000000000..7b8154d4c --- /dev/null +++ b/crypto/test/src/crypto/test/Haraka256DigestTest.cs @@ -0,0 +1,196 @@ +using System; +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace BouncyCastle.Crypto.Tests +{ + public class Haraka256DigestTest : SimpleTest + { + public override string Name + { + get { return "Haraka 256"; } + } + + public void TestKnownVector() + { + byte[] input = new byte[32]; + for (int t = 0; t < input.Length; t++) + { + input[t] = (byte)t; + } + + // From Appendix B, Haraka-256 v2, https://eprint.iacr.org/2016/098.pdf + byte[] expected256 = Hex.Decode("8027ccb87949774b78d0545fb72bf70c695c2a0923cbd47bba1159efbf2b2c1c"); + + Haraka256Digest haraka = new Haraka256Digest(); + haraka.Update(input, 0, input.Length); + byte[] output = new byte[haraka.GetDigestSize()]; + haraka.DoFinal(output, 0); + Assert.IsTrue(Arrays.AreEqual(expected256, output)); + } + + + public void TestInputTooShort() + { + try + { + Haraka256Digest haraka = new Haraka256Digest(); + byte[] input = new byte[31]; + haraka.Update(input, 0, input.Length); + haraka.DoFinal(null, 0); + Assert.Fail("fail on input not 32 bytes."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "input must be exactly 32 bytes")); + } + } + + public void TestInputTooLong() + { + try + { + Haraka256Digest haraka = new Haraka256Digest(); + byte[] input = new byte[33]; + haraka.Update(input, 0, input.Length); + haraka.DoFinal(null, 0); + Assert.Fail("fail on input not 32 bytes."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "total input cannot be more than 32 bytes")); + } + } + + public void TestOutput() + { + + // + // Buffer too short. + // + try + { + Haraka256Digest harakaCipher = new Haraka256Digest(); + byte[] input = new byte[32]; + harakaCipher.Update(input, 0, input.Length); + byte[] output = new byte[31]; + harakaCipher.DoFinal(output, 0); + Assert.Fail("Output too short for digest result."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "output too short to receive digest")); + } + + // + // Offset puts end past length of buffer. + // + try + { + Haraka256Digest harakaCipher = new Haraka256Digest(); + byte[] input = new byte[32]; + harakaCipher.Update(input, 0, input.Length); + byte[] output = new byte[48]; + harakaCipher.DoFinal(output, 17); + Assert.Fail("Output too short for digest result."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "output too short to receive digest")); + } + + // + // Offset output.. + // + try + { + byte[] input = new byte[32]; + for (int t = 0; t < input.Length; t++) + { + input[t] = (byte)t; + } + + byte[] expected256 = Hex.Decode("000000008027ccb87949774b78d0545fb72bf70c695c2a0923cbd47bba1159efbf2b2c1c"); + + Haraka256Digest harakaCipher = new Haraka256Digest(); + harakaCipher.Update(input, 0, input.Length); + byte[] output = new byte[harakaCipher.GetDigestSize() + 4]; + harakaCipher.DoFinal(output, 4); + Assert.IsTrue(Arrays.AreEqual(expected256, output)); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "output too short to receive digest")); + } + } + + void TestMonty() + { + int c = 0; + string[][] vectors = new string[][]{new string[] + { + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "e78599d7163ab58f1c90f0171c6fc4e852eb4b8cc29a4af63194fd9977c1de84" + }, + new string[]{ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "c4cebda63c00c4cd312f36ea92afd4b0f6048507c5b367326ef9d8fdd2d5c09a" + } + }; + + for (int i = 0; i != vectors.Length; i++) + { + // + // 1000 rounds of digest application, where alternative outputs are copied over alternate halves of the input. + // + string[] vector = vectors[i]; + + byte[] expected = Hex.Decode(vector[1]); + + // Load initial message. + + Haraka256Digest haraka = new Haraka256Digest(); + byte[] result = Hex.Decode(vector[0]); + for (int t = 0; t < 1000; t++) + { + haraka.Update(result, 0, result.Length); + haraka.DoFinal(result, 0); + } + Assert.IsTrue(Arrays.AreEqual(expected, result)); + + // + // Deliberately introduce incorrect value. + // + + result[0] ^= 1; + Assert.IsTrue(!Arrays.AreEqual(expected, result)); + c++; + } + } + + private bool Contains(string message, string sub) + { + return message.IndexOf(sub) >= 0; + } + + public override void PerformTest() + { + TestKnownVector(); + TestInputTooLong(); + TestInputTooShort(); + TestOutput(); + TestMonty(); + } + + //public static void Main() + //{ + // //runTest(new Haraka256DigestTest()); + // var t = new Haraka256DigestTest(); + // t.PerformTest(); + //} + } +} \ No newline at end of file diff --git a/crypto/test/src/crypto/test/Haraka512DigestTest.cs b/crypto/test/src/crypto/test/Haraka512DigestTest.cs new file mode 100644 index 000000000..634b20724 --- /dev/null +++ b/crypto/test/src/crypto/test/Haraka512DigestTest.cs @@ -0,0 +1,192 @@ +using System; +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace BouncyCastle.Crypto.Tests +{ + public class Haraka512DigestTest : SimpleTest + { + public override string Name + { + get { return "Haraka 512"; } + } + + public void TestKnownVector() + { + byte[] input = new byte[64]; + for (int t = 0; t < input.Length; t++) + { + input[t] = (byte)t; + } + + // From Appendix B, Haraka-512 v2, https://eprint.iacr.org/2016/098.pdf + byte[] expected512 = Hex.Decode("be7f723b4e80a99813b292287f306f625a6d57331cae5f34dd9277b0945be2aa"); + + Haraka512Digest haraka = new Haraka512Digest(); + haraka.Update(input, 0, input.Length); + byte[] output = new byte[haraka.GetDigestSize()]; + haraka.DoFinal(output, 0); + Assert.IsTrue(Arrays.AreEqual(expected512, output)); + } + + public void TestInputTooShort() + { + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] input = new byte[63]; + haraka.Update(input, 0, input.Length); + haraka.DoFinal(null, 0); + Assert.Fail("fail on input not 64 bytes."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "input must be exactly 64 bytes")); + } + } + + public void TestInputTooLong() + { + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] input = new byte[65]; + haraka.Update(input, 0, input.Length); + haraka.DoFinal(null, 0); + Assert.Fail("fail on input not 64 bytes."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "total input cannot be more than 64 bytes")); + } + } + + public void TestOutput() + { + // + // Buffer too short. + // + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] input = new byte[64]; + haraka.Update(input, 0, input.Length); + byte[] output = new byte[31]; + haraka.DoFinal(output, 0); + Assert.Fail("Output too short for digest result."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "output too short to receive digest")); + } + + // + // Offset puts end past length of buffer. + // + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] input = new byte[64]; + haraka.Update(input, 0, input.Length); + byte[] output = new byte[48]; + haraka.DoFinal(output, 17); + Assert.Fail("Output too short for digest result."); + } + catch (ArgumentException e) + { + Assert.IsTrue(Contains(e.Message, "output too short to receive digest")); + } + + // + // Offset output.. + // + { + byte[] input = new byte[64]; + for (int t = 0; t < input.Length; t++) + { + input[t] = (byte)t; + } + + byte[] expected512 = Hex.Decode("00000000be7f723b4e80a99813b292287f306f625a6d57331cae5f34dd9277b0945be2aa"); + + Haraka512Digest haraka = new Haraka512Digest(); + haraka.Update(input, 0, input.Length); + byte[] output = new byte[haraka.GetDigestSize() + 4]; + haraka.DoFinal(output, 4); + Assert.IsTrue(Arrays.AreEqual(expected512, output)); + } + + } + + void TestMonty() + { + int c = 0; + string[][] vectors = new string[][]{ + new string[]{ + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F", + "ABE210FE673F3B28E70E5100C476D82F61A7E2BDB3D8423FB0A15E5DE3D3A4DE" + }, + new string[]{ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "5F5ECB52C61F5036C96BE555D2E18C520AB3ED093954700C283A322D14DBFE02" + } + }; + + for (int i = 0; i != vectors.Length; i++) + { + // + // 1000 rounds of digest application, where alternative outputs are copied over alternate halves of the input. + // + string[] vector = vectors[i]; + + byte[] expected = Hex.Decode(vector[1]); + + // Load initial message. + byte[] input = Hex.Decode(vector[0]); + Haraka512Digest haraka = new Haraka512Digest(); + byte[] result = new byte[haraka.GetDigestSize()]; + for (int t = 0; t < 1000; t++) + { + haraka.Update(input, 0, input.Length); + haraka.DoFinal(result, 0); + + if ((t & 0x01) == 1) + { + Array.Copy(result, 0, input, 0, result.Length); + } + else + { + Array.Copy(result, 0, input, result.Length, result.Length); + } + } + Assert.IsTrue(Arrays.AreEqual(expected, result)); + + // + // Deliberately introduce incorrect value. + // + + result[0] ^= 1; + Assert.IsTrue(!Arrays.AreEqual(expected, result)); + c++; + } + } + + private bool Contains(string message, string sub) + { + return message.IndexOf(sub) >= 0; + } + + public override void PerformTest() + { + TestKnownVector(); + TestInputTooLong(); + TestInputTooShort(); + TestOutput(); + TestMonty(); + } + } +} \ No newline at end of file |