rsa-https.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. const PUBLIC_KEY = import.meta.env.VITE_PUBLIC_KEY
  2. const PRIVATE_KEY = import.meta.env.VITE_PRIVATE_KEY
  3. let publicKey: CryptoKey
  4. let privateKey: CryptoKey
  5. async function setPublicKey() {
  6. const publicKeyBuffer = pemToBuffer(PUBLIC_KEY);
  7. publicKey = await window.crypto.subtle.importKey(
  8. "spki", // 这边如果私钥则是pkcs8
  9. publicKeyBuffer,
  10. {
  11. name: "RSA-OAEP",
  12. hash: { name: 'SHA-256' },
  13. },
  14. true,
  15. ["encrypt"] // 用于加密所以是公钥,私钥就是 decrypt
  16. )
  17. // console.log(publicKey)
  18. }
  19. async function setPrivateKey() {
  20. const privateBuffer = pemToBuffer(PRIVATE_KEY);
  21. privateKey = await window.crypto.subtle.importKey(
  22. "pkcs8", // 这边如果私钥则是pkcs8
  23. privateBuffer,
  24. {
  25. name: "RSA-OAEP",
  26. hash: { name: 'SHA-256' },
  27. },
  28. true,
  29. ["decrypt"] // 用于加密所以是公钥,私钥就是 decrypt
  30. )
  31. // console.log(privateKey)
  32. }
  33. setPublicKey()
  34. // setPrivateKey()
  35. // setTimeout(() => {
  36. // // encrypt('asdfasdf').then(res => {
  37. // // console.log(res)
  38. // // })
  39. // decrypt('uts03JfyTGh/l8ivwQX/n9a6UpaVpfGgLaelrPfyMMdbslJmj79UNnv30NqktM7E6LhOyp4Ebt+EoJ8ss1FPyMlKpxwPHCFIanaClyR/aTCzeQGxVH2kZKJuZu02vrX1m2qXjn0Z1aV43GV5bNB40qPHzUZsMzMBHOqCAvqYO2zZwGpmFRFRu/93CPgpxgbhsbH7dCwOqJt9I7DMx9KaiiJmnPlbDSI4HG/wP/J2L1GHnZPK9zq+ccHm7WUYeVhf2xVYvma+hSzLWSiuwT1n5vRMIUKwjlT66usKJkEVhIiLTPmR6KLqEmWN21a/p6Dus/MCkFlA5hAURBalDqlnMQ==').then(res => {
  40. // console.log(res)
  41. // })
  42. // }, 300)
  43. export function encrypt(str: string) {
  44. const enc = new TextEncoder()
  45. const data = enc.encode(str) // 这边将要加密的字符串转为utf-8的Uint8Array
  46. return new Promise(async (resolve) => {
  47. const buffer = await window.crypto.subtle.encrypt(
  48. {
  49. name: "RSA-OAEP"
  50. },
  51. publicKey, // 生成或者导入的CryptoKey对象
  52. data
  53. )
  54. const resStr = window.btoa(String.fromCharCode(...new Uint8Array(buffer)))
  55. resolve(resStr)
  56. })
  57. }
  58. export function decrypt(base64String: string) {
  59. return new Promise(async (resolve) => {
  60. const buffer = await window.crypto.subtle.decrypt(
  61. {
  62. name: "RSA-OAEP"
  63. },
  64. privateKey,
  65. base64ToUint8Array(base64String)
  66. )
  67. const resStr = new TextDecoder().decode(buffer);
  68. resolve(resStr)
  69. })
  70. }
  71. function pemToBuffer(pem: string) {
  72. const lines = pem.split('\n');
  73. const encoded = lines.slice(1, -1).join('');
  74. const decoded = window.atob(encoded);
  75. const buffer = new Uint8Array(decoded.length);
  76. for (let i = 0; i < decoded.length; ++i) {
  77. buffer[i] = decoded.charCodeAt(i);
  78. }
  79. return buffer.buffer
  80. }
  81. function base64ToUint8Array(base64String: string) {
  82. const padding = '='.repeat((4 - base64String.length % 4) % 4)
  83. const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/')
  84. const rawData = window.atob(base64)
  85. const outputArray = new Uint8Array(rawData.length)
  86. for (let i = 0; i < rawData.length; ++i) {
  87. outputArray[i] = rawData.charCodeAt(i)
  88. }
  89. return outputArray
  90. }
  91. //#region 生成公钥私钥
  92. // generateKey()
  93. function generateKey() {
  94. window.crypto.subtle.generateKey(
  95. {
  96. name: "RSA-OAEP",
  97. modulusLength: 2048,
  98. publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
  99. hash: {
  100. name: "SHA-256" // 这边如果后端使用公钥加密,要注意与前端一致
  101. },
  102. },
  103. true,
  104. ["encrypt", "decrypt"] // must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
  105. ).then(key => {
  106. getPemText('spki', key.publicKey)
  107. getPemText('pkcs8', key.privateKey)
  108. })
  109. }
  110. function getPemText(type: "pkcs8" | "spki", key: CryptoKey) {
  111. // 导出私钥
  112. window.crypto.subtle.exportKey(type, key).then(function (res) {
  113. const key = RSA2text(res, type) // 私钥pem
  114. console.log(key)
  115. console.log(key.length)
  116. }).catch(function (err) {
  117. console.error(err)
  118. })
  119. }
  120. // pem格式文本
  121. function RSA2text(buffer: ArrayBuffer, type: "pkcs8" | "spki") {
  122. const isPrivate = type === 'pkcs8'
  123. let binary = ''
  124. const bytes = new Uint8Array(buffer)
  125. const len = bytes.byteLength
  126. for (let i = 0; i < len; i++) {
  127. binary += String.fromCharCode(bytes[i])
  128. }
  129. const base64 = window.btoa(binary)
  130. console.log(base64)
  131. console.log('\n')
  132. let text = "-----BEGIN " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----\n" // 这里-----BEGIN和-----是固定的
  133. text += base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n") // 中间base64编码
  134. text += "\n-----END " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----" // 这里-----END和-----是固定的
  135. return text
  136. }
  137. //#endregion