Change default FeedbackSize for TripleDES internal implementation
authorKevin Jones <kevin@vcsjones.com>
Tue, 13 Oct 2020 19:11:46 +0000 (15:11 -0400)
committerGitHub <noreply@github.com>
Tue, 13 Oct 2020 19:11:46 +0000 (12:11 -0700)
In .NET Framework, TripleDESCryptoServiceProvider defaults to a feedback
size of 8, and TripleDESCng defaults to a feedback size of 64. The
static Create by default would return TripleDESCryptoServiceProvider,
thus the TripleDES from Create would have a default feedback size of 8.

This changes the default sizes of TripleDES to behave more
similarly to .NET Framework to make porting CFB code from Framework
easier.

The internal 3DES implementation (and thus
TripleDESCryptoServiceProvider, since that is a wrapper around the
internal implementation) now defaults to a feedback size of 8.
TripleDESCng and user-derived classes from TripleDES will continue to
use a feedback size of 64.

src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/AES/AesContractTests.cs
src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/TripleDES/TripleDESCipherTests.cs
src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/TripleDesImplementation.cs
src/libraries/System.Security.Cryptography.Algorithms/tests/AesTests.cs
src/libraries/System.Security.Cryptography.Algorithms/tests/TripleDesTests.cs
src/libraries/System.Security.Cryptography.Cng/tests/TripleDESCngTests.cs
src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs
src/libraries/System.Security.Cryptography.Csp/tests/TripleDESCryptoServiceProviderTests.cs

index 8fe23f2..8c0c79d 100644 (file)
@@ -17,6 +17,7 @@ namespace System.Security.Cryptography.Encryption.Aes.Tests
             {
                 Assert.Equal(128, aes.BlockSize);
                 Assert.Equal(256, aes.KeySize);
+                Assert.Equal(8, aes.FeedbackSize);
                 Assert.Equal(CipherMode.CBC, aes.Mode);
                 Assert.Equal(PaddingMode.PKCS7, aes.Padding);
             }
index dcab872..ffdd484 100644 (file)
@@ -827,5 +827,27 @@ namespace System.Security.Cryptography.Encryption.TripleDes.Tests
             string decrypted = Encoding.ASCII.GetString(outputBytes, 0, outputOffset);
             Assert.Equal(ExpectedOutput, decrypted);
         }
+
+        [Fact]
+        public static void VerifyNetFxCompat_CFB8_PKCS7Padding()
+        {
+            // .NET Framework would always pad to the nearest block
+            // with CFB8 and PKCS7 padding even though the shortest possible
+            // padding is always 1 byte. This ensures we can continue to decrypt
+            // .NET Framework encrypted data with the excessive padding.
+
+            byte[] key = "531bd715cbf785c10169b6e4926562b8e1e5c4c8884ed791".HexToByteArray();
+            byte[] iv = "dbeba40532a5304a".HexToByteArray();
+            byte[] plaintext = "70656e6e79".HexToByteArray();
+            byte[] ciphertext = "8798c2da055c9ea0".HexToByteArray();
+
+            using TripleDES tdes = TripleDESFactory.Create();
+            tdes.Mode = CipherMode.CFB;
+            tdes.Padding = PaddingMode.PKCS7;
+            tdes.FeedbackSize = 8;
+
+            byte[] decrypted = TripleDESDecryptDirectKey(tdes, key, iv, ciphertext);
+            Assert.Equal(plaintext, decrypted);
+        }
     }
 }
index 6218d71..691c573 100644 (file)
@@ -11,6 +11,13 @@ namespace Internal.Cryptography
     {
         private const int BitsPerByte = 8;
 
+        public TripleDesImplementation()
+        {
+            // Default CFB to CFB8 to match .NET Framework's default for TripleDES.Create()
+            // and TripleDESCryptoServiceProvider.
+            FeedbackSizeValue = 8;
+        }
+
         public override ICryptoTransform CreateDecryptor()
         {
             return CreateTransform(Key, IV, encrypting: false);
index 516bcf7..e8c9f02 100644 (file)
@@ -15,6 +15,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
             {
                 Assert.Equal(256, aes.KeySize);
                 Assert.Equal(128, aes.BlockSize);
+                Assert.Equal(8, aes.FeedbackSize);
                 Assert.Equal(CipherMode.CBC, aes.Mode);
                 Assert.Equal(PaddingMode.PKCS7, aes.Padding);
             }
index 0400cfc..ebb44ed 100644 (file)
@@ -19,6 +19,20 @@ namespace System.Security.Cryptography.Encryption.TripleDes.Tests
             {
                 Assert.Equal(192, tdes.KeySize);
                 Assert.Equal(64, tdes.BlockSize);
+                Assert.Equal(64, tdes.FeedbackSize);
+                Assert.Equal(CipherMode.CBC, tdes.Mode);
+                Assert.Equal(PaddingMode.PKCS7, tdes.Padding);
+            }
+        }
+
+        [Fact]
+        public static void TripleDesInternalDefault()
+        {
+            using (TripleDES tdes = TripleDES.Create())
+            {
+                Assert.Equal(192, tdes.KeySize);
+                Assert.Equal(64, tdes.BlockSize);
+                Assert.Equal(8, tdes.FeedbackSize);
                 Assert.Equal(CipherMode.CBC, tdes.Mode);
                 Assert.Equal(PaddingMode.PKCS7, tdes.Padding);
             }
index 60934e5..0786018 100644 (file)
@@ -11,6 +11,20 @@ namespace System.Security.Cryptography.Cng.Tests
 
         private static readonly CngAlgorithm s_cngAlgorithm = new CngAlgorithm("3DES");
 
+        [Fact]
+        public static void VerifyDefaults()
+        {
+            using TripleDES tdes = new TripleDESCng();
+            Assert.Equal(64, tdes.BlockSize);
+            Assert.Equal(192, tdes.KeySize);
+            Assert.Equal(CipherMode.CBC, tdes.Mode);
+            Assert.Equal(PaddingMode.PKCS7, tdes.Padding);
+
+            // .NET Framework Compat: The default feedback size of TripleDESCng
+            // is 64 while TripleDESCryptoServiceProvider defaults to 8.
+            Assert.Equal(64, tdes.FeedbackSize);
+        }
+
         [OuterLoop(/* Creates/Deletes a persisted key, limit exposure to key leaking */)]
         [ConditionalTheory(nameof(SupportsPersistedSymmetricKeys))]
         // 3DES192-ECB-NoPadding 2 blocks.
index fcac011..9bedeec 100644 (file)
@@ -16,7 +16,6 @@ namespace System.Security.Cryptography
         {
             // This class wraps TripleDES
             _impl = TripleDES.Create();
-            _impl.FeedbackSize = 8;
         }
 
         public override int FeedbackSize
index cb6f9a8..b358bf4 100644 (file)
@@ -19,6 +19,7 @@ namespace System.Security.Cryptography.Encryption.TripleDES.Tests
             {
                 Assert.Equal(64, alg.BlockSize);
                 Assert.Equal(192, alg.KeySize);
+                Assert.Equal(8, alg.FeedbackSize);
                 Assert.Equal(CipherMode.CBC, alg.Mode);
                 Assert.Equal(PaddingMode.PKCS7, alg.Padding);
             }