hmac.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /**
  2. * HMAC: RFC2104 message authentication code.
  3. * @module
  4. */
  5. import { abytes, aexists, ahash, clean, Hash, toBytes } from "./utils.js";
  6. export class HMAC extends Hash {
  7. constructor(hash, _key) {
  8. super();
  9. this.finished = false;
  10. this.destroyed = false;
  11. ahash(hash);
  12. const key = toBytes(_key);
  13. this.iHash = hash.create();
  14. if (typeof this.iHash.update !== 'function')
  15. throw new Error('Expected instance of class which extends utils.Hash');
  16. this.blockLen = this.iHash.blockLen;
  17. this.outputLen = this.iHash.outputLen;
  18. const blockLen = this.blockLen;
  19. const pad = new Uint8Array(blockLen);
  20. // blockLen can be bigger than outputLen
  21. pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
  22. for (let i = 0; i < pad.length; i++)
  23. pad[i] ^= 0x36;
  24. this.iHash.update(pad);
  25. // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
  26. this.oHash = hash.create();
  27. // Undo internal XOR && apply outer XOR
  28. for (let i = 0; i < pad.length; i++)
  29. pad[i] ^= 0x36 ^ 0x5c;
  30. this.oHash.update(pad);
  31. clean(pad);
  32. }
  33. update(buf) {
  34. aexists(this);
  35. this.iHash.update(buf);
  36. return this;
  37. }
  38. digestInto(out) {
  39. aexists(this);
  40. abytes(out, this.outputLen);
  41. this.finished = true;
  42. this.iHash.digestInto(out);
  43. this.oHash.update(out);
  44. this.oHash.digestInto(out);
  45. this.destroy();
  46. }
  47. digest() {
  48. const out = new Uint8Array(this.oHash.outputLen);
  49. this.digestInto(out);
  50. return out;
  51. }
  52. _cloneInto(to) {
  53. // Create new instance without calling constructor since key already in state and we don't know it.
  54. to || (to = Object.create(Object.getPrototypeOf(this), {}));
  55. const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
  56. to = to;
  57. to.finished = finished;
  58. to.destroyed = destroyed;
  59. to.blockLen = blockLen;
  60. to.outputLen = outputLen;
  61. to.oHash = oHash._cloneInto(to.oHash);
  62. to.iHash = iHash._cloneInto(to.iHash);
  63. return to;
  64. }
  65. clone() {
  66. return this._cloneInto();
  67. }
  68. destroy() {
  69. this.destroyed = true;
  70. this.oHash.destroy();
  71. this.iHash.destroy();
  72. }
  73. }
  74. /**
  75. * HMAC: RFC2104 message authentication code.
  76. * @param hash - function that would be used e.g. sha256
  77. * @param key - message key
  78. * @param message - message data
  79. * @example
  80. * import { hmac } from '@noble/hashes/hmac';
  81. * import { sha256 } from '@noble/hashes/sha2';
  82. * const mac1 = hmac(sha256, 'key', 'message');
  83. */
  84. export const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
  85. hmac.create = (hash, key) => new HMAC(hash, key);
  86. //# sourceMappingURL=hmac.js.map