1
0

hash.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. const {
  2. bytesToBase64,
  3. bytesToBin,
  4. bytesToHex,
  5. stringToUtf8Bytes,
  6. toByteArray
  7. } = require('../../utils/binary-utils.js')
  8. const MASK_64 = 0xFFFFFFFFFFFFFFFFn
  9. const HASH_ALGORITHM_PRESETS = [
  10. { key: 'md5', label: 'MD5', kind: 'hash', hash: 'md5' },
  11. { key: 'sha1', label: 'SHA1', kind: 'hash', hash: 'sha1' },
  12. { key: 'sha224', label: 'SHA224', kind: 'hash', hash: 'sha224' },
  13. { key: 'sha256', label: 'SHA256', kind: 'hash', hash: 'sha256' },
  14. { key: 'sha384', label: 'SHA384', kind: 'hash', hash: 'sha384' },
  15. { key: 'sha512', label: 'SHA512', kind: 'hash', hash: 'sha512' },
  16. { key: 'hmac-md5', label: 'HMAC-MD5', kind: 'hmac', hash: 'md5' },
  17. { key: 'hmac-sha1', label: 'HMAC-SHA1', kind: 'hmac', hash: 'sha1' },
  18. { key: 'hmac-sha224', label: 'HMAC-SHA224', kind: 'hmac', hash: 'sha224' },
  19. { key: 'hmac-sha256', label: 'HMAC-SHA256', kind: 'hmac', hash: 'sha256' },
  20. { key: 'hmac-sha384', label: 'HMAC-SHA384', kind: 'hmac', hash: 'sha384' },
  21. { key: 'hmac-sha512', label: 'HMAC-SHA512', kind: 'hmac', hash: 'sha512' },
  22. { key: 'pbkdf2', label: 'PBKDF2', kind: 'pbkdf2', hash: 'sha256' }
  23. ]
  24. const SHA256_K = [
  25. 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
  26. 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
  27. 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
  28. 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
  29. 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
  30. 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
  31. 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
  32. 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
  33. 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
  34. 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
  35. 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
  36. 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
  37. 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
  38. 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
  39. 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
  40. 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
  41. ]
  42. const SHA512_K = [
  43. 0x428A2F98D728AE22n, 0x7137449123EF65CDn, 0xB5C0FBCFEC4D3B2Fn, 0xE9B5DBA58189DBBCn,
  44. 0x3956C25BF348B538n, 0x59F111F1B605D019n, 0x923F82A4AF194F9Bn, 0xAB1C5ED5DA6D8118n,
  45. 0xD807AA98A3030242n, 0x12835B0145706FBEn, 0x243185BE4EE4B28Cn, 0x550C7DC3D5FFB4E2n,
  46. 0x72BE5D74F27B896Fn, 0x80DEB1FE3B1696B1n, 0x9BDC06A725C71235n, 0xC19BF174CF692694n,
  47. 0xE49B69C19EF14AD2n, 0xEFBE4786384F25E3n, 0x0FC19DC68B8CD5B5n, 0x240CA1CC77AC9C65n,
  48. 0x2DE92C6F592B0275n, 0x4A7484AA6EA6E483n, 0x5CB0A9DCBD41FBD4n, 0x76F988DA831153B5n,
  49. 0x983E5152EE66DFABn, 0xA831C66D2DB43210n, 0xB00327C898FB213Fn, 0xBF597FC7BEEF0EE4n,
  50. 0xC6E00BF33DA88FC2n, 0xD5A79147930AA725n, 0x06CA6351E003826Fn, 0x142929670A0E6E70n,
  51. 0x27B70A8546D22FFCn, 0x2E1B21385C26C926n, 0x4D2C6DFC5AC42AEDn, 0x53380D139D95B3DFn,
  52. 0x650A73548BAF63DEn, 0x766A0ABB3C77B2A8n, 0x81C2C92E47EDAEE6n, 0x92722C851482353Bn,
  53. 0xA2BFE8A14CF10364n, 0xA81A664BBC423001n, 0xC24B8B70D0F89791n, 0xC76C51A30654BE30n,
  54. 0xD192E819D6EF5218n, 0xD69906245565A910n, 0xF40E35855771202An, 0x106AA07032BBD1B8n,
  55. 0x19A4C116B8D2D0C8n, 0x1E376C085141AB53n, 0x2748774CDF8EEB99n, 0x34B0BCB5E19B48A8n,
  56. 0x391C0CB3C5C95A63n, 0x4ED8AA4AE3418ACBn, 0x5B9CCA4F7763E373n, 0x682E6FF3D6B2B8A3n,
  57. 0x748F82EE5DEFB2FCn, 0x78A5636F43172F60n, 0x84C87814A1F0AB72n, 0x8CC702081A6439ECn,
  58. 0x90BEFFFA23631E28n, 0xA4506CEBDE82BDE9n, 0xBEF9A3F7B2C67915n, 0xC67178F2E372532Bn,
  59. 0xCA273ECEEA26619Cn, 0xD186B8C721C0C207n, 0xEADA7DD6CDE0EB1En, 0xF57D4F7FEE6ED178n,
  60. 0x06F067AA72176FBAn, 0x0A637DC5A2C898A6n, 0x113F9804BEF90DAEn, 0x1B710B35131C471Bn,
  61. 0x28DB77F523047D84n, 0x32CAAB7B40C72493n, 0x3C9EBE0A15C9BEBCn, 0x431D67C49C100D4Cn,
  62. 0x4CC5D4BECB3E42B6n, 0x597F299CFC657E2An, 0x5FCB6FAB3AD6FAECn, 0x6C44198C4A475817n
  63. ]
  64. function add32(...values) {
  65. return values.reduce((sum, value) => (sum + (value >>> 0)) >>> 0, 0)
  66. }
  67. function rotl32(value, bits) {
  68. return ((value << bits) | (value >>> (32 - bits))) >>> 0
  69. }
  70. function rotr32(value, bits) {
  71. return ((value >>> bits) | (value << (32 - bits))) >>> 0
  72. }
  73. function writeWord32BE(value, output) {
  74. output.push((value >>> 24) & 0xFF, (value >>> 16) & 0xFF, (value >>> 8) & 0xFF, value & 0xFF)
  75. }
  76. function writeWord32LE(value, output) {
  77. output.push(value & 0xFF, (value >>> 8) & 0xFF, (value >>> 16) & 0xFF, (value >>> 24) & 0xFF)
  78. }
  79. function padBlock64BE(bytes) {
  80. const message = toByteArray(bytes)
  81. const bitLength = BigInt(message.length) * 8n
  82. const padded = message.slice()
  83. padded.push(0x80)
  84. while (padded.length % 64 !== 56) padded.push(0)
  85. for (let shift = 56; shift >= 0; shift -= 8) {
  86. padded.push(Number((bitLength >> BigInt(shift)) & 0xFFn))
  87. }
  88. return padded
  89. }
  90. function md5(bytes) {
  91. const shifts = [
  92. 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
  93. 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
  94. 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
  95. 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
  96. ]
  97. const constants = []
  98. const message = toByteArray(bytes)
  99. const bitLength = BigInt(message.length) * 8n
  100. const padded = message.slice()
  101. for (let index = 0; index < 64; index += 1) {
  102. constants[index] = Math.floor(Math.abs(Math.sin(index + 1)) * 0x100000000) >>> 0
  103. }
  104. padded.push(0x80)
  105. while (padded.length % 64 !== 56) padded.push(0)
  106. for (let shift = 0; shift < 64; shift += 8) {
  107. padded.push(Number((bitLength >> BigInt(shift)) & 0xFFn))
  108. }
  109. let a0 = 0x67452301
  110. let b0 = 0xEFCDAB89
  111. let c0 = 0x98BADCFE
  112. let d0 = 0x10325476
  113. for (let offset = 0; offset < padded.length; offset += 64) {
  114. const words = []
  115. for (let index = 0; index < 16; index += 1) {
  116. const base = offset + index * 4
  117. words[index] = (
  118. (padded[base] & 0xFF) |
  119. ((padded[base + 1] & 0xFF) << 8) |
  120. ((padded[base + 2] & 0xFF) << 16) |
  121. ((padded[base + 3] & 0xFF) << 24)
  122. ) >>> 0
  123. }
  124. let a = a0
  125. let b = b0
  126. let c = c0
  127. let d = d0
  128. for (let index = 0; index < 64; index += 1) {
  129. let f
  130. let g
  131. if (index < 16) {
  132. f = (b & c) | ((~b) & d)
  133. g = index
  134. } else if (index < 32) {
  135. f = (d & b) | ((~d) & c)
  136. g = (5 * index + 1) % 16
  137. } else if (index < 48) {
  138. f = b ^ c ^ d
  139. g = (3 * index + 5) % 16
  140. } else {
  141. f = c ^ (b | (~d))
  142. g = (7 * index) % 16
  143. }
  144. const next = d
  145. d = c
  146. c = b
  147. b = add32(b, rotl32(add32(a, f, constants[index], words[g]), shifts[index]))
  148. a = next
  149. }
  150. a0 = add32(a0, a)
  151. b0 = add32(b0, b)
  152. c0 = add32(c0, c)
  153. d0 = add32(d0, d)
  154. }
  155. const output = []
  156. ;[a0, b0, c0, d0].forEach((word) => writeWord32LE(word, output))
  157. return output
  158. }
  159. function sha1(bytes) {
  160. const padded = padBlock64BE(bytes)
  161. const words = []
  162. let h0 = 0x67452301
  163. let h1 = 0xEFCDAB89
  164. let h2 = 0x98BADCFE
  165. let h3 = 0x10325476
  166. let h4 = 0xC3D2E1F0
  167. for (let offset = 0; offset < padded.length; offset += 64) {
  168. for (let index = 0; index < 16; index += 1) {
  169. const base = offset + index * 4
  170. words[index] = (
  171. ((padded[base] & 0xFF) << 24) |
  172. ((padded[base + 1] & 0xFF) << 16) |
  173. ((padded[base + 2] & 0xFF) << 8) |
  174. (padded[base + 3] & 0xFF)
  175. ) >>> 0
  176. }
  177. for (let index = 16; index < 80; index += 1) {
  178. words[index] = rotl32(words[index - 3] ^ words[index - 8] ^ words[index - 14] ^ words[index - 16], 1)
  179. }
  180. let a = h0
  181. let b = h1
  182. let c = h2
  183. let d = h3
  184. let e = h4
  185. for (let index = 0; index < 80; index += 1) {
  186. let f
  187. let k
  188. if (index < 20) {
  189. f = (b & c) | ((~b) & d)
  190. k = 0x5A827999
  191. } else if (index < 40) {
  192. f = b ^ c ^ d
  193. k = 0x6ED9EBA1
  194. } else if (index < 60) {
  195. f = (b & c) | (b & d) | (c & d)
  196. k = 0x8F1BBCDC
  197. } else {
  198. f = b ^ c ^ d
  199. k = 0xCA62C1D6
  200. }
  201. const temp = add32(rotl32(a, 5), f, e, k, words[index])
  202. e = d
  203. d = c
  204. c = rotl32(b, 30)
  205. b = a
  206. a = temp
  207. }
  208. h0 = add32(h0, a)
  209. h1 = add32(h1, b)
  210. h2 = add32(h2, c)
  211. h3 = add32(h3, d)
  212. h4 = add32(h4, e)
  213. }
  214. const output = []
  215. ;[h0, h1, h2, h3, h4].forEach((word) => writeWord32BE(word, output))
  216. return output
  217. }
  218. function sha256Family(bytes, mode) {
  219. const padded = padBlock64BE(bytes)
  220. const words = []
  221. const hash = mode === 'sha224'
  222. ? [0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4]
  223. : [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19]
  224. for (let offset = 0; offset < padded.length; offset += 64) {
  225. for (let index = 0; index < 16; index += 1) {
  226. const base = offset + index * 4
  227. words[index] = (
  228. ((padded[base] & 0xFF) << 24) |
  229. ((padded[base + 1] & 0xFF) << 16) |
  230. ((padded[base + 2] & 0xFF) << 8) |
  231. (padded[base + 3] & 0xFF)
  232. ) >>> 0
  233. }
  234. for (let index = 16; index < 64; index += 1) {
  235. const s0 = rotr32(words[index - 15], 7) ^ rotr32(words[index - 15], 18) ^ (words[index - 15] >>> 3)
  236. const s1 = rotr32(words[index - 2], 17) ^ rotr32(words[index - 2], 19) ^ (words[index - 2] >>> 10)
  237. words[index] = add32(words[index - 16], s0, words[index - 7], s1)
  238. }
  239. let a = hash[0]
  240. let b = hash[1]
  241. let c = hash[2]
  242. let d = hash[3]
  243. let e = hash[4]
  244. let f = hash[5]
  245. let g = hash[6]
  246. let h = hash[7]
  247. for (let index = 0; index < 64; index += 1) {
  248. const s1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25)
  249. const ch = (e & f) ^ ((~e) & g)
  250. const temp1 = add32(h, s1, ch, SHA256_K[index], words[index])
  251. const s0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22)
  252. const maj = (a & b) ^ (a & c) ^ (b & c)
  253. const temp2 = add32(s0, maj)
  254. h = g
  255. g = f
  256. f = e
  257. e = add32(d, temp1)
  258. d = c
  259. c = b
  260. b = a
  261. a = add32(temp1, temp2)
  262. }
  263. hash[0] = add32(hash[0], a)
  264. hash[1] = add32(hash[1], b)
  265. hash[2] = add32(hash[2], c)
  266. hash[3] = add32(hash[3], d)
  267. hash[4] = add32(hash[4], e)
  268. hash[5] = add32(hash[5], f)
  269. hash[6] = add32(hash[6], g)
  270. hash[7] = add32(hash[7], h)
  271. }
  272. const output = []
  273. hash.slice(0, mode === 'sha224' ? 7 : 8).forEach((word) => writeWord32BE(word, output))
  274. return output
  275. }
  276. function rotr64(value, bits) {
  277. const shift = BigInt(bits)
  278. return ((value >> shift) | (value << (64n - shift))) & MASK_64
  279. }
  280. function writeWord64BE(value, output) {
  281. for (let shift = 56; shift >= 0; shift -= 8) {
  282. output.push(Number((value >> BigInt(shift)) & 0xFFn))
  283. }
  284. }
  285. function readWord64BE(bytes, offset) {
  286. let value = 0n
  287. for (let index = 0; index < 8; index += 1) {
  288. value = (value << 8n) | BigInt(bytes[offset + index] & 0xFF)
  289. }
  290. return value
  291. }
  292. function padBlock128BE(bytes) {
  293. const message = toByteArray(bytes)
  294. const bitLength = BigInt(message.length) * 8n
  295. const padded = message.slice()
  296. padded.push(0x80)
  297. while (padded.length % 128 !== 112) padded.push(0)
  298. for (let shift = 120; shift >= 0; shift -= 8) {
  299. padded.push(Number((bitLength >> BigInt(shift)) & 0xFFn))
  300. }
  301. return padded
  302. }
  303. function sha512Family(bytes, mode) {
  304. const padded = padBlock128BE(bytes)
  305. const words = []
  306. const hash = mode === 'sha384'
  307. ? [
  308. 0xCBBB9D5DC1059ED8n, 0x629A292A367CD507n, 0x9159015A3070DD17n, 0x152FECD8F70E5939n,
  309. 0x67332667FFC00B31n, 0x8EB44A8768581511n, 0xDB0C2E0D64F98FA7n, 0x47B5481DBEFA4FA4n
  310. ]
  311. : [
  312. 0x6A09E667F3BCC908n, 0xBB67AE8584CAA73Bn, 0x3C6EF372FE94F82Bn, 0xA54FF53A5F1D36F1n,
  313. 0x510E527FADE682D1n, 0x9B05688C2B3E6C1Fn, 0x1F83D9ABFB41BD6Bn, 0x5BE0CD19137E2179n
  314. ]
  315. for (let offset = 0; offset < padded.length; offset += 128) {
  316. for (let index = 0; index < 16; index += 1) {
  317. words[index] = readWord64BE(padded, offset + index * 8)
  318. }
  319. for (let index = 16; index < 80; index += 1) {
  320. const s0 = rotr64(words[index - 15], 1) ^ rotr64(words[index - 15], 8) ^ (words[index - 15] >> 7n)
  321. const s1 = rotr64(words[index - 2], 19) ^ rotr64(words[index - 2], 61) ^ (words[index - 2] >> 6n)
  322. words[index] = (words[index - 16] + s0 + words[index - 7] + s1) & MASK_64
  323. }
  324. let a = hash[0]
  325. let b = hash[1]
  326. let c = hash[2]
  327. let d = hash[3]
  328. let e = hash[4]
  329. let f = hash[5]
  330. let g = hash[6]
  331. let h = hash[7]
  332. for (let index = 0; index < 80; index += 1) {
  333. const s1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41)
  334. const ch = (e & f) ^ ((MASK_64 ^ e) & g)
  335. const temp1 = (h + s1 + ch + SHA512_K[index] + words[index]) & MASK_64
  336. const s0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39)
  337. const maj = (a & b) ^ (a & c) ^ (b & c)
  338. const temp2 = (s0 + maj) & MASK_64
  339. h = g
  340. g = f
  341. f = e
  342. e = (d + temp1) & MASK_64
  343. d = c
  344. c = b
  345. b = a
  346. a = (temp1 + temp2) & MASK_64
  347. }
  348. hash[0] = (hash[0] + a) & MASK_64
  349. hash[1] = (hash[1] + b) & MASK_64
  350. hash[2] = (hash[2] + c) & MASK_64
  351. hash[3] = (hash[3] + d) & MASK_64
  352. hash[4] = (hash[4] + e) & MASK_64
  353. hash[5] = (hash[5] + f) & MASK_64
  354. hash[6] = (hash[6] + g) & MASK_64
  355. hash[7] = (hash[7] + h) & MASK_64
  356. }
  357. const output = []
  358. hash.slice(0, mode === 'sha384' ? 6 : 8).forEach((word) => writeWord64BE(word, output))
  359. return output
  360. }
  361. function digestBytes(hash, bytes) {
  362. if (hash === 'md5') return md5(bytes)
  363. if (hash === 'sha1') return sha1(bytes)
  364. if (hash === 'sha224') return sha256Family(bytes, 'sha224')
  365. if (hash === 'sha256') return sha256Family(bytes, 'sha256')
  366. if (hash === 'sha384') return sha512Family(bytes, 'sha384')
  367. if (hash === 'sha512') return sha512Family(bytes, 'sha512')
  368. throw new Error('不支持的哈希算法')
  369. }
  370. function getBlockSize(hash) {
  371. return hash === 'sha384' || hash === 'sha512' ? 128 : 64
  372. }
  373. function hmacBytes(hash, keyBytes, dataBytes) {
  374. const blockSize = getBlockSize(hash)
  375. let key = toByteArray(keyBytes)
  376. if (key.length > blockSize) {
  377. key = digestBytes(hash, key)
  378. }
  379. while (key.length < blockSize) key.push(0)
  380. const innerPad = []
  381. const outerPad = []
  382. for (let index = 0; index < blockSize; index += 1) {
  383. innerPad[index] = key[index] ^ 0x36
  384. outerPad[index] = key[index] ^ 0x5C
  385. }
  386. return digestBytes(hash, outerPad.concat(digestBytes(hash, innerPad.concat(toByteArray(dataBytes)))))
  387. }
  388. function parsePositiveInteger(value, label, fallback, maxValue) {
  389. const numberValue = Number(value || fallback)
  390. if (!Number.isInteger(numberValue) || numberValue <= 0) {
  391. throw new Error(`${label}需为正整数`)
  392. }
  393. if (numberValue > maxValue) {
  394. throw new Error(`${label}不能超过 ${maxValue}`)
  395. }
  396. return numberValue
  397. }
  398. function pbkdf2Bytes(hash, passwordBytes, saltBytes, iterations, outputLength) {
  399. const rounds = parsePositiveInteger(iterations, '迭代次数', 1000, 100000)
  400. const length = parsePositiveInteger(outputLength, '输出长度', 32, 4096)
  401. const hashLength = digestBytes(hash, []).length
  402. const blockCount = Math.ceil(length / hashLength)
  403. const output = []
  404. for (let blockIndex = 1; blockIndex <= blockCount; blockIndex += 1) {
  405. const blockIndexBytes = [
  406. (blockIndex >>> 24) & 0xFF,
  407. (blockIndex >>> 16) & 0xFF,
  408. (blockIndex >>> 8) & 0xFF,
  409. blockIndex & 0xFF
  410. ]
  411. let previous = hmacBytes(hash, passwordBytes, toByteArray(saltBytes).concat(blockIndexBytes))
  412. const block = previous.slice()
  413. for (let round = 1; round < rounds; round += 1) {
  414. previous = hmacBytes(hash, passwordBytes, previous)
  415. for (let index = 0; index < block.length; index += 1) {
  416. block[index] ^= previous[index]
  417. }
  418. }
  419. output.push(...block)
  420. }
  421. return output.slice(0, length)
  422. }
  423. function getPreset(key) {
  424. return HASH_ALGORITHM_PRESETS.find((preset) => preset.key === key) || HASH_ALGORITHM_PRESETS[0]
  425. }
  426. function calculateHash(bytes, config = {}) {
  427. const preset = getPreset(config.key)
  428. const dataBytes = toByteArray(bytes)
  429. let resultBytes
  430. if (preset.kind === 'hmac') {
  431. resultBytes = hmacBytes(preset.hash, stringToUtf8Bytes(config.hmacKey || ''), dataBytes)
  432. } else if (preset.kind === 'pbkdf2') {
  433. resultBytes = pbkdf2Bytes(
  434. preset.hash,
  435. dataBytes,
  436. stringToUtf8Bytes(config.pbkdf2Salt || ''),
  437. config.pbkdf2Iterations,
  438. config.pbkdf2Length
  439. )
  440. } else {
  441. resultBytes = digestBytes(preset.hash, dataBytes)
  442. }
  443. return {
  444. base64: bytesToBase64(resultBytes),
  445. bin: bytesToBin(resultBytes),
  446. bytes: resultBytes,
  447. hex: bytesToHex(resultBytes),
  448. width: resultBytes.length * 8
  449. }
  450. }
  451. module.exports = {
  452. HASH_ALGORITHM_PRESETS,
  453. bytesToBase64,
  454. bytesToBin,
  455. bytesToHex,
  456. calculateHash,
  457. digestBytes,
  458. hmacBytes,
  459. pbkdf2Bytes,
  460. stringToUtf8Bytes,
  461. toByteArray
  462. }