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); }
public static byte[] Encode(byte[] input, byte[] key, byte[] nonce) { var subNonce = new byte[12]; if (nonce.Length == 24) { var hNonce = new byte[16]; System.Buffer.BlockCopy(nonce, 0, hNonce, 0, 16); System.Buffer.BlockCopy(nonce, 16, subNonce, 4, 8); key = HChaCha20.Encode(key, hNonce); } else if (nonce.Length == 12) { System.Buffer.BlockCopy(nonce, 0, subNonce, 0, 12); } else { throw new System.ArgumentException(); } return(NormalEncode(input, key, subNonce)); }