--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -143,86 +143,104 @@ nsRFPService::IsTimerPrecisionReductionE
#define LRU_CACHE_SIZE (45)
#define HASH_DIGEST_SIZE_BITS (256)
#define HASH_DIGEST_SIZE_BYTES (HASH_DIGEST_SIZE_BITS / 8)
class LRUCache final
{
public:
LRUCache()
- : mLock("mozilla.resistFingerprinting.LRUCache") {
+ : mLock("mozilla.resistFingerprinting.LRUCache")
+ {
this->cache.SetLength(LRU_CACHE_SIZE);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LRUCache)
- nsCString Get(long long aKey) {
+ nsCString
+ Get(long long aKeyPart1, long long aKeyPart2)
+ {
for (auto & cacheEntry : this->cache) {
// Read optimistically befor locking
- if (cacheEntry.key == aKey) {
+ if (cacheEntry.keyPart1 == aKeyPart1 &&
+ cacheEntry.keyPart2 == aKeyPart2) {
MutexAutoLock lock(mLock);
// Double check after we have a lock
- if (MOZ_UNLIKELY(cacheEntry.key != aKey)) {
+ if (MOZ_UNLIKELY(cacheEntry.keyPart1 != aKeyPart1 ||
+ cacheEntry.keyPart2 != aKeyPart2)) {
// Got evicted in a race
- long long tmp_key = cacheEntry.key;
+ long long tmp_keyPart1 = cacheEntry.keyPart1;
+ long long tmp_keyPart2 = cacheEntry.keyPart2;
MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
- ("LRU Cache HIT-MISS with %lli != %lli", aKey, tmp_key));
+ ("LRU Cache HIT-MISS with %lli != %lli and %lli != %lli",
+ aKeyPart1, tmp_keyPart1, aKeyPart2, tmp_keyPart2));
return EmptyCString();
}
cacheEntry.accessTime = PR_Now();
MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
- ("LRU Cache HIT with %lli", aKey));
+ ("LRU Cache HIT with %lli %lli", aKeyPart1, aKeyPart2));
return cacheEntry.data;
}
}
return EmptyCString();
}
- void Store(long long aKey, const nsCString& aValue) {
+ void
+ Store(long long aKeyPart1, long long aKeyPart2, const nsCString& aValue)
+ {
MOZ_DIAGNOSTIC_ASSERT(aValue.Length() == HASH_DIGEST_SIZE_BYTES);
MutexAutoLock lock(mLock);
CacheEntry* lowestKey = &this->cache[0];
for (auto & cacheEntry : this->cache) {
- if (MOZ_UNLIKELY(cacheEntry.key == aKey)) {
+ if (MOZ_UNLIKELY(cacheEntry.keyPart1 == aKeyPart1 &&
+ cacheEntry.keyPart2 == aKeyPart2)) {
// Another thread inserted before us, don't insert twice
MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
- ("LRU Cache DOUBLE STORE with %lli", aKey));
+ ("LRU Cache DOUBLE STORE with %lli %lli", aKeyPart1, aKeyPart2));
return;
}
if (cacheEntry.accessTime < lowestKey->accessTime) {
lowestKey = &cacheEntry;
}
}
- lowestKey->key = aKey;
+ lowestKey->keyPart1 = aKeyPart1;
+ lowestKey->keyPart2 = aKeyPart2;
lowestKey->data = aValue;
lowestKey->accessTime = PR_Now();
- MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose, ("LRU Cache STORE with %lli", aKey));
+ MOZ_LOG(gResistFingerprintingLog, LogLevel::Verbose,
+ ("LRU Cache STORE with %lli %lli", aKeyPart1, aKeyPart2));
}
private:
~LRUCache() = default;
- struct CacheEntry {
- Atomic<long long, Relaxed> key;
+ struct CacheEntry
+ {
+ Atomic<long long, Relaxed> keyPart1;
+ Atomic<long long, Relaxed> keyPart2;
PRTime accessTime = 0;
nsCString data;
- CacheEntry() {
- this->key = 0xFFFFFFFFFFFFFFFF;
+ CacheEntry()
+ {
+ this->keyPart1 = 0xFFFFFFFFFFFFFFFF;
+ this->keyPart2 = 0xFFFFFFFFFFFFFFFF;
this->accessTime = 0;
this->data = nullptr;
}
- CacheEntry(const CacheEntry &obj) {
- this->key.exchange(obj.key);
+ CacheEntry(const CacheEntry &obj)
+ {
+ this->keyPart1.exchange(obj.keyPart1);
+ this->keyPart2.exchange(obj.keyPart2);
this->accessTime = obj.accessTime;
this->data = obj.data;
}
};
AutoTArray<CacheEntry, LRU_CACHE_SIZE> cache;
mozilla::Mutex mLock;
};
@@ -338,17 +356,17 @@ nsRFPService::RandomMidpoint(long long a
* kClampTimesPerDigest (just like we reduced the real time value to aClampedTime!)
*
* Then we hash _that_ value (assuming it's not in the cache) and index into the digest result
* the appropriate bit offset.
*/
long long reducedResolution = aResolutionUSec * kClampTimesPerDigest;
long long extraClampedTime = (aClampedTimeUSec / reducedResolution) * reducedResolution;
- nsCString hashResult = cache->Get(extraClampedTime);
+ nsCString hashResult = cache->Get(extraClampedTime, aContextMixin);
if(hashResult.Length() != HASH_DIGEST_SIZE_BYTES) { // Cache Miss =(
// If someone has pased in the testing-only parameter, replace our seed with it
if (aSecretSeed != nullptr) {
StaticMutexAutoLock lock(sLock);
if (sSecretMidpointSeed) {
delete[] sSecretMidpointSeed;
}
@@ -397,25 +415,28 @@ nsRFPService::RandomMidpoint(long long a
NS_ENSURE_SUCCESS(rv, rv);
rv = hasher->Init(nsICryptoHash::SHA256);
NS_ENSURE_SUCCESS(rv, rv);
rv = hasher->Update(sSecretMidpointSeed, kSeedSize);
NS_ENSURE_SUCCESS(rv, rv);
+ rv = hasher->Update((const uint8_t *)&aContextMixin, sizeof(aContextMixin));
+ NS_ENSURE_SUCCESS(rv, rv);
+
rv = hasher->Update((const uint8_t *)&extraClampedTime, sizeof(extraClampedTime));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCStringN<HASH_DIGEST_SIZE_BYTES> derivedSecret;
rv = hasher->Finish(false, derivedSecret);
NS_ENSURE_SUCCESS(rv, rv);
// Finally, store it in the cache
- cache->Store(extraClampedTime, derivedSecret);
+ cache->Store(extraClampedTime, aContextMixin, derivedSecret);
hashResult = derivedSecret;
}
// Offset the appropriate index into the hash output, and then turn it into a random midpoint
// between 0 and aResolutionUSec. Sometimes out input time is negative, we ride the negative
// out to the end until we start doing pointer math. (We also triple check we're in bounds.)
int byteOffset = abs(((aClampedTimeUSec - extraClampedTime) / aResolutionUSec) * 4);
if (MOZ_UNLIKELY(byteOffset > (HASH_DIGEST_SIZE_BYTES - 4))) {
--- a/toolkit/components/resistfingerprinting/tests/test_reduceprecision.cpp
+++ b/toolkit/components/resistfingerprinting/tests/test_reduceprecision.cpp
@@ -217,90 +217,91 @@ TEST(ResistFingerprinting, ReducePrecisi
* Here's our test vector. First we set the secret to the 16 byte value
* 0x000102030405060708 0x101112131415161718
*
* Then we work with a resolution of 500 us which will bucket things as such:
* Per-Clamp Buckets: [0, 500], [500, 1000], ...
* Per-Hash Buckets: [0, 4000], [4000, 8000], ...
*
* The first two hash values should be
- * 0: SHA-256(0x000102030405060708 || 0x101112131415161718 || 0x0000000000000000)
- * 32ca0459 bdb518be c72096dc 2667cd7a a76f94e4 c33fa679 9a1bd499 bfa4ec57
- * 4000: SHA-256(0x000102030405060708 || 0x101112131415161718 || 0xa00f000000000000)
- * bd0bf282 120fd8c2 459c4d05 0170179c 25136f6f 70db5c82 5807558d 148c7745
+ * 0: SHA-256(0x0001020304050607 || 0x1011121314151617 || 0xa00f000000000000 || 0x0000000000000000)
+ * 78d2d811 804fcaa4 7d472a1e 9fe043d2 dd77b3df 06c1c4f2 9f35f28a e3afbec0
+ * 4000: SHA-256(0x0001020304050607 || 0x1011121314151617 || 0xa00f000000000000 || 0xa00f000000000000)
+ * 1571bf19 92a89cd0 829259d5 b260a4a6 b8da8ad5 2e3ae33c 5571bb8d 8f69cca6
*
- * The midpoints are:
- * 0 : 32ca0459 % 500 = 130
- * 500 : bdb518be % 500 = 429
- * 1500: c72096dc % 500 = 311
- * 2000: 2667cd7a % 500 = 138
- * 2500: a76f94e4 % 500 = 159
- * 3000: c33fa679 % 500 = 435
- * 3500: 9a1bd499 % 500 = 246
- * 4000: bfa4ec57 % 500 = 463
- * 4500: bd0bf282 % 500 = 297
- * 5000: 120fd8c2 % 500 = 38
- * 5500: 459c4d05 % 500 = 357
+ * The midpoints are (if you're doing this manually, you need to correct endian-ness):
+ * 0 : 78d2d811 % 500 = 328
+ * 500 : 804fcaa4 % 500 = 48
+ * 1000: 7d472a1e % 500 = 293
+ * 1500: 9fe043d2 % 500 = 275
+ * 2000: dd77b3df % 500 = 297
+ * 2500: 06c1c4f2 % 500 = 242
+ * 3000: 9f35f28a % 500 = 247
+ * 3500: e3afbec0 % 500 = 339
+ * 4000: 1571bf19 % 500 = 225
+ * 4500: 92a89cd0 % 500 = 198
+ * 5000: 829259d5 % 500 = 218
+ * 5500: b260a4a6 % 500 = 14
*/
// Set the secret
long long throwAway;
uint8_t hardcodedSecret[16] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
nsRFPService::RandomMidpoint(0, 500, -1, &throwAway, hardcodedSecret);
// Run the test vectors
double result;
- result = nsRFPService::ReduceTimePrecisionImpl(1, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(1, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 0);
- result = nsRFPService::ReduceTimePrecisionImpl(129, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(327, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 0);
- result = nsRFPService::ReduceTimePrecisionImpl(130, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(328, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 500);
- result = nsRFPService::ReduceTimePrecisionImpl(131, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(329, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 500);
- result = nsRFPService::ReduceTimePrecisionImpl(499, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(499, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 500);
- result = nsRFPService::ReduceTimePrecisionImpl(500, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(500, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 500);
- result = nsRFPService::ReduceTimePrecisionImpl(600, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(540, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 500);
- result = nsRFPService::ReduceTimePrecisionImpl(928, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(547, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 500);
- result = nsRFPService::ReduceTimePrecisionImpl(929, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(548, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 1000);
- result = nsRFPService::ReduceTimePrecisionImpl(930, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(930, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 1000);
- result = nsRFPService::ReduceTimePrecisionImpl(1255, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(1255, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 1000);
- result = nsRFPService::ReduceTimePrecisionImpl(4000, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4000, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4000);
- result = nsRFPService::ReduceTimePrecisionImpl(4295, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4220, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4000);
- result = nsRFPService::ReduceTimePrecisionImpl(4296, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4224, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4000);
- result = nsRFPService::ReduceTimePrecisionImpl(4297, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4225, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4500);
- result = nsRFPService::ReduceTimePrecisionImpl(4298, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4340, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4500);
- result = nsRFPService::ReduceTimePrecisionImpl(4499, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4499, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4500);
- result = nsRFPService::ReduceTimePrecisionImpl(4500, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4500, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4500);
- result = nsRFPService::ReduceTimePrecisionImpl(4536, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4536, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4500);
- result = nsRFPService::ReduceTimePrecisionImpl(4537, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4695, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 4500);
- result = nsRFPService::ReduceTimePrecisionImpl(4538, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4698, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 5000);
- result = nsRFPService::ReduceTimePrecisionImpl(4539, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(4726, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 5000);
- result = nsRFPService::ReduceTimePrecisionImpl(5106, nsRFPService::TimeScale::MicroSeconds, 500, -1, TimerPrecisionType::All);
+ result = nsRFPService::ReduceTimePrecisionImpl(5106, nsRFPService::TimeScale::MicroSeconds, 500, 4000, TimerPrecisionType::All);
ASSERT_EQ(result, 5000);
cleanupJitter(jitterEnabled);
}