public void AuthenticatedSymmetricAlgorithmCreateTest()
        {
            // AuthenticatedAesCng should be the default implementation
            using (AuthenticatedSymmetricAlgorithm alg = AuthenticatedSymmetricAlgorithm.Create())
            {
                Assert.IsInstanceOfType(alg, typeof(AuthenticatedAesCng));
            }

            using (AuthenticatedSymmetricAlgorithm alg = AuthenticatedSymmetricAlgorithm.Create("AuthenticatedAesCng"))
            {
                Assert.IsInstanceOfType(alg, typeof(AuthenticatedAesCng));
            }

            Assert.IsNull(AuthenticatedAes.Create("AuthenticatedAesDoesntExist"));
            Assert.IsNull(AuthenticatedAes.Create("AesCng"));
        }
        public void AuthenticatedSymmetricAlgorithmValidTagSizeTest()
        {
            using (AuthenticatedSymmetricAlgorithm alg = AuthenticatedSymmetricAlgorithm.Create())
            {
                foreach (KeySizes tagSizeRange in alg.LegalTagSizes)
                {
                    Assert.IsTrue(alg.ValidTagSize(tagSizeRange.MinSize));
                    Assert.IsTrue(alg.ValidTagSize(tagSizeRange.MaxSize));

                    if (tagSizeRange.MinSize != tagSizeRange.MaxSize)
                    {
                        for (int tagSize = tagSizeRange.MinSize; tagSize < tagSizeRange.MaxSize; tagSize += tagSizeRange.SkipSize)
                        {
                            Assert.IsTrue(alg.ValidTagSize(tagSize));
                        }
                    }
                }

                Assert.IsFalse(alg.ValidTagSize(0));
                Assert.IsFalse(alg.ValidTagSize(Int32.MaxValue));
            }
        }
        /// <summary>
        ///     Utility to encapsulate round-tripping ciphertext
        /// </summary>
        private static bool RoundTripHelper <TEncryptionAlgorithm, TDecryptionAlgorithm>(Action <TEncryptionAlgorithm> encryptionSetup,
                                                                                         Action <TDecryptionAlgorithm> decryptionSetup)
            where TEncryptionAlgorithm : AuthenticatedSymmetricAlgorithm, new()
            where TDecryptionAlgorithm : AuthenticatedSymmetricAlgorithm, new()
        {
            // Encryption parameters
            byte[] key = null;
            byte[] iv  = null;
            byte[] authenticatedData = Encoding.UTF8.GetBytes("Additional authenticated data");

            // Round tripping data
            byte[] plainText  = Encoding.UTF8.GetBytes("Authenticated round trip message");
            byte[] cipherText = null;
            byte[] tag        = null;
            AuthenticatedSymmetricEncryptionState encryptionState = null;

            AuthenticatedSymmetricAlgorithm encryptionObject = null;

            try
            {
                // Setup the encryption algorithm
                encryptionObject = new TEncryptionAlgorithm();
                encryptionObject.AuthenticatedData = authenticatedData;
                encryptionObject.IV = new byte[] { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
                encryptionSetup(encryptionObject as TEncryptionAlgorithm);
                encryptionObject = encryptionObject.EnableLogging();

                // Encrypt the data
                using (MemoryStream ms = new MemoryStream())
                    using (IAuthenticatedCryptoTransform encryptor = encryptionObject.CreateAuthenticatedEncryptor())
                        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                        {
                            cs.Write(plainText, 0, plainText.Length);
                            cs.FlushFinalBlock();

                            cipherText = ms.ToArray();
                            tag        = encryptor.GetTag();
                        }

                // Save the encryption parameters
                key = encryptionObject.Key;
                iv  = encryptionObject.IV;
                authenticatedData = encryptionObject.AuthenticatedData;
                encryptionState   = encryptionObject.GetLastEncryptionState();
            }
            finally
            {
                if (encryptionObject != null)
                {
                    (encryptionObject as IDisposable).Dispose();
                }
            }

            byte[] roundTrip = null;

            // Now verify the data
            AuthenticatedSymmetricAlgorithm decryptionObject = null;

            try
            {
                decryptionObject = new TDecryptionAlgorithm();

                decryptionObject.Key = key;
                decryptionObject.IV  = iv;
                decryptionObject.AuthenticatedData = authenticatedData;
                decryptionObject.Tag = tag;

                decryptionSetup(decryptionObject as TDecryptionAlgorithm);
                decryptionObject = decryptionObject.EnableDecryptionVerification(encryptionState);

                using (MemoryStream ms = new MemoryStream())
                    using (CryptoStream cs = new CryptoStream(ms, decryptionObject.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherText, 0, cipherText.Length);
                        cs.FlushFinalBlock();

                        roundTrip = ms.ToArray();
                    }
            }
            finally
            {
                if (decryptionObject != null)
                {
                    (decryptionObject as IDisposable).Dispose();
                }
            }

            if (roundTrip.Length != plainText.Length)
            {
                return(false);
            }

            for (int i = 0; i < roundTrip.Length; ++i)
            {
                if (roundTrip[i] != plainText[i])
                {
                    return(false);
                }
            }

            return(true);
        }
        public void AuthenticatedSymmetricAlgorithmVerifierNegativeThreadingTest()
        {
            // Synchronization state
            object lockCheckParameter = new object();
            AuthenticatedSymmetricAlgorithm encryptorInstance = null;
            bool lockChecked = false;

            SymmetricAlgorithmDiagnosticOptions diagnosticOptions = new SymmetricAlgorithmDiagnosticOptions
            {
                CheckThreadSafety  = true,
                LockCheckParameter = lockCheckParameter,
                LockCheckCallback  = delegate(CryptographyLockContext <SymmetricAlgorithm> lockCheck)
                {
                    Assert.AreSame(lockCheck.Parameter, lockCheckParameter, "Unexpected lock check parameter");
                    Assert.AreSame(lockCheck.Algorithm, encryptorInstance, "Unexpected algorithm check parameter");
                    lockChecked = true;
                    return(false);
                }
            };

            // Encryption state
            bool      encryptionSucceeded = true;
            Exception encryptionException = null;

            try
            {
                encryptorInstance = new AuthenticatedAesCng();
                AuthenticatedSymmetricAlgorithm encryptor = encryptorInstance.EnableLogging(diagnosticOptions);

                // Thread to do the encryption
                Thread encryptionThread = new Thread(delegate()
                {
                    try
                    {
                        using (MemoryStream ms = new MemoryStream())
                            using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                            {
                                byte[] plainText = Encoding.UTF8.GetBytes("Secret round trip message");
                                cs.Write(plainText, 0, plainText.Length);
                                cs.FlushFinalBlock();
                            }

                        encryptionSucceeded = true;
                    }
                    catch (Exception e)
                    {
                        encryptionException = e;
                        encryptionSucceeded = false;
                    }
                });

                encryptionThread.Start();
                encryptionThread.Join();
            }
            finally
            {
                if (encryptorInstance != null)
                {
                    (encryptorInstance as IDisposable).Dispose();
                }
            }

            // Verify that our lock check was called, that we failed encryption, and that we got the correct exception
            Assert.IsTrue(lockChecked, "Lock check callback was not performed");
            Assert.IsFalse(encryptionSucceeded, "Encryption should not have succeeded");
            Assert.IsInstanceOfType(encryptionException, typeof(CryptographicDiagnosticException), "Did not get expected exception");
        }