Bug 825891 - Remove the code for per-client randomization in the url-classifier. r=dcamp
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Tue, 08 Jan 2013 16:43:33 +0100
changeset 118098 b6d93a7be19da2a6237195db39dd7701cc51edd4
parent 118097 d13052681690e3c0c57aa2aa5c4037c747f61144
child 118099 66de0c58bdadbd586327bbd4d1d443d5adbb21ec
push idunknown
push userunknown
push dateunknown
reviewersdcamp
bugs825891
milestone21.0a1
Bug 825891 - Remove the code for per-client randomization in the url-classifier. r=dcamp
b2g/app/b2g.js
browser/app/profile/firefox.js
mobile/android/app/mobile.js
toolkit/components/url-classifier/Classifier.cpp
toolkit/components/url-classifier/Classifier.h
toolkit/components/url-classifier/HashStore.cpp
toolkit/components/url-classifier/LookupCache.cpp
toolkit/components/url-classifier/LookupCache.h
toolkit/components/url-classifier/ProtocolParser.cpp
toolkit/components/url-classifier/ProtocolParser.h
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -323,19 +323,16 @@ pref("browser.geolocation.warning.infoUR
 
 // Name of the about: page contributed by safebrowsing to handle display of error
 // pages on phishing/malware hits.  (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
 
-// Randomize all UrlClassifier data with a per-client key.
-pref("urlclassifier.randomizeclient", false);
-
 // The list of tables that use the gethash request to confirm partial results.
 pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
 
 // If an urlclassifier table has not been updated in this number of seconds,
 // a gethash request will be forced to check that the result is still in
 // the database.
 pref("urlclassifier.max-complete-age", 2700);
 
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -731,19 +731,16 @@ pref("browser.safebrowsing.malware.repor
 
 // Name of the about: page contributed by safebrowsing to handle display of error
 // pages on phishing/malware hits.  (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
 
-// Randomize all UrlClassifier data with a per-client key.
-pref("urlclassifier.randomizeclient", false);
-
 // The list of tables that use the gethash request to confirm partial results.
 pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
 
 // If an urlclassifier table has not been updated in this number of seconds,
 // a gethash request will be forced to check that the result is still in
 // the database.
 pref("urlclassifier.max-complete-age", 2700);
 #endif
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -570,19 +570,16 @@ pref("browser.safebrowsing.malware.repor
 
 // Name of the about: page contributed by safebrowsing to handle display of error
 // pages on phishing/malware hits.  (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
 
-// Randomize all UrlClassifier data with a per-client key.
-pref("urlclassifier.randomizeclient", false);
-
 // The list of tables that use the gethash request to confirm partial results.
 pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
 
 // If an urlclassifier table has not been updated in this number of seconds,
 // a gethash request will be forced to check that the result is still in
 // the database.
 pref("urlclassifier.max-complete-age", 2700);
 #endif
--- a/toolkit/components/url-classifier/Classifier.cpp
+++ b/toolkit/components/url-classifier/Classifier.cpp
@@ -29,96 +29,24 @@ extern PRLogModuleInfo *gUrlClassifierDb
 #define TO_DELETE_DIR_SUFFIX NS_LITERAL_CSTRING("-to_delete")
 #define BACKUP_DIR_SUFFIX    NS_LITERAL_CSTRING("-backup")
 
 namespace mozilla {
 namespace safebrowsing {
 
 Classifier::Classifier()
   : mFreshTime(45 * 60)
-  , mPerClientRandomize(true)
 {
 }
 
 Classifier::~Classifier()
 {
   Close();
 }
 
-/*
- * Generate a unique 32-bit key for this user, which we will
- * use to rehash all prefixes. This ensures that different users
- * will get hash collisions on different prefixes, which in turn
- * avoids that "unlucky" URLs get mysterious slowdowns, and that
- * the servers get spammed if any such URL should get slashdotted.
- * https://bugzilla.mozilla.org/show_bug.cgi?id=669407#c10
- */
-nsresult
-Classifier::InitKey()
-{
-  nsCOMPtr<nsIFile> storeFile;
-  nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = storeFile->AppendNative(NS_LITERAL_CSTRING("classifier.hashkey"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool exists;
-  rv = storeFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!exists) {
-    // generate and store key
-    nsCOMPtr<nsIRandomGenerator> rg =
-      do_GetService("@mozilla.org/security/random-generator;1");
-    NS_ENSURE_STATE(rg);
-
-    uint8_t *temp;
-    nsresult rv = rg->GenerateRandomBytes(sizeof(mHashKey), &temp);
-    NS_ENSURE_SUCCESS(rv, rv);
-    memcpy(&mHashKey, temp, sizeof(mHashKey));
-    NS_Free(temp);
-
-    nsCOMPtr<nsIOutputStream> out;
-    rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out), storeFile,
-                                       -1, -1, 0);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    uint32_t written;
-    rv = out->Write(reinterpret_cast<char*>(&mHashKey), sizeof(uint32_t), &written);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsISafeOutputStream> safeOut = do_QueryInterface(out);
-    rv = safeOut->Finish();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    LOG(("Initialized classifier, key = %X", mHashKey));
-  } else {
-    // read key
-    nsCOMPtr<nsIInputStream> inputStream;
-    rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), storeFile,
-                                    -1, -1, 0);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(inputStream);
-    nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    void *buffer = &mHashKey;
-    rv = NS_ReadInputStreamToBuffer(inputStream,
-                                    &buffer,
-                                    sizeof(uint32_t));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    LOG(("Loaded classifier key = %X", mHashKey));
-  }
-
-  return NS_OK;
-}
-
 nsresult
 Classifier::SetupPathNames()
 {
   // Get the root directory where to store all the databases.
   nsresult rv = mCacheDirectory->Clone(getter_AddRefs(mStoreDirectory));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mStoreDirectory->AppendNative(STORE_DIRECTORY);
@@ -193,23 +121,16 @@ Classifier::Open(nsIFile& aCacheDirector
 
   // Make sure the main store directory exists.
   rv = CreateStoreDirectory();
   NS_ENSURE_SUCCESS(rv, rv);
 
   mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = InitKey();
-  if (NS_FAILED(rv)) {
-    // Without a usable key the database is useless
-    Reset();
-    return NS_ERROR_FAILURE;
-  }
-
   mTableFreshness.Init();
 
   // Build the list of know urlclassifier lists
   // XXX: Disk IO potentially on the main thread during startup
   RegenActiveTables();
 
   return NS_OK;
 }
@@ -316,19 +237,17 @@ Classifier::Check(const nsACString& aSpe
       nsAutoCString checking;
       lookupHash.ToString(checking);
       LOG(("Checking %s (%X)", checking.get(), lookupHash.ToUint32()));
     }
 #endif
     for (uint32_t i = 0; i < cacheArray.Length(); i++) {
       LookupCache *cache = cacheArray[i];
       bool has, complete;
-      Prefix codedPrefix;
-      rv = cache->Has(lookupHash, hostKey, mHashKey,
-                      &has, &complete, &codedPrefix);
+      rv = cache->Has(lookupHash, &has, &complete);
       NS_ENSURE_SUCCESS(rv, rv);
       if (has) {
         LookupResult *result = aResults.AppendElement();
         if (!result)
           return NS_ERROR_OUT_OF_MEMORY;
 
         int64_t age;
         bool found = mTableFreshness.Get(cache->TableName(), &age);
@@ -340,17 +259,16 @@ Classifier::Check(const nsACString& aSpe
         }
 
         LOG(("Found a result in %s: %s (Age: %Lds)",
              cache->TableName().get(),
              complete ? "complete." : "Not complete.",
              age));
 
         result->hash.complete = lookupHash;
-        result->mCodedPrefix = codedPrefix;
         result->mComplete = complete;
         result->mFresh = (age < mFreshTime);
         result->mTableName.Assign(cache->TableName());
       }
     }
 
   }
 
@@ -753,18 +671,17 @@ LookupCache *
 Classifier::GetLookupCache(const nsACString& aTable)
 {
   for (uint32_t i = 0; i < mLookupCaches.Length(); i++) {
     if (mLookupCaches[i]->TableName().Equals(aTable)) {
       return mLookupCaches[i];
     }
   }
 
-  LookupCache *cache = new LookupCache(aTable, mStoreDirectory,
-                                       mPerClientRandomize);
+  LookupCache *cache = new LookupCache(aTable, mStoreDirectory);
   nsresult rv = cache->Init();
   if (NS_FAILED(rv)) {
     return nullptr;
   }
   rv = cache->Open();
   if (NS_FAILED(rv)) {
     if (rv == NS_ERROR_FILE_CORRUPTED) {
       Reset();
--- a/toolkit/components/url-classifier/Classifier.h
+++ b/toolkit/components/url-classifier/Classifier.h
@@ -55,17 +55,16 @@ public:
   /**
    * Failed update. Spoil the entries so we don't block hosts
    * unnecessarily
    */
   nsresult MarkSpoiled(nsTArray<nsCString>& aTables);
   nsresult CacheCompletions(const CacheResultArray& aResults);
   uint32_t GetHashKey(void) { return mHashKey; }
   void SetFreshTime(uint32_t aTime) { mFreshTime = aTime; }
-  void SetPerClientRandomize(bool aRandomize) { mPerClientRandomize = aRandomize; }
   /*
    * Get a bunch of extra prefixes to query for completion
    * and mask the real entry being requested
    */
   nsresult ReadNoiseEntries(const Prefix& aPrefix,
                             const nsACString& aTableName,
                             uint32_t aCount,
                             PrefixArray* aNoiseEntries);
@@ -79,32 +78,30 @@ private:
   nsresult RemoveBackupTables();
   nsresult RegenActiveTables();
   nsresult ScanStoreDir(nsTArray<nsCString>& aTables);
 
   nsresult ApplyTableUpdates(nsTArray<TableUpdate*>* aUpdates,
                              const nsACString& aTable);
 
   LookupCache *GetLookupCache(const nsACString& aTable);
-  nsresult InitKey();
 
   // Root dir of the Local profile.
   nsCOMPtr<nsIFile> mCacheDirectory;
   // Main directory where to store the databases.
   nsCOMPtr<nsIFile> mStoreDirectory;
   // Used for atomically updating the other dirs.
   nsCOMPtr<nsIFile> mBackupDirectory;
   nsCOMPtr<nsIFile> mToDeleteDirectory;
   nsCOMPtr<nsICryptoHash> mCryptoHash;
   nsTArray<HashStore*> mHashStores;
   nsTArray<LookupCache*> mLookupCaches;
   nsTArray<nsCString> mActiveTablesCache;
   uint32_t mHashKey;
   // Stores the last time a given table was updated (seconds).
   nsDataHashtable<nsCStringHashKey, int64_t> mTableFreshness;
   uint32_t mFreshTime;
-  bool mPerClientRandomize;
 };
 
 }
 }
 
 #endif
--- a/toolkit/components/url-classifier/HashStore.cpp
+++ b/toolkit/components/url-classifier/HashStore.cpp
@@ -989,23 +989,16 @@ HashStore::ProcessSubs()
   EnsureSorted(&mAddCompletes);
   EnsureSorted(&mSubCompletes);
   LOG(("All databases seem to have a consistent sort order."));
 #endif
 
   RemoveMatchingPrefixes(mSubPrefixes, &mAddCompletes);
   RemoveMatchingPrefixes(mSubPrefixes, &mSubCompletes);
 
-  // Clean up temporary subs (without per-client randomization),
-  // that we temporarily stored so we could knock out completes.
-  ChunkSet dummyChunks;
-  dummyChunks.Set(0);
-  ExpireEntries(&mSubPrefixes, dummyChunks);
-  mSubChunks.Remove(dummyChunks);
-
   // Remove any remaining subbed prefixes from both addprefixes
   // and addcompletes.
   KnockoutSubs(&mSubPrefixes,  &mAddPrefixes);
   KnockoutSubs(&mSubCompletes, &mAddCompletes);
 
   // Remove any remaining subprefixes referring to addchunks that
   // we have (and hence have been processed above).
   RemoveDeadSubPrefixes(mSubPrefixes, mAddChunks);
--- a/toolkit/components/url-classifier/LookupCache.cpp
+++ b/toolkit/components/url-classifier/LookupCache.cpp
@@ -43,20 +43,18 @@ extern PRLogModuleInfo *gUrlClassifierDb
 #endif
 
 namespace mozilla {
 namespace safebrowsing {
 
 const uint32_t LOOKUPCACHE_MAGIC = 0x1231af3e;
 const uint32_t CURRENT_VERSION = 2;
 
-LookupCache::LookupCache(const nsACString& aTableName, nsIFile* aStoreDir,
-                         bool aPerClientRandomize)
+LookupCache::LookupCache(const nsACString& aTableName, nsIFile* aStoreDir)
   : mPrimed(false)
-  , mPerClientRandomize(aPerClientRandomize)
   , mTableName(aTableName)
   , mStoreDirectory(aStoreDir)
 {
 }
 
 nsresult
 LookupCache::Init()
 {
@@ -186,35 +184,24 @@ LookupCache::Dump()
     mCompletions[i].ToString(str);
     LOG(("Completion: %s", str.get()));
   }
 }
 #endif
 
 nsresult
 LookupCache::Has(const Completion& aCompletion,
-                 const Completion& aHostkey,
-                 const uint32_t aHashKey,
-                 bool* aHas, bool* aComplete,
-                 Prefix* aOrigPrefix)
+                 bool* aHas, bool* aComplete)
 {
   *aHas = *aComplete = false;
 
   uint32_t prefix = aCompletion.ToUint32();
-  uint32_t hostkey = aHostkey.ToUint32();
-  uint32_t codedkey;
-  nsresult rv = KeyedHash(prefix, hostkey, aHashKey, &codedkey, !mPerClientRandomize);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  Prefix codedPrefix;
-  codedPrefix.FromUint32(codedkey);
-  *aOrigPrefix = codedPrefix;
 
   bool found;
-  rv = mPrefixSet->Contains(codedkey, &found);
+  nsresult rv = mPrefixSet->Contains(prefix, &found);
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOG(("Probe in %s: %X, found %d", mTableName.get(), prefix, found));
 
   if (found) {
     *aHas = true;
   }
 
@@ -589,73 +576,16 @@ LookupCache::GetHostKeys(const nsACStrin
     lookupHost2->Assign(hostComponents[last - 2]);
     lookupHost2->Append(".");
     lookupHost2->Append(*lookupHost);
   }
 
   return NS_OK;
 }
 
-/* We have both a prefix and a domain. Drop the domain, but
-   hash the domain, the prefix and a random value together,
-   ensuring any collisions happens at a different points for
-   different users.
-*/
-/* static */ nsresult LookupCache::KeyedHash(uint32_t aPref, uint32_t aHostKey,
-                                             uint32_t aUserKey, uint32_t* aOut,
-                                             bool aPassthrough)
-{
-  /* Do not do any processing in passthrough mode. */
-  if (aPassthrough) {
-    *aOut = aPref;
-    return NS_OK;
-  }
-
-  /* This is a reimplementation of MurmurHash3 32-bit
-     based on the public domain C++ sources.
-     http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
-     for nblocks = 2
-  */
-  uint32_t c1 = 0xCC9E2D51;
-  uint32_t c2 = 0x1B873593;
-  uint32_t c3 = 0xE6546B64;
-  uint32_t c4 = 0x85EBCA6B;
-  uint32_t c5 = 0xC2B2AE35;
-  uint32_t h1 = aPref; // seed
-  uint32_t k1;
-  uint32_t karr[2];
-
-  karr[0] = aHostKey;
-  karr[1] = aUserKey;
-
-  for (uint32_t i = 0; i < 2; i++) {
-    k1 = karr[i];
-    k1 *= c1;
-    k1 = (k1 << 15) | (k1 >> (32-15));
-    k1 *= c2;
-
-    h1 ^= k1;
-    h1 = (h1 << 13) | (h1 >> (32-13));
-    h1 *= 5;
-    h1 += c3;
-  }
-
-  h1 ^= 2; // len
-  // fmix
-  h1 ^= h1 >> 16;
-  h1 *= c4;
-  h1 ^= h1 >> 13;
-  h1 *= c5;
-  h1 ^= h1 >> 16;
-
-  *aOut = h1;
-
-  return NS_OK;
-}
-
 bool LookupCache::IsPrimed()
 {
   return mPrimed;
 }
 
 #ifdef DEBUG
 template <class T>
 static void EnsureSorted(T* aArray)
--- a/toolkit/components/url-classifier/LookupCache.h
+++ b/toolkit/components/url-classifier/LookupCache.h
@@ -40,19 +40,16 @@ public:
 
   // True if we have a complete match for this hash in the table.
   bool mComplete;
 
   // True if this is a noise entry, i.e. an extra entry
   // that is inserted to mask the true URL we are requesting
   bool mNoise;
 
-  // Value of actual key looked up in the prefixset (coded with client key)
-  Prefix mCodedPrefix;
-
   // True if we've updated this table recently-enough.
   bool mFresh;
 
   bool mProtocolConfirmed;
 
   nsCString mTableName;
 };
 
@@ -84,28 +81,17 @@ public:
   // Get the database key for a given URI.  This is the top three
   // domain components if they exist, otherwise the top two.
   //  hostname.com/foo/bar -> hostname.com
   //  mail.hostname.com/foo/bar -> mail.hostname.com
   //  www.mail.hostname.com/foo/bar -> mail.hostname.com
   static nsresult GetKey(const nsACString& aSpec, Completion* aHash,
                          nsCOMPtr<nsICryptoHash>& aCryptoHash);
 
-  /* We have both a prefix and a domain. Drop the domain, but
-     hash the domain, the prefix and a random value together,
-     ensuring any collisions happens at a different points for
-     different users. If aPassthrough is set, we ignore the
-     random value and copy prefix directly into output.
-  */
-  static nsresult KeyedHash(uint32_t aPref, uint32_t aHostKey,
-                            uint32_t aUserKey, uint32_t* aOut,
-                            bool aPassthrough);
-
-  LookupCache(const nsACString& aTableName, nsIFile* aStoreFile,
-              bool aPerClientRandomize);
+  LookupCache(const nsACString& aTableName, nsIFile* aStoreFile);
   ~LookupCache();
 
   const nsCString &TableName() const { return mTableName; }
 
   nsresult Init();
   nsresult Open();
   // The directory handle where we operate will
   // be moved away when a backup is made.
@@ -116,20 +102,17 @@ public:
   nsresult GetPrefixes(nsTArray<uint32_t>* aAddPrefixes);
   void ClearCompleteCache();
 
 #if DEBUG && defined(PR_LOGGING)
   void Dump();
 #endif
   nsresult WriteFile();
   nsresult Has(const Completion& aCompletion,
-               const Completion& aHostkey,
-               uint32_t aHashKey,
-               bool* aHas, bool* aComplete,
-               Prefix* aOrigPrefix);
+               bool* aHas, bool* aComplete);
   bool IsPrimed();
 
 private:
   void ClearAll();
   nsresult Reset();
   void UpdateHeader();
   nsresult ReadHeader(nsIInputStream* aInputStream);
   nsresult ReadCompletions(nsIInputStream* aInputStream);
