private void InternalDecrypt( ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaKey key, XChaChaNonce nonce, ReadOnlySpan <byte> additionalData) { ValidateDecryptParameters(ciphertext, message, nonce); // nsec is always null for the XChaCha AEAD construction, here we pass IntPtr.Zero. var result = crypto_aead_xchacha20poly1305_ietf_decrypt( ref MemoryMarshal.GetReference(message), out var messageLength, IntPtr.Zero, in MemoryMarshal.GetReference(ciphertext), (UInt64)ciphertext.Length, in MemoryMarshal.GetReference(additionalData), (UInt64)additionalData.Length, in nonce.Handle, key.Handle); if (result != 0) { throw new CryptographicException("decryption failed"); } }
private static void ValidateNonce(XChaChaNonce nonce) { if (nonce.IsEmpty) { throw new ArgumentException($"{nameof(nonce)} is empty"); } }
/// <summary> /// Encrypts the <paramref name="message"/> and returns the computed ciphertext. /// </summary> /// <param name="message">The message to encrypt.</param> /// <param name="key">The encryption key.</param> /// <param name="nonce">The nonce to use when encrypting the <paramref name="message"/>.</param> /// <returns>The computed ciphertext.</returns> public byte[] Encrypt(ReadOnlySpan <byte> message, XChaChaKey key, XChaChaNonce nonce) { this.ValidateMaxMessageLength(message); var ciphertext = new byte[GetCipherTextLength(message.Length)]; this.Encrypt(message, ciphertext, key, nonce); return(ciphertext); }
/// <summary> /// Decrypts the <paramref name="ciphertext"/>, verifies the authenticaion tag, and if successful, /// returns the decrypted message. /// </summary> /// <param name="ciphertext">The ciphertext to decrypt.</param> /// <param name="key">The encryption key.</param> /// <param name="nonce">The nonce to use when decrypting the <paramref name="ciphertext"/>.</param> /// <returns>The decrypted message.</returns> public byte[] Decrypt(ReadOnlySpan <byte> ciphertext, XChaChaKey key, XChaChaNonce nonce) { var messageLength = GetPlaintextLength(ciphertext.Length); var message = new byte[messageLength]; this.Decrypt(ciphertext, message, key, nonce); return(message); }
private protected override void InternalDecrypt( ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaKey key, XChaChaNonce nonce) { this.InternalDecrypt(ciphertext, message, key, nonce, ReadOnlySpan <byte> .Empty); }
/// <summary> /// Decrypts the <paramref name="ciphertext"/>, verifies the authenticaion tag, and if successful, /// writes the output to <paramref name="message"/>. /// </summary> /// <param name="ciphertext">The ciphertext to decrypt.</param> /// <param name="message">The buffer in which to write the decrypted message.</param> /// <param name="key">The encryption key.</param> /// <param name="nonce">The nonce to use when decrypting the <paramref name="ciphertext"/>.</param> /// <param name="additionalData">The associated data to use for computing the authentication tag.</param> public void Decrypt( ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaKey key, XChaChaNonce nonce, ReadOnlySpan <byte> additionalData) { this.InternalDecrypt(ciphertext, message, key, nonce, additionalData); }
/// <summary> /// Encrypts the <paramref name="message"/> and writes computed ciphertext to <paramref name="ciphertext"/>. /// </summary> /// <param name="message">The message to encrypt.</param> /// <param name="ciphertext">The buffer in which to write the ciphertext.</param> /// <param name="key">The encryption key.</param> /// <param name="nonce">The nonce to use when encrypting the <paramref name="message"/>.</param> /// <param name="additionalData">The associated data to use for computing the authentication tag.</param> public void Encrypt( ReadOnlySpan <byte> message, Span <byte> ciphertext, XChaChaKey key, XChaChaNonce nonce, ReadOnlySpan <byte> additionalData) { InternalEncrypt(message, ciphertext, key, nonce, additionalData); }
public void Test_Encrypt_ReturnsNonZeroCiphertext(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); var message = TestConstants.MessageBytes; var ciphertext = cipher.Encrypt(message, key, nonce); Assert.False(ciphertext.All(b => b == 0)); } }
public void Test_Encrypt_WithAdditionalData_ReturnsNonZeroOutput() { using (var key = XChaChaKey.Generate()) { var aeadCipher = new XChaChaAeadCipher(); var nonce = XChaChaNonce.Generate(); var additionalData = Encoding.UTF8.GetBytes(DateTime.Now.ToString()); var message = RandomBytesGenerator.NextBytes(1024 * 1024); var ciphertext = aeadCipher.Encrypt(message, key, nonce, additionalData); Assert.False(ciphertext.All(b => b == 0)); } }
private protected override void InternalEncrypt( ReadOnlySpan <byte> message, Span <byte> ciphertext, XChaChaKey key, XChaChaNonce nonce) { ValidateEncryptParameters(message, ciphertext, nonce); crypto_secretbox_xchacha20poly1305_easy( ref MemoryMarshal.GetReference(ciphertext), in MemoryMarshal.GetReference(message), (UInt64)message.Length, in nonce.Handle, key.Handle); }
public void Test_Decrypt_CanDecryptCiphertext(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); var message = TestConstants.MessageBytes; var ciphertext = cipher.Encrypt(message, key, nonce); var result = cipher.Decrypt(ciphertext, key, nonce); Assert.Equal(message, result); } }
public void Test_Encrypt_ProducesNonZeroOutput(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); var message = TestConstants.MessageBytes; var ciphertext = new byte[cipher.GetCipherTextLength(message.Length)]; cipher.Encrypt(message, ciphertext, key, nonce); Assert.False(ciphertext.All(b => b == 0)); } }
public void Test_Decrypt_ReturnsMessage(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); const int messageLength = 1024 * 1024; var message = RandomBytesGenerator.NextBytes(messageLength); var ciphertext = cipher.Encrypt(message, key, nonce); var result = cipher.Decrypt(ciphertext, key, nonce); Assert.Equal(message, result); } }
public void Test_Decrypt_WithAdditionalData_Success() { using (var key = XChaChaKey.Generate()) { var aeadCipher = new XChaChaAeadCipher(); var nonce = XChaChaNonce.Generate(); var additionalData = Encoding.UTF8.GetBytes(DateTime.Now.ToString()); const int messageLength = 1024 * 1024; var message = RandomBytesGenerator.NextBytes(messageLength); var ciphertext = aeadCipher.Encrypt(message, key, nonce, additionalData); var result = aeadCipher.Decrypt(ciphertext, key, nonce, additionalData); Assert.Equal(message, result); } }
public void Test_Encrypt_NonceEmpty_ThrowsArgumentException(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var message = TestConstants.MessageBytes; var nonce = new XChaChaNonce(); Action action = () => { cipher.Encrypt(message, key, nonce); }; var exception = Assert.Throws <ArgumentException>(action); Assert.Equal("nonce is empty", exception.Message); } }
/// <summary> /// Tries to decrypt the <paramref name="ciphertext"/>, verifies the authenticaion tag, and if successful, /// writes the output to <paramref name="message"/>. /// </summary> /// <param name="ciphertext">The ciphertext to decrypt.</param> /// <param name="message">The buffer in which to write the decrypted message.</param> /// <param name="key">The encryption key.</param> /// <param name="nonce">The nonce to use when decrypting the <paramref name="ciphertext"/>.</param> /// <param name="additionalData">The associated data to use for computing the authentication tag.</param> /// <returns>Whether the decryption succeeded.</returns> public bool TryDecrypt( ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaKey key, XChaChaNonce nonce, ReadOnlySpan <byte> additionalData) { try { this.InternalDecrypt(ciphertext, message, key, nonce, additionalData); return(true); } catch { return(false); } }
public void Test_Encrypt_CiphertextBufferTooSmall_ThrowsArgumentException(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var message = TestConstants.MessageBytes; var ciphertext = Array.Empty <byte>(); var nonce = XChaChaNonce.Generate(); Action action = () => { cipher.Encrypt(message, ciphertext, key, nonce); }; var exception = Assert.Throws <ArgumentException>(action); Assert.Equal("ciphertext buffer is not large enough", exception.Message); } }
public void Test_TryDecrypt_Fails_ReturnsFalse(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); const int messageLength = 1024 * 1024; var message = RandomBytesGenerator.NextBytes(messageLength); var ciphertext = new byte[cipher.GetCipherTextLength(message.Length)]; cipher.Encrypt(message, ciphertext, key, nonce); var wrongNonce = XChaChaNonce.Generate(); var result = cipher.TryDecrypt(ciphertext, ciphertext, key, wrongNonce); Assert.False(result); } }
public void Test_Decrypt_MessageBufferTooSmall_ThrowsArgumentException(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var message = Array.Empty <byte>(); var ciphertext = new byte[cipher.GetCipherTextLength(1)]; var nonce = XChaChaNonce.Generate(); Action action = () => { cipher.Decrypt(ciphertext, message, key, nonce); }; var exception = Assert.Throws <ArgumentException>(action); Assert.Equal("message buffer is not large enough", exception.Message); } }
private protected override void InternalDecrypt( ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaKey key, XChaChaNonce nonce) { ValidateDecryptParameters(ciphertext, message, nonce); var returnCode = crypto_secretbox_xchacha20poly1305_open_easy( ref MemoryMarshal.GetReference(message), in MemoryMarshal.GetReference(ciphertext), (UInt64)ciphertext.Length, in nonce.Handle, key.Handle); if (returnCode != 0) { throw new CryptographicException("decryption failed"); } }
public void Test_EncryptWithReturn_MaxMessageLengthExceeded_ThrowsException(Type cipherType) { unsafe { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); Action action = () => { var message = new ReadOnlySpan <byte>(IntPtr.Zero.ToPointer(), int.MaxValue); var nonce = XChaChaNonce.Generate(); cipher.Encrypt(message, key, nonce); }; var exception = Assert.Throws <ArgumentException>(action); Assert.Equal("message is too long", exception.Message); } } }
public void Test_Decrypt_WithInvalidAdditionalData_Fails() { using (var key = XChaChaKey.Generate()) { var aeadCipher = new XChaChaAeadCipher(); var nonce = XChaChaNonce.Generate().ToArray(); var additionalData = Encoding.UTF8.GetBytes(DateTime.Now.ToString()); const int messageLength = 1024 * 1024; var message = RandomBytesGenerator.NextBytes(messageLength); var ciphertext = aeadCipher.Encrypt(message, key, new XChaChaNonce(nonce), additionalData); var invalidAdditionalData = Encoding.UTF8.GetBytes("banana"); Action action = () => { aeadCipher.Decrypt(ciphertext, key, new XChaChaNonce(nonce), invalidAdditionalData); }; var exception = Assert.Throws <CryptographicException>(action); Assert.Equal("decryption failed", exception.Message); } }
public void Test_TryDecrypt_CanDecryptCiphertext(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); const int messageLength = 1024 * 1024; var message = RandomBytesGenerator.NextBytes(messageLength); var ciphertext = new byte[cipher.GetCipherTextLength(message.Length)]; cipher.Encrypt(message, ciphertext, key, nonce); var decryptedMessage = new byte[messageLength]; var result = cipher.TryDecrypt(ciphertext, decryptedMessage, key, nonce); Assert.True(result); Assert.Equal(message, decryptedMessage); } }
public void Test_Decrypt_WrongNonce_ThrowsException(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); var message = TestConstants.MessageBytes; var ciphertext = cipher.Encrypt(message, key, nonce); Action action = () => { var wrongNonce = XChaChaNonce.Generate(); var result = cipher.Decrypt(ciphertext, key, wrongNonce); }; var exception = Assert.Throws <CryptographicException>(action); Assert.Equal("decryption failed", exception.Message); } }
private void InternalEncrypt( ReadOnlySpan <byte> message, Span <byte> ciphertext, XChaChaKey key, XChaChaNonce nonce, ReadOnlySpan <byte> additionalData) { ValidateEncryptParameters(message, ciphertext, nonce); // nsec is always null for the XChaCha AEAD construction, here we pass IntPtr.Zero. crypto_aead_xchacha20poly1305_ietf_encrypt( ref MemoryMarshal.GetReference(ciphertext), out var ciphertextLongLength, in MemoryMarshal.GetReference(message), (UInt64)message.Length, in MemoryMarshal.GetReference(additionalData), (UInt64)additionalData.Length, IntPtr.Zero, in nonce.Handle, key.Handle); }
public void Test_EncryptWithReturn_MaxMessageLengthExceeded_ThrowsException() { unsafe { using (var key = XChaChaKey.Generate()) { var aeadCipher = new XChaChaAeadCipher(); Action action = () => { var message = new ReadOnlySpan <byte>(IntPtr.Zero.ToPointer(), int.MaxValue); var additionalData = Encoding.UTF8.GetBytes(DateTime.Now.ToString()); var nonce = XChaChaNonce.Generate(); aeadCipher.Encrypt(message, key, nonce, additionalData); }; var exception = Assert.Throws <ArgumentException>(action); Assert.Equal("message is too long", exception.Message); } } }
public void Test_Decrypt_Fails_ThrowsCryptographicException(Type cipherType) { using (var key = XChaChaKey.Generate()) { var cipher = (XChaChaSecretKeyCipher)Activator.CreateInstance(cipherType); var nonce = XChaChaNonce.Generate(); const int messageLength = 1024 * 1024; var message = RandomBytesGenerator.NextBytes(messageLength); var ciphertext = new byte[cipher.GetCipherTextLength(message.Length)]; cipher.Encrypt(message, ciphertext, key, nonce); Action action = () => { var wrongNonce = XChaChaNonce.Generate(); cipher.Decrypt(ciphertext, ciphertext, key, wrongNonce); }; var exception = Assert.Throws <CryptographicException>(action); Assert.Equal("decryption failed", exception.Message); } }
/// <summary> /// Encrypts the <paramref name="message"/> and writes computed ciphertext to <paramref name="ciphertext"/>. /// </summary> /// <param name="message">The message to encrypt.</param> /// <param name="ciphertext">The buffer in which to write the ciphertext.</param> /// <param name="key">The encryption key.</param> /// <param name="nonce">The nonce to use when encrypting the <paramref name="message"/>.</param> public void Encrypt(ReadOnlySpan <byte> message, Span <byte> ciphertext, XChaChaKey key, XChaChaNonce nonce) { this.InternalEncrypt(message, ciphertext, key, nonce); }
private protected void ValidateEncryptParameters(ReadOnlySpan <byte> message, Span <byte> ciphertext, XChaChaNonce nonce) { ValidateMaxMessageLength(message); ValidateCiphertextLength(message, ciphertext); ValidateNonce(nonce); }
private protected void ValidateDecryptParameters(ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaNonce nonce) { ValidateMessageLength(ciphertext, message); ValidateNonce(nonce); }