utils.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* eslint-disable no-bitwise, no-mixed-operators, no-use-before-define, max-len */
  2. const {BigInteger, SecureRandom} = require('jsbn')
  3. const {ECCurveFp} = require('./ec')
  4. const rng = new SecureRandom()
  5. const {curve, G, n} = generateEcparam()
  6. /**
  7. * 获取公共椭圆曲线
  8. */
  9. function getGlobalCurve() {
  10. return curve
  11. }
  12. /**
  13. * 生成ecparam
  14. */
  15. function generateEcparam() {
  16. // 椭圆曲线
  17. const p = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16)
  18. const a = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16)
  19. const b = new BigInteger('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16)
  20. const curve = new ECCurveFp(p, a, b)
  21. // 基点
  22. const gxHex = '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7'
  23. const gyHex = 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0'
  24. const G = curve.decodePointHex('04' + gxHex + gyHex)
  25. const n = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16)
  26. return {curve, G, n}
  27. }
  28. /**
  29. * 生成密钥对:publicKey = privateKey * G
  30. */
  31. function generateKeyPairHex(a, b, c) {
  32. const random = a ? new BigInteger(a, b, c) : new BigInteger(n.bitLength(), rng)
  33. const d = random.mod(n.subtract(BigInteger.ONE)).add(BigInteger.ONE) // 随机数
  34. const privateKey = leftPad(d.toString(16), 64)
  35. const P = G.multiply(d) // P = dG,p 为公钥,d 为私钥
  36. const Px = leftPad(P.getX().toBigInteger().toString(16), 64)
  37. const Py = leftPad(P.getY().toBigInteger().toString(16), 64)
  38. const publicKey = '04' + Px + Py
  39. return {privateKey, publicKey}
  40. }
  41. /**
  42. * 生成压缩公钥
  43. */
  44. function compressPublicKeyHex(s) {
  45. if (s.length !== 130) throw new Error('Invalid public key to compress')
  46. const len = (s.length - 2) / 2
  47. const xHex = s.substr(2, len)
  48. const y = new BigInteger(s.substr(len + 2, len), 16)
  49. let prefix = '03'
  50. if (y.mod(new BigInteger('2')).equals(BigInteger.ZERO)) prefix = '02'
  51. return prefix + xHex
  52. }
  53. /**
  54. * utf8串转16进制串
  55. */
  56. function utf8ToHex(input) {
  57. input = unescape(encodeURIComponent(input))
  58. const length = input.length
  59. // 转换到字数组
  60. const words = []
  61. for (let i = 0; i < length; i++) {
  62. words[i >>> 2] |= (input.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8)
  63. }
  64. // 转换到16进制
  65. const hexChars = []
  66. for (let i = 0; i < length; i++) {
  67. const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
  68. hexChars.push((bite >>> 4).toString(16))
  69. hexChars.push((bite & 0x0f).toString(16))
  70. }
  71. return hexChars.join('')
  72. }
  73. /**
  74. * 补全16进制字符串
  75. */
  76. function leftPad(input, num) {
  77. if (input.length >= num) return input
  78. return (new Array(num - input.length + 1)).join('0') + input
  79. }
  80. /**
  81. * 转成16进制串
  82. */
  83. function arrayToHex(arr) {
  84. return arr.map(item => {
  85. item = item.toString(16)
  86. return item.length === 1 ? '0' + item : item
  87. }).join('')
  88. }
  89. /**
  90. * 转成utf8串
  91. */
  92. function arrayToUtf8(arr) {
  93. const words = []
  94. let j = 0
  95. for (let i = 0; i < arr.length * 2; i += 2) {
  96. words[i >>> 3] |= parseInt(arr[j], 10) << (24 - (i % 8) * 4)
  97. j++
  98. }
  99. try {
  100. const latin1Chars = []
  101. for (let i = 0; i < arr.length; i++) {
  102. const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
  103. latin1Chars.push(String.fromCharCode(bite))
  104. }
  105. return decodeURIComponent(escape(latin1Chars.join('')))
  106. } catch (e) {
  107. throw new Error('Malformed UTF-8 data')
  108. }
  109. }
  110. /**
  111. * 转成字节数组
  112. */
  113. function hexToArray(hexStr) {
  114. const words = []
  115. let hexStrLength = hexStr.length
  116. if (hexStrLength % 2 !== 0) {
  117. hexStr = leftPad(hexStr, hexStrLength + 1)
  118. }
  119. hexStrLength = hexStr.length
  120. for (let i = 0; i < hexStrLength; i += 2) {
  121. words.push(parseInt(hexStr.substr(i, 2), 16))
  122. }
  123. return words
  124. }
  125. /**
  126. * 验证公钥是否为椭圆曲线上的点
  127. */
  128. function verifyPublicKey(publicKey) {
  129. const point = curve.decodePointHex(publicKey)
  130. if (!point) return false
  131. const x = point.getX()
  132. const y = point.getY()
  133. // 验证 y^2 是否等于 x^3 + ax + b
  134. return y.square().equals(x.multiply(x.square()).add(x.multiply(curve.a)).add(curve.b))
  135. }
  136. /**
  137. * 验证公钥是否等价,等价返回true
  138. */
  139. function comparePublicKeyHex(publicKey1, publicKey2) {
  140. const point1 = curve.decodePointHex(publicKey1)
  141. if (!point1) return false
  142. const point2 = curve.decodePointHex(publicKey2)
  143. if (!point2) return false
  144. return point1.equals(point2)
  145. }
  146. module.exports = {
  147. getGlobalCurve,
  148. generateEcparam,
  149. generateKeyPairHex,
  150. compressPublicKeyHex,
  151. utf8ToHex,
  152. leftPad,
  153. arrayToHex,
  154. arrayToUtf8,
  155. hexToArray,
  156. verifyPublicKey,
  157. comparePublicKeyHex,
  158. }