@@ -142,17 +125,16 @@ private:
   struct Header {
     uint32_t magic;
     uint32_t version;
     uint32_t numCompletions;
   };
   Header mHeader;
 
   bool mPrimed;
-  bool mPerClientRandomize;
   nsCString mTableName;
   nsCOMPtr<nsIFile> mStoreDirectory;
   CompletionArray mCompletions;
   // Set of prefixes known to be in the database
   nsRefPtr<nsUrlClassifierPrefixSet> mPrefixSet;
 };
 
 }
--- a/toolkit/components/url-classifier/ProtocolParser.cpp
+++ b/toolkit/components/url-classifier/ProtocolParser.cpp
@@ -60,36 +60,34 @@ ParseChunkRange(nsACString::const_iterat
   if (numRead == 1) {
     *aLast = *aFirst;
     return true;
   }
 
   return false;
 }
 
-ProtocolParser::ProtocolParser(uint32_t aHashKey)
+ProtocolParser::ProtocolParser()
     : mState(PROTOCOL_STATE_CONTROL)
-  , mHashKey(aHashKey)
   , mUpdateStatus(NS_OK)
   , mUpdateWait(0)
   , mResetRequested(false)
   , mRekeyRequested(false)
 {
 }
 
 ProtocolParser::~ProtocolParser()
 {
   CleanupUpdates();
 }
 
 nsresult
