93 lines
No EOL
3.1 KiB
JavaScript
93 lines
No EOL
3.1 KiB
JavaScript
/**
|
|
* HMAC: RFC2104 message authentication code.
|
|
* @module
|
|
*/
|
|
import { abytes, aexists, ahash, aoutput, clean, } from "./utils.js";
|
|
/**
|
|
* Internal class for HMAC.
|
|
* Accepts any byte key, although RFC 2104 ยง3 recommends keys at least
|
|
* `HashLen` bytes long.
|
|
*/
|
|
export class _HMAC {
|
|
oHash;
|
|
iHash;
|
|
blockLen;
|
|
outputLen;
|
|
canXOF = false;
|
|
finished = false;
|
|
destroyed = false;
|
|
constructor(hash, key) {
|
|
ahash(hash);
|
|
abytes(key, undefined, 'key');
|
|
this.iHash = hash.create();
|
|
if (typeof this.iHash.update !== 'function')
|
|
throw new Error('Expected instance of class which extends utils.Hash');
|
|
this.blockLen = this.iHash.blockLen;
|
|
this.outputLen = this.iHash.outputLen;
|
|
const blockLen = this.blockLen;
|
|
const pad = new Uint8Array(blockLen);
|
|
// blockLen can be bigger than outputLen
|
|
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
for (let i = 0; i < pad.length; i++)
|
|
pad[i] ^= 0x36;
|
|
this.iHash.update(pad);
|
|
// By doing update (processing of the first block) of the outer hash here,
|
|
// we can re-use it between multiple calls via clone.
|
|
this.oHash = hash.create();
|
|
// Undo internal XOR && apply outer XOR
|
|
for (let i = 0; i < pad.length; i++)
|
|
pad[i] ^= 0x36 ^ 0x5c;
|
|
this.oHash.update(pad);
|
|
clean(pad);
|
|
}
|
|
update(buf) {
|
|
aexists(this);
|
|
this.iHash.update(buf);
|
|
return this;
|
|
}
|
|
digestInto(out) {
|
|
aexists(this);
|
|
aoutput(out, this);
|
|
this.finished = true;
|
|
const buf = out.subarray(0, this.outputLen);
|
|
// Reuse the first outputLen bytes for the inner digest; the outer hash consumes them before
|
|
// overwriting that same prefix with the final tag, leaving any oversized tail untouched.
|
|
this.iHash.digestInto(buf);
|
|
this.oHash.update(buf);
|
|
this.oHash.digestInto(buf);
|
|
this.destroy();
|
|
}
|
|
digest() {
|
|
const out = new Uint8Array(this.oHash.outputLen);
|
|
this.digestInto(out);
|
|
return out;
|
|
}
|
|
_cloneInto(to) {
|
|
// Create new instance without calling constructor since the key
|
|
// is already in state and we don't know it.
|
|
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
to = to;
|
|
to.finished = finished;
|
|
to.destroyed = destroyed;
|
|
to.blockLen = blockLen;
|
|
to.outputLen = outputLen;
|
|
to.oHash = oHash._cloneInto(to.oHash);
|
|
to.iHash = iHash._cloneInto(to.iHash);
|
|
return to;
|
|
}
|
|
clone() {
|
|
return this._cloneInto();
|
|
}
|
|
destroy() {
|
|
this.destroyed = true;
|
|
this.oHash.destroy();
|
|
this.iHash.destroy();
|
|
}
|
|
}
|
|
export const hmac = /* @__PURE__ */ (() => {
|
|
const hmac_ = ((hash, key, message) => new _HMAC(hash, key).update(message).digest());
|
|
hmac_.create = (hash, key) => new _HMAC(hash, key);
|
|
return hmac_;
|
|
})();
|
|
//# sourceMappingURL=hmac.js.map
|