Example #1
0
        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");
            }
        }
Example #2
0
 private static void ValidateNonce(XChaChaNonce nonce)
 {
     if (nonce.IsEmpty)
     {
         throw new ArgumentException($"{nameof(nonce)} is empty");
     }
 }
Example #3
0
        /// <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);
        }
Example #4
0
        /// <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);
        }
Example #5
0
 private protected override void InternalDecrypt(
     ReadOnlySpan <byte> ciphertext,
     Span <byte> message,
     XChaChaKey key,
     XChaChaNonce nonce)
 {
     this.InternalDecrypt(ciphertext, message, key, nonce, ReadOnlySpan <byte> .Empty);
 }
Example #6
0
 /// <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);
 }
Example #7
0
 /// <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);
            }
        }
Example #16
0
 /// <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);
            }
        }
Example #25
0
 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);
            }
        }
Example #28
0
 /// <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);
 }
Example #29
0
 private protected void ValidateEncryptParameters(ReadOnlySpan <byte> message, Span <byte> ciphertext, XChaChaNonce nonce)
 {
     ValidateMaxMessageLength(message);
     ValidateCiphertextLength(message, ciphertext);
     ValidateNonce(nonce);
 }
Example #30
0
 private protected void ValidateDecryptParameters(ReadOnlySpan <byte> ciphertext, Span <byte> message, XChaChaNonce nonce)
 {
     ValidateMessageLength(ciphertext, message);
     ValidateNonce(nonce);
 }