-ProtocolParser::Init(nsICryptoHash* aHasher, bool aPerClientRandomize)
+ProtocolParser::Init(nsICryptoHash* aHasher)
 {
   mCryptoHash = aHasher;
-  mPerClientRandomize = aPerClientRandomize;
   return NS_OK;
 }
 
 /**
  * Initialize HMAC for the stream.
  *
  * If serverMAC is empty, the update stream will need to provide a
  * server MAC.
@@ -421,43 +419,33 @@ ProtocolParser::ProcessChunk(bool* aDone
 nsresult
 ProtocolParser::ProcessPlaintextChunk(const nsACString& aChunk)
 {
   if (!mTableUpdate) {
     NS_WARNING("Chunk received with no table.");
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv;
   nsTArray<nsCString> lines;
   ParseString(PromiseFlatCString(aChunk), '\n', lines);
 
   // non-hashed tables need to be hashed
   for (uint32_t i = 0; i < lines.Length(); i++) {
     nsCString& line = lines[i];
 
     if (mChunkState.type == CHUNK_ADD) {
       if (mChunkState.hashSize == COMPLETE_SIZE) {
         Completion hash;
         hash.FromPlaintext(line, mCryptoHash);
         mTableUpdate->NewAddComplete(mChunkState.num, hash);
       } else {
         NS_ASSERTION(mChunkState.hashSize == 4, "Only 32- or 4-byte hashes can be used for add chunks.");
-        Completion hash;
-        Completion domHash;
-        Prefix newHash;
-        rv = LookupCache::GetKey(line, &domHash, mCryptoHash);
-        NS_ENSURE_SUCCESS(rv, rv);
+        Prefix hash;
         hash.FromPlaintext(line, mCryptoHash);
-        uint32_t codedHash;
-        rv = LookupCache::KeyedHash(hash.ToUint32(), domHash.ToUint32(), mHashKey,
-                                    &codedHash, !mPerClientRandomize);
-        NS_ENSURE_SUCCESS(rv, rv);
-        newHash.FromUint32(codedHash);
-        mTableUpdate->NewAddPrefix(mChunkState.num, newHash);
+        mTableUpdate->NewAddPrefix(mChunkState.num, hash);
       }
     } else {
       nsCString::const_iterator begin, iter, end;
       line.BeginReading(begin);
       line.EndReading(end);
       iter = begin;
       uint32_t addChunk;
       if (!FindCharInReadable(':', iter, end) ||
@@ -469,31 +457,18 @@ ProtocolParser::ProcessPlaintextChunk(co
 
       if (mChunkState.hashSize == COMPLETE_SIZE) {
         Completion hash;
         hash.FromPlaintext(Substring(iter, end), mCryptoHash);
         mTableUpdate->NewSubComplete(addChunk, hash, mChunkState.num);
       } else {
         NS_ASSERTION(mChunkState.hashSize == 4, "Only 32- or 4-byte hashes can be used for add chunks.");
         Prefix hash;
-        Completion domHash;
-        rv = LookupCache::GetKey(Substring(iter, end), &domHash, mCryptoHash);
-        NS_ENSURE_SUCCESS(rv, rv);
         hash.FromPlaintext(Substring(iter, end), mCryptoHash);
-        uint32_t codedHash;
-        rv = LookupCache::KeyedHash(hash.ToUint32(), domHash.ToUint32(), mHashKey,
-                                    &codedHash, !mPerClientRandomize);
-        NS_ENSURE_SUCCESS(rv, rv);
-        Prefix newHash;
-        newHash.FromUint32(codedHash);
-        mTableUpdate->NewSubPrefix(addChunk, newHash, mChunkState.num);
-        // Needed to knock out completes
-        // Fake chunk nr, will cause it to be removed next update
-        mTableUpdate->NewSubPrefix(addChunk, hash, 0);
-        mTableUpdate->NewSubChunk(0);
+        mTableUpdate->NewSubPrefix(addChunk, hash, mChunkState.num);
       }
     }
   }
 
   return NS_OK;
 }
 
 nsresult
@@ -534,83 +509,57 @@ ProtocolParser::ProcessShaChunk(const ns
 
 nsresult
 ProtocolParser::ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries,
                                const nsACString& aChunk, uint32_t* aStart)
 {
   NS_ASSERTION(mChunkState.hashSize == PREFIX_SIZE,
                "ProcessHostAdd should only be called for prefix hashes.");
 
-  uint32_t codedHash;
-  uint32_t domHash = aDomain.ToUint32();
-
   if (aNumEntries == 0) {
-    nsresult rv = LookupCache::KeyedHash(domHash, domHash, mHashKey, &codedHash,
-                                         !mPerClientRandomize);
-    NS_ENSURE_SUCCESS(rv, rv);
-    Prefix newHash;
-    newHash.FromUint32(codedHash);
-    mTableUpdate->NewAddPrefix(mChunkState.num, newHash);
+    mTableUpdate->NewAddPrefix(mChunkState.num, aDomain);
     return NS_OK;
   }
 
   if (*aStart + (PREFIX_SIZE * aNumEntries) > aChunk.Length()) {
     NS_WARNING("Chunk is not long enough to contain the expected entries.");
     return NS_ERROR_FAILURE;
   }
 
   for (uint8_t i = 0; i < aNumEntries; i++) {
     Prefix hash;
     hash.Assign(Substring(aChunk, *aStart, PREFIX_SIZE));
-    nsresult rv = LookupCache::KeyedHash(hash.ToUint32(), domHash, mHashKey, &codedHash,
-                                         !mPerClientRandomize);
-    NS_ENSURE_SUCCESS(rv, rv);
-    Prefix newHash;
-    newHash.FromUint32(codedHash);
-    mTableUpdate->NewAddPrefix(mChunkState.num, newHash);
+    mTableUpdate->NewAddPrefix(mChunkState.num, hash);
     *aStart += PREFIX_SIZE;
   }
 
   return NS_OK;
 }
 
 nsresult
 ProtocolParser::ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries,
                                const nsACString& aChunk, uint32_t *aStart)
 {
   NS_ASSERTION(mChunkState.hashSize == PREFIX_SIZE,
                "ProcessHostSub should only be called for prefix hashes.");
 
-  uint32_t codedHash;
-  uint32_t domHash = aDomain.ToUint32();
-
   if (aNumEntries == 0) {
     if ((*aStart) + 4 > aChunk.Length()) {
       NS_WARNING("Received a zero-entry sub chunk without an associated add.");
       return NS_ERROR_FAILURE;
     }
 
     const nsCSubstring& addChunkStr = Substring(aChunk, *aStart, 4);
     *aStart += 4;
 
     uint32_t addChunk;
     memcpy(&addChunk, addChunkStr.BeginReading(), 4);
     addChunk = PR_ntohl(addChunk);
 
-    nsresult rv = LookupCache::KeyedHash(domHash, domHash, mHashKey, &codedHash,
-                                         !mPerClientRandomize);
-    NS_ENSURE_SUCCESS(rv, rv);
-    Prefix newHash;
-    newHash.FromUint32(codedHash);
-
-    mTableUpdate->NewSubPrefix(addChunk, newHash, mChunkState.num);
-    // Needed to knock out completes
-    // Fake chunk nr, will cause it to be removed next update
-    mTableUpdate->NewSubPrefix(addChunk, aDomain, 0);
-    mTableUpdate->NewSubChunk(0);
+    mTableUpdate->NewSubPrefix(addChunk, aDomain, mChunkState.num);
     return NS_OK;
   }
 
   if (*aStart + ((PREFIX_SIZE + 4) * aNumEntries) > aChunk.Length()) {
     NS_WARNING("Chunk is not long enough to contain the expected entries.");
     return NS_ERROR_FAILURE;
   }
 
@@ -621,27 +570,17 @@ ProtocolParser::ProcessHostSub(const Pre
     uint32_t addChunk;
     memcpy(&addChunk, addChunkStr.BeginReading(), 4);
     addChunk = PR_ntohl(addChunk);
 
     Prefix prefix;
     prefix.Assign(Substring(aChunk, *aStart, PREFIX_SIZE));
     *aStart += PREFIX_SIZE;
 
-    nsresult rv = LookupCache::KeyedHash(prefix.ToUint32(), domHash, mHashKey,
-                                         &codedHash, !mPerClientRandomize);
-    NS_ENSURE_SUCCESS(rv, rv);
-    Prefix newHash;
-    newHash.FromUint32(codedHash);
-
-    mTableUpdate->NewSubPrefix(addChunk, newHash, mChunkState.num);
-    // Needed to knock out completes
-    // Fake chunk nr, will cause it to be removed next update
-    mTableUpdate->NewSubPrefix(addChunk, prefix, 0);
-    mTableUpdate->NewSubChunk(0);
+    mTableUpdate->NewSubPrefix(addChunk, prefix, mChunkState.num);
   }
 
   return NS_OK;
 }
 
 nsresult
 ProtocolParser::ProcessHostAddComplete(uint8_t aNumEntries,
                                        const nsACString& aChunk, uint32_t* aStart)
--- a/toolkit/components/url-classifier/ProtocolParser.h
+++ b/toolkit/components/url-classifier/ProtocolParser.h
@@ -18,22 +18,22 @@ namespace safebrowsing {
 class ProtocolParser {
 public:
   struct ForwardedUpdate {
     nsCString table;
     nsCString url;
     nsCString mac;
   };
 
-  ProtocolParser(uint32_t aHashKey);
+  ProtocolParser();
   ~ProtocolParser();
 
   nsresult Status() const { return mUpdateStatus; }
 
-  nsresult Init(nsICryptoHash* aHasher, bool mPerClientRandomize);
+  nsresult Init(nsICryptoHash* aHasher);
 
   nsresult InitHMAC(const nsACString& aClientKey,
                     const nsACString& aServerMAC);
   nsresult FinishHMAC();
 
   void SetCurrentTable(const nsACString& aTable);
 
   nsresult Begin();
@@ -88,18 +88,16 @@ private:
     ChunkType type;
     uint32_t num;
     uint32_t hashSize;
     uint32_t length;
     void Clear() { num = 0; hashSize = 0; length = 0; }
   };
   ChunkState mChunkState;
 
-  uint32_t mHashKey;
-  bool mPerClientRandomize;
   nsCOMPtr<nsICryptoHash> mCryptoHash;
 
   nsresult mUpdateStatus;
   nsCString mPending;
 
   nsCOMPtr<nsICryptoHMAC> mHMAC;
   nsCString mServerMAC;
 
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -58,19 +58,16 @@ PRLogModuleInfo *gUrlClassifierDbService
 
 // Prefs for implementing nsIURIClassifier to block page loads
 #define CHECK_MALWARE_PREF      "browser.safebrowsing.malware.enabled"
 #define CHECK_MALWARE_DEFAULT   false
 
 #define CHECK_PHISHING_PREF     "browser.safebrowsing.enabled"
 #define CHECK_PHISHING_DEFAULT  false
 
-#define RANDOMIZE_CLIENT_PREF      "urlclassifier.randomizeclient"
-#define RANDOMIZE_CLIENT_DEFAULT   false
-
 #define GETHASH_NOISE_PREF      "urlclassifier.gethashnoise"
 #define GETHASH_NOISE_DEFAULT   4
 
 #define GETHASH_TABLES_PREF     "urlclassifier.gethashtables"
 
 #define CONFIRM_AGE_PREF        "urlclassifier.max-complete-age"
 #define CONFIRM_AGE_DEFAULT_SEC (45 * 60)
 
@@ -112,18 +109,17 @@ class nsUrlClassifierDBServiceWorker MOZ
 {
 public:
   nsUrlClassifierDBServiceWorker();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIURLCLASSIFIERDBSERVICE
   NS_DECL_NSIURLCLASSIFIERDBSERVICEWORKER
 
-  nsresult Init(uint32_t aGethashNoise, nsCOMPtr<nsIFile> aCacheDir,
-                bool aPerClientRandomize);
+  nsresult Init(uint32_t aGethashNoise, nsCOMPtr<nsIFile> aCacheDir);
 
   // Queue a lookup for the worker to perform, called in the main thread.
   nsresult QueueLookup(const nsACString& lookupKey,
                        nsIUrlClassifierLookupCallback* callback);
 
   // Handle any queued-up lookups.  We call this function during long-running
   // update operations to prevent lookups from blocking for too long.
   nsresult HandlePendingLookups();
@@ -176,25 +172,19 @@ private:
   nsTArray<nsCString> mUpdateTables;
 
   nsCOMPtr<nsIUrlClassifierUpdateObserver> mUpdateObserver;
   bool mInStream;
 
   // The client key with which the data from the server will be MAC'ed.
   nsCString mUpdateClientKey;
 
-  // The client-specific hash key to rehash
-  uint32_t mHashKey;
-
   // The number of noise entries to add to the set of lookup results.
   uint32_t mGethashNoise;
 
-  // Randomize clients with a key or not.
-  bool mPerClientRandomize;
-
   // Pending lookups are stored in a queue for processing.  The queue
   // is protected by mPendingLookupLock.
   Mutex mPendingLookupLock;
 
   class PendingLookup {
   public:
     TimeStamp mStartTime;
     nsCString mKey;
@@ -207,36 +197,33 @@ private:
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsUrlClassifierDBServiceWorker,
                               nsIUrlClassifierDBServiceWorker,
                               nsIUrlClassifierDBService)
 
 nsUrlClassifierDBServiceWorker::nsUrlClassifierDBServiceWorker()
   : mInStream(false)
   , mGethashNoise(0)
-  , mPerClientRandomize(true)
   , mPendingLookupLock("nsUrlClassifierDBServerWorker.mPendingLookupLock")
 {
 }
 
 nsUrlClassifierDBServiceWorker::~nsUrlClassifierDBServiceWorker()
 {
   NS_ASSERTION(!mClassifier,
                "Db connection not closed, leaking memory!  Call CloseDb "
                "to close the connection.");
 }
 
 nsresult
 nsUrlClassifierDBServiceWorker::Init(uint32_t aGethashNoise,
-                                     nsCOMPtr<nsIFile> aCacheDir,
-                                     bool aPerClientRandomize)
+                                     nsCOMPtr<nsIFile> aCacheDir)
 {
   mGethashNoise = aGethashNoise;
   mCacheDir = aCacheDir;
-  mPerClientRandomize = aPerClientRandomize;
 
   ResetUpdate();
 
   return NS_OK;
 }
 
 nsresult
 nsUrlClassifierDBServiceWorker::QueueLookup(const nsACString& spec,
@@ -318,17 +305,17 @@ nsUrlClassifierDBServiceWorker::DoLookup
     }
   }
 
   for (uint32_t i = 0; i < completes->Length(); i++) {
     if (!completes->ElementAt(i).Confirmed()) {
       // We're going to be doing a gethash request, add some extra entries.
       // Note that we cannot pass the first two by reference, because we
       // add to completes, whicah can cause completes to reallocate and move.
-      AddNoise(completes->ElementAt(i).mCodedPrefix,
+      AddNoise(completes->ElementAt(i).hash.prefix,
                completes->ElementAt(i).mTableName,
                mGethashNoise, *completes);
       break;
     }
   }
 
   // At this point ownership of 'results' is handed to the callback.
   c->LookupComplete(completes.forget());
@@ -480,21 +467,21 @@ nsUrlClassifierDBServiceWorker::BeginStr
 
   NS_ENSURE_STATE(mUpdateObserver);
   NS_ENSURE_STATE(!mInStream);
 
   mInStream = true;
 
   NS_ASSERTION(!mProtocolParser, "Should not have a protocol parser.");
 
-  mProtocolParser = new ProtocolParser(mHashKey);
+  mProtocolParser = new ProtocolParser();
   if (!mProtocolParser)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  mProtocolParser->Init(mCryptoHash, mPerClientRandomize);
+  mProtocolParser->Init(mCryptoHash);
 
   nsresult rv;
 
   // If we're expecting a MAC, create the nsICryptoHMAC component now.
   if (!mUpdateClientKey.IsEmpty()) {
     LOG(("Expecting MAC in this stream"));
     rv = mProtocolParser->InitHMAC(mUpdateClientKey, serverMAC);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -704,17 +691,17 @@ nsUrlClassifierDBServiceWorker::CacheCom
 {
   LOG(("nsUrlClassifierDBServiceWorker::CacheCompletions [%p]", this));
   if (!mClassifier)
     return NS_OK;
 
   // Ownership is transferred in to us
   nsAutoPtr<CacheResultArray> resultsPtr(results);
 
-  nsAutoPtr<ProtocolParser> pParse(new ProtocolParser(mHashKey));
+  nsAutoPtr<ProtocolParser> pParse(new ProtocolParser());
   nsTArray<TableUpdate*> updates;
 
   // Only cache results for tables that we have, don't take
   // in tables we might accidentally have hit during a completion.
   // This happens due to goog vs googpub lists existing.
   nsTArray<nsCString> tables;
   nsresult rv = mClassifier->ActiveTables(tables);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -775,22 +762,20 @@ nsUrlClassifierDBServiceWorker::OpenDb()
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoPtr<Classifier> classifier(new Classifier());
   if (!classifier) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   classifier->SetFreshTime(gFreshnessGuarantee);
-  classifier->SetPerClientRandomize(mPerClientRandomize);
 
   rv = classifier->Open(*mCacheDir);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mHashKey = classifier->GetHashKey();
   mClassifier = classifier;
 
   return NS_OK;
 }
 
 // -------------------------------------------------------------------------
 // nsUrlClassifierLookupCallback
 //
@@ -1102,17 +1087,16 @@ nsUrlClassifierDBService::GetInstance(ns
   }
   return sUrlClassifierDBService;
 }
 
 
 nsUrlClassifierDBService::nsUrlClassifierDBService()
  : mCheckMalware(CHECK_MALWARE_DEFAULT)
  , mCheckPhishing(CHECK_PHISHING_DEFAULT)
- , mPerClientRandomize(true)
  , mInUpdate(false)
 {
 }
 
 nsUrlClassifierDBService::~nsUrlClassifierDBService()
 {
   sUrlClassifierDBService = nullptr;
 }
@@ -1154,25 +1138,16 @@ nsUrlClassifierDBService::Init()
     }
 
     prefs->AddObserver(GETHASH_TABLES_PREF, this, false);
 
     rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint);
     PR_ATOMIC_SET(&gFreshnessGuarantee, NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC);
 
     prefs->AddObserver(CONFIRM_AGE_PREF, this, false);
-
-    rv = prefs->GetBoolPref(RANDOMIZE_CLIENT_PREF, &tmpbool);
-    mPerClientRandomize = NS_SUCCEEDED(rv) ? tmpbool : RANDOMIZE_CLIENT_DEFAULT;
-
-    LOG(("Per client randomization is %s",
-         mPerClientRandomize ? "enabled" : "DISABLED"));
-
-    /* We do not observe for runtime changes as changing this preference
-       in flight kills the database, so it's not really supported. */
   }
 
   // Force PSM loading on main thread
   nsCOMPtr<nsICryptoHash> acryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Directory providers must also be accessed on the main thread.
   nsCOMPtr<nsIFile> cacheDir;
@@ -1187,17 +1162,17 @@ nsUrlClassifierDBService::Init()
   rv = NS_NewNamedThread("URL Classifier", &gDbBackgroundThread);
   if (NS_FAILED(rv))
     return rv;
 
   mWorker = new nsUrlClassifierDBServiceWorker();
   if (!mWorker)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  rv = mWorker->Init(gethashNoise, cacheDir, mPerClientRandomize);
+  rv = mWorker->Init(gethashNoise, cacheDir);
   if (NS_FAILED(rv)) {
     mWorker = nullptr;
     return rv;
   }
 
   // Proxy for calling the worker on the background thread
   mWorkerProxy = new UrlClassifierDBServiceWorkerProxy(mWorker);