Bug 414635 - nsICryptoHash reinitialization implementation is inefficient, PSM part, r=kaie+wtc
authorHonza Bambas <honzab.moz@firemni.cz>
Sun, 28 Jun 2009 12:02:50 +0200
changeset 29784 ca23d3b5a999
parent 29783 4ceba37b3b22
child 29786 29b767814d87
push id106
push userhsivonen@iki.fi
push dateSun, 28 Jun 2009 17:44:42 +0000
reviewerskaie
bugs414635
milestone1.9.2a1pre
Bug 414635 - nsICryptoHash reinitialization implementation is inefficient, PSM part, r=kaie+wtc
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSComponent.h
security/manager/ssl/tests/unit/test_hash_algorithms.js
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -2545,38 +2545,53 @@ nsNSSComponent::IsNSSInitialized(PRBool 
 }
 
 //---------------------------------------------
 // Implementing nsICryptoHash
 //---------------------------------------------
 
 nsCryptoHash::nsCryptoHash()
   : mHashContext(nsnull)
+  , mInitialized(PR_FALSE)
 {
 }
 
 nsCryptoHash::~nsCryptoHash()
 {
   if (mHashContext)
     HASH_Destroy(mHashContext);
 }
 
 NS_IMPL_ISUPPORTS1(nsCryptoHash, nsICryptoHash)
 
 NS_IMETHODIMP 
 nsCryptoHash::Init(PRUint32 algorithm)
 {
+  HASH_HashType hashType = (HASH_HashType)algorithm;
   if (mHashContext)
+  {
+    if ((!mInitialized) && (HASH_GetType(mHashContext) == hashType))
+    {
+      mInitialized = PR_TRUE;
+      HASH_Begin(mHashContext);
+      return NS_OK;
+    }
+
+    // Destroy current hash context if the type was different
+    // or Finish method wasn't called.
     HASH_Destroy(mHashContext);
-
-  mHashContext = HASH_Create((HASH_HashType) algorithm);
+    mInitialized = PR_FALSE;
+  }
+
+  mHashContext = HASH_Create(hashType);
   if (!mHashContext)
     return NS_ERROR_INVALID_ARG;
 
   HASH_Begin(mHashContext);
+  mInitialized = PR_TRUE;
   return NS_OK; 
 }
 
 NS_IMETHODIMP
 nsCryptoHash::InitWithString(const nsACString & aAlgorithm)
 {
   if (aAlgorithm.LowerCaseEqualsLiteral("md2"))
     return Init(nsICryptoHash::MD2);
@@ -2597,27 +2612,27 @@ nsCryptoHash::InitWithString(const nsACS
     return Init(nsICryptoHash::SHA512);
 
   return NS_ERROR_INVALID_ARG;
 }
 
 NS_IMETHODIMP
 nsCryptoHash::Update(const PRUint8 *data, PRUint32 len)
 {
-  if (!mHashContext)
+  if (!mInitialized)
     return NS_ERROR_NOT_INITIALIZED;
 
   HASH_Update(mHashContext, data, len);
   return NS_OK; 
 }
 
 NS_IMETHODIMP
 nsCryptoHash::UpdateFromStream(nsIInputStream *data, PRUint32 len)
 {
-  if (!mHashContext)
+  if (!mInitialized)
     return NS_ERROR_NOT_INITIALIZED;
 
   if (!data)
     return NS_ERROR_INVALID_ARG;
 
   PRUint32 n;
   nsresult rv = data->Available(&n);
   if (NS_FAILED(rv))
@@ -2655,27 +2670,26 @@ nsCryptoHash::UpdateFromStream(nsIInputS
   }
   
   return rv;
 }
 
 NS_IMETHODIMP
 nsCryptoHash::Finish(PRBool ascii, nsACString & _retval)
 {
-  if (!mHashContext)
+  if (!mInitialized)
     return NS_ERROR_NOT_INITIALIZED;
   
   PRUint32 hashLen = 0;
   unsigned char buffer[HASH_LENGTH_MAX];
   unsigned char* pbuffer = buffer;
 
   HASH_End(mHashContext, pbuffer, &hashLen, HASH_LENGTH_MAX);
-  HASH_Destroy(mHashContext);
-
-  mHashContext = nsnull;
+
+  mInitialized = PR_FALSE;
 
   if (ascii)
   {
     char *asciiData = BTOA_DataToAscii(buffer, hashLen);
     NS_ENSURE_TRUE(asciiData, NS_ERROR_OUT_OF_MEMORY);
 
     _retval.Assign(asciiData);
     PORT_Free(asciiData);
--- a/security/manager/ssl/src/nsNSSComponent.h
+++ b/security/manager/ssl/src/nsNSSComponent.h
@@ -197,17 +197,19 @@ class nsCryptoHash : public nsICryptoHas
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICRYPTOHASH
 
   nsCryptoHash();
 
 private:
   ~nsCryptoHash();
+
   HASHContext* mHashContext;
+  PRBool mInitialized;
 };
 
 class nsCryptoHMAC : public nsICryptoHMAC
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICRYPTOHMAC
 
--- a/security/manager/ssl/tests/unit/test_hash_algorithms.js
+++ b/security/manager/ssl/tests/unit/test_hash_algorithms.js
@@ -65,21 +65,31 @@ function hexdigest(data) {
 
 function doHash(algo, value, cmp) {
   var converter = new ScriptableUnicodeConverter();
   var hash = new CryptoHash(algo);
 
   converter.charset = 'utf8';
   value = converter.convertToByteArray(value, {});
   hash.update(value, value.length);
-  hash = hexdigest(hash.finish(false));
-  if (cmp != hash) {
+  var hash1 = hexdigest(hash.finish(false));
+  if (cmp != hash1) {
     do_throw("Hash mismatch!\n" +
              "  Expected: " + cmp + "\n" +
-             "  Actual: " + hash + "\n" +
+             "  Actual: " + hash1 + "\n" +
+             "  Algo: " + algo);
+  }                                                                                                                                                                                                                                  
+
+  hash.initWithString(algo);
+  hash.update(value, value.length);
+  var hash2 = hexdigest(hash.finish(false));
+  if (cmp != hash2) {
+    do_throw("Hash mismatch after crypto hash re-init!\n" +
+             "  Expected: " + cmp + "\n" +
+             "  Actual: " + hash2 + "\n" +
              "  Algo: " + algo);
   }
 }
 
 function doHashStream(algo, value, cmp) {
   var converter = new ScriptableUnicodeConverter();
   var hash = new CryptoHash(algo);