sm3.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // 消息扩展
  2. const W = new Uint32Array(68)
  3. const M = new Uint32Array(64) // W'
  4. /**
  5. * 循环左移
  6. */
  7. function rotl(x, n) {
  8. const s = n & 31
  9. return (x << s) | (x >>> (32 - s))
  10. }
  11. /**
  12. * 二进制异或运算
  13. */
  14. function xor(x, y) {
  15. const result = []
  16. for (let i = x.length - 1; i >= 0; i--) result[i] = (x[i] ^ y[i]) & 0xff
  17. return result
  18. }
  19. /**
  20. * 压缩函数中的置换函数 P0(X) = X xor (X <<< 9) xor (X <<< 17)
  21. */
  22. function P0(X) {
  23. return (X ^ rotl(X, 9)) ^ rotl(X, 17)
  24. }
  25. /**
  26. * 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
  27. */
  28. function P1(X) {
  29. return (X ^ rotl(X, 15)) ^ rotl(X, 23)
  30. }
  31. /**
  32. * sm3 本体
  33. */
  34. function sm3(array) {
  35. let len = array.length * 8
  36. // k 是满足 len + 1 + k = 448mod512 的最小的非负整数
  37. let k = len % 512
  38. // 如果 448 <= (512 % len) < 512,需要多补充 (len % 448) 比特'0'以满足总比特长度为512的倍数
  39. k = k >= 448 ? 512 - (k % 448) - 1 : 448 - k - 1
  40. // 填充
  41. const kArr = new Array((k - 7) / 8)
  42. const lenArr = new Array(8)
  43. for (let i = 0, len = kArr.length; i < len; i++) kArr[i] = 0
  44. for (let i = 0, len = lenArr.length; i < len; i++) lenArr[i] = 0
  45. len = len.toString(2)
  46. for (let i = 7; i >= 0; i--) {
  47. if (len.length > 8) {
  48. const start = len.length - 8
  49. lenArr[i] = parseInt(len.substr(start), 2)
  50. len = len.substr(0, start)
  51. } else if (len.length > 0) {
  52. lenArr[i] = parseInt(len, 2)
  53. len = ''
  54. }
  55. }
  56. const m = new Uint8Array([...array, 0x80, ...kArr, ...lenArr])
  57. const dataView = new DataView(m.buffer, 0)
  58. // 迭代压缩
  59. const n = m.length / 64
  60. const V = new Uint32Array([0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e])
  61. for (let i = 0; i < n; i++) {
  62. W.fill(0)
  63. M.fill(0)
  64. // 将消息分组B划分为 16 个字 W0, W1,……,W15
  65. const start = 16 * i
  66. for (let j = 0; j < 16; j++) {
  67. W[j] = dataView.getUint32((start + j) * 4, false)
  68. }
  69. // W16 ~ W67:W[j] <- P1(W[j−16] xor W[j−9] xor (W[j−3] <<< 15)) xor (W[j−13] <<< 7) xor W[j−6]
  70. for (let j = 16; j < 68; j++) {
  71. W[j] = (P1((W[j - 16] ^ W[j - 9]) ^ rotl(W[j - 3], 15)) ^ rotl(W[j - 13], 7)) ^ W[j - 6]
  72. }
  73. // W′0 ~ W′63:W′[j] = W[j] xor W[j+4]
  74. for (let j = 0; j < 64; j++) {
  75. M[j] = W[j] ^ W[j + 4]
  76. }
  77. // 压缩
  78. const T1 = 0x79cc4519
  79. const T2 = 0x7a879d8a
  80. // 字寄存器
  81. let A = V[0]
  82. let B = V[1]
  83. let C = V[2]
  84. let D = V[3]
  85. let E = V[4]
  86. let F = V[5]
  87. let G = V[6]
  88. let H = V[7]
  89. // 中间变量
  90. let SS1
  91. let SS2
  92. let TT1
  93. let TT2
  94. let T
  95. for (let j = 0; j < 64; j++) {
  96. T = j >= 0 && j <= 15 ? T1 : T2
  97. SS1 = rotl(rotl(A, 12) + E + rotl(T, j), 7)
  98. SS2 = SS1 ^ rotl(A, 12)
  99. TT1 = (j >= 0 && j <= 15 ? ((A ^ B) ^ C) : (((A & B) | (A & C)) | (B & C))) + D + SS2 + M[j]
  100. TT2 = (j >= 0 && j <= 15 ? ((E ^ F) ^ G) : ((E & F) | ((~E) & G))) + H + SS1 + W[j]
  101. D = C
  102. C = rotl(B, 9)
  103. B = A
  104. A = TT1
  105. H = G
  106. G = rotl(F, 19)
  107. F = E
  108. E = P0(TT2)
  109. }
  110. V[0] ^= A
  111. V[1] ^= B
  112. V[2] ^= C
  113. V[3] ^= D
  114. V[4] ^= E
  115. V[5] ^= F
  116. V[6] ^= G
  117. V[7] ^= H
  118. }
  119. // 转回 uint8
  120. const result = []
  121. for (let i = 0, len = V.length; i < len; i++) {
  122. const word = V[i]
  123. result.push((word & 0xff000000) >>> 24, (word & 0xff0000) >>> 16, (word & 0xff00) >>> 8, word & 0xff)
  124. }
  125. return result
  126. }
  127. /**
  128. * hmac 实现
  129. */
  130. const blockLen = 64
  131. const iPad = new Uint8Array(blockLen)
  132. const oPad = new Uint8Array(blockLen)
  133. for (let i = 0; i < blockLen; i++) {
  134. iPad[i] = 0x36
  135. oPad[i] = 0x5c
  136. }
  137. function hmac(input, key) {
  138. // 密钥填充
  139. if (key.length > blockLen) key = sm3(key)
  140. while (key.length < blockLen) key.push(0)
  141. const iPadKey = xor(key, iPad)
  142. const oPadKey = xor(key, oPad)
  143. const hash = sm3([...iPadKey, ...input])
  144. return sm3([...oPadKey, ...hash])
  145. }
  146. module.exports = {
  147. sm3,
  148. hmac,
  149. }