sodium-javascript/crypto_auth.js
Christian Bundy 94f270857d Fix verification using bitwise OR on booleans
Problem: Using bitwise operations on booleans doesn't make any sense,
and I didn't even catch that this was a problem until I ran `tsc` on the
codebase and saw the complaint. Static analysis rocks. In the libsodium
code these methods return `0` or `-1`, so the bitwise OR acts like a
boolean AND (`(0 | -1) === -1` like `(true && false === false)`.

Solution: Convert bitwise OR to boolean AND and then confirm that this
is the reason that the faulty truncated comparison fixed in fa39bc5 is
now captured by the tests in my pull request into sodium-test.

See-Also: https://github.com/sodium-friends/sodium-test/pull/14
2020-09-21 11:59:33 +02:00

89 lines
2.7 KiB
JavaScript

/* eslint-disable camelcase */
const { crypto_verify_32, crypto_verify_64 } = require('./crypto_verify')
const { sodium_memcmp } = require('./helpers')
const Sha256 = require('sha256-universal')
const Sha512 = require('sha512-universal')
const assert = require('nanoassert')
const crypto_auth_hmacsha256_BYTES = 32
const crypto_auth_hmacsha256_KEYBYTES = 32
const crypto_auth_hmacsha512_BYTES = 64
const crypto_auth_hmacsha512_KEYBYTES = 32
const crypto_auth_hmacsha512256_BYTES = 32
const crypto_auth_hmacsha512256_KEYBYTES = 32
const crypto_auth_BYTES = crypto_auth_hmacsha512256_BYTES
const crypto_auth_KEYBYTES = crypto_auth_hmacsha512256_KEYBYTES
function crypto_auth_hmacsha256 (out, input, k) {
assert(out.byteLength === crypto_auth_hmacsha256_BYTES, "out should be 'crypto_auth_hmacsha256_BYTES' in length")
const hmac = Sha256.HMAC(k)
hmac.update(input)
return hmac.digest(out)
}
function crypto_auth_hmacsha256_verify (h, input, k) {
const correct = Sha256.HMAC(k).update(input).digest()
return crypto_verify_32(h, 0, correct, 0) && sodium_memcmp(correct, h, 32)
}
function crypto_auth_hmacsha512 (out, input, k) {
assert(out.byteLength === crypto_auth_hmacsha512_BYTES, "out should be 'crypto_auth_hmacsha512_BYTES' in length")
const hmac = Sha512.HMAC(k)
hmac.update(input)
return hmac.digest(out)
}
function crypto_auth_hmacsha512_verify (h, input, k) {
const correct = Sha512.HMAC(k).update(input).digest()
return crypto_verify_64(h, 0, correct, 0) && sodium_memcmp(correct, h, 64)
}
function crypto_auth_hmacsha512256 (out, input, k) {
assert(out.byteLength === crypto_auth_hmacsha512256_BYTES, "out should be 'crypto_auth_hmacsha512256_BYTES' in length")
const out0 = new Uint8Array(64)
const hmac = Sha512.HMAC(k)
hmac.update(input)
hmac.digest(out0)
out.set(out0.subarray(0, 32))
}
function crypto_auth_hmacsha512256_verify (h, input, k) {
const correct = Sha512.HMAC(k).update(input).digest()
return crypto_verify_32(h, 0, correct, 0) && sodium_memcmp(correct.subarray(0, 32), h, 32)
}
function crypto_auth (out, input, k) {
return crypto_auth_hmacsha512256(out, input, k)
}
function crypto_auth_verify (h, input, k) {
return crypto_auth_hmacsha512256_verify(h, input, k)
}
module.exports = {
crypto_auth_BYTES,
crypto_auth_KEYBYTES,
crypto_auth_hmacsha256_BYTES,
crypto_auth_hmacsha256_KEYBYTES,
crypto_auth_hmacsha512_BYTES,
crypto_auth_hmacsha512_KEYBYTES,
crypto_auth_hmacsha512256_BYTES,
crypto_auth_hmacsha512256_KEYBYTES,
crypto_auth,
crypto_auth_verify,
crypto_auth_hmacsha256,
crypto_auth_hmacsha256_verify,
crypto_auth_hmacsha512,
crypto_auth_hmacsha512256,
crypto_auth_hmacsha512256_verify,
crypto_auth_hmacsha512_verify
}