Exemple #1
0
        protected void OneShotRoundtripTest(byte[] plaintext, byte[] ciphertext, PaddingMode padding, CipherMode mode, int feedbackSize = 0)
        {
            using (SymmetricAlgorithm alg = CreateAlgorithm())
            {
                int paddingSizeBytes = mode == CipherMode.CFB ? feedbackSize / 8 : alg.BlockSize / 8;
                alg.Key = Key;

                // Set the instance to use a different mode and padding than what will be used
                // in the one-shots to test that the one shot "wins".
                alg.FeedbackSize = 8;
                alg.Mode         = mode == CipherMode.ECB ? CipherMode.CBC : CipherMode.ECB;
                alg.Padding      = padding == PaddingMode.None ? PaddingMode.PKCS7 : PaddingMode.None;

                byte[] encrypted = mode switch
                {
                    CipherMode.ECB => alg.EncryptEcb(plaintext, padding),
                    CipherMode.CBC => alg.EncryptCbc(plaintext, IV, padding),
                    CipherMode.CFB => alg.EncryptCfb(plaintext, IV, padding, feedbackSize),
                    _ => throw new NotImplementedException(),
                };
                byte[] decrypted = mode switch
                {
                    CipherMode.ECB => alg.DecryptEcb(encrypted, padding),
                    CipherMode.CBC => alg.DecryptCbc(encrypted, IV, padding),
                    CipherMode.CFB => alg.DecryptCfb(encrypted, IV, padding, feedbackSize),
                    _ => throw new NotImplementedException(),
                };

                AssertPlaintexts(plaintext, decrypted, padding);
                AssertCiphertexts(encrypted, ciphertext, padding, paddingSizeBytes);

                decrypted = mode switch
                {
                    CipherMode.ECB => alg.DecryptEcb(ciphertext, padding),
                    CipherMode.CBC => alg.DecryptCbc(ciphertext, IV, padding),
                    CipherMode.CFB => alg.DecryptCfb(ciphertext, IV, padding, feedbackSize),
                    _ => throw new NotImplementedException(),
                };
                encrypted = mode switch
                {
                    CipherMode.ECB => alg.EncryptEcb(decrypted, padding),
                    CipherMode.CBC => alg.EncryptCbc(decrypted, IV, padding),
                    CipherMode.CFB => alg.EncryptCfb(decrypted, IV, padding, feedbackSize),
                    _ => throw new NotImplementedException(),
                };

                AssertPlaintexts(plaintext, decrypted, padding);
                AssertCiphertexts(ciphertext, encrypted, padding, paddingSizeBytes);
            }
        }
Exemple #2
0
        internal static void VerifyPersistedKey(
            string keyName,
            int plainBytesCount,
            Func <string, SymmetricAlgorithm> persistedFunc,
            Func <SymmetricAlgorithm> ephemeralFunc,
            CipherMode cipherMode,
            PaddingMode paddingMode,
            int feedbackSizeInBits)
        {
            byte[] plainBytes = GenerateRandom(plainBytesCount);

            using (SymmetricAlgorithm persisted = persistedFunc(keyName))
                using (SymmetricAlgorithm ephemeral = ephemeralFunc())
                {
                    persisted.Mode    = ephemeral.Mode = cipherMode;
                    persisted.Padding = ephemeral.Padding = paddingMode;

                    if (cipherMode == CipherMode.CFB)
                    {
                        persisted.FeedbackSize = ephemeral.FeedbackSize = feedbackSizeInBits;
                    }

                    ephemeral.Key = persisted.Key;
                    ephemeral.GenerateIV();
                    persisted.IV = ephemeral.IV;

                    using (ICryptoTransform persistedEncryptor = persisted.CreateEncryptor())
                        using (ICryptoTransform persistedDecryptor = persisted.CreateDecryptor())
                            using (ICryptoTransform ephemeralEncryptor = ephemeral.CreateEncryptor())
                            {
                                Assert.True(
                                    persistedEncryptor.CanTransformMultipleBlocks,
                                    "Pre-condition: persistedEncryptor.CanTransformMultipleBlocks");

                                byte[] persistedEncrypted = persistedEncryptor.TransformFinalBlock(plainBytes, 0, plainBytesCount);
                                byte[] ephemeralEncrypted = ephemeralEncryptor.TransformFinalBlock(plainBytes, 0, plainBytesCount);

                                Assert.Equal(ephemeralEncrypted, persistedEncrypted);

                                byte[] cipherBytes        = persistedEncrypted;
                                byte[] persistedDecrypted = persistedDecryptor.TransformFinalBlock(cipherBytes, 0,
                                                                                                   cipherBytes.Length);

                                byte[] expectedBytes = plainBytes;

                                if (persistedDecrypted.Length > plainBytes.Length)
                                {
                                    // This should only ever happen in
                                    Assert.Equal(PaddingMode.Zeros, paddingMode);

                                    expectedBytes = new byte[persistedDecrypted.Length];
                                    Buffer.BlockCopy(plainBytes, 0, expectedBytes, 0, plainBytesCount);
                                }

                                Assert.Equal(expectedBytes, persistedDecrypted);
                            }

                    byte[] oneShotPersistedEncrypted = null;
                    byte[] oneShotEphemeralEncrypted = null;
                    byte[] oneShotPersistedDecrypted = null;

                    if (cipherMode == CipherMode.ECB)
                    {
                        oneShotPersistedEncrypted = persisted.EncryptEcb(plainBytes, paddingMode);
                        oneShotEphemeralEncrypted = ephemeral.EncryptEcb(plainBytes, paddingMode);
                        oneShotPersistedDecrypted = persisted.DecryptEcb(oneShotEphemeralEncrypted, paddingMode);
                    }
                    else if (cipherMode == CipherMode.CBC)
                    {
                        oneShotPersistedEncrypted = persisted.EncryptCbc(plainBytes, persisted.IV, paddingMode);
                        oneShotEphemeralEncrypted = ephemeral.EncryptCbc(plainBytes, ephemeral.IV, paddingMode);
                        oneShotPersistedDecrypted = persisted.DecryptCbc(oneShotEphemeralEncrypted, persisted.IV, paddingMode);
                    }
                    else if (cipherMode == CipherMode.CFB)
                    {
                        oneShotPersistedEncrypted = persisted.EncryptCfb(plainBytes, persisted.IV, paddingMode, feedbackSizeInBits);
                        oneShotEphemeralEncrypted = ephemeral.EncryptCfb(plainBytes, ephemeral.IV, paddingMode, feedbackSizeInBits);
                        oneShotPersistedDecrypted = persisted.DecryptCfb(oneShotEphemeralEncrypted, persisted.IV, paddingMode, feedbackSizeInBits);
                    }

                    if (oneShotPersistedEncrypted is not null)
                    {
                        Assert.Equal(oneShotEphemeralEncrypted, oneShotPersistedEncrypted);

                        if (paddingMode == PaddingMode.Zeros)
                        {
                            byte[] plainPadded = new byte[oneShotPersistedDecrypted.Length];
                            plainBytes.AsSpan().CopyTo(plainPadded);
                            Assert.Equal(plainPadded, oneShotPersistedDecrypted);
                        }
                        else
                        {
                            Assert.Equal(plainBytes, oneShotPersistedDecrypted);
                        }
                    }
                }
        }
Exemple #3
0
        public static void VerifyCfbPersistedUnsupportedFeedbackSize(
            CngAlgorithm algorithm,
            Func <string, SymmetricAlgorithm> persistedFunc,
            int notSupportedFeedbackSizeInBits)
        {
            string keyName            = Guid.NewGuid().ToString();
            string feedbackSizeString = notSupportedFeedbackSizeInBits.ToString();

            // We try to delete the key later which will also dispose of it, so no need
            // to put this in a using.
            CngKey cngKey = CngKey.Create(algorithm, keyName);

            try
            {
                using (SymmetricAlgorithm alg = persistedFunc(keyName))
                {
                    alg.Mode         = CipherMode.CFB;
                    alg.FeedbackSize = notSupportedFeedbackSizeInBits;
                    alg.Padding      = PaddingMode.None;

                    byte[] destination        = new byte[alg.BlockSize / 8];
                    CryptographicException ce = Assert.ThrowsAny <CryptographicException>(() =>
                                                                                          alg.EncryptCfb(Array.Empty <byte>(), destination, PaddingMode.None, notSupportedFeedbackSizeInBits));

                    Assert.Contains(feedbackSizeString, ce.Message);

                    ce = Assert.ThrowsAny <CryptographicException>(() =>
                                                                   alg.DecryptCfb(Array.Empty <byte>(), destination, PaddingMode.None, notSupportedFeedbackSizeInBits));

                    Assert.Contains(feedbackSizeString, ce.Message);

                    ce = Assert.ThrowsAny <CryptographicException>(() => alg.CreateDecryptor());
                    Assert.Contains(feedbackSizeString, ce.Message);

                    ce = Assert.ThrowsAny <CryptographicException>(() => alg.CreateEncryptor());
                    Assert.Contains(feedbackSizeString, ce.Message);
                }
            }
            finally
            {
                cngKey.Delete();
            }
        }