Skip to content

Commit 962d66c

Browse files
committed
ensure that compareDigest uses a time-constant algorithm, in this case Double HMAC Verification
1 parent 83d9658 commit 962d66c

1 file changed

Lines changed: 15 additions & 7 deletions

File tree

src/cmap/auth/scram.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ async function continueScramConversation(
186186
const r = await connection.command(ns(`${db}.$cmd`), saslContinueCmd, undefined);
187187
const parsedResponse = parsePayload(r.payload);
188188

189-
if (!compareDigest(ByteUtils.fromBase64(parsedResponse.v), serverSignature)) {
189+
if (!(await compareDigest(ByteUtils.fromBase64(parsedResponse.v), serverSignature))) {
190190
throw new MongoRuntimeError('Server returned an invalid signature');
191191
}
192192

@@ -342,17 +342,25 @@ async function HI(data: string, salt: Uint8Array, iterations: number, cryptoMeth
342342
return saltedData;
343343
}
344344

345-
function compareDigest(lhs: Uint8Array, rhs: Uint8Array) {
345+
async function compareDigest(lhs: Uint8Array, rhs: Uint8Array) {
346346
if (lhs.length !== rhs.length) {
347347
return false;
348348
}
349349

350-
let result = 0;
351-
for (let i = 0; i < lhs.length; i++) {
352-
result |= lhs[i] ^ rhs[i];
353-
}
350+
// Compare values using a time-constant algorithm to prevent against timing attacks
351+
// The approach is called "Double HMAC Verification". The basic idea is:
352+
// 1. Generate a random key
353+
// 2. HMAC the random key with both values
354+
// 3. Compare the HMACs using an equality check
355+
356+
const randomKey = crypto.getRandomValues(new Uint8Array(32));
357+
const lhsHMAC = await HMAC('sha256', randomKey, lhs);
358+
const rhsHMAC = await HMAC('sha256', randomKey, rhs);
359+
const lhsHex = ByteUtils.toHex(lhsHMAC);
360+
const rhsHex = ByteUtils.toHex(rhsHMAC);
361+
const areEqual = lhsHex === rhsHex;
354362

355-
return result === 0;
363+
return areEqual;
356364
}
357365

358366
export class ScramSHA1 extends ScramSHA {

0 commit comments

Comments
 (0)