Source: hkdf.js

  1. /** @fileOverview HKDF implementation.
  2. *
  3. * @author Steve Thomas
  4. */
  5. /** HKDF with the specified hash function.
  6. * @param {bitArray} ikm The input keying material.
  7. * @param {Number} keyBitLength The output key length, in bits.
  8. * @param {String|bitArray} salt The salt for HKDF.
  9. * @param {String|bitArray} info The info for HKDF.
  10. * @param {Object} [Hash=sjcl.hash.sha256] The hash function to use.
  11. * @return {bitArray} derived key.
  12. */
  13. sjcl.misc.hkdf = function (ikm, keyBitLength, salt, info, Hash) {
  14. var hmac, key, i, hashLen, loops, curOut, ret = [];
  15. Hash = Hash || sjcl.hash.sha256;
  16. if (typeof info === "string") {
  17. info = sjcl.codec.utf8String.toBits(info);
  18. }
  19. if (typeof salt === "string") {
  20. salt = sjcl.codec.utf8String.toBits(salt);
  21. } else if (!salt) {
  22. salt = [];
  23. }
  24. hmac = new sjcl.misc.hmac(salt, Hash);
  25. key = hmac.mac(ikm);
  26. hashLen = sjcl.bitArray.bitLength(key);
  27. loops = Math.ceil(keyBitLength / hashLen);
  28. if (loops > 255) {
  29. throw new sjcl.exception.invalid("key bit length is too large for hkdf");
  30. }
  31. hmac = new sjcl.misc.hmac(key, Hash);
  32. curOut = [];
  33. for (i = 1; i <= loops; i++) {
  34. hmac.update(curOut);
  35. hmac.update(info);
  36. hmac.update([sjcl.bitArray.partial(8, i)]);
  37. curOut = hmac.digest();
  38. ret = sjcl.bitArray.concat(ret, curOut);
  39. }
  40. return sjcl.bitArray.clamp(ret, keyBitLength);
  41. };