protected /*virtual */ void UpdateRecordMacText(Poly1305 mac, BufferSegment buf) { mac.BlockUpdate(buf.Data, buf.Offset, buf.Count); int partial = buf.Count % 16; if (partial != 0) { mac.BlockUpdate(Zeroes, 0, 16 - partial); } }
private void testReset() { CipherKeyGenerator gen = new Poly1305KeyGenerator(); gen.Init(new KeyGenerationParameters(new SecureRandom(), 256)); byte[] k = gen.GenerateKey(); byte[] m = new byte[10000]; byte[] check = new byte[16]; byte[] output = new byte[16]; // Generate baseline IMac poly = new Poly1305(new AesFastEngine()); poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16])); poly.BlockUpdate(m, 0, m.Length); poly.DoFinal(check, 0); // Check reset after doFinal poly.BlockUpdate(m, 0, m.Length); poly.DoFinal(output, 0); if (!Arrays.AreEqual(check, output)) { Fail("Mac not reset after doFinal"); } // Check reset poly.Update((byte)1); poly.Update((byte)2); poly.Reset(); poly.BlockUpdate(m, 0, m.Length); poly.DoFinal(output, 0); if (!Arrays.AreEqual(check, output)) { Fail("Mac not reset after doFinal"); } // Check init resets poly.Update((byte)1); poly.Update((byte)2); poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16])); poly.BlockUpdate(m, 0, m.Length); poly.DoFinal(output, 0); if (!Arrays.AreEqual(check, output)) { Fail("Mac not reset after doFinal"); } }
public void PolyReferenceTests(byte[] key, byte[] iv, byte[] data, byte[] expected) { Poly pmac = new Poly(Common.AesFactory); pmac.Init(key, iv, 16); pmac.Process(new ArraySegment <byte>(data)); byte[] mac = pmac.Compute(); var bcpoly = new Poly1305(new AesEngine()); bcpoly.Init(new ParametersWithIV(new KeyParameter(key), iv)); bcpoly.BlockUpdate(data, 0, data.Length); byte[] bcmac = new byte[bcpoly.GetMacSize()]; bcpoly.DoFinal(bcmac, 0); var _key = string.Join(", ", key.Select(b => $"0x{b:x2}")); var _iv = string.Join(", ", iv.Select(b => $"0x{b:x2}")); var _data = string.Join(", ", data.Select(b => $"0x{b:x2}")); var _expected = string.Join(", ", bcmac.Select(b => $"0x{b:x2}")); Log.Verbose($"[InlineData(new byte[] {{{_key}}}, new byte[] {{{_iv}}}, new byte[] {{{_data}}}, new byte[] {{{_expected}}})]"); Assert.Equal(expected, mac); Assert.Equal(expected, bcmac); }
private byte[] CalcMac(byte[] key, byte[] nonce, byte[] cipherText, byte[] ad) { var mac = new Poly1305(); var polyKey = EncryptOrDecrypt(true, new byte[32], key, nonce, false); mac.Init(new KeyParameter(polyKey)); mac.BlockUpdate(ad, 0, ad.Length); Pad(mac, ad.Length); mac.BlockUpdate(cipherText, 0, cipherText.Length); Pad(mac, cipherText.Length); WriteLE(mac, ad.Length); WriteLE(mac, cipherText.Length); var tag = new byte[16]; var macreslen = mac.DoFinal(tag, 0); Debug.Assert(macreslen == 16); return(tag); }
/// <summary> /// Branca specification-level token generation /// </summary> /// <param name="payload">The payload to be encrypted into the Branca token</param> /// <param name="key">32-byte private key used to encrypt and decrypt the Branca token</param> /// <returns>Base62 encoded Branca Token</returns> public virtual string CreateToken(string payload, byte[] key) { if (string.IsNullOrWhiteSpace(payload)) { throw new ArgumentNullException(nameof(payload)); } if (!IsValidKey(key)) { throw new InvalidOperationException("Invalid encryption key"); } var nonce = new byte[24]; RandomNumberGenerator.Create().GetBytes(nonce); var timestamp = Convert.ToUInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); // header var header = new byte[29]; using (var stream = new MemoryStream(header)) { // version stream.WriteByte(0xBA); // timestamp stream.Write(BitConverter.GetBytes(timestamp), 0, 4); // nonce stream.Write(nonce, 0, nonce.Length); } var keyMaterial = new KeyParameter(key); var parameters = new ParametersWithIV(keyMaterial, nonce); var engine = new XChaChaEngine(); engine.Init(true, parameters); var plaintextBytes = Encoding.UTF8.GetBytes(payload); var ciphertext = new byte[plaintextBytes.Length + 16]; engine.ProcessBytes(plaintextBytes, 0, plaintextBytes.Length, ciphertext, 0); var poly = new Poly1305(); poly.Init(keyMaterial); poly.BlockUpdate(header, 0, header.Length); poly.DoFinal(ciphertext, plaintextBytes.Length); var tokenBytes = new byte[header.Length + ciphertext.Length]; Buffer.BlockCopy(header, 0, tokenBytes, 0, header.Length); Buffer.BlockCopy(ciphertext, 0, tokenBytes, header.Length, ciphertext.Length); return(Base62.Encode(tokenBytes)); }
private void Pad(Poly1305 mac, int length) { var n = length % 16; if (n != 0) { var padding = new byte[16 - n]; mac.BlockUpdate(padding, 0, padding.Length); } }
private static byte[] CalculateMac(byte[] key, byte[] data) { var tag = new byte[16]; Poly1305 poly = new Poly1305(); poly.Init(new KeyParameter(key)); poly.BlockUpdate(data, 0, data.Length); poly.DoFinal(tag, 0); return(tag); }
static bool crypto_aead_chacha20poly1305_ietf_decrypt_detached(Memory <byte> m, ReadOnlyMemory <byte> c, ReadOnlyMemory <byte> mac, ReadOnlyMemory <byte> ad, ReadOnlyMemory <byte> npub, ReadOnlyMemory <byte> k) { var kk = k._AsSegment(); var nn = npub._AsSegment(); var cc = c._AsSegment(); var aa = ad._AsSegment(); var mm = m._AsSegment(); byte[] block0 = new byte[64]; ChaCha7539Engine ctx = new ChaCha7539Engine(); ctx.Init(true, new ParametersWithIV(new KeyParameter(kk.Array, kk.Offset, kk.Count), nn.Array, nn.Offset, nn.Count)); ctx.ProcessBytes(block0, 0, block0.Length, block0, 0); Poly1305 state = new Poly1305(); state.Init(new KeyParameter(block0, 0, AeadChaCha20Poly1305KeySize)); state.BlockUpdate(aa.Array, aa.Offset, aa.Count); if ((aa.Count % 16) != 0) { state.BlockUpdate(zero15, 0, 16 - (aa.Count % 16)); } state.BlockUpdate(cc.Array, cc.Offset, cc.Count); if ((cc.Count % 16) != 0) { state.BlockUpdate(zero15, 0, 16 - (cc.Count % 16)); } byte[] slen = BitConverter.GetBytes((ulong)aa.Count); if (Env.IsBigEndian) { Array.Reverse(slen); } state.BlockUpdate(slen, 0, slen.Length); byte[] mlen = BitConverter.GetBytes((ulong)cc.Count); if (Env.IsBigEndian) { Array.Reverse(mlen); } state.BlockUpdate(mlen, 0, mlen.Length); byte[] computed_mac = new byte[AeadChaCha20Poly1305MacSize]; state.DoFinal(computed_mac, 0); if (computed_mac.AsSpan().SequenceEqual(mac.Span) == false) { return(false); } ctx.ProcessBytes(cc.Array, cc.Offset, cc.Count, mm.Array, mm.Offset); return(true); }
private void CheckVector(byte[] keyMaterial, byte[] input, byte[] tag) { Poly1305 poly1305 = new Poly1305(); poly1305.Init(new KeyParameter(keyMaterial)); poly1305.BlockUpdate(input, 0, input.Length); byte[] mac = new byte[poly1305.GetMacSize()]; poly1305.DoFinal(mac, 0); if (!Arrays.AreEqual(tag, mac)) { Fail("rfc7539", Hex.ToHexString(tag), Hex.ToHexString(mac)); } }
private byte[] EncryptXSalsa20Poly1305(byte[] bytes, byte[] key, byte[] nonce) { var salsa = new XSalsa20Engine(); var poly = new Poly1305(); salsa.Init(true, new ParametersWithIV(new KeyParameter(key), nonce)); byte[] subKey = new byte[key.Length]; salsa.ProcessBytes(subKey, 0, key.Length, subKey, 0); byte[] output = new byte[bytes.Length + poly.GetMacSize()]; salsa.ProcessBytes(bytes, 0, bytes.Length, output, poly.GetMacSize()); poly.Init(new KeyParameter(subKey)); poly.BlockUpdate(output, poly.GetMacSize(), bytes.Length); poly.DoFinal(output, 0); return(output); }
public void BasicPolyTests(int ivBytes, int dataBytes, int macSize) { RandomNumberGenerator rng = new RandomNumberGenerator(); byte[] iv = rng.Generate(ivBytes); byte[] key = rng.Generate(32); byte[] data = rng.Generate(dataBytes); Poly pmac = new Poly(Common.AesFactory); var bcpoly = new Poly1305(new AesEngine()); pmac.Init(key, iv, macSize); bcpoly.Init(new ParametersWithIV(new KeyParameter(key), iv)); pmac.Process(new ArraySegment <byte>(data)); byte[] mac = pmac.Compute(); bcpoly.BlockUpdate(data, 0, data.Length); byte[] bcmac = new byte[bcpoly.GetMacSize()]; bcpoly.DoFinal(bcmac, 0); bcmac = bcmac.Take(macSize).ToArray(); Assert.Equal(bcmac, mac); }
public void PolyReuseKeyTest(int ivBytes, int dataBytes, int macSize) { RandomNumberGenerator rng = new RandomNumberGenerator(); byte[] iv = rng.Generate(ivBytes); byte[] key = rng.Generate(32); byte[] data1 = rng.Generate(dataBytes); byte[] data2 = rng.Generate(dataBytes); var pmac = new Poly(Common.AesFactory); pmac.Init(key, iv, macSize); pmac.Process(new ArraySegment <byte>(data1)); byte[] mac1 = pmac.Compute(); pmac.Init(key, iv, macSize); pmac.Process(new ArraySegment <byte>(data2)); byte[] mac2 = pmac.Compute(); var bcpoly1 = new Poly1305(new AesEngine()); bcpoly1.Init(new ParametersWithIV(new KeyParameter(key), iv)); bcpoly1.BlockUpdate(data1, 0, data1.Length); byte[] bcmac1 = new byte[bcpoly1.GetMacSize()]; bcpoly1.DoFinal(bcmac1, 0); bcmac1 = bcmac1.Take(macSize).ToArray(); var bcpoly2 = new Poly1305(new AesEngine()); bcpoly2.Init(new ParametersWithIV(new KeyParameter(key), iv)); bcpoly2.BlockUpdate(data2, 0, data2.Length); byte[] bcmac2 = new byte[bcpoly2.GetMacSize()]; bcpoly2.DoFinal(bcmac2, 0); bcmac2 = bcmac2.Take(macSize).ToArray(); Assert.Equal(bcmac1, mac1); Assert.Equal(bcmac2, mac2); }
public static void SelfTest() { byte[] key = new byte[] { 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 }; byte[] nonce = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; byte[] cipherText = new byte[] { 0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4, 0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd, 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89, 0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2, 0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee, 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0, 0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00, 0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf, 0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce, 0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81, 0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd, 0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55, 0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61, 0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38, 0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0, 0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4, 0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46, 0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9, 0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e, 0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e, 0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15, 0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a, 0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea, 0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a, 0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99, 0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e, 0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10, 0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10, 0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94, 0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30, 0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf, 0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29, 0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70, 0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22, 0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, 0x38 }; byte[] aad = new byte[] { 0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x91 }; byte[] plainText = new byte[] { 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80, 0x9d }; Poly1305 p = new Poly1305(); byte[] pKey = new byte[] { 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b }; KeyParameter paramsX = new KeyParameter(pKey); p.Init(paramsX); byte[] msg = UTF8Encoding.ASCII.GetBytes("Cryptographic Forum Research Group"); p.BlockUpdate(msg, 0, msg.Length); byte[] output = new byte[30]; p.DoFinal(output, 0); ChaCha20Poly1305 cipher = new ChaCha20Poly1305(); KeyParameter ContentKey = new KeyParameter(key); AeadParameters parameters = new AeadParameters(ContentKey, 128, nonce, aad); cipher.Init(true, parameters); byte[] C = new byte[cipher.GetOutputSize(plainText.Length)]; int len = cipher.ProcessBytes(plainText, 0, plainText.Length, C, 0); len += cipher.DoFinal(C, len); }
public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len) { poly.BlockUpdate(inBytes, inOff, len); aadLength += len; }
protected /*virtual */ void UpdateRecordMacLength(Poly1305 mac, int len) { byte[] longLen = Pack.UInt64_To_LE((ulong)len); mac.BlockUpdate(longLen, 0, longLen.Length); }
/// <summary> /// Branca specification level token decryption. /// </summary> /// <param name="token">Base62 encoded Branca token</param> /// <param name="key">32-byte private key used to encrypt and decrypt the Branca token</param> /// <returns>Pared and decrypted Branca Token</returns> public virtual BrancaToken DecryptToken(string token, byte[] key) { if (string.IsNullOrWhiteSpace(token)) { throw new ArgumentNullException(nameof(token)); } if (!CanReadToken(token)) { throw new InvalidCastException("Unable to read token"); } if (!IsValidKey(key)) { throw new InvalidOperationException("Invalid decryption key"); } var tokenBytes = Base62.Decode(token); using (var stream = new MemoryStream(tokenBytes, false)) { // header var header = GuaranteedRead(stream, 29); byte[] nonce; uint timestamp; using (var headerStream = new MemoryStream(header)) { // version var version = headerStream.ReadByte(); if (version != 0xBA) { throw new SecurityTokenException("Unsupported Branca version"); } // timestamp var timestampBytes = GuaranteedRead(headerStream, 4); timestamp = BitConverter.ToUInt32(timestampBytes, 0); // nonce nonce = GuaranteedRead(headerStream, 24); } // ciphertext var ciphertextLength = (stream.Length - 16) - stream.Position; var ciphertext = GuaranteedRead(stream, (int)ciphertextLength); // tag var tag = GuaranteedRead(stream, 16); // XChaCha20-Poly1305 var keyMaterial = new KeyParameter(key); var parameters = new ParametersWithIV(keyMaterial, nonce); var headerMac = new byte[16]; var poly1305 = new Poly1305(); poly1305.Init(keyMaterial); poly1305.BlockUpdate(header, 0, header.Length); poly1305.DoFinal(headerMac, 0); if (!headerMac.SequenceEqual(tag)) { throw new SecurityTokenException("Invalid message authentication code"); } var engine = new XChaChaEngine(); engine.Init(false, parameters); var decryptedPlaintext = new byte[ciphertext.Length]; engine.ProcessBytes(ciphertext, 0, ciphertext.Length, decryptedPlaintext, 0); return(new BrancaToken( Encoding.UTF8.GetString(decryptedPlaintext), timestamp)); } }
private void WriteLE(Poly1305 mac, int length) { var s = Utils.ToBytes((ulong)length, true); mac.BlockUpdate(s, 0, 8); }
private void testSequential() { // Sequential test, adapted from test-poly1305aes int len; byte[] kr = new byte[32]; byte[] m = new byte[MAXLEN]; byte[] n = new byte[16]; byte[] output = new byte[16]; int c = 0; IMac mac = new Poly1305(new AesFastEngine()); for (int loop = 0; loop < 13; loop++) { len = 0; for (;;) { c++; mac.Init(new ParametersWithIV(new KeyParameter(kr), n)); mac.BlockUpdate(m, 0, len); mac.DoFinal(output, 0); // if (c == 678) // { // TestCase tc = CASES[0]; // // if (!Arrays.AreEqual(tc.key, kr)) // { // System.err.println("Key bad"); // System.err.println(Hex.ToHexString(tc.key))); // System.err.println(Hex.ToHexString(kr))); // System.exit(1); // } // if (!Arrays.AreEqual(tc.nonce, n)) // { // System.err.println("Nonce bad"); // System.exit(1); // } // System.out.printf("[%d] m: %s\n", c, Hex.ToHexString(m, 0, len))); // System.out.printf("[%d] K: %s\n", c, new string(Hex.encodje(kr))); // System.out.printf("[%d] N: %s\n", c, Hex.ToHexString(n))); // System.out.printf("[%d] M: ", c); // } // System.out.printf("%d/%s\n", c, Hex.ToHexString(out))); if (len >= MAXLEN) { break; } n[0] = (byte)(n[0] ^ loop); for (int i = 0; i < 16; ++i) { n[i] ^= output[i]; } if (len % 2 != 0) { for (int i = 0; i < 16; ++i) { kr[i] ^= output[i]; } } if (len % 3 != 0) { for (int i = 0; i < 16; ++i) { kr[i + 16] ^= output[i]; } } Poly1305KeyGenerator.Clamp(kr); m[len++] ^= output[0]; } } // Output after 13 loops as generated by poly1305 ref if (c != 13013 || !Arrays.AreEqual(output, Hex.Decode("c96f60a23701a5b0fd2016f58cbe4f7e"))) { Fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", Hex.ToHexString(output)); } }