Erase temporary copies of plaintext during de/padding operations
authorJeremy Barton <jbarton@microsoft.com>
Fri, 31 Aug 2018 05:20:57 +0000 (22:20 -0700)
committerGitHub <noreply@github.com>
Fri, 31 Aug 2018 05:20:57 +0000 (22:20 -0700)
When symmetric block padding is added, or removed, the
UniversalCryptoDecryptor and UniversalCryptoEncryptor classes make a
temporary buffer to hold the padded result (for encryption this is the input to
the cryptographic transform, for decryption it is the output before calling
DepadBlock).

While these buffers are usually marked as unused by the GC in short order, and
overwritten by new objects in short order, some applications are more sensitive
to having plaintext residuals in memory; and we should clear these out before
abandoning them to the garbage collector.

Commit migrated from https://github.com/dotnet/corefx/commit/bb54ed5540d19a1595443bab0233e3c985da9dad

src/libraries/Common/src/Internal/Cryptography/UniversalCryptoDecryptor.cs
src/libraries/Common/src/Internal/Cryptography/UniversalCryptoEncryptor.cs

index 6415ec6..5b44d44 100644 (file)
@@ -97,7 +97,18 @@ namespace Internal.Cryptography
             byte[] outputData;
             if (ciphertext.Length > 0)
             {
-                outputData = DepadBlock(decryptedBytes, 0, decryptedBytes.Length);
+                unsafe
+                {
+                    fixed (byte* decryptedBytesPtr = decryptedBytes)
+                    {
+                        outputData = DepadBlock(decryptedBytes, 0, decryptedBytes.Length);
+
+                        if (outputData != decryptedBytes)
+                        {
+                            CryptographicOperations.ZeroMemory(decryptedBytes);
+                        }
+                    }
+                }
             }
             else
             {
index bfe4430..937d6e5 100644 (file)
@@ -30,11 +30,21 @@ namespace Internal.Cryptography
             return BasicSymmetricCipher.Transform(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
         }
 
-        protected sealed override byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
+        protected sealed override unsafe byte[] UncheckedTransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
         {
             byte[] paddedBlock = PadBlock(inputBuffer, inputOffset, inputCount);
-            byte[] output = BasicSymmetricCipher.TransformFinal(paddedBlock, 0, paddedBlock.Length);
-            return output;
+
+            fixed (byte* paddedBlockPtr = paddedBlock)
+            {
+                byte[] output = BasicSymmetricCipher.TransformFinal(paddedBlock, 0, paddedBlock.Length);
+
+                if (paddedBlock != inputBuffer)
+                {
+                    CryptographicOperations.ZeroMemory(paddedBlock);
+                }
+
+                return output;
+            }
         }
 
         private byte[] PadBlock(byte[] block, int offset, int count)