hkdf.lua 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. local HMAC = require("lockbox.mac.hmac");
  2. local Stream = require("lockbox.util.stream");
  3. local Array = require("lockbox.util.array");
  4. local HKDF = function()
  5. local public = {};
  6. local Digest = nil;
  7. local inputKeyMaterial;
  8. local salt = Array.fromHex("0000000000000000000000000000000000000000");
  9. local info;
  10. local outputLen;
  11. local hashLen;
  12. local secret;
  13. local extract = function()
  14. local res = HMAC()
  15. .setDigest(Digest)
  16. .setKey(salt)
  17. .init()
  18. .update(Stream.fromArray(inputKeyMaterial))
  19. .finish()
  20. .asBytes();
  21. hashLen = #res;
  22. return res;
  23. end
  24. local expand = function(prk)
  25. local iterations = math.ceil(outputLen / hashLen);
  26. local mixin = {};
  27. local results = {};
  28. local remainingBytes = outputLen;
  29. for i = 1, iterations do
  30. local mac = HMAC()
  31. .setDigest(Digest)
  32. .setKey(prk)
  33. .init();
  34. mac.update(Stream.fromArray(mixin));
  35. if info then
  36. mac.update(Stream.fromArray(info));
  37. end
  38. mac.update(Stream.fromArray({ i }));
  39. local stepResult = mac.finish().asBytes();
  40. local stepSize = math.min(remainingBytes, #stepResult);
  41. for j = 1, stepSize do
  42. results[#results + 1] = stepResult[j];
  43. end
  44. mixin = stepResult;
  45. remainingBytes = remainingBytes - stepSize;
  46. end
  47. return results;
  48. end
  49. public.setDigest = function(digestModule)
  50. Digest = digestModule;
  51. return public;
  52. end
  53. public.setInputKeyMaterial = function(ikm)
  54. inputKeyMaterial = ikm;
  55. return public;
  56. end
  57. public.setSalt = function(s)
  58. salt = s or salt;
  59. return public;
  60. end
  61. public.setInfo = function(i)
  62. info = i;
  63. return public;
  64. end
  65. public.setOutputLen = function(len)
  66. outputLen = len;
  67. return public;
  68. end
  69. public.finish = function()
  70. local prk = extract(salt, inputKeyMaterial);
  71. secret = expand(prk, info);
  72. return public;
  73. end
  74. public.asBytes = function()
  75. return secret;
  76. end
  77. public.asHex = function()
  78. return Array.toHex(secret);
  79. end
  80. public.asString = function()
  81. return Array.toString(secret);
  82. end
  83. return public;
  84. end
  85. return HKDF;