otpauth.umd.js 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878
  1. //! otpauth 9.3.1 | (c) Héctor Molinero Fernández | MIT | https://github.com/hectorm/otpauth
  2. //! noble-hashes 1.4.0 | (c) Paul Miller | MIT | https://github.com/paulmillr/noble-hashes
  3. /// <reference types="./otpauth.d.ts" />
  4. // @ts-nocheck
  5. (function (global, factory) {
  6. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  7. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  8. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.OTPAuth = {}));
  9. })(this, (function (exports) { 'use strict';
  10. /**
  11. * Converts an integer to an Uint8Array.
  12. * @param {number} num Integer.
  13. * @returns {Uint8Array} Uint8Array.
  14. */ const uintDecode = (num)=>{
  15. const buf = new ArrayBuffer(8);
  16. const arr = new Uint8Array(buf);
  17. let acc = num;
  18. for(let i = 7; i >= 0; i--){
  19. if (acc === 0) break;
  20. arr[i] = acc & 255;
  21. acc -= arr[i];
  22. acc /= 256;
  23. }
  24. return arr;
  25. };
  26. function number(n) {
  27. if (!Number.isSafeInteger(n) || n < 0) throw new Error(`positive integer expected, not ${n}`);
  28. }
  29. // copied from utils
  30. function isBytes(a) {
  31. return a instanceof Uint8Array || a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array';
  32. }
  33. function bytes(b, ...lengths) {
  34. if (!isBytes(b)) throw new Error('Uint8Array expected');
  35. if (lengths.length > 0 && !lengths.includes(b.length)) throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`);
  36. }
  37. function hash(h) {
  38. if (typeof h !== 'function' || typeof h.create !== 'function') throw new Error('Hash should be wrapped by utils.wrapConstructor');
  39. number(h.outputLen);
  40. number(h.blockLen);
  41. }
  42. function exists(instance, checkFinished = true) {
  43. if (instance.destroyed) throw new Error('Hash instance has been destroyed');
  44. if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called');
  45. }
  46. function output(out, instance) {
  47. bytes(out);
  48. const min = instance.outputLen;
  49. if (out.length < min) {
  50. throw new Error(`digestInto() expects output buffer of length at least ${min}`);
  51. }
  52. }
  53. /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */ // We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
  54. // node.js versions earlier than v19 don't declare it in global scope.
  55. // For node.js, package.json#exports field mapping rewrites import
  56. // from `crypto` to `cryptoNode`, which imports native module.
  57. // Makes the utils un-importable in browsers without a bundler.
  58. // Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
  59. const u32 = (arr)=>new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
  60. // Cast array to view
  61. const createView = (arr)=>new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
  62. // The rotate right (circular right shift) operation for uint32
  63. const rotr = (word, shift)=>word << 32 - shift | word >>> shift;
  64. // The rotate left (circular left shift) operation for uint32
  65. const rotl = (word, shift)=>word << shift | word >>> 32 - shift >>> 0;
  66. const isLE = new Uint8Array(new Uint32Array([
  67. 0x11223344
  68. ]).buffer)[0] === 0x44;
  69. // The byte swap operation for uint32
  70. const byteSwap = (word)=>word << 24 & 0xff000000 | word << 8 & 0xff0000 | word >>> 8 & 0xff00 | word >>> 24 & 0xff;
  71. // In place byte swap for Uint32Array
  72. function byteSwap32(arr) {
  73. for(let i = 0; i < arr.length; i++){
  74. arr[i] = byteSwap(arr[i]);
  75. }
  76. }
  77. /**
  78. * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
  79. */ function utf8ToBytes(str) {
  80. if (typeof str !== 'string') throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
  81. return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
  82. }
  83. /**
  84. * Normalizes (non-hex) string or Uint8Array to Uint8Array.
  85. * Warning: when Uint8Array is passed, it would NOT get copied.
  86. * Keep in mind for future mutable operations.
  87. */ function toBytes(data) {
  88. if (typeof data === 'string') data = utf8ToBytes(data);
  89. bytes(data);
  90. return data;
  91. }
  92. // For runtime check if class implements interface
  93. class Hash {
  94. // Safe version that clones internal state
  95. clone() {
  96. return this._cloneInto();
  97. }
  98. }
  99. function wrapConstructor(hashCons) {
  100. const hashC = (msg)=>hashCons().update(toBytes(msg)).digest();
  101. const tmp = hashCons();
  102. hashC.outputLen = tmp.outputLen;
  103. hashC.blockLen = tmp.blockLen;
  104. hashC.create = ()=>hashCons();
  105. return hashC;
  106. }
  107. // HMAC (RFC 2104)
  108. class HMAC extends Hash {
  109. update(buf) {
  110. exists(this);
  111. this.iHash.update(buf);
  112. return this;
  113. }
  114. digestInto(out) {
  115. exists(this);
  116. bytes(out, this.outputLen);
  117. this.finished = true;
  118. this.iHash.digestInto(out);
  119. this.oHash.update(out);
  120. this.oHash.digestInto(out);
  121. this.destroy();
  122. }
  123. digest() {
  124. const out = new Uint8Array(this.oHash.outputLen);
  125. this.digestInto(out);
  126. return out;
  127. }
  128. _cloneInto(to) {
  129. // Create new instance without calling constructor since key already in state and we don't know it.
  130. to || (to = Object.create(Object.getPrototypeOf(this), {}));
  131. const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
  132. to = to;
  133. to.finished = finished;
  134. to.destroyed = destroyed;
  135. to.blockLen = blockLen;
  136. to.outputLen = outputLen;
  137. to.oHash = oHash._cloneInto(to.oHash);
  138. to.iHash = iHash._cloneInto(to.iHash);
  139. return to;
  140. }
  141. destroy() {
  142. this.destroyed = true;
  143. this.oHash.destroy();
  144. this.iHash.destroy();
  145. }
  146. constructor(hash$1, _key){
  147. super();
  148. this.finished = false;
  149. this.destroyed = false;
  150. hash(hash$1);
  151. const key = toBytes(_key);
  152. this.iHash = hash$1.create();
  153. if (typeof this.iHash.update !== 'function') throw new Error('Expected instance of class which extends utils.Hash');
  154. this.blockLen = this.iHash.blockLen;
  155. this.outputLen = this.iHash.outputLen;
  156. const blockLen = this.blockLen;
  157. const pad = new Uint8Array(blockLen);
  158. // blockLen can be bigger than outputLen
  159. pad.set(key.length > blockLen ? hash$1.create().update(key).digest() : key);
  160. for(let i = 0; i < pad.length; i++)pad[i] ^= 0x36;
  161. this.iHash.update(pad);
  162. // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
  163. this.oHash = hash$1.create();
  164. // Undo internal XOR && apply outer XOR
  165. for(let i = 0; i < pad.length; i++)pad[i] ^= 0x36 ^ 0x5c;
  166. this.oHash.update(pad);
  167. pad.fill(0);
  168. }
  169. }
  170. /**
  171. * HMAC: RFC2104 message authentication code.
  172. * @param hash - function that would be used e.g. sha256
  173. * @param key - message key
  174. * @param message - message data
  175. */ const hmac = (hash, key, message)=>new HMAC(hash, key).update(message).digest();
  176. hmac.create = (hash, key)=>new HMAC(hash, key);
  177. // Polyfill for Safari 14
  178. function setBigUint64(view, byteOffset, value, isLE) {
  179. if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);
  180. const _32n = BigInt(32);
  181. const _u32_max = BigInt(0xffffffff);
  182. const wh = Number(value >> _32n & _u32_max);
  183. const wl = Number(value & _u32_max);
  184. const h = isLE ? 4 : 0;
  185. const l = isLE ? 0 : 4;
  186. view.setUint32(byteOffset + h, wh, isLE);
  187. view.setUint32(byteOffset + l, wl, isLE);
  188. }
  189. // Choice: a ? b : c
  190. const Chi = (a, b, c)=>a & b ^ ~a & c;
  191. // Majority function, true if any two inpust is true
  192. const Maj = (a, b, c)=>a & b ^ a & c ^ b & c;
  193. /**
  194. * Merkle-Damgard hash construction base class.
  195. * Could be used to create MD5, RIPEMD, SHA1, SHA2.
  196. */ class HashMD extends Hash {
  197. update(data) {
  198. exists(this);
  199. const { view, buffer, blockLen } = this;
  200. data = toBytes(data);
  201. const len = data.length;
  202. for(let pos = 0; pos < len;){
  203. const take = Math.min(blockLen - this.pos, len - pos);
  204. // Fast path: we have at least one block in input, cast it to view and process
  205. if (take === blockLen) {
  206. const dataView = createView(data);
  207. for(; blockLen <= len - pos; pos += blockLen)this.process(dataView, pos);
  208. continue;
  209. }
  210. buffer.set(data.subarray(pos, pos + take), this.pos);
  211. this.pos += take;
  212. pos += take;
  213. if (this.pos === blockLen) {
  214. this.process(view, 0);
  215. this.pos = 0;
  216. }
  217. }
  218. this.length += data.length;
  219. this.roundClean();
  220. return this;
  221. }
  222. digestInto(out) {
  223. exists(this);
  224. output(out, this);
  225. this.finished = true;
  226. // Padding
  227. // We can avoid allocation of buffer for padding completely if it
  228. // was previously not allocated here. But it won't change performance.
  229. const { buffer, view, blockLen, isLE } = this;
  230. let { pos } = this;
  231. // append the bit '1' to the message
  232. buffer[pos++] = 0b10000000;
  233. this.buffer.subarray(pos).fill(0);
  234. // we have less than padOffset left in buffer, so we cannot put length in
  235. // current block, need process it and pad again
  236. if (this.padOffset > blockLen - pos) {
  237. this.process(view, 0);
  238. pos = 0;
  239. }
  240. // Pad until full block byte with zeros
  241. for(let i = pos; i < blockLen; i++)buffer[i] = 0;
  242. // Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
  243. // You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
  244. // So we just write lowest 64 bits of that value.
  245. setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
  246. this.process(view, 0);
  247. const oview = createView(out);
  248. const len = this.outputLen;
  249. // NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
  250. if (len % 4) throw new Error('_sha2: outputLen should be aligned to 32bit');
  251. const outLen = len / 4;
  252. const state = this.get();
  253. if (outLen > state.length) throw new Error('_sha2: outputLen bigger than state');
  254. for(let i = 0; i < outLen; i++)oview.setUint32(4 * i, state[i], isLE);
  255. }
  256. digest() {
  257. const { buffer, outputLen } = this;
  258. this.digestInto(buffer);
  259. const res = buffer.slice(0, outputLen);
  260. this.destroy();
  261. return res;
  262. }
  263. _cloneInto(to) {
  264. to || (to = new this.constructor());
  265. to.set(...this.get());
  266. const { blockLen, buffer, length, finished, destroyed, pos } = this;
  267. to.length = length;
  268. to.pos = pos;
  269. to.finished = finished;
  270. to.destroyed = destroyed;
  271. if (length % blockLen) to.buffer.set(buffer);
  272. return to;
  273. }
  274. constructor(blockLen, outputLen, padOffset, isLE){
  275. super();
  276. this.blockLen = blockLen;
  277. this.outputLen = outputLen;
  278. this.padOffset = padOffset;
  279. this.isLE = isLE;
  280. this.finished = false;
  281. this.length = 0;
  282. this.pos = 0;
  283. this.destroyed = false;
  284. this.buffer = new Uint8Array(blockLen);
  285. this.view = createView(this.buffer);
  286. }
  287. }
  288. // SHA1 (RFC 3174) was cryptographically broken. It's still used. Don't use it for a new protocol.
  289. // Initial state
  290. const SHA1_IV = /* @__PURE__ */ new Uint32Array([
  291. 0x67452301,
  292. 0xefcdab89,
  293. 0x98badcfe,
  294. 0x10325476,
  295. 0xc3d2e1f0
  296. ]);
  297. // Temporary buffer, not used to store anything between runs
  298. // Named this way because it matches specification.
  299. const SHA1_W = /* @__PURE__ */ new Uint32Array(80);
  300. class SHA1 extends HashMD {
  301. get() {
  302. const { A, B, C, D, E } = this;
  303. return [
  304. A,
  305. B,
  306. C,
  307. D,
  308. E
  309. ];
  310. }
  311. set(A, B, C, D, E) {
  312. this.A = A | 0;
  313. this.B = B | 0;
  314. this.C = C | 0;
  315. this.D = D | 0;
  316. this.E = E | 0;
  317. }
  318. process(view, offset) {
  319. for(let i = 0; i < 16; i++, offset += 4)SHA1_W[i] = view.getUint32(offset, false);
  320. for(let i = 16; i < 80; i++)SHA1_W[i] = rotl(SHA1_W[i - 3] ^ SHA1_W[i - 8] ^ SHA1_W[i - 14] ^ SHA1_W[i - 16], 1);
  321. // Compression function main loop, 80 rounds
  322. let { A, B, C, D, E } = this;
  323. for(let i = 0; i < 80; i++){
  324. let F, K;
  325. if (i < 20) {
  326. F = Chi(B, C, D);
  327. K = 0x5a827999;
  328. } else if (i < 40) {
  329. F = B ^ C ^ D;
  330. K = 0x6ed9eba1;
  331. } else if (i < 60) {
  332. F = Maj(B, C, D);
  333. K = 0x8f1bbcdc;
  334. } else {
  335. F = B ^ C ^ D;
  336. K = 0xca62c1d6;
  337. }
  338. const T = rotl(A, 5) + F + E + K + SHA1_W[i] | 0;
  339. E = D;
  340. D = C;
  341. C = rotl(B, 30);
  342. B = A;
  343. A = T;
  344. }
  345. // Add the compressed chunk to the current hash value
  346. A = A + this.A | 0;
  347. B = B + this.B | 0;
  348. C = C + this.C | 0;
  349. D = D + this.D | 0;
  350. E = E + this.E | 0;
  351. this.set(A, B, C, D, E);
  352. }
  353. roundClean() {
  354. SHA1_W.fill(0);
  355. }
  356. destroy() {
  357. this.set(0, 0, 0, 0, 0);
  358. this.buffer.fill(0);
  359. }
  360. constructor(){
  361. super(64, 20, 8, false);
  362. this.A = SHA1_IV[0] | 0;
  363. this.B = SHA1_IV[1] | 0;
  364. this.C = SHA1_IV[2] | 0;
  365. this.D = SHA1_IV[3] | 0;
  366. this.E = SHA1_IV[4] | 0;
  367. }
  368. }
  369. const sha1 = /* @__PURE__ */ wrapConstructor(()=>new SHA1());
  370. // SHA2-256 need to try 2^128 hashes to execute birthday attack.
  371. // BTC network is doing 2^67 hashes/sec as per early 2023.
  372. // Round constants:
  373. // first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
  374. // prettier-ignore
  375. const SHA256_K = /* @__PURE__ */ new Uint32Array([
  376. 0x428a2f98,
  377. 0x71374491,
  378. 0xb5c0fbcf,
  379. 0xe9b5dba5,
  380. 0x3956c25b,
  381. 0x59f111f1,
  382. 0x923f82a4,
  383. 0xab1c5ed5,
  384. 0xd807aa98,
  385. 0x12835b01,
  386. 0x243185be,
  387. 0x550c7dc3,
  388. 0x72be5d74,
  389. 0x80deb1fe,
  390. 0x9bdc06a7,
  391. 0xc19bf174,
  392. 0xe49b69c1,
  393. 0xefbe4786,
  394. 0x0fc19dc6,
  395. 0x240ca1cc,
  396. 0x2de92c6f,
  397. 0x4a7484aa,
  398. 0x5cb0a9dc,
  399. 0x76f988da,
  400. 0x983e5152,
  401. 0xa831c66d,
  402. 0xb00327c8,
  403. 0xbf597fc7,
  404. 0xc6e00bf3,
  405. 0xd5a79147,
  406. 0x06ca6351,
  407. 0x14292967,
  408. 0x27b70a85,
  409. 0x2e1b2138,
  410. 0x4d2c6dfc,
  411. 0x53380d13,
  412. 0x650a7354,
  413. 0x766a0abb,
  414. 0x81c2c92e,
  415. 0x92722c85,
  416. 0xa2bfe8a1,
  417. 0xa81a664b,
  418. 0xc24b8b70,
  419. 0xc76c51a3,
  420. 0xd192e819,
  421. 0xd6990624,
  422. 0xf40e3585,
  423. 0x106aa070,
  424. 0x19a4c116,
  425. 0x1e376c08,
  426. 0x2748774c,
  427. 0x34b0bcb5,
  428. 0x391c0cb3,
  429. 0x4ed8aa4a,
  430. 0x5b9cca4f,
  431. 0x682e6ff3,
  432. 0x748f82ee,
  433. 0x78a5636f,
  434. 0x84c87814,
  435. 0x8cc70208,
  436. 0x90befffa,
  437. 0xa4506ceb,
  438. 0xbef9a3f7,
  439. 0xc67178f2
  440. ]);
  441. // Initial state:
  442. // first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
  443. // prettier-ignore
  444. const SHA256_IV = /* @__PURE__ */ new Uint32Array([
  445. 0x6a09e667,
  446. 0xbb67ae85,
  447. 0x3c6ef372,
  448. 0xa54ff53a,
  449. 0x510e527f,
  450. 0x9b05688c,
  451. 0x1f83d9ab,
  452. 0x5be0cd19
  453. ]);
  454. // Temporary buffer, not used to store anything between runs
  455. // Named this way because it matches specification.
  456. const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
  457. class SHA256 extends HashMD {
  458. get() {
  459. const { A, B, C, D, E, F, G, H } = this;
  460. return [
  461. A,
  462. B,
  463. C,
  464. D,
  465. E,
  466. F,
  467. G,
  468. H
  469. ];
  470. }
  471. // prettier-ignore
  472. set(A, B, C, D, E, F, G, H) {
  473. this.A = A | 0;
  474. this.B = B | 0;
  475. this.C = C | 0;
  476. this.D = D | 0;
  477. this.E = E | 0;
  478. this.F = F | 0;
  479. this.G = G | 0;
  480. this.H = H | 0;
  481. }
  482. process(view, offset) {
  483. // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
  484. for(let i = 0; i < 16; i++, offset += 4)SHA256_W[i] = view.getUint32(offset, false);
  485. for(let i = 16; i < 64; i++){
  486. const W15 = SHA256_W[i - 15];
  487. const W2 = SHA256_W[i - 2];
  488. const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
  489. const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
  490. SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
  491. }
  492. // Compression function main loop, 64 rounds
  493. let { A, B, C, D, E, F, G, H } = this;
  494. for(let i = 0; i < 64; i++){
  495. const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
  496. const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
  497. const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
  498. const T2 = sigma0 + Maj(A, B, C) | 0;
  499. H = G;
  500. G = F;
  501. F = E;
  502. E = D + T1 | 0;
  503. D = C;
  504. C = B;
  505. B = A;
  506. A = T1 + T2 | 0;
  507. }
  508. // Add the compressed chunk to the current hash value
  509. A = A + this.A | 0;
  510. B = B + this.B | 0;
  511. C = C + this.C | 0;
  512. D = D + this.D | 0;
  513. E = E + this.E | 0;
  514. F = F + this.F | 0;
  515. G = G + this.G | 0;
  516. H = H + this.H | 0;
  517. this.set(A, B, C, D, E, F, G, H);
  518. }
  519. roundClean() {
  520. SHA256_W.fill(0);
  521. }
  522. destroy() {
  523. this.set(0, 0, 0, 0, 0, 0, 0, 0);
  524. this.buffer.fill(0);
  525. }
  526. constructor(){
  527. super(64, 32, 8, false);
  528. // We cannot use array here since array allows indexing by variable
  529. // which means optimizer/compiler cannot use registers.
  530. this.A = SHA256_IV[0] | 0;
  531. this.B = SHA256_IV[1] | 0;
  532. this.C = SHA256_IV[2] | 0;
  533. this.D = SHA256_IV[3] | 0;
  534. this.E = SHA256_IV[4] | 0;
  535. this.F = SHA256_IV[5] | 0;
  536. this.G = SHA256_IV[6] | 0;
  537. this.H = SHA256_IV[7] | 0;
  538. }
  539. }
  540. // Constants from https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
  541. class SHA224 extends SHA256 {
  542. constructor(){
  543. super();
  544. this.A = 0xc1059ed8 | 0;
  545. this.B = 0x367cd507 | 0;
  546. this.C = 0x3070dd17 | 0;
  547. this.D = 0xf70e5939 | 0;
  548. this.E = 0xffc00b31 | 0;
  549. this.F = 0x68581511 | 0;
  550. this.G = 0x64f98fa7 | 0;
  551. this.H = 0xbefa4fa4 | 0;
  552. this.outputLen = 28;
  553. }
  554. }
  555. /**
  556. * SHA2-256 hash function
  557. * @param message - data that would be hashed
  558. */ const sha256 = /* @__PURE__ */ wrapConstructor(()=>new SHA256());
  559. const sha224 = /* @__PURE__ */ wrapConstructor(()=>new SHA224());
  560. const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
  561. const _32n = /* @__PURE__ */ BigInt(32);
  562. // We are not using BigUint64Array, because they are extremely slow as per 2022
  563. function fromBig(n, le = false) {
  564. if (le) return {
  565. h: Number(n & U32_MASK64),
  566. l: Number(n >> _32n & U32_MASK64)
  567. };
  568. return {
  569. h: Number(n >> _32n & U32_MASK64) | 0,
  570. l: Number(n & U32_MASK64) | 0
  571. };
  572. }
  573. function split(lst, le = false) {
  574. let Ah = new Uint32Array(lst.length);
  575. let Al = new Uint32Array(lst.length);
  576. for(let i = 0; i < lst.length; i++){
  577. const { h, l } = fromBig(lst[i], le);
  578. [Ah[i], Al[i]] = [
  579. h,
  580. l
  581. ];
  582. }
  583. return [
  584. Ah,
  585. Al
  586. ];
  587. }
  588. const toBig = (h, l)=>BigInt(h >>> 0) << _32n | BigInt(l >>> 0);
  589. // for Shift in [0, 32)
  590. const shrSH = (h, _l, s)=>h >>> s;
  591. const shrSL = (h, l, s)=>h << 32 - s | l >>> s;
  592. // Right rotate for Shift in [1, 32)
  593. const rotrSH = (h, l, s)=>h >>> s | l << 32 - s;
  594. const rotrSL = (h, l, s)=>h << 32 - s | l >>> s;
  595. // Right rotate for Shift in (32, 64), NOTE: 32 is special case.
  596. const rotrBH = (h, l, s)=>h << 64 - s | l >>> s - 32;
  597. const rotrBL = (h, l, s)=>h >>> s - 32 | l << 64 - s;
  598. // Right rotate for shift===32 (just swaps l&h)
  599. const rotr32H = (_h, l)=>l;
  600. const rotr32L = (h, _l)=>h;
  601. // Left rotate for Shift in [1, 32)
  602. const rotlSH = (h, l, s)=>h << s | l >>> 32 - s;
  603. const rotlSL = (h, l, s)=>l << s | h >>> 32 - s;
  604. // Left rotate for Shift in (32, 64), NOTE: 32 is special case.
  605. const rotlBH = (h, l, s)=>l << s - 32 | h >>> 64 - s;
  606. const rotlBL = (h, l, s)=>h << s - 32 | l >>> 64 - s;
  607. // JS uses 32-bit signed integers for bitwise operations which means we cannot
  608. // simple take carry out of low bit sum by shift, we need to use division.
  609. function add(Ah, Al, Bh, Bl) {
  610. const l = (Al >>> 0) + (Bl >>> 0);
  611. return {
  612. h: Ah + Bh + (l / 2 ** 32 | 0) | 0,
  613. l: l | 0
  614. };
  615. }
  616. // Addition with more than 2 elements
  617. const add3L = (Al, Bl, Cl)=>(Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
  618. const add3H = (low, Ah, Bh, Ch)=>Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
  619. const add4L = (Al, Bl, Cl, Dl)=>(Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
  620. const add4H = (low, Ah, Bh, Ch, Dh)=>Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0;
  621. const add5L = (Al, Bl, Cl, Dl, El)=>(Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
  622. const add5H = (low, Ah, Bh, Ch, Dh, Eh)=>Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
  623. // prettier-ignore
  624. const u64 = {
  625. fromBig,
  626. split,
  627. toBig,
  628. shrSH,
  629. shrSL,
  630. rotrSH,
  631. rotrSL,
  632. rotrBH,
  633. rotrBL,
  634. rotr32H,
  635. rotr32L,
  636. rotlSH,
  637. rotlSL,
  638. rotlBH,
  639. rotlBL,
  640. add,
  641. add3L,
  642. add3H,
  643. add4L,
  644. add4H,
  645. add5H,
  646. add5L
  647. };
  648. // Round contants (first 32 bits of the fractional parts of the cube roots of the first 80 primes 2..409):
  649. // prettier-ignore
  650. const [SHA512_Kh, SHA512_Kl] = /* @__PURE__ */ (()=>u64.split([
  651. '0x428a2f98d728ae22',
  652. '0x7137449123ef65cd',
  653. '0xb5c0fbcfec4d3b2f',
  654. '0xe9b5dba58189dbbc',
  655. '0x3956c25bf348b538',
  656. '0x59f111f1b605d019',
  657. '0x923f82a4af194f9b',
  658. '0xab1c5ed5da6d8118',
  659. '0xd807aa98a3030242',
  660. '0x12835b0145706fbe',
  661. '0x243185be4ee4b28c',
  662. '0x550c7dc3d5ffb4e2',
  663. '0x72be5d74f27b896f',
  664. '0x80deb1fe3b1696b1',
  665. '0x9bdc06a725c71235',
  666. '0xc19bf174cf692694',
  667. '0xe49b69c19ef14ad2',
  668. '0xefbe4786384f25e3',
  669. '0x0fc19dc68b8cd5b5',
  670. '0x240ca1cc77ac9c65',
  671. '0x2de92c6f592b0275',
  672. '0x4a7484aa6ea6e483',
  673. '0x5cb0a9dcbd41fbd4',
  674. '0x76f988da831153b5',
  675. '0x983e5152ee66dfab',
  676. '0xa831c66d2db43210',
  677. '0xb00327c898fb213f',
  678. '0xbf597fc7beef0ee4',
  679. '0xc6e00bf33da88fc2',
  680. '0xd5a79147930aa725',
  681. '0x06ca6351e003826f',
  682. '0x142929670a0e6e70',
  683. '0x27b70a8546d22ffc',
  684. '0x2e1b21385c26c926',
  685. '0x4d2c6dfc5ac42aed',
  686. '0x53380d139d95b3df',
  687. '0x650a73548baf63de',
  688. '0x766a0abb3c77b2a8',
  689. '0x81c2c92e47edaee6',
  690. '0x92722c851482353b',
  691. '0xa2bfe8a14cf10364',
  692. '0xa81a664bbc423001',
  693. '0xc24b8b70d0f89791',
  694. '0xc76c51a30654be30',
  695. '0xd192e819d6ef5218',
  696. '0xd69906245565a910',
  697. '0xf40e35855771202a',
  698. '0x106aa07032bbd1b8',
  699. '0x19a4c116b8d2d0c8',
  700. '0x1e376c085141ab53',
  701. '0x2748774cdf8eeb99',
  702. '0x34b0bcb5e19b48a8',
  703. '0x391c0cb3c5c95a63',
  704. '0x4ed8aa4ae3418acb',
  705. '0x5b9cca4f7763e373',
  706. '0x682e6ff3d6b2b8a3',
  707. '0x748f82ee5defb2fc',
  708. '0x78a5636f43172f60',
  709. '0x84c87814a1f0ab72',
  710. '0x8cc702081a6439ec',
  711. '0x90befffa23631e28',
  712. '0xa4506cebde82bde9',
  713. '0xbef9a3f7b2c67915',
  714. '0xc67178f2e372532b',
  715. '0xca273eceea26619c',
  716. '0xd186b8c721c0c207',
  717. '0xeada7dd6cde0eb1e',
  718. '0xf57d4f7fee6ed178',
  719. '0x06f067aa72176fba',
  720. '0x0a637dc5a2c898a6',
  721. '0x113f9804bef90dae',
  722. '0x1b710b35131c471b',
  723. '0x28db77f523047d84',
  724. '0x32caab7b40c72493',
  725. '0x3c9ebe0a15c9bebc',
  726. '0x431d67c49c100d4c',
  727. '0x4cc5d4becb3e42b6',
  728. '0x597f299cfc657e2a',
  729. '0x5fcb6fab3ad6faec',
  730. '0x6c44198c4a475817'
  731. ].map((n)=>BigInt(n))))();
  732. // Temporary buffer, not used to store anything between runs
  733. const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
  734. const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
  735. class SHA512 extends HashMD {
  736. // prettier-ignore
  737. get() {
  738. const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
  739. return [
  740. Ah,
  741. Al,
  742. Bh,
  743. Bl,
  744. Ch,
  745. Cl,
  746. Dh,
  747. Dl,
  748. Eh,
  749. El,
  750. Fh,
  751. Fl,
  752. Gh,
  753. Gl,
  754. Hh,
  755. Hl
  756. ];
  757. }
  758. // prettier-ignore
  759. set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
  760. this.Ah = Ah | 0;
  761. this.Al = Al | 0;
  762. this.Bh = Bh | 0;
  763. this.Bl = Bl | 0;
  764. this.Ch = Ch | 0;
  765. this.Cl = Cl | 0;
  766. this.Dh = Dh | 0;
  767. this.Dl = Dl | 0;
  768. this.Eh = Eh | 0;
  769. this.El = El | 0;
  770. this.Fh = Fh | 0;
  771. this.Fl = Fl | 0;
  772. this.Gh = Gh | 0;
  773. this.Gl = Gl | 0;
  774. this.Hh = Hh | 0;
  775. this.Hl = Hl | 0;
  776. }
  777. process(view, offset) {
  778. // Extend the first 16 words into the remaining 64 words w[16..79] of the message schedule array
  779. for(let i = 0; i < 16; i++, offset += 4){
  780. SHA512_W_H[i] = view.getUint32(offset);
  781. SHA512_W_L[i] = view.getUint32(offset += 4);
  782. }
  783. for(let i = 16; i < 80; i++){
  784. // s0 := (w[i-15] rightrotate 1) xor (w[i-15] rightrotate 8) xor (w[i-15] rightshift 7)
  785. const W15h = SHA512_W_H[i - 15] | 0;
  786. const W15l = SHA512_W_L[i - 15] | 0;
  787. const s0h = u64.rotrSH(W15h, W15l, 1) ^ u64.rotrSH(W15h, W15l, 8) ^ u64.shrSH(W15h, W15l, 7);
  788. const s0l = u64.rotrSL(W15h, W15l, 1) ^ u64.rotrSL(W15h, W15l, 8) ^ u64.shrSL(W15h, W15l, 7);
  789. // s1 := (w[i-2] rightrotate 19) xor (w[i-2] rightrotate 61) xor (w[i-2] rightshift 6)
  790. const W2h = SHA512_W_H[i - 2] | 0;
  791. const W2l = SHA512_W_L[i - 2] | 0;
  792. const s1h = u64.rotrSH(W2h, W2l, 19) ^ u64.rotrBH(W2h, W2l, 61) ^ u64.shrSH(W2h, W2l, 6);
  793. const s1l = u64.rotrSL(W2h, W2l, 19) ^ u64.rotrBL(W2h, W2l, 61) ^ u64.shrSL(W2h, W2l, 6);
  794. // SHA256_W[i] = s0 + s1 + SHA256_W[i - 7] + SHA256_W[i - 16];
  795. const SUMl = u64.add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);
  796. const SUMh = u64.add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]);
  797. SHA512_W_H[i] = SUMh | 0;
  798. SHA512_W_L[i] = SUMl | 0;
  799. }
  800. let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
  801. // Compression function main loop, 80 rounds
  802. for(let i = 0; i < 80; i++){
  803. // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)
  804. const sigma1h = u64.rotrSH(Eh, El, 14) ^ u64.rotrSH(Eh, El, 18) ^ u64.rotrBH(Eh, El, 41);
  805. const sigma1l = u64.rotrSL(Eh, El, 14) ^ u64.rotrSL(Eh, El, 18) ^ u64.rotrBL(Eh, El, 41);
  806. //const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 0;
  807. const CHIh = Eh & Fh ^ ~Eh & Gh;
  808. const CHIl = El & Fl ^ ~El & Gl;
  809. // T1 = H + sigma1 + Chi(E, F, G) + SHA512_K[i] + SHA512_W[i]
  810. // prettier-ignore
  811. const T1ll = u64.add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);
  812. const T1h = u64.add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);
  813. const T1l = T1ll | 0;
  814. // S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)
  815. const sigma0h = u64.rotrSH(Ah, Al, 28) ^ u64.rotrBH(Ah, Al, 34) ^ u64.rotrBH(Ah, Al, 39);
  816. const sigma0l = u64.rotrSL(Ah, Al, 28) ^ u64.rotrBL(Ah, Al, 34) ^ u64.rotrBL(Ah, Al, 39);
  817. const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch;
  818. const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl;
  819. Hh = Gh | 0;
  820. Hl = Gl | 0;
  821. Gh = Fh | 0;
  822. Gl = Fl | 0;
  823. Fh = Eh | 0;
  824. Fl = El | 0;
  825. ({ h: Eh, l: El } = u64.add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
  826. Dh = Ch | 0;
  827. Dl = Cl | 0;
  828. Ch = Bh | 0;
  829. Cl = Bl | 0;
  830. Bh = Ah | 0;
  831. Bl = Al | 0;
  832. const All = u64.add3L(T1l, sigma0l, MAJl);
  833. Ah = u64.add3H(All, T1h, sigma0h, MAJh);
  834. Al = All | 0;
  835. }
  836. // Add the compressed chunk to the current hash value
  837. ({ h: Ah, l: Al } = u64.add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
  838. ({ h: Bh, l: Bl } = u64.add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
  839. ({ h: Ch, l: Cl } = u64.add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
  840. ({ h: Dh, l: Dl } = u64.add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
  841. ({ h: Eh, l: El } = u64.add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
  842. ({ h: Fh, l: Fl } = u64.add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
  843. ({ h: Gh, l: Gl } = u64.add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
  844. ({ h: Hh, l: Hl } = u64.add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
  845. this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
  846. }
  847. roundClean() {
  848. SHA512_W_H.fill(0);
  849. SHA512_W_L.fill(0);
  850. }
  851. destroy() {
  852. this.buffer.fill(0);
  853. this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  854. }
  855. constructor(){
  856. super(128, 64, 16, false);
  857. // We cannot use array here since array allows indexing by variable which means optimizer/compiler cannot use registers.
  858. // Also looks cleaner and easier to verify with spec.
  859. // Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
  860. // h -- high 32 bits, l -- low 32 bits
  861. this.Ah = 0x6a09e667 | 0;
  862. this.Al = 0xf3bcc908 | 0;
  863. this.Bh = 0xbb67ae85 | 0;
  864. this.Bl = 0x84caa73b | 0;
  865. this.Ch = 0x3c6ef372 | 0;
  866. this.Cl = 0xfe94f82b | 0;
  867. this.Dh = 0xa54ff53a | 0;
  868. this.Dl = 0x5f1d36f1 | 0;
  869. this.Eh = 0x510e527f | 0;
  870. this.El = 0xade682d1 | 0;
  871. this.Fh = 0x9b05688c | 0;
  872. this.Fl = 0x2b3e6c1f | 0;
  873. this.Gh = 0x1f83d9ab | 0;
  874. this.Gl = 0xfb41bd6b | 0;
  875. this.Hh = 0x5be0cd19 | 0;
  876. this.Hl = 0x137e2179 | 0;
  877. }
  878. }
  879. class SHA384 extends SHA512 {
  880. constructor(){
  881. super();
  882. // h -- high 32 bits, l -- low 32 bits
  883. this.Ah = 0xcbbb9d5d | 0;
  884. this.Al = 0xc1059ed8 | 0;
  885. this.Bh = 0x629a292a | 0;
  886. this.Bl = 0x367cd507 | 0;
  887. this.Ch = 0x9159015a | 0;
  888. this.Cl = 0x3070dd17 | 0;
  889. this.Dh = 0x152fecd8 | 0;
  890. this.Dl = 0xf70e5939 | 0;
  891. this.Eh = 0x67332667 | 0;
  892. this.El = 0xffc00b31 | 0;
  893. this.Fh = 0x8eb44a87 | 0;
  894. this.Fl = 0x68581511 | 0;
  895. this.Gh = 0xdb0c2e0d | 0;
  896. this.Gl = 0x64f98fa7 | 0;
  897. this.Hh = 0x47b5481d | 0;
  898. this.Hl = 0xbefa4fa4 | 0;
  899. this.outputLen = 48;
  900. }
  901. }
  902. const sha512 = /* @__PURE__ */ wrapConstructor(()=>new SHA512());
  903. const sha384 = /* @__PURE__ */ wrapConstructor(()=>new SHA384());
  904. // SHA3 (keccak) is based on a new design: basically, the internal state is bigger than output size.
  905. // It's called a sponge function.
  906. // Various per round constants calculations
  907. const SHA3_PI = [];
  908. const SHA3_ROTL = [];
  909. const _SHA3_IOTA = [];
  910. const _0n = /* @__PURE__ */ BigInt(0);
  911. const _1n = /* @__PURE__ */ BigInt(1);
  912. const _2n = /* @__PURE__ */ BigInt(2);
  913. const _7n = /* @__PURE__ */ BigInt(7);
  914. const _256n = /* @__PURE__ */ BigInt(256);
  915. const _0x71n = /* @__PURE__ */ BigInt(0x71);
  916. for(let round = 0, R = _1n, x = 1, y = 0; round < 24; round++){
  917. // Pi
  918. [x, y] = [
  919. y,
  920. (2 * x + 3 * y) % 5
  921. ];
  922. SHA3_PI.push(2 * (5 * y + x));
  923. // Rotational
  924. SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
  925. // Iota
  926. let t = _0n;
  927. for(let j = 0; j < 7; j++){
  928. R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
  929. if (R & _2n) t ^= _1n << (_1n << /* @__PURE__ */ BigInt(j)) - _1n;
  930. }
  931. _SHA3_IOTA.push(t);
  932. }
  933. const [SHA3_IOTA_H, SHA3_IOTA_L] = /* @__PURE__ */ split(_SHA3_IOTA, true);
  934. // Left rotation (without 0, 32, 64)
  935. const rotlH = (h, l, s)=>s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
  936. const rotlL = (h, l, s)=>s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
  937. // Same as keccakf1600, but allows to skip some rounds
  938. function keccakP(s, rounds = 24) {
  939. const B = new Uint32Array(5 * 2);
  940. // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)
  941. for(let round = 24 - rounds; round < 24; round++){
  942. // Theta θ
  943. for(let x = 0; x < 10; x++)B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
  944. for(let x = 0; x < 10; x += 2){
  945. const idx1 = (x + 8) % 10;
  946. const idx0 = (x + 2) % 10;
  947. const B0 = B[idx0];
  948. const B1 = B[idx0 + 1];
  949. const Th = rotlH(B0, B1, 1) ^ B[idx1];
  950. const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
  951. for(let y = 0; y < 50; y += 10){
  952. s[x + y] ^= Th;
  953. s[x + y + 1] ^= Tl;
  954. }
  955. }
  956. // Rho (ρ) and Pi (π)
  957. let curH = s[2];
  958. let curL = s[3];
  959. for(let t = 0; t < 24; t++){
  960. const shift = SHA3_ROTL[t];
  961. const Th = rotlH(curH, curL, shift);
  962. const Tl = rotlL(curH, curL, shift);
  963. const PI = SHA3_PI[t];
  964. curH = s[PI];
  965. curL = s[PI + 1];
  966. s[PI] = Th;
  967. s[PI + 1] = Tl;
  968. }
  969. // Chi (χ)
  970. for(let y = 0; y < 50; y += 10){
  971. for(let x = 0; x < 10; x++)B[x] = s[y + x];
  972. for(let x = 0; x < 10; x++)s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
  973. }
  974. // Iota (ι)
  975. s[0] ^= SHA3_IOTA_H[round];
  976. s[1] ^= SHA3_IOTA_L[round];
  977. }
  978. B.fill(0);
  979. }
  980. class Keccak extends Hash {
  981. keccak() {
  982. if (!isLE) byteSwap32(this.state32);
  983. keccakP(this.state32, this.rounds);
  984. if (!isLE) byteSwap32(this.state32);
  985. this.posOut = 0;
  986. this.pos = 0;
  987. }
  988. update(data) {
  989. exists(this);
  990. const { blockLen, state } = this;
  991. data = toBytes(data);
  992. const len = data.length;
  993. for(let pos = 0; pos < len;){
  994. const take = Math.min(blockLen - this.pos, len - pos);
  995. for(let i = 0; i < take; i++)state[this.pos++] ^= data[pos++];
  996. if (this.pos === blockLen) this.keccak();
  997. }
  998. return this;
  999. }
  1000. finish() {
  1001. if (this.finished) return;
  1002. this.finished = true;
  1003. const { state, suffix, pos, blockLen } = this;
  1004. // Do the padding
  1005. state[pos] ^= suffix;
  1006. if ((suffix & 0x80) !== 0 && pos === blockLen - 1) this.keccak();
  1007. state[blockLen - 1] ^= 0x80;
  1008. this.keccak();
  1009. }
  1010. writeInto(out) {
  1011. exists(this, false);
  1012. bytes(out);
  1013. this.finish();
  1014. const bufferOut = this.state;
  1015. const { blockLen } = this;
  1016. for(let pos = 0, len = out.length; pos < len;){
  1017. if (this.posOut >= blockLen) this.keccak();
  1018. const take = Math.min(blockLen - this.posOut, len - pos);
  1019. out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
  1020. this.posOut += take;
  1021. pos += take;
  1022. }
  1023. return out;
  1024. }
  1025. xofInto(out) {
  1026. // Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF
  1027. if (!this.enableXOF) throw new Error('XOF is not possible for this instance');
  1028. return this.writeInto(out);
  1029. }
  1030. xof(bytes) {
  1031. number(bytes);
  1032. return this.xofInto(new Uint8Array(bytes));
  1033. }
  1034. digestInto(out) {
  1035. output(out, this);
  1036. if (this.finished) throw new Error('digest() was already called');
  1037. this.writeInto(out);
  1038. this.destroy();
  1039. return out;
  1040. }
  1041. digest() {
  1042. return this.digestInto(new Uint8Array(this.outputLen));
  1043. }
  1044. destroy() {
  1045. this.destroyed = true;
  1046. this.state.fill(0);
  1047. }
  1048. _cloneInto(to) {
  1049. const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
  1050. to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
  1051. to.state32.set(this.state32);
  1052. to.pos = this.pos;
  1053. to.posOut = this.posOut;
  1054. to.finished = this.finished;
  1055. to.rounds = rounds;
  1056. // Suffix can change in cSHAKE
  1057. to.suffix = suffix;
  1058. to.outputLen = outputLen;
  1059. to.enableXOF = enableXOF;
  1060. to.destroyed = this.destroyed;
  1061. return to;
  1062. }
  1063. // NOTE: we accept arguments in bytes instead of bits here.
  1064. constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24){
  1065. super();
  1066. this.blockLen = blockLen;
  1067. this.suffix = suffix;
  1068. this.outputLen = outputLen;
  1069. this.enableXOF = enableXOF;
  1070. this.rounds = rounds;
  1071. this.pos = 0;
  1072. this.posOut = 0;
  1073. this.finished = false;
  1074. this.destroyed = false;
  1075. // Can be passed from user as dkLen
  1076. number(outputLen);
  1077. // 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes
  1078. if (0 >= this.blockLen || this.blockLen >= 200) throw new Error('Sha3 supports only keccak-f1600 function');
  1079. this.state = new Uint8Array(200);
  1080. this.state32 = u32(this.state);
  1081. }
  1082. }
  1083. const gen = (suffix, blockLen, outputLen)=>wrapConstructor(()=>new Keccak(blockLen, suffix, outputLen));
  1084. const sha3_224 = /* @__PURE__ */ gen(0x06, 144, 224 / 8);
  1085. /**
  1086. * SHA3-256 hash function
  1087. * @param message - that would be hashed
  1088. */ const sha3_256 = /* @__PURE__ */ gen(0x06, 136, 256 / 8);
  1089. const sha3_384 = /* @__PURE__ */ gen(0x06, 104, 384 / 8);
  1090. const sha3_512 = /* @__PURE__ */ gen(0x06, 72, 512 / 8);
  1091. /**
  1092. * "globalThis" ponyfill.
  1093. * @see [A horrifying globalThis polyfill in universal JavaScript](https://mathiasbynens.be/notes/globalthis)
  1094. * @type {Object.<string, *>}
  1095. */ const globalScope = (()=>{
  1096. if (typeof globalThis === "object") return globalThis;
  1097. else {
  1098. Object.defineProperty(Object.prototype, "__GLOBALTHIS__", {
  1099. get () {
  1100. return this;
  1101. },
  1102. configurable: true
  1103. });
  1104. try {
  1105. // @ts-ignore
  1106. // eslint-disable-next-line no-undef
  1107. if (typeof __GLOBALTHIS__ !== "undefined") return __GLOBALTHIS__;
  1108. } finally{
  1109. // @ts-ignore
  1110. delete Object.prototype.__GLOBALTHIS__;
  1111. }
  1112. }
  1113. // Still unable to determine "globalThis", fall back to a naive method.
  1114. if (typeof self !== "undefined") return self;
  1115. else if (typeof window !== "undefined") return window;
  1116. else if (typeof global !== "undefined") return global;
  1117. return undefined;
  1118. })();
  1119. /**
  1120. * OpenSSL-Noble hashes map.
  1121. * @type {Object.<string, sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512>}
  1122. */ const OPENSSL_NOBLE_HASHES = {
  1123. SHA1: sha1,
  1124. SHA224: sha224,
  1125. SHA256: sha256,
  1126. SHA384: sha384,
  1127. SHA512: sha512,
  1128. "SHA3-224": sha3_224,
  1129. "SHA3-256": sha3_256,
  1130. "SHA3-384": sha3_384,
  1131. "SHA3-512": sha3_512
  1132. };
  1133. /**
  1134. * Calculates an HMAC digest.
  1135. * In Node.js, the command "openssl list -digest-algorithms" displays the available digest algorithms.
  1136. * @param {string} algorithm Algorithm.
  1137. * @param {Uint8Array} key Key.
  1138. * @param {Uint8Array} message Message.
  1139. * @returns {Uint8Array} Digest.
  1140. */ const hmacDigest = (algorithm, key, message)=>{
  1141. if (hmac) {
  1142. const hash = OPENSSL_NOBLE_HASHES[algorithm.toUpperCase()];
  1143. if (!hash) throw new TypeError("Unknown hash function");
  1144. return hmac(hash, key, message);
  1145. } else {
  1146. throw new Error("Missing HMAC function");
  1147. }
  1148. };
  1149. /**
  1150. * RFC 4648 base32 alphabet without pad.
  1151. * @type {string}
  1152. */ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  1153. /**
  1154. * Converts a base32 string to an Uint8Array (RFC 4648).
  1155. * @see [LinusU/base32-decode](https://github.com/LinusU/base32-decode)
  1156. * @param {string} str Base32 string.
  1157. * @returns {Uint8Array} Uint8Array.
  1158. */ const base32Decode = (str)=>{
  1159. // Canonicalize to all upper case and remove padding if it exists.
  1160. let end = str.length;
  1161. while(str[end - 1] === "=")--end;
  1162. const cstr = (end < str.length ? str.substring(0, end) : str).toUpperCase();
  1163. const buf = new ArrayBuffer(cstr.length * 5 / 8 | 0);
  1164. const arr = new Uint8Array(buf);
  1165. let bits = 0;
  1166. let value = 0;
  1167. let index = 0;
  1168. for(let i = 0; i < cstr.length; i++){
  1169. const idx = ALPHABET.indexOf(cstr[i]);
  1170. if (idx === -1) throw new TypeError(`Invalid character found: ${cstr[i]}`);
  1171. value = value << 5 | idx;
  1172. bits += 5;
  1173. if (bits >= 8) {
  1174. bits -= 8;
  1175. arr[index++] = value >>> bits;
  1176. }
  1177. }
  1178. return arr;
  1179. };
  1180. /**
  1181. * Converts an Uint8Array to a base32 string (RFC 4648).
  1182. * @see [LinusU/base32-encode](https://github.com/LinusU/base32-encode)
  1183. * @param {Uint8Array} arr Uint8Array.
  1184. * @returns {string} Base32 string.
  1185. */ const base32Encode = (arr)=>{
  1186. let bits = 0;
  1187. let value = 0;
  1188. let str = "";
  1189. for(let i = 0; i < arr.length; i++){
  1190. value = value << 8 | arr[i];
  1191. bits += 8;
  1192. while(bits >= 5){
  1193. str += ALPHABET[value >>> bits - 5 & 31];
  1194. bits -= 5;
  1195. }
  1196. }
  1197. if (bits > 0) {
  1198. str += ALPHABET[value << 5 - bits & 31];
  1199. }
  1200. return str;
  1201. };
  1202. /**
  1203. * Converts a hexadecimal string to an Uint8Array.
  1204. * @param {string} str Hexadecimal string.
  1205. * @returns {Uint8Array} Uint8Array.
  1206. */ const hexDecode = (str)=>{
  1207. const buf = new ArrayBuffer(str.length / 2);
  1208. const arr = new Uint8Array(buf);
  1209. for(let i = 0; i < str.length; i += 2){
  1210. arr[i / 2] = parseInt(str.substring(i, i + 2), 16);
  1211. }
  1212. return arr;
  1213. };
  1214. /**
  1215. * Converts an Uint8Array to a hexadecimal string.
  1216. * @param {Uint8Array} arr Uint8Array.
  1217. * @returns {string} Hexadecimal string.
  1218. */ const hexEncode = (arr)=>{
  1219. let str = "";
  1220. for(let i = 0; i < arr.length; i++){
  1221. const hex = arr[i].toString(16);
  1222. if (hex.length === 1) str += "0";
  1223. str += hex;
  1224. }
  1225. return str.toUpperCase();
  1226. };
  1227. /**
  1228. * Converts a Latin-1 string to an Uint8Array.
  1229. * @param {string} str Latin-1 string.
  1230. * @returns {Uint8Array} Uint8Array.
  1231. */ const latin1Decode = (str)=>{
  1232. const buf = new ArrayBuffer(str.length);
  1233. const arr = new Uint8Array(buf);
  1234. for(let i = 0; i < str.length; i++){
  1235. arr[i] = str.charCodeAt(i) & 0xff;
  1236. }
  1237. return arr;
  1238. };
  1239. /**
  1240. * Converts an Uint8Array to a Latin-1 string.
  1241. * @param {Uint8Array} arr Uint8Array.
  1242. * @returns {string} Latin-1 string.
  1243. */ const latin1Encode = (arr)=>{
  1244. let str = "";
  1245. for(let i = 0; i < arr.length; i++){
  1246. str += String.fromCharCode(arr[i]);
  1247. }
  1248. return str;
  1249. };
  1250. /**
  1251. * TextEncoder instance.
  1252. * @type {TextEncoder|null}
  1253. */ const ENCODER = globalScope.TextEncoder ? new globalScope.TextEncoder() : null;
  1254. /**
  1255. * TextDecoder instance.
  1256. * @type {TextDecoder|null}
  1257. */ const DECODER = globalScope.TextDecoder ? new globalScope.TextDecoder() : null;
  1258. /**
  1259. * Converts an UTF-8 string to an Uint8Array.
  1260. * @param {string} str String.
  1261. * @returns {Uint8Array} Uint8Array.
  1262. */ const utf8Decode = (str)=>{
  1263. if (!ENCODER) {
  1264. throw new Error("Encoding API not available");
  1265. }
  1266. return ENCODER.encode(str);
  1267. };
  1268. /**
  1269. * Converts an Uint8Array to an UTF-8 string.
  1270. * @param {Uint8Array} arr Uint8Array.
  1271. * @returns {string} String.
  1272. */ const utf8Encode = (arr)=>{
  1273. if (!DECODER) {
  1274. throw new Error("Encoding API not available");
  1275. }
  1276. return DECODER.decode(arr);
  1277. };
  1278. /**
  1279. * Returns random bytes.
  1280. * @param {number} size Size.
  1281. * @returns {Uint8Array} Random bytes.
  1282. */ const randomBytes = (size)=>{
  1283. {
  1284. if (!globalScope.crypto?.getRandomValues) {
  1285. throw new Error("Cryptography API not available");
  1286. }
  1287. return globalScope.crypto.getRandomValues(new Uint8Array(size));
  1288. }
  1289. };
  1290. /**
  1291. * OTP secret key.
  1292. */ class Secret {
  1293. /**
  1294. * Converts a Latin-1 string to a Secret object.
  1295. * @param {string} str Latin-1 string.
  1296. * @returns {Secret} Secret object.
  1297. */ static fromLatin1(str) {
  1298. return new Secret({
  1299. buffer: latin1Decode(str).buffer
  1300. });
  1301. }
  1302. /**
  1303. * Converts an UTF-8 string to a Secret object.
  1304. * @param {string} str UTF-8 string.
  1305. * @returns {Secret} Secret object.
  1306. */ static fromUTF8(str) {
  1307. return new Secret({
  1308. buffer: utf8Decode(str).buffer
  1309. });
  1310. }
  1311. /**
  1312. * Converts a base32 string to a Secret object.
  1313. * @param {string} str Base32 string.
  1314. * @returns {Secret} Secret object.
  1315. */ static fromBase32(str) {
  1316. return new Secret({
  1317. buffer: base32Decode(str).buffer
  1318. });
  1319. }
  1320. /**
  1321. * Converts a hexadecimal string to a Secret object.
  1322. * @param {string} str Hexadecimal string.
  1323. * @returns {Secret} Secret object.
  1324. */ static fromHex(str) {
  1325. return new Secret({
  1326. buffer: hexDecode(str).buffer
  1327. });
  1328. }
  1329. /**
  1330. * Secret key buffer.
  1331. * @deprecated For backward compatibility, the "bytes" property should be used instead.
  1332. * @type {ArrayBufferLike}
  1333. */ get buffer() {
  1334. return this.bytes.buffer;
  1335. }
  1336. /**
  1337. * Latin-1 string representation of secret key.
  1338. * @type {string}
  1339. */ get latin1() {
  1340. Object.defineProperty(this, "latin1", {
  1341. enumerable: true,
  1342. writable: false,
  1343. configurable: false,
  1344. value: latin1Encode(this.bytes)
  1345. });
  1346. return this.latin1;
  1347. }
  1348. /**
  1349. * UTF-8 string representation of secret key.
  1350. * @type {string}
  1351. */ get utf8() {
  1352. Object.defineProperty(this, "utf8", {
  1353. enumerable: true,
  1354. writable: false,
  1355. configurable: false,
  1356. value: utf8Encode(this.bytes)
  1357. });
  1358. return this.utf8;
  1359. }
  1360. /**
  1361. * Base32 string representation of secret key.
  1362. * @type {string}
  1363. */ get base32() {
  1364. Object.defineProperty(this, "base32", {
  1365. enumerable: true,
  1366. writable: false,
  1367. configurable: false,
  1368. value: base32Encode(this.bytes)
  1369. });
  1370. return this.base32;
  1371. }
  1372. /**
  1373. * Hexadecimal string representation of secret key.
  1374. * @type {string}
  1375. */ get hex() {
  1376. Object.defineProperty(this, "hex", {
  1377. enumerable: true,
  1378. writable: false,
  1379. configurable: false,
  1380. value: hexEncode(this.bytes)
  1381. });
  1382. return this.hex;
  1383. }
  1384. /**
  1385. * Creates a secret key object.
  1386. * @param {Object} [config] Configuration options.
  1387. * @param {ArrayBufferLike} [config.buffer] Secret key buffer.
  1388. * @param {number} [config.size=20] Number of random bytes to generate, ignored if 'buffer' is provided.
  1389. */ constructor({ buffer, size = 20 } = {}){
  1390. /**
  1391. * Secret key.
  1392. * @type {Uint8Array}
  1393. * @readonly
  1394. */ this.bytes = typeof buffer === "undefined" ? randomBytes(size) : new Uint8Array(buffer);
  1395. // Prevent the "bytes" property from being modified.
  1396. Object.defineProperty(this, "bytes", {
  1397. enumerable: true,
  1398. writable: false,
  1399. configurable: false,
  1400. value: this.bytes
  1401. });
  1402. }
  1403. }
  1404. /**
  1405. * Returns true if a is equal to b, without leaking timing information that would allow an attacker to guess one of the values.
  1406. * @param {string} a String a.
  1407. * @param {string} b String b.
  1408. * @returns {boolean} Equality result.
  1409. */ const timingSafeEqual = (a, b)=>{
  1410. {
  1411. if (a.length !== b.length) {
  1412. throw new TypeError("Input strings must have the same length");
  1413. }
  1414. let i = -1;
  1415. let out = 0;
  1416. while(++i < a.length){
  1417. out |= a.charCodeAt(i) ^ b.charCodeAt(i);
  1418. }
  1419. return out === 0;
  1420. }
  1421. };
  1422. /**
  1423. * HOTP: An HMAC-based One-time Password Algorithm.
  1424. * @see [RFC 4226](https://tools.ietf.org/html/rfc4226)
  1425. */ class HOTP {
  1426. /**
  1427. * Default configuration.
  1428. * @type {{
  1429. * issuer: string,
  1430. * label: string,
  1431. * issuerInLabel: boolean,
  1432. * algorithm: string,
  1433. * digits: number,
  1434. * counter: number
  1435. * window: number
  1436. * }}
  1437. */ static get defaults() {
  1438. return {
  1439. issuer: "",
  1440. label: "OTPAuth",
  1441. issuerInLabel: true,
  1442. algorithm: "SHA1",
  1443. digits: 6,
  1444. counter: 0,
  1445. window: 1
  1446. };
  1447. }
  1448. /**
  1449. * Generates an HOTP token.
  1450. * @param {Object} config Configuration options.
  1451. * @param {Secret} config.secret Secret key.
  1452. * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
  1453. * @param {number} [config.digits=6] Token length.
  1454. * @param {number} [config.counter=0] Counter value.
  1455. * @returns {string} Token.
  1456. */ static generate({ secret, algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter }) {
  1457. const digest = hmacDigest(algorithm, secret.bytes, uintDecode(counter));
  1458. const offset = digest[digest.byteLength - 1] & 15;
  1459. const otp = ((digest[offset] & 127) << 24 | (digest[offset + 1] & 255) << 16 | (digest[offset + 2] & 255) << 8 | digest[offset + 3] & 255) % 10 ** digits;
  1460. return otp.toString().padStart(digits, "0");
  1461. }
  1462. /**
  1463. * Generates an HOTP token.
  1464. * @param {Object} [config] Configuration options.
  1465. * @param {number} [config.counter=this.counter++] Counter value.
  1466. * @returns {string} Token.
  1467. */ generate({ counter = this.counter++ } = {}) {
  1468. return HOTP.generate({
  1469. secret: this.secret,
  1470. algorithm: this.algorithm,
  1471. digits: this.digits,
  1472. counter
  1473. });
  1474. }
  1475. /**
  1476. * Validates an HOTP token.
  1477. * @param {Object} config Configuration options.
  1478. * @param {string} config.token Token value.
  1479. * @param {Secret} config.secret Secret key.
  1480. * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
  1481. * @param {number} config.digits Token length.
  1482. * @param {number} [config.counter=0] Counter value.
  1483. * @param {number} [config.window=1] Window of counter values to test.
  1484. * @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
  1485. */ static validate({ token, secret, algorithm, digits, counter = HOTP.defaults.counter, window = HOTP.defaults.window }) {
  1486. // Return early if the token length does not match the digit number.
  1487. if (token.length !== digits) return null;
  1488. let delta = null;
  1489. const check = (/** @type {number} */ i)=>{
  1490. const generatedToken = HOTP.generate({
  1491. secret,
  1492. algorithm,
  1493. digits,
  1494. counter: i
  1495. });
  1496. if (timingSafeEqual(token, generatedToken)) {
  1497. delta = i - counter;
  1498. }
  1499. };
  1500. check(counter);
  1501. for(let i = 1; i <= window && delta === null; ++i){
  1502. check(counter - i);
  1503. if (delta !== null) break;
  1504. check(counter + i);
  1505. if (delta !== null) break;
  1506. }
  1507. return delta;
  1508. }
  1509. /**
  1510. * Validates an HOTP token.
  1511. * @param {Object} config Configuration options.
  1512. * @param {string} config.token Token value.
  1513. * @param {number} [config.counter=this.counter] Counter value.
  1514. * @param {number} [config.window=1] Window of counter values to test.
  1515. * @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
  1516. */ validate({ token, counter = this.counter, window }) {
  1517. return HOTP.validate({
  1518. token,
  1519. secret: this.secret,
  1520. algorithm: this.algorithm,
  1521. digits: this.digits,
  1522. counter,
  1523. window
  1524. });
  1525. }
  1526. /**
  1527. * Returns a Google Authenticator key URI.
  1528. * @returns {string} URI.
  1529. */ toString() {
  1530. const e = encodeURIComponent;
  1531. return "otpauth://hotp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `counter=${e(this.counter)}`;
  1532. }
  1533. /**
  1534. * Creates an HOTP object.
  1535. * @param {Object} [config] Configuration options.
  1536. * @param {string} [config.issuer=''] Account provider.
  1537. * @param {string} [config.label='OTPAuth'] Account label.
  1538. * @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
  1539. * @param {Secret|string} [config.secret=Secret] Secret key.
  1540. * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
  1541. * @param {number} [config.digits=6] Token length.
  1542. * @param {number} [config.counter=0] Initial counter value.
  1543. */ constructor({ issuer = HOTP.defaults.issuer, label = HOTP.defaults.label, issuerInLabel = HOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = HOTP.defaults.algorithm, digits = HOTP.defaults.digits, counter = HOTP.defaults.counter } = {}){
  1544. /**
  1545. * Account provider.
  1546. * @type {string}
  1547. */ this.issuer = issuer;
  1548. /**
  1549. * Account label.
  1550. * @type {string}
  1551. */ this.label = label;
  1552. /**
  1553. * Include issuer prefix in label.
  1554. * @type {boolean}
  1555. */ this.issuerInLabel = issuerInLabel;
  1556. /**
  1557. * Secret key.
  1558. * @type {Secret}
  1559. */ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
  1560. /**
  1561. * HMAC hashing algorithm.
  1562. * @type {string}
  1563. */ this.algorithm = algorithm.toUpperCase();
  1564. /**
  1565. * Token length.
  1566. * @type {number}
  1567. */ this.digits = digits;
  1568. /**
  1569. * Initial counter value.
  1570. * @type {number}
  1571. */ this.counter = counter;
  1572. }
  1573. }
  1574. /**
  1575. * TOTP: Time-Based One-Time Password Algorithm.
  1576. * @see [RFC 6238](https://tools.ietf.org/html/rfc6238)
  1577. */ class TOTP {
  1578. /**
  1579. * Default configuration.
  1580. * @type {{
  1581. * issuer: string,
  1582. * label: string,
  1583. * issuerInLabel: boolean,
  1584. * algorithm: string,
  1585. * digits: number,
  1586. * period: number
  1587. * window: number
  1588. * }}
  1589. */ static get defaults() {
  1590. return {
  1591. issuer: "",
  1592. label: "OTPAuth",
  1593. issuerInLabel: true,
  1594. algorithm: "SHA1",
  1595. digits: 6,
  1596. period: 30,
  1597. window: 1
  1598. };
  1599. }
  1600. /**
  1601. * Generates a TOTP token.
  1602. * @param {Object} config Configuration options.
  1603. * @param {Secret} config.secret Secret key.
  1604. * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
  1605. * @param {number} [config.digits=6] Token length.
  1606. * @param {number} [config.period=30] Token time-step duration.
  1607. * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
  1608. * @returns {string} Token.
  1609. */ static generate({ secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now() }) {
  1610. return HOTP.generate({
  1611. secret,
  1612. algorithm,
  1613. digits,
  1614. counter: Math.floor(timestamp / 1000 / period)
  1615. });
  1616. }
  1617. /**
  1618. * Generates a TOTP token.
  1619. * @param {Object} [config] Configuration options.
  1620. * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
  1621. * @returns {string} Token.
  1622. */ generate({ timestamp = Date.now() } = {}) {
  1623. return TOTP.generate({
  1624. secret: this.secret,
  1625. algorithm: this.algorithm,
  1626. digits: this.digits,
  1627. period: this.period,
  1628. timestamp
  1629. });
  1630. }
  1631. /**
  1632. * Validates a TOTP token.
  1633. * @param {Object} config Configuration options.
  1634. * @param {string} config.token Token value.
  1635. * @param {Secret} config.secret Secret key.
  1636. * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
  1637. * @param {number} config.digits Token length.
  1638. * @param {number} [config.period=30] Token time-step duration.
  1639. * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
  1640. * @param {number} [config.window=1] Window of counter values to test.
  1641. * @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
  1642. */ static validate({ token, secret, algorithm, digits, period = TOTP.defaults.period, timestamp = Date.now(), window }) {
  1643. return HOTP.validate({
  1644. token,
  1645. secret,
  1646. algorithm,
  1647. digits,
  1648. counter: Math.floor(timestamp / 1000 / period),
  1649. window
  1650. });
  1651. }
  1652. /**
  1653. * Validates a TOTP token.
  1654. * @param {Object} config Configuration options.
  1655. * @param {string} config.token Token value.
  1656. * @param {number} [config.timestamp=Date.now] Timestamp value in milliseconds.
  1657. * @param {number} [config.window=1] Window of counter values to test.
  1658. * @returns {number|null} Token delta or null if it is not found in the search window, in which case it should be considered invalid.
  1659. */ validate({ token, timestamp, window }) {
  1660. return TOTP.validate({
  1661. token,
  1662. secret: this.secret,
  1663. algorithm: this.algorithm,
  1664. digits: this.digits,
  1665. period: this.period,
  1666. timestamp,
  1667. window
  1668. });
  1669. }
  1670. /**
  1671. * Returns a Google Authenticator key URI.
  1672. * @returns {string} URI.
  1673. */ toString() {
  1674. const e = encodeURIComponent;
  1675. return "otpauth://totp/" + `${this.issuer.length > 0 ? this.issuerInLabel ? `${e(this.issuer)}:${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?issuer=${e(this.issuer)}&` : `${e(this.label)}?`}` + `secret=${e(this.secret.base32)}&` + `algorithm=${e(this.algorithm)}&` + `digits=${e(this.digits)}&` + `period=${e(this.period)}`;
  1676. }
  1677. /**
  1678. * Creates a TOTP object.
  1679. * @param {Object} [config] Configuration options.
  1680. * @param {string} [config.issuer=''] Account provider.
  1681. * @param {string} [config.label='OTPAuth'] Account label.
  1682. * @param {boolean} [config.issuerInLabel=true] Include issuer prefix in label.
  1683. * @param {Secret|string} [config.secret=Secret] Secret key.
  1684. * @param {string} [config.algorithm='SHA1'] HMAC hashing algorithm.
  1685. * @param {number} [config.digits=6] Token length.
  1686. * @param {number} [config.period=30] Token time-step duration.
  1687. */ constructor({ issuer = TOTP.defaults.issuer, label = TOTP.defaults.label, issuerInLabel = TOTP.defaults.issuerInLabel, secret = new Secret(), algorithm = TOTP.defaults.algorithm, digits = TOTP.defaults.digits, period = TOTP.defaults.period } = {}){
  1688. /**
  1689. * Account provider.
  1690. * @type {string}
  1691. */ this.issuer = issuer;
  1692. /**
  1693. * Account label.
  1694. * @type {string}
  1695. */ this.label = label;
  1696. /**
  1697. * Include issuer prefix in label.
  1698. * @type {boolean}
  1699. */ this.issuerInLabel = issuerInLabel;
  1700. /**
  1701. * Secret key.
  1702. * @type {Secret}
  1703. */ this.secret = typeof secret === "string" ? Secret.fromBase32(secret) : secret;
  1704. /**
  1705. * HMAC hashing algorithm.
  1706. * @type {string}
  1707. */ this.algorithm = algorithm.toUpperCase();
  1708. /**
  1709. * Token length.
  1710. * @type {number}
  1711. */ this.digits = digits;
  1712. /**
  1713. * Token time-step duration.
  1714. * @type {number}
  1715. */ this.period = period;
  1716. }
  1717. }
  1718. /**
  1719. * Key URI regex (otpauth://TYPE/[ISSUER:]LABEL?PARAMETERS).
  1720. * @type {RegExp}
  1721. */ const OTPURI_REGEX = /^otpauth:\/\/([ht]otp)\/(.+)\?([A-Z0-9.~_-]+=[^?&]*(?:&[A-Z0-9.~_-]+=[^?&]*)*)$/i;
  1722. /**
  1723. * RFC 4648 base32 alphabet with pad.
  1724. * @type {RegExp}
  1725. */ const SECRET_REGEX = /^[2-7A-Z]+=*$/i;
  1726. /**
  1727. * Regex for supported algorithms.
  1728. * @type {RegExp}
  1729. */ const ALGORITHM_REGEX = /^SHA(?:1|224|256|384|512|3-224|3-256|3-384|3-512)$/i;
  1730. /**
  1731. * Integer regex.
  1732. * @type {RegExp}
  1733. */ const INTEGER_REGEX = /^[+-]?\d+$/;
  1734. /**
  1735. * Positive integer regex.
  1736. * @type {RegExp}
  1737. */ const POSITIVE_INTEGER_REGEX = /^\+?[1-9]\d*$/;
  1738. /**
  1739. * HOTP/TOTP object/string conversion.
  1740. * @see [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
  1741. */ class URI {
  1742. /**
  1743. * Parses a Google Authenticator key URI and returns an HOTP/TOTP object.
  1744. * @param {string} uri Google Authenticator Key URI.
  1745. * @returns {HOTP|TOTP} HOTP/TOTP object.
  1746. */ static parse(uri) {
  1747. let uriGroups;
  1748. try {
  1749. uriGroups = uri.match(OTPURI_REGEX);
  1750. // eslint-disable-next-line no-unused-vars
  1751. } catch (_) {
  1752. /* Handled below */ }
  1753. if (!Array.isArray(uriGroups)) {
  1754. throw new URIError("Invalid URI format");
  1755. }
  1756. // Extract URI groups.
  1757. const uriType = uriGroups[1].toLowerCase();
  1758. const uriLabel = uriGroups[2].split(/(?::|%3A) *(.+)/i, 2).map(decodeURIComponent);
  1759. /** @type {Object.<string, string>} */ const uriParams = uriGroups[3].split("&").reduce((acc, cur)=>{
  1760. const pairArr = cur.split(/=(.*)/, 2).map(decodeURIComponent);
  1761. const pairKey = pairArr[0].toLowerCase();
  1762. const pairVal = pairArr[1];
  1763. /** @type {Object.<string, string>} */ const pairAcc = acc;
  1764. pairAcc[pairKey] = pairVal;
  1765. return pairAcc;
  1766. }, {});
  1767. // 'OTP' will be instantiated with 'config' argument.
  1768. let OTP;
  1769. const config = {};
  1770. if (uriType === "hotp") {
  1771. OTP = HOTP;
  1772. // Counter: required
  1773. if (typeof uriParams.counter !== "undefined" && INTEGER_REGEX.test(uriParams.counter)) {
  1774. config.counter = parseInt(uriParams.counter, 10);
  1775. } else {
  1776. throw new TypeError("Missing or invalid 'counter' parameter");
  1777. }
  1778. } else if (uriType === "totp") {
  1779. OTP = TOTP;
  1780. // Period: optional
  1781. if (typeof uriParams.period !== "undefined") {
  1782. if (POSITIVE_INTEGER_REGEX.test(uriParams.period)) {
  1783. config.period = parseInt(uriParams.period, 10);
  1784. } else {
  1785. throw new TypeError("Invalid 'period' parameter");
  1786. }
  1787. }
  1788. } else {
  1789. throw new TypeError("Unknown OTP type");
  1790. }
  1791. // Label: required
  1792. // Issuer: optional
  1793. if (typeof uriParams.issuer !== "undefined") {
  1794. config.issuer = uriParams.issuer;
  1795. }
  1796. if (uriLabel.length === 2) {
  1797. config.label = uriLabel[1];
  1798. if (typeof config.issuer === "undefined" || config.issuer === "") {
  1799. config.issuer = uriLabel[0];
  1800. } else if (uriLabel[0] === "") {
  1801. config.issuerInLabel = false;
  1802. }
  1803. } else {
  1804. config.label = uriLabel[0];
  1805. if (typeof config.issuer !== "undefined" && config.issuer !== "") {
  1806. config.issuerInLabel = false;
  1807. }
  1808. }
  1809. // Secret: required
  1810. if (typeof uriParams.secret !== "undefined" && SECRET_REGEX.test(uriParams.secret)) {
  1811. config.secret = uriParams.secret;
  1812. } else {
  1813. throw new TypeError("Missing or invalid 'secret' parameter");
  1814. }
  1815. // Algorithm: optional
  1816. if (typeof uriParams.algorithm !== "undefined") {
  1817. if (ALGORITHM_REGEX.test(uriParams.algorithm)) {
  1818. config.algorithm = uriParams.algorithm;
  1819. } else {
  1820. throw new TypeError("Invalid 'algorithm' parameter");
  1821. }
  1822. }
  1823. // Digits: optional
  1824. if (typeof uriParams.digits !== "undefined") {
  1825. if (POSITIVE_INTEGER_REGEX.test(uriParams.digits)) {
  1826. config.digits = parseInt(uriParams.digits, 10);
  1827. } else {
  1828. throw new TypeError("Invalid 'digits' parameter");
  1829. }
  1830. }
  1831. return new OTP(config);
  1832. }
  1833. /**
  1834. * Converts an HOTP/TOTP object to a Google Authenticator key URI.
  1835. * @param {HOTP|TOTP} otp HOTP/TOTP object.
  1836. * @returns {string} Google Authenticator Key URI.
  1837. */ static stringify(otp) {
  1838. if (otp instanceof HOTP || otp instanceof TOTP) {
  1839. return otp.toString();
  1840. }
  1841. throw new TypeError("Invalid 'HOTP/TOTP' object");
  1842. }
  1843. }
  1844. /**
  1845. * Library version.
  1846. * @type {string}
  1847. */ const version = "9.3.1";
  1848. exports.HOTP = HOTP;
  1849. exports.Secret = Secret;
  1850. exports.TOTP = TOTP;
  1851. exports.URI = URI;
  1852. exports.version = version;
  1853. }));