public void EncryptDecryptWithNonceTest() { var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); for (var i = 0; i < 100; i++) { var message = new byte[100]; rnd.NextBytes(message); var aad = new byte[16]; rnd.NextBytes(aad); var nonce = new byte[12]; rnd.NextBytes(nonce); var ciphertext = aead.Encrypt(message, aad, nonce); var decrypted = aead.Decrypt(ciphertext, aad, nonce); //Assert.AreEqual(message, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted)); } }
public void EncryptDecryptLongMessagesWithNonceTest() { var rnd = new Random(); var dataSize = 16; while (dataSize <= (1 << 24)) { var plaintext = new byte[dataSize]; rnd.NextBytes(plaintext); var aad = new byte[dataSize / 3]; rnd.NextBytes(aad); var nonce = new byte[12]; rnd.NextBytes(nonce); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); var ciphertext = aead.Encrypt(plaintext, aad, nonce); var decrypted = aead.Decrypt(ciphertext, aad, nonce); //Assert.AreEqual(plaintext, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(plaintext, decrypted)); dataSize += 5 * dataSize / 11; } }
/// <summary>Method which encrypts a string using ChaCha20.</summary> private void Encrypt() { var enc = new ChaCha20Poly1305(Encoding.ASCII.GetBytes(Key)); EncryptedPassword = enc.Encrypt(Encoding.ASCII.GetBytes(HashedPassword)); EncryptedPasswordb64 = Convert.ToBase64String(EncryptedPassword); }
public void EncryptWhenNonceLengthIsInvalidFails() { // Arrange, Act & Assert var aead = new ChaCha20Poly1305(new byte[Snuffle.KEY_SIZE_IN_BYTES]); Assert.Throws <CryptographicException>(() => aead.Encrypt(new byte[0], new byte[0], new byte[12 + TestHelpers.ReturnRandomPositiveNegative()]), EXCEPTION_MESSAGE_NONCE_LENGTH); }
public void RandomNonceTest() { var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); var message = new byte[0]; var aad = new byte[0]; var ciphertexts = new HashSet <string>(); var samples = 1 << 17; for (var i = 0; i < samples; i++) { var ct = aead.Encrypt(message, aad); var ctHex = CryptoBytes.ToHexStringLower(ct); Assert.IsFalse(ciphertexts.Contains(ctHex)); ciphertexts.Add(ctHex); } Assert.AreEqual(samples, ciphertexts.Count); }
public void EncryptWhenNonceIsEmptyFails() { // Arrange, Act & Assert var aead = new ChaCha20Poly1305(new byte[Snuffle.KEY_SIZE_IN_BYTES]); Assert.Throws <CryptographicException>(() => aead.Encrypt(new byte[0], new byte[0], new byte[0]), EXCEPTION_MESSAGE_NONCE_LENGTH); }
//Can we change the ChaCha20Poly1305 input to some kind of ICrypto interface or action with 'Encrypt' and 'Decrypt'? private void Pack(IBufferWriter <byte> output, CryptoDtoHeaderDto header, ChaCha20Poly1305 crypto, ReadOnlySpan <byte> dtoNameBuffer, ReadOnlySpan <byte> dtoBuffer) { lock (bufferLock) { headerBuffer.Clear(); MessagePackSerializer.Serialize(headerBuffer, header); ReadOnlySpan <byte> headerBytes = headerBuffer.WrittenSpan; ushort headerLength = (ushort)headerBytes.Length; BinaryPrimitives.WriteUInt16LittleEndian(headerLengthBytes, headerLength); ushort dtoNameLength = (ushort)dtoNameBuffer.Length; BinaryPrimitives.WriteUInt16LittleEndian(dtoNameLengthBytes, dtoNameLength); ushort dtoLength = (ushort)dtoBuffer.Length; BinaryPrimitives.WriteUInt16LittleEndian(dtoLengthBytes, dtoLength); switch (header.Mode) { case CryptoDtoMode.ChaCha20Poly1305: { int adLength = 2 + headerLength; int aeLength = 2 + dtoNameLength + 2 + dtoLength; // Copy data into associated data buffer adBuffer.Clear(); adBuffer.Write(headerLengthBytes); adBuffer.Write(headerBytes); // Copy data into authenticated encryption buffer aeBuffer.Clear(); aeBuffer.Write(dtoNameLengthBytes); aeBuffer.Write(dtoNameBuffer); aeBuffer.Write(dtoLengthBytes); aeBuffer.Write(dtoBuffer); Span <byte> nonceSpan = new Span <byte>(nonceBytes); BinaryPrimitives.WriteUInt64LittleEndian(nonceSpan.Slice(4), header.Sequence); var adSpan = adBuffer.WrittenSpan; var aeSpan = aeBuffer.WrittenSpan; var cipherTextSpan = cipherText.Span.Slice(0, aeLength); cipherTextSpan.Clear(); Span <byte> tagSpan = tagBuffer; tagSpan.Clear(); crypto.Encrypt(nonceSpan, aeSpan, cipherTextSpan, tagSpan, adSpan); output.Write(adSpan); output.Write(cipherTextSpan); output.Write(tagSpan); break; } default: throw new CryptographicException("Mode not recognised"); } } }
public void ModifiedCiphertextFails() { var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aad = new byte[16]; rnd.NextBytes(aad); var message = new byte[32]; rnd.NextBytes(message); var aead = new ChaCha20Poly1305(key); var ciphertext = aead.Encrypt(message, aad); // Flipping bits for (var b = 0; b < ciphertext.Length; b++) { for (var bit = 0; bit < 8; bit++) { var modified = new byte[ciphertext.Length]; Array.Copy(ciphertext, modified, ciphertext.Length); modified[b] ^= (byte)(1 << bit); Assert.Throws <CryptographicException>(() => aead.Decrypt(modified, aad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); } } // Truncate the message for (var length = 0; length < ciphertext.Length; length++) { var modified = new byte[length]; Array.Copy(ciphertext, modified, length); Assert.Throws <CryptographicException>(() => aead.Decrypt(modified, aad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); } // Modify AAD for (var b = 0; b < aad.Length; b++) { for (var bit = 0; bit < 8; bit++) { var modified = new byte[aad.Length]; Array.Copy(aad, modified, aad.Length); modified[b] ^= (byte)(1 << bit); Assert.Throws <CryptographicException>(() => aead.Decrypt(modified, aad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); } } }
public static void TwoEncryptionsAndDecryptionsUsingOneInstance() { byte[] key = "fde37f01fe9ca260f432e0ed98b3e0bb23895ca1ca1ce2cfcaaca2ccc98889d7".HexToByteArray(); byte[] originalData1 = Enumerable.Range(1, 15).Select((x) => (byte)x).ToArray(); byte[] originalData2 = Enumerable.Range(14, 97).Select((x) => (byte)x).ToArray(); byte[] associatedData2 = Enumerable.Range(100, 109).Select((x) => (byte)x).ToArray(); byte[] nonce1 = "b41329dd64af2c3036661b46".HexToByteArray(); byte[] nonce2 = "8ba10892e8b87d031196bf99".HexToByteArray(); byte[] expectedCiphertext1 = "75f5aafbbabab80a3cfa2ecfd1bc58".HexToByteArray(); byte[] expectedTag1 = "1ed70acc454fba01f0354e93eba9b428".HexToByteArray(); byte[] expectedCiphertext2 = ( "f95cc19929463ba96a2cfc21fac5345ec308e2748995ba285af6b21ca3d665bc" + "00144604b38e9645fb2d5f5893fc78871bd8f5fc91caaa013eac5f80397fd65c" + "358c239f013f3c75da17ddbd14de01eb67f5204dfa787986fb27a098fe21b2c5" + "07").HexToByteArray(); byte[] expectedTag2 = "9877f87f29f68b5f9efb071c1351ccf6".HexToByteArray(); using (var chaChaPoly = new ChaCha20Poly1305(key)) { byte[] ciphertext1 = new byte[originalData1.Length]; byte[] tag1 = new byte[expectedTag1.Length]; chaChaPoly.Encrypt(nonce1, originalData1, ciphertext1, tag1); Assert.Equal(expectedCiphertext1, ciphertext1); Assert.Equal(expectedTag1, tag1); byte[] ciphertext2 = new byte[originalData2.Length]; byte[] tag2 = new byte[expectedTag2.Length]; chaChaPoly.Encrypt(nonce2, originalData2, ciphertext2, tag2, associatedData2); Assert.Equal(expectedCiphertext2, ciphertext2); Assert.Equal(expectedTag2, tag2); byte[] plaintext1 = new byte[originalData1.Length]; chaChaPoly.Decrypt(nonce1, ciphertext1, tag1, plaintext1); Assert.Equal(originalData1, plaintext1); byte[] plaintext2 = new byte[originalData2.Length]; chaChaPoly.Decrypt(nonce2, ciphertext2, tag2, plaintext2, associatedData2); Assert.Equal(originalData2, plaintext2); } }
public void ModifiedAssociatedDataFails() { var rnd = new Random(); var key = new byte[Snuffle.KEY_SIZE_IN_BYTES]; rnd.NextBytes(key); var aead = new ChaCha20Poly1305(key); var aad = new byte[0]; for (var msgSize = 0; msgSize < 75; msgSize++) { var message = new byte[msgSize]; rnd.NextBytes(message); // encrypting with aad as a 0-length array var ciphertext = aead.Encrypt(message, aad); var decrypted = aead.Decrypt(ciphertext, aad); //Assert.AreEqual(message, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted)); var decrypted2 = aead.Decrypt(ciphertext, null); //Assert.AreEqual(message, decrypted2); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted2)); var badAad = new byte[] { 1, 2, 3 }; Assert.Throws <CryptographicException>(() => aead.Decrypt(ciphertext, badAad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); // encrypting with aad equal to null ciphertext = aead.Encrypt(message, null); decrypted = aead.Decrypt(ciphertext, aad); //Assert.AreEqual(message, decrypted); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted)); decrypted2 = aead.Decrypt(ciphertext, null); //Assert.AreEqual(message, decrypted2); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(message, decrypted2)); Assert.Throws <CryptographicException>(() => aead.Decrypt(ciphertext, badAad), SnufflePoly1305.AEAD_EXCEPTION_INVALID_TAG); } }
private static byte[] Pack(string channelTag, CryptoDtoMode mode, ReadOnlySpan <byte> transmitKey, ulong sequenceToBeSent, byte[] dtoNameBuffer, byte[] dtoBuffer) { CryptoDtoHeaderDto header = new CryptoDtoHeaderDto { ChannelTag = channelTag, Sequence = sequenceToBeSent, Mode = mode }; var headerBuffer = MessagePackSerializer.Serialize(header); ushort headerLength = (ushort)headerBuffer.Length; ushort dtoNameLength = (ushort)dtoNameBuffer.Length; ushort dtoLength = (ushort)dtoBuffer.Length; switch (header.Mode) { case CryptoDtoMode.ChaCha20Poly1305: { int aePayloadLength = 2 + dtoNameLength + 2 + dtoLength; var aePayloadBuffer = new byte[aePayloadLength]; Array.Copy(BitConverter.GetBytes(dtoNameLength), 0, aePayloadBuffer, 0, 2); Array.Copy(dtoNameBuffer, 0, aePayloadBuffer, 2, dtoNameLength); Array.Copy(BitConverter.GetBytes(dtoLength), 0, aePayloadBuffer, 2 + dtoNameLength, 2); Array.Copy(dtoBuffer, 0, aePayloadBuffer, 2 + dtoNameLength + 2, dtoLength); int adPayloadLength = 2 + headerLength; var adPayloadBuffer = new byte[adPayloadLength]; Array.Copy(BitConverter.GetBytes(headerLength), 0, adPayloadBuffer, 0, 2); Array.Copy(headerBuffer, 0, adPayloadBuffer, 2, headerLength); Span <byte> nonceBuffer = stackalloc byte[Aead.NonceSize]; BinaryPrimitives.WriteUInt64LittleEndian(nonceBuffer.Slice(4), header.Sequence); var aead = new ChaCha20Poly1305(transmitKey.ToArray()); byte[] aeadPayload = aead.Encrypt(aePayloadBuffer, adPayloadBuffer, nonceBuffer); int aeadPayloadLength = aeadPayload.Length; byte[] packetBuffer = new byte[2 + headerLength + aeadPayloadLength]; Array.Copy(BitConverter.GetBytes(headerLength), 0, packetBuffer, 0, 2); Array.Copy(headerBuffer, 0, packetBuffer, 2, headerLength); Array.Copy(aeadPayload, 0, packetBuffer, 2 + headerLength, aeadPayloadLength); return(packetBuffer); } default: throw new CryptographicException("Mode not recognised"); } }
public static void EncryptDecryptNullTag() { byte[] key = "fde37f01fe9ca260f432e0ed98b3e0bb23895ca1ca1ce2cfcaaca2ccc98889d7".HexToByteArray(); byte[] nonce = new byte[NonceSizeInBytes]; byte[] plaintext = new byte[0]; byte[] ciphertext = new byte[0]; using (var chaChaPoly = new ChaCha20Poly1305(key)) { Assert.Throws <ArgumentNullException>(() => chaChaPoly.Encrypt(nonce, plaintext, ciphertext, (byte[])null)); Assert.Throws <ArgumentNullException>(() => chaChaPoly.Decrypt(nonce, ciphertext, (byte[])null, plaintext)); } }
public static void PlaintextAndCiphertextSizeDiffer(int ptLen, int ctLen) { byte[] key = new byte[KeySizeInBytes]; byte[] nonce = new byte[NonceSizeInBytes]; byte[] plaintext = new byte[ptLen]; byte[] ciphertext = new byte[ctLen]; byte[] tag = new byte[TagSizeInBytes]; using (var chaChaPoly = new ChaCha20Poly1305(key)) { Assert.Throws <ArgumentException>(() => chaChaPoly.Encrypt(nonce, plaintext, ciphertext, tag)); Assert.Throws <ArgumentException>(() => chaChaPoly.Decrypt(nonce, ciphertext, tag, plaintext)); } }
public static void Rfc8439Tests(AEADTest testCase) { using (var chaChaPoly = new ChaCha20Poly1305(testCase.Key)) { byte[] ciphertext = new byte[testCase.Plaintext.Length]; byte[] tag = new byte[testCase.Tag.Length]; chaChaPoly.Encrypt(testCase.Nonce, testCase.Plaintext, ciphertext, tag, testCase.AssociatedData); Assert.Equal(testCase.Ciphertext, ciphertext); Assert.Equal(testCase.Tag, tag); byte[] plaintext = new byte[testCase.Plaintext.Length]; chaChaPoly.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData); Assert.Equal(testCase.Plaintext, plaintext); } }
public static void InvalidTagSize(int tagSize) { int dataLength = 30; byte[] plaintext = Enumerable.Range(1, dataLength).Select((x) => (byte)x).ToArray(); byte[] ciphertext = new byte[dataLength]; byte[] key = RandomNumberGenerator.GetBytes(KeySizeInBytes); byte[] nonce = RandomNumberGenerator.GetBytes(NonceSizeInBytes); byte[] tag = new byte[tagSize]; using (var chaChaPoly = new ChaCha20Poly1305(key)) { Assert.Throws <ArgumentException>("tag", () => chaChaPoly.Encrypt(nonce, plaintext, ciphertext, tag)); } }
public static void InplaceEncryptDecrypt() { byte[] key = "fde37f01fe9ca260f432e0ed98b3e0bb23895ca1ca1ce2cfcaaca2ccc98889d7".HexToByteArray(); byte[] nonce = RandomNumberGenerator.GetBytes(NonceSizeInBytes); byte[] originalPlaintext = new byte[] { 1, 2, 8, 12, 16, 99, 0 }; byte[] data = (byte[])originalPlaintext.Clone(); byte[] tag = new byte[TagSizeInBytes]; using (var chaChaPoly = new ChaCha20Poly1305(key)) { chaChaPoly.Encrypt(nonce, data, data, tag); Assert.NotEqual(originalPlaintext, data); chaChaPoly.Decrypt(nonce, data, tag, data); Assert.Equal(originalPlaintext, data); } }
public static void Rfc8439TestsTamperTag(AEADTest testCase) { using (var chaChaPoly = new ChaCha20Poly1305(testCase.Key)) { byte[] ciphertext = new byte[testCase.Plaintext.Length]; byte[] tag = new byte[testCase.Tag.Length]; chaChaPoly.Encrypt(testCase.Nonce, testCase.Plaintext, ciphertext, tag, testCase.AssociatedData); Assert.Equal(testCase.Ciphertext, ciphertext); Assert.Equal(testCase.Tag, tag); tag[0] ^= 1; byte[] plaintext = RandomNumberGenerator.GetBytes(testCase.Plaintext.Length); Assert.Throws <CryptographicException>( () => chaChaPoly.Decrypt(testCase.Nonce, ciphertext, tag, plaintext, testCase.AssociatedData)); Assert.Equal(new byte[plaintext.Length], plaintext); } }
public string Encode(string payload, int?timestamp = null) { if (!timestamp.HasValue) { timestamp = (int)DateTime.UtcNow.Ticks; } var versionByte = new byte[VersionByte]; Buffer.BlockCopy(Version.ToCharArray(), 0, versionByte, 0, VersionByte); var nonceBytes = new byte[NonceBytes]; var rng = new RNGCryptoServiceProvider(); rng.GetBytes(nonceBytes); var timestampBytes = new byte[TimestampBytes]; Buffer.BlockCopy(timestamp.ToString().ToCharArray(), 0, timestampBytes, 0, timestampBytes.Length); var headerBytes = new byte[HeaderBytes]; Buffer.BlockCopy(versionByte, 0, headerBytes, 0, VersionByte); Buffer.BlockCopy(timestampBytes, 0, headerBytes, VersionByte, TimestampBytes); Buffer.BlockCopy(nonceBytes, 0, headerBytes, VersionByte + TimestampBytes, NonceBytes); var plainTextBytes = new byte[payload.GetBytes().Length]; Buffer.BlockCopy(payload.GetBytes(), 0, plainTextBytes, 0, plainTextBytes.Length); var keyBytes = new byte[Snuffle.KEY_SIZE_IN_BYTES]; Buffer.BlockCopy(_key.ToCharArray(), 0, keyBytes, 0, _key.ToCharArray().Length); var aead = new ChaCha20Poly1305(keyBytes); var cipherTextBytes = aead.Encrypt(plainTextBytes, null, nonceBytes); var tokenBytes = new byte[headerBytes.Length + cipherTextBytes.Length]; Buffer.BlockCopy(headerBytes, 0, tokenBytes, 0, headerBytes.Length); Buffer.BlockCopy(cipherTextBytes, 0, tokenBytes, headerBytes.Length, cipherTextBytes.Length); return(tokenBytes.ToBase62()); }
public void ChaCha20Poly1305TestVector2() { // https://tools.ietf.org/html/rfc8439 // Arrange foreach (var test in Rfc8439TestVector.Rfc7634AeadTestVectors) { // Act var aead = new ChaCha20Poly1305(test.Key); var ct = aead.Encrypt(test.PlainText, test.Aad, test.Nonce); Assert.That(ct, Is.EqualTo(CryptoBytes.Combine(test.CipherText, test.Tag))); var output = aead.Decrypt(ct, test.Aad, test.Nonce); // Assert //Assert.That(output, Is.EqualTo(test.PlainText)); Assert.IsTrue(CryptoBytes.ConstantTimeEquals(test.PlainText, output)); } }
public static void ValidNonceAndTagSize() { const int dataLength = 35; byte[] plaintext = Enumerable.Range(1, dataLength).Select((x) => (byte)x).ToArray(); byte[] ciphertext = new byte[dataLength]; byte[] key = RandomNumberGenerator.GetBytes(KeySizeInBytes); byte[] nonce = RandomNumberGenerator.GetBytes(NonceSizeInBytes); byte[] tag = new byte[TagSizeInBytes]; using (var chaChaPoly = new ChaCha20Poly1305(key)) { chaChaPoly.Encrypt(nonce, plaintext, ciphertext, tag); byte[] decrypted = new byte[dataLength]; chaChaPoly.Decrypt(nonce, ciphertext, tag, decrypted); Assert.Equal(plaintext, decrypted); } }
public static void Test(string[] testVector) { var plaintext = testVector[0]; var aad = testVector[1]; var key = testVector[2]; var nonce = testVector[3]; var ciphertext = testVector[4]; var tag = testVector[5]; var a = new ChaCha20Poly1305(); using (var k = Key.Import(a, key.DecodeHex(), KeyBlobFormat.RawSymmetricKey)) { var b = a.Encrypt(k, new Nonce(nonce.DecodeHex(), 0), aad.DecodeHex(), plaintext.DecodeHex()); Assert.Equal((ciphertext + tag).DecodeHex(), b); var r = a.Decrypt(k, new Nonce(nonce.DecodeHex(), 0), aad.DecodeHex(), b); Assert.Equal(plaintext.DecodeHex(), r); } }
public int EncryptWithAd(ReadOnlySpan <byte> ad, ReadOnlySpan <byte> plaintext, Span <byte> ciphertext) { Debug.Assert(_key.Length == Aead.KEY_SIZE); Debug.Assert(ciphertext.Length >= plaintext.Length + Aead.TAG_SIZE); Span <byte> nonce = stackalloc byte[Aead.NONCE_SIZE]; BinaryPrimitives.WriteUInt64LittleEndian(nonce.Slice(4), _nonce); var cipher = new ChaCha20Poly1305(_key); var cipherTextOutput = ciphertext.Slice(0, plaintext.Length); var tag = ciphertext.Slice(plaintext.Length, Aead.TAG_SIZE); _logger.LogDebug($"Encrypting text length - {plaintext.Length} with nonce - {_nonce}"); cipher.Encrypt(nonce, plaintext.ToArray(), cipherTextOutput, tag, ad.ToArray()); _nonce++; return(cipherTextOutput.Length + tag.Length); }
public static void EncryptTamperAADDecrypt(int dataLength, int additionalDataLength) { byte[] additionalData = new byte[additionalDataLength]; RandomNumberGenerator.Fill(additionalData); byte[] plaintext = Enumerable.Range(1, dataLength).Select((x) => (byte)x).ToArray(); byte[] ciphertext = new byte[dataLength]; byte[] key = RandomNumberGenerator.GetBytes(KeySizeInBytes); byte[] nonce = RandomNumberGenerator.GetBytes(NonceSizeInBytes); byte[] tag = new byte[TagSizeInBytes]; using (var chaChaPoly = new ChaCha20Poly1305(key)) { chaChaPoly.Encrypt(nonce, plaintext, ciphertext, tag, additionalData); additionalData[0] ^= 1; byte[] decrypted = new byte[dataLength]; Assert.Throws <CryptographicException>( () => chaChaPoly.Decrypt(nonce, ciphertext, tag, decrypted, additionalData)); } }
public byte[] Encrypt() => aead.Encrypt(message, aad);
public void Encrypt() { var ciphertext = new byte[message.Length]; aead.Encrypt(nonce, message, ciphertext, tag, aad); }
public void Encrypt() => aead.Encrypt(nonce.Span, message.Span, ciphertext.Span, tag.Span, aad.Span);
public bool Poly1305Match(string msg, byte[] shortPoly1305) { var msgPoly1305 = cipherPoly1305.Encrypt(Encoding.ASCII.GetBytes(msg), null, iv); return(msgPoly1305.Skip(msgPoly1305.Length - 4).SequenceEqual(shortPoly1305)); }