argon2.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.argon2idAsync = exports.argon2iAsync = exports.argon2dAsync = exports.argon2id = exports.argon2i = exports.argon2d = void 0;
  4. /**
  5. * Argon2 KDF from RFC 9106. Can be used to create a key from password and salt.
  6. * We suggest to use Scrypt. JS Argon is 2-10x slower than native code because of 64-bitness:
  7. * * argon uses uint64, but JS doesn't have fast uint64array
  8. * * uint64 multiplication is 1/3 of time
  9. * * `P` function would be very nice with u64, because most of value will be in registers,
  10. * hovewer with u32 it will require 32 registers, which is too much.
  11. * * JS arrays do slow bound checks, so reading from `A2_BUF` slows it down
  12. * @module
  13. */
  14. const _u64_ts_1 = require("./_u64.js");
  15. const blake2_ts_1 = require("./blake2.js");
  16. const utils_ts_1 = require("./utils.js");
  17. const AT = { Argond2d: 0, Argon2i: 1, Argon2id: 2 };
  18. const ARGON2_SYNC_POINTS = 4;
  19. const abytesOrZero = (buf) => {
  20. if (buf === undefined)
  21. return Uint8Array.of();
  22. return (0, utils_ts_1.kdfInputToBytes)(buf);
  23. };
  24. // u32 * u32 = u64
  25. function mul(a, b) {
  26. const aL = a & 0xffff;
  27. const aH = a >>> 16;
  28. const bL = b & 0xffff;
  29. const bH = b >>> 16;
  30. const ll = Math.imul(aL, bL);
  31. const hl = Math.imul(aH, bL);
  32. const lh = Math.imul(aL, bH);
  33. const hh = Math.imul(aH, bH);
  34. const carry = (ll >>> 16) + (hl & 0xffff) + lh;
  35. const high = (hh + (hl >>> 16) + (carry >>> 16)) | 0;
  36. const low = (carry << 16) | (ll & 0xffff);
  37. return { h: high, l: low };
  38. }
  39. function mul2(a, b) {
  40. // 2 * a * b (via shifts)
  41. const { h, l } = mul(a, b);
  42. return { h: ((h << 1) | (l >>> 31)) & 4294967295, l: (l << 1) & 4294967295 };
  43. }
  44. // BlaMka permutation for Argon2
  45. // A + B + (2 * u32(A) * u32(B))
  46. function blamka(Ah, Al, Bh, Bl) {
  47. const { h: Ch, l: Cl } = mul2(Al, Bl);
  48. // A + B + (2 * A * B)
  49. const Rll = (0, _u64_ts_1.add3L)(Al, Bl, Cl);
  50. return { h: (0, _u64_ts_1.add3H)(Rll, Ah, Bh, Ch), l: Rll | 0 };
  51. }
  52. // Temporary block buffer
  53. const A2_BUF = new Uint32Array(256); // 1024 bytes (matrix 16x16)
  54. function G(a, b, c, d) {
  55. let Al = A2_BUF[2 * a], Ah = A2_BUF[2 * a + 1]; // prettier-ignore
  56. let Bl = A2_BUF[2 * b], Bh = A2_BUF[2 * b + 1]; // prettier-ignore
  57. let Cl = A2_BUF[2 * c], Ch = A2_BUF[2 * c + 1]; // prettier-ignore
  58. let Dl = A2_BUF[2 * d], Dh = A2_BUF[2 * d + 1]; // prettier-ignore
  59. ({ h: Ah, l: Al } = blamka(Ah, Al, Bh, Bl));
  60. ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
  61. ({ Dh, Dl } = { Dh: (0, _u64_ts_1.rotr32H)(Dh, Dl), Dl: (0, _u64_ts_1.rotr32L)(Dh, Dl) });
  62. ({ h: Ch, l: Cl } = blamka(Ch, Cl, Dh, Dl));
  63. ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
  64. ({ Bh, Bl } = { Bh: (0, _u64_ts_1.rotrSH)(Bh, Bl, 24), Bl: (0, _u64_ts_1.rotrSL)(Bh, Bl, 24) });
  65. ({ h: Ah, l: Al } = blamka(Ah, Al, Bh, Bl));
  66. ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
  67. ({ Dh, Dl } = { Dh: (0, _u64_ts_1.rotrSH)(Dh, Dl, 16), Dl: (0, _u64_ts_1.rotrSL)(Dh, Dl, 16) });
  68. ({ h: Ch, l: Cl } = blamka(Ch, Cl, Dh, Dl));
  69. ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
  70. ({ Bh, Bl } = { Bh: (0, _u64_ts_1.rotrBH)(Bh, Bl, 63), Bl: (0, _u64_ts_1.rotrBL)(Bh, Bl, 63) });
  71. (A2_BUF[2 * a] = Al), (A2_BUF[2 * a + 1] = Ah);
  72. (A2_BUF[2 * b] = Bl), (A2_BUF[2 * b + 1] = Bh);
  73. (A2_BUF[2 * c] = Cl), (A2_BUF[2 * c + 1] = Ch);
  74. (A2_BUF[2 * d] = Dl), (A2_BUF[2 * d + 1] = Dh);
  75. }
  76. // prettier-ignore
  77. function P(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14, v15) {
  78. G(v00, v04, v08, v12);
  79. G(v01, v05, v09, v13);
  80. G(v02, v06, v10, v14);
  81. G(v03, v07, v11, v15);
  82. G(v00, v05, v10, v15);
  83. G(v01, v06, v11, v12);
  84. G(v02, v07, v08, v13);
  85. G(v03, v04, v09, v14);
  86. }
  87. function block(x, xPos, yPos, outPos, needXor) {
  88. for (let i = 0; i < 256; i++)
  89. A2_BUF[i] = x[xPos + i] ^ x[yPos + i];
  90. // columns (8)
  91. for (let i = 0; i < 128; i += 16) {
  92. // prettier-ignore
  93. P(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15);
  94. }
  95. // rows (8)
  96. for (let i = 0; i < 16; i += 2) {
  97. // prettier-ignore
  98. P(i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113);
  99. }
  100. if (needXor)
  101. for (let i = 0; i < 256; i++)
  102. x[outPos + i] ^= A2_BUF[i] ^ x[xPos + i] ^ x[yPos + i];
  103. else
  104. for (let i = 0; i < 256; i++)
  105. x[outPos + i] = A2_BUF[i] ^ x[xPos + i] ^ x[yPos + i];
  106. (0, utils_ts_1.clean)(A2_BUF);
  107. }
  108. // Variable-Length Hash Function H'
  109. function Hp(A, dkLen) {
  110. const A8 = (0, utils_ts_1.u8)(A);
  111. const T = new Uint32Array(1);
  112. const T8 = (0, utils_ts_1.u8)(T);
  113. T[0] = dkLen;
  114. // Fast path
  115. if (dkLen <= 64)
  116. return blake2_ts_1.blake2b.create({ dkLen }).update(T8).update(A8).digest();
  117. const out = new Uint8Array(dkLen);
  118. let V = blake2_ts_1.blake2b.create({}).update(T8).update(A8).digest();
  119. let pos = 0;
  120. // First block
  121. out.set(V.subarray(0, 32));
  122. pos += 32;
  123. // Rest blocks
  124. for (; dkLen - pos > 64; pos += 32) {
  125. const Vh = blake2_ts_1.blake2b.create({}).update(V);
  126. Vh.digestInto(V);
  127. Vh.destroy();
  128. out.set(V.subarray(0, 32), pos);
  129. }
  130. // Last block
  131. out.set((0, blake2_ts_1.blake2b)(V, { dkLen: dkLen - pos }), pos);
  132. (0, utils_ts_1.clean)(V, T);
  133. return (0, utils_ts_1.u32)(out);
  134. }
  135. // Used only inside process block!
  136. function indexAlpha(r, s, laneLen, segmentLen, index, randL, sameLane = false) {
  137. // This is ugly, but close enough to reference implementation.
  138. let area;
  139. if (r === 0) {
  140. if (s === 0)
  141. area = index - 1;
  142. else if (sameLane)
  143. area = s * segmentLen + index - 1;
  144. else
  145. area = s * segmentLen + (index == 0 ? -1 : 0);
  146. }
  147. else if (sameLane)
  148. area = laneLen - segmentLen + index - 1;
  149. else
  150. area = laneLen - segmentLen + (index == 0 ? -1 : 0);
  151. const startPos = r !== 0 && s !== ARGON2_SYNC_POINTS - 1 ? (s + 1) * segmentLen : 0;
  152. const rel = area - 1 - mul(area, mul(randL, randL).h).h;
  153. return (startPos + rel) % laneLen;
  154. }
  155. const maxUint32 = Math.pow(2, 32);
  156. function isU32(num) {
  157. return Number.isSafeInteger(num) && num >= 0 && num < maxUint32;
  158. }
  159. function argon2Opts(opts) {
  160. const merged = {
  161. version: 0x13,
  162. dkLen: 32,
  163. maxmem: maxUint32 - 1,
  164. asyncTick: 10,
  165. };
  166. for (let [k, v] of Object.entries(opts))
  167. if (v != null)
  168. merged[k] = v;
  169. const { dkLen, p, m, t, version, onProgress } = merged;
  170. if (!isU32(dkLen) || dkLen < 4)
  171. throw new Error('dkLen should be at least 4 bytes');
  172. if (!isU32(p) || p < 1 || p >= Math.pow(2, 24))
  173. throw new Error('p should be 1 <= p < 2^24');
  174. if (!isU32(m))
  175. throw new Error('m should be 0 <= m < 2^32');
  176. if (!isU32(t) || t < 1)
  177. throw new Error('t (iterations) should be 1 <= t < 2^32');
  178. if (onProgress !== undefined && typeof onProgress !== 'function')
  179. throw new Error('progressCb should be function');
  180. /*
  181. Memory size m MUST be an integer number of kibibytes from 8*p to 2^(32)-1. The actual number of blocks is m', which is m rounded down to the nearest multiple of 4*p.
  182. */
  183. if (!isU32(m) || m < 8 * p)
  184. throw new Error('memory should be at least 8*p bytes');
  185. if (version !== 0x10 && version !== 0x13)
  186. throw new Error('unknown version=' + version);
  187. return merged;
  188. }
  189. function argon2Init(password, salt, type, opts) {
  190. password = (0, utils_ts_1.kdfInputToBytes)(password);
  191. salt = (0, utils_ts_1.kdfInputToBytes)(salt);
  192. (0, utils_ts_1.abytes)(password);
  193. (0, utils_ts_1.abytes)(salt);
  194. if (!isU32(password.length))
  195. throw new Error('password should be less than 4 GB');
  196. if (!isU32(salt.length) || salt.length < 8)
  197. throw new Error('salt should be at least 8 bytes and less than 4 GB');
  198. if (!Object.values(AT).includes(type))
  199. throw new Error('invalid type');
  200. let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress, asyncTick } = argon2Opts(opts);
  201. // Validation
  202. key = abytesOrZero(key);
  203. personalization = abytesOrZero(personalization);
  204. // H_0 = H^(64)(LE32(p) || LE32(T) || LE32(m) || LE32(t) ||
  205. // LE32(v) || LE32(y) || LE32(length(P)) || P ||
  206. // LE32(length(S)) || S || LE32(length(K)) || K ||
  207. // LE32(length(X)) || X)
  208. const h = blake2_ts_1.blake2b.create({});
  209. const BUF = new Uint32Array(1);
  210. const BUF8 = (0, utils_ts_1.u8)(BUF);
  211. for (let item of [p, dkLen, m, t, version, type]) {
  212. BUF[0] = item;
  213. h.update(BUF8);
  214. }
  215. for (let i of [password, salt, key, personalization]) {
  216. BUF[0] = i.length; // BUF is u32 array, this is valid
  217. h.update(BUF8).update(i);
  218. }
  219. const H0 = new Uint32Array(18);
  220. const H0_8 = (0, utils_ts_1.u8)(H0);
  221. h.digestInto(H0_8);
  222. // 256 u32 = 1024 (BLOCK_SIZE), fills A2_BUF on processing
  223. // Params
  224. const lanes = p;
  225. // m' = 4 * p * floor (m / 4p)
  226. const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p));
  227. //q = m' / p columns
  228. const laneLen = Math.floor(mP / p);
  229. const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS);
  230. const memUsed = mP * 256;
  231. if (!isU32(maxmem) || memUsed > maxmem)
  232. throw new Error('mem should be less than 2**32, got: maxmem=' + maxmem + ', memused=' + memUsed);
  233. const B = new Uint32Array(memUsed);
  234. // Fill first blocks
  235. for (let l = 0; l < p; l++) {
  236. const i = 256 * laneLen * l;
  237. // B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i))
  238. H0[17] = l;
  239. H0[16] = 0;
  240. B.set(Hp(H0, 1024), i);
  241. // B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i))
  242. H0[16] = 1;
  243. B.set(Hp(H0, 1024), i + 256);
  244. }
  245. let perBlock = () => { };
  246. if (onProgress) {
  247. const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen;
  248. // Invoke callback if progress changes from 10.01 to 10.02
  249. // Allows to draw smooth progress bar on up to 8K screen
  250. const callbackPer = Math.max(Math.floor(totalBlock / 10000), 1);
  251. let blockCnt = 0;
  252. perBlock = () => {
  253. blockCnt++;
  254. if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock))
  255. onProgress(blockCnt / totalBlock);
  256. };
  257. }
  258. (0, utils_ts_1.clean)(BUF, H0);
  259. return { type, mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick };
  260. }
  261. function argon2Output(B, p, laneLen, dkLen) {
  262. const B_final = new Uint32Array(256);
  263. for (let l = 0; l < p; l++)
  264. for (let j = 0; j < 256; j++)
  265. B_final[j] ^= B[256 * (laneLen * l + laneLen - 1) + j];
  266. const res = (0, utils_ts_1.u8)(Hp(B_final, dkLen));
  267. (0, utils_ts_1.clean)(B_final);
  268. return res;
  269. }
  270. function processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor) {
  271. if (offset % laneLen)
  272. prev = offset - 1;
  273. let randL, randH;
  274. if (dataIndependent) {
  275. let i128 = index % 128;
  276. if (i128 === 0) {
  277. address[256 + 12]++;
  278. block(address, 256, 2 * 256, 0, false);
  279. block(address, 0, 2 * 256, 0, false);
  280. }
  281. randL = address[2 * i128];
  282. randH = address[2 * i128 + 1];
  283. }
  284. else {
  285. const T = 256 * prev;
  286. randL = B[T];
  287. randH = B[T + 1];
  288. }
  289. // address block
  290. const refLane = r === 0 && s === 0 ? l : randH % lanes;
  291. const refPos = indexAlpha(r, s, laneLen, segmentLen, index, randL, refLane == l);
  292. const refBlock = laneLen * refLane + refPos;
  293. // B[i][j] = G(B[i][j-1], B[l][z])
  294. block(B, 256 * prev, 256 * refBlock, offset * 256, needXor);
  295. }
  296. function argon2(type, password, salt, opts) {
  297. const { mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock } = argon2Init(password, salt, type, opts);
  298. // Pre-loop setup
  299. // [address, input, zero_block] format so we can pass single U32 to block function
  300. const address = new Uint32Array(3 * 256);
  301. address[256 + 6] = mP;
  302. address[256 + 8] = t;
  303. address[256 + 10] = type;
  304. for (let r = 0; r < t; r++) {
  305. const needXor = r !== 0 && version === 0x13;
  306. address[256 + 0] = r;
  307. for (let s = 0; s < ARGON2_SYNC_POINTS; s++) {
  308. address[256 + 4] = s;
  309. const dataIndependent = type == AT.Argon2i || (type == AT.Argon2id && r === 0 && s < 2);
  310. for (let l = 0; l < p; l++) {
  311. address[256 + 2] = l;
  312. address[256 + 12] = 0;
  313. let startPos = 0;
  314. if (r === 0 && s === 0) {
  315. startPos = 2;
  316. if (dataIndependent) {
  317. address[256 + 12]++;
  318. block(address, 256, 2 * 256, 0, false);
  319. block(address, 0, 2 * 256, 0, false);
  320. }
  321. }
  322. // current block postion
  323. let offset = l * laneLen + s * segmentLen + startPos;
  324. // previous block position
  325. let prev = offset % laneLen ? offset - 1 : offset + laneLen - 1;
  326. for (let index = startPos; index < segmentLen; index++, offset++, prev++) {
  327. perBlock();
  328. processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor);
  329. }
  330. }
  331. }
  332. }
  333. (0, utils_ts_1.clean)(address);
  334. return argon2Output(B, p, laneLen, dkLen);
  335. }
  336. /** argon2d GPU-resistant version. */
  337. const argon2d = (password, salt, opts) => argon2(AT.Argond2d, password, salt, opts);
  338. exports.argon2d = argon2d;
  339. /** argon2i side-channel-resistant version. */
  340. const argon2i = (password, salt, opts) => argon2(AT.Argon2i, password, salt, opts);
  341. exports.argon2i = argon2i;
  342. /** argon2id, combining i+d, the most popular version from RFC 9106 */
  343. const argon2id = (password, salt, opts) => argon2(AT.Argon2id, password, salt, opts);
  344. exports.argon2id = argon2id;
  345. async function argon2Async(type, password, salt, opts) {
  346. const { mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick } = argon2Init(password, salt, type, opts);
  347. // Pre-loop setup
  348. // [address, input, zero_block] format so we can pass single U32 to block function
  349. const address = new Uint32Array(3 * 256);
  350. address[256 + 6] = mP;
  351. address[256 + 8] = t;
  352. address[256 + 10] = type;
  353. let ts = Date.now();
  354. for (let r = 0; r < t; r++) {
  355. const needXor = r !== 0 && version === 0x13;
  356. address[256 + 0] = r;
  357. for (let s = 0; s < ARGON2_SYNC_POINTS; s++) {
  358. address[256 + 4] = s;
  359. const dataIndependent = type == AT.Argon2i || (type == AT.Argon2id && r === 0 && s < 2);
  360. for (let l = 0; l < p; l++) {
  361. address[256 + 2] = l;
  362. address[256 + 12] = 0;
  363. let startPos = 0;
  364. if (r === 0 && s === 0) {
  365. startPos = 2;
  366. if (dataIndependent) {
  367. address[256 + 12]++;
  368. block(address, 256, 2 * 256, 0, false);
  369. block(address, 0, 2 * 256, 0, false);
  370. }
  371. }
  372. // current block postion
  373. let offset = l * laneLen + s * segmentLen + startPos;
  374. // previous block position
  375. let prev = offset % laneLen ? offset - 1 : offset + laneLen - 1;
  376. for (let index = startPos; index < segmentLen; index++, offset++, prev++) {
  377. perBlock();
  378. processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor);
  379. // Date.now() is not monotonic, so in case if clock goes backwards we return return control too
  380. const diff = Date.now() - ts;
  381. if (!(diff >= 0 && diff < asyncTick)) {
  382. await (0, utils_ts_1.nextTick)();
  383. ts += diff;
  384. }
  385. }
  386. }
  387. }
  388. }
  389. (0, utils_ts_1.clean)(address);
  390. return argon2Output(B, p, laneLen, dkLen);
  391. }
  392. /** argon2d async GPU-resistant version. */
  393. const argon2dAsync = (password, salt, opts) => argon2Async(AT.Argond2d, password, salt, opts);
  394. exports.argon2dAsync = argon2dAsync;
  395. /** argon2i async side-channel-resistant version. */
  396. const argon2iAsync = (password, salt, opts) => argon2Async(AT.Argon2i, password, salt, opts);
  397. exports.argon2iAsync = argon2iAsync;
  398. /** argon2id async, combining i+d, the most popular version from RFC 9106 */
  399. const argon2idAsync = (password, salt, opts) => argon2Async(AT.Argon2id, password, salt, opts);
  400. exports.argon2idAsync = argon2idAsync;
  401. //# sourceMappingURL=argon2.js.map