Use one-shot hash functions where possible. (#39455)
authorKevin Jones <kevin@vcsjones.com>
Fri, 17 Jul 2020 00:18:40 +0000 (20:18 -0400)
committerGitHub <noreply@github.com>
Fri, 17 Jul 2020 00:18:40 +0000 (17:18 -0700)
src/libraries/System.Net.HttpListener/src/System/Net/WebSockets/HttpWebSocket.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/AppleCertificatePal.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ManagedCertificateFinder.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ManagedX509ExtensionProcessor.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509SubjectKeyIdentifierExtension.cs

index c844372..f89b58f 100644 (file)
@@ -18,17 +18,12 @@ namespace System.Net.WebSockets
         [SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 used only for hashing purposes, not for crypto.")]
         internal static string GetSecWebSocketAcceptString(string secWebSocketKey)
         {
-            string retVal;
+            string acceptString = string.Concat(secWebSocketKey, HttpWebSocket.SecWebSocketKeyGuid);
+            byte[] toHash = Encoding.UTF8.GetBytes(acceptString);
 
             // SHA1 used only for hashing purposes, not for crypto. Check here for FIPS compat.
-            using (SHA1 sha1 = SHA1.Create())
-            {
-                string acceptString = string.Concat(secWebSocketKey, HttpWebSocket.SecWebSocketKeyGuid);
-                byte[] toHash = Encoding.UTF8.GetBytes(acceptString);
-                retVal = Convert.ToBase64String(sha1.ComputeHash(toHash));
-            }
-
-            return retVal;
+            byte[] hash = SHA1.HashData(toHash);
+            return Convert.ToBase64String(hash);
         }
 
         // return value here signifies if a Sec-WebSocket-Protocol header should be returned by the server.
index be5d106..fd70ac8 100644 (file)
@@ -363,11 +363,7 @@ namespace Internal.Cryptography.Pal
             get
             {
                 EnsureCertData();
-
-                using (SHA1 hash = SHA1.Create())
-                {
-                    return hash.ComputeHash(_certData.RawData);
-                }
+                return SHA1.HashData(_certData.RawData);
             }
         }
 
index 409e2a1..ee401a4 100644 (file)
@@ -266,13 +266,8 @@ namespace Internal.Cryptography.Pal
                         // SubjectPublicKeyInfo block, and returns that.
                         //
                         // https://msdn.microsoft.com/en-us/library/windows/desktop/aa376079%28v=vs.85%29.aspx
-
-                        using (HashAlgorithm hash = SHA1.Create())
-                        {
-                            byte[] publicKeyInfoBytes = GetSubjectPublicKeyInfo(cert);
-
-                            certKeyId = hash.ComputeHash(publicKeyInfoBytes);
-                        }
+                        byte[] publicKeyInfoBytes = GetSubjectPublicKeyInfo(cert);
+                        certKeyId = SHA1.HashData(publicKeyInfoBytes);
                     }
 
                     return keyIdentifier.ContentsEqual(certKeyId);
index 62c2197..976021f 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
+using System.Diagnostics;
 using System.Formats.Asn1;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
@@ -225,9 +226,21 @@ namespace Internal.Cryptography.Pal
             AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
             spki.Encode(writer);
 
-            using (SHA1 hash = SHA1.Create())
+            byte[] rented = CryptoPool.Rent(writer.GetEncodedLength());
+
+            try
+            {
+                if (!writer.TryEncode(rented, out int bytesWritten))
+                {
+                    Debug.Fail("TryEncode failed with a pre-allocated buffer");
+                    throw new CryptographicException();
+                }
+
+                return SHA1.HashData(rented.AsSpan(0, bytesWritten));
+            }
+            finally
             {
-                return hash.ComputeHash(writer.Encode());
+                CryptoPool.Return(rented, clearSize: 0); // SubjectPublicKeyInfo is not sensitive.
             }
         }
 
index b46b126..aaeefd3 100644 (file)
@@ -92,16 +92,17 @@ namespace System.Security.Cryptography.X509Certificates
             return EncodeExtension(subjectKeyIdentifier);
         }
 
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is required by RFC3280")]
         private static byte[] GenerateSubjectKeyIdentifierFromPublicKey(PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm)
         {
             switch (algorithm)
             {
                 case X509SubjectKeyIdentifierHashAlgorithm.Sha1:
-                    return ComputeSha1(key.EncodedKeyValue.RawData);
+                    return SHA1.HashData(key.EncodedKeyValue.RawData);
 
                 case X509SubjectKeyIdentifierHashAlgorithm.ShortSha1:
                     {
-                        byte[] sha1 = ComputeSha1(key.EncodedKeyValue.RawData);
+                        byte[] sha1 = SHA1.HashData(key.EncodedKeyValue.RawData);
 
                         //  ShortSha1: The keyIdentifier is composed of a four bit type field with
                         //  the value 0100 followed by the least significant 60 bits of the
@@ -122,15 +123,6 @@ namespace System.Security.Cryptography.X509Certificates
             }
         }
 
-        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 is required by RFC3280")]
-        private static byte[] ComputeSha1(byte[] data)
-        {
-            using (SHA1 sha1 = SHA1.Create())
-            {
-                return sha1.ComputeHash(data);
-            }
-        }
-
         private string? _subjectKeyIdentifier;
         private bool _decoded;
     }