private static byte[] XChaCha20Poly1305(bool isEncryption, byte[] key, byte[] nonce, byte[] message, byte[] aad = null) { if (key.Length != 32) { throw new ArgumentException("Key must be 32 bytes", nameof(key)); } if (nonce.Length != 24) { throw new ArgumentException("Nonce must be 24 bytes", nameof(nonce)); } // subkey (hchacha20(key, nonce[0:15])) var subkey = HChaCha20.CreateSubkey(key, nonce); // TODO: parse nonce bytes to pass through here instead // nonce (chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23]) var chaChaNonce = new byte[12]; Array.Copy(new byte[] { 0, 0, 0, 0 }, chaChaNonce, 4); Array.Copy(nonce, 16, chaChaNonce, 4, 8); // chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr) var outputLength = message.Length; if (isEncryption) { outputLength += 16; } else { outputLength -= 16; } var output = new byte[outputLength]; var keyMaterial = new KeyParameter(subkey); var parameters = new ParametersWithIV(keyMaterial, chaChaNonce); var chaCha20Poly1305 = new ChaCha20Poly1305(); chaCha20Poly1305.Init(isEncryption, parameters); // if aditional data present if (aad != null) { chaCha20Poly1305.ProcessAadBytes(aad, 0, aad.Length); } var len = chaCha20Poly1305.ProcessBytes(message, 0, message.Length, output, 0); chaCha20Poly1305.DoFinal(output, len); return(output); }
private void CheckTestCase( ChaCha20Poly1305 encCipher, ChaCha20Poly1305 decCipher, string testName, byte[] SA, byte[] P, byte[] C, byte[] T) { byte[] enc = new byte[encCipher.GetOutputSize(P.Length)]; if (SA != null) { encCipher.ProcessAadBytes(SA, 0, SA.Length); } int len = encCipher.ProcessBytes(P, 0, P.Length, enc, 0); len += encCipher.DoFinal(enc, len); if (enc.Length != len) { Fail("encryption reported incorrect length: " + testName); } byte[] mac = encCipher.GetMac(); byte[] data = new byte[P.Length]; Array.Copy(enc, 0, data, 0, data.Length); byte[] tail = new byte[enc.Length - P.Length]; Array.Copy(enc, P.Length, tail, 0, tail.Length); if (!AreEqual(C, data)) { Fail("incorrect encrypt in: " + testName); } if (!AreEqual(T, mac)) { Fail("getMac() returned wrong mac in: " + testName); } if (!AreEqual(T, tail)) { Fail("stream contained wrong mac in: " + testName); } byte[] dec = new byte[decCipher.GetOutputSize(enc.Length)]; if (SA != null) { decCipher.ProcessAadBytes(SA, 0, SA.Length); } len = decCipher.ProcessBytes(enc, 0, enc.Length, dec, 0); len += decCipher.DoFinal(dec, len); mac = decCipher.GetMac(); data = new byte[C.Length]; Array.Copy(dec, 0, data, 0, data.Length); if (!AreEqual(P, data)) { Fail("incorrect decrypt in: " + testName); } }
private void RandomTest(SecureRandom random) { int kLength = 32; byte[] K = new byte[kLength]; random.NextBytes(K); int pHead = random.Next(256); int pLength = random.Next(65536); int pTail = random.Next(256); byte[] P = new byte[pHead + pLength + pTail]; random.NextBytes(P); int aLength = random.Next(256); byte[] A = new byte[aLength]; random.NextBytes(A); int saLength = random.Next(256); byte[] SA = new byte[saLength]; random.NextBytes(SA); int nonceLength = 12; byte[] nonce = new byte[nonceLength]; random.NextBytes(nonce); AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, nonce, A); ChaCha20Poly1305 cipher = InitCipher(true, parameters); int ctLength = cipher.GetOutputSize(pLength); byte[] C = new byte[saLength + ctLength]; Array.Copy(SA, 0, C, 0, saLength); int split = NextInt(random, saLength + 1); cipher.ProcessAadBytes(C, 0, split); cipher.ProcessAadBytes(C, split, saLength - split); int predicted = cipher.GetUpdateOutputSize(pLength); int len = cipher.ProcessBytes(P, pHead, pLength, C, saLength); if (predicted != len) { Fail("encryption reported incorrect update length in randomised test"); } len += cipher.DoFinal(C, saLength + len); if (ctLength != len) { Fail("encryption reported incorrect length in randomised test"); } byte[] encT = cipher.GetMac(); byte[] tail = new byte[ctLength - pLength]; Array.Copy(C, saLength + pLength, tail, 0, tail.Length); if (!AreEqual(encT, tail)) { Fail("stream contained wrong mac in randomised test"); } cipher.Init(false, parameters); int decPHead = random.Next(256); int decPLength = cipher.GetOutputSize(ctLength); int decPTail = random.Next(256); byte[] decP = new byte[decPHead + decPLength + decPTail]; split = NextInt(random, saLength + 1); cipher.ProcessAadBytes(C, 0, split); cipher.ProcessAadBytes(C, split, saLength - split); predicted = cipher.GetUpdateOutputSize(ctLength); len = cipher.ProcessBytes(C, saLength, ctLength, decP, decPHead); if (predicted != len) { Fail("decryption reported incorrect update length in randomised test"); } len += cipher.DoFinal(decP, decPHead + len); if (!AreEqual(P, pHead, pHead + pLength, decP, decPHead, decPHead + decPLength)) { Fail("incorrect decrypt in randomised test"); } byte[] decT = cipher.GetMac(); if (!AreEqual(encT, decT)) { Fail("decryption produced different mac from encryption"); } // // key reuse test // cipher.Init(false, AeadTestUtilities.ReuseKey(parameters)); decPHead = random.Next(256); decPLength = cipher.GetOutputSize(ctLength); decPTail = random.Next(256); decP = new byte[decPHead + decPLength + decPTail]; split = NextInt(random, saLength + 1); cipher.ProcessAadBytes(C, 0, split); cipher.ProcessAadBytes(C, split, saLength - split); len = cipher.ProcessBytes(C, saLength, ctLength, decP, decPHead); len += cipher.DoFinal(decP, decPHead + len); if (!AreEqual(P, pHead, pHead + pLength, decP, decPHead, decPHead + decPLength)) { Fail("incorrect decrypt in randomised test"); } decT = cipher.GetMac(); if (!AreEqual(encT, decT)) { Fail("decryption produced different mac from encryption"); } }