rsa-https.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. export function encrypt(str: string) {
  36. const enc = new TextEncoder()
  37. const data = enc.encode(str) // 这边将要加密的字符串转为utf-8的Uint8Array
  38. return new Promise(async (resolve) => {
  39. const buffer = await window.crypto.subtle.encrypt(
  40. {
  41. name: "RSA-OAEP"
  42. },
  43. publicKey, // 生成或者导入的CryptoKey对象
  44. data
  45. )
  46. const resStr = window.btoa(String.fromCharCode(...new Uint8Array(buffer)))
  47. resolve(resStr)
  48. })
  49. }
  50. export function decrypt(base64String: string) {
  51. return new Promise(async (resolve) => {
  52. const buffer = await window.crypto.subtle.decrypt(
  53. {
  54. name: "RSA-OAEP"
  55. },
  56. privateKey,
  57. base64ToUint8Array(base64String)
  58. )
  59. const resStr = new TextDecoder().decode(buffer);
  60. resolve(resStr)
  61. })
  62. }
  63. function pemToBuffer(pem: string) {
  64. const lines = pem.split('\n');
  65. const encoded = lines.slice(1, -1).join('');
  66. const decoded = window.atob(encoded);
  67. const buffer = new Uint8Array(decoded.length);
  68. for (let i = 0; i < decoded.length; ++i) {
  69. buffer[i] = decoded.charCodeAt(i);
  70. }
  71. return buffer.buffer
  72. }
  73. function base64ToUint8Array(base64String: string) {
  74. const padding = '='.repeat((4 - base64String.length % 4) % 4)
  75. const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/')
  76. const rawData = window.atob(base64)
  77. const outputArray = new Uint8Array(rawData.length)
  78. for (let i = 0; i < rawData.length; ++i) {
  79. outputArray[i] = rawData.charCodeAt(i)
  80. }
  81. return outputArray
  82. }
  83. //#region 生成公钥私钥
  84. // generateKey()
  85. function generateKey() {
  86. window.crypto.subtle.generateKey(
  87. {
  88. name: "RSA-OAEP",
  89. modulusLength: 2048,
  90. publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
  91. hash: {
  92. name: "SHA-256" // 这边如果后端使用公钥加密,要注意与前端一致
  93. },
  94. },
  95. true,
  96. ["encrypt", "decrypt"] // must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
  97. ).then(key => {
  98. getPemText('spki', key.publicKey)
  99. getPemText('pkcs8', key.privateKey)
  100. })
  101. }
  102. function getPemText(type: "pkcs8" | "spki", key: CryptoKey) {
  103. // 导出私钥
  104. window.crypto.subtle.exportKey(type, key).then(function (res) {
  105. const key = RSA2text(res, type) // 私钥pem
  106. console.log(key)
  107. console.log(key.length)
  108. }).catch(function (err) {
  109. console.error(err)
  110. })
  111. }
  112. // pem格式文本
  113. function RSA2text(buffer: ArrayBuffer, type: "pkcs8" | "spki") {
  114. const isPrivate = type === 'pkcs8'
  115. let binary = ''
  116. const bytes = new Uint8Array(buffer)
  117. const len = bytes.byteLength
  118. for (let i = 0; i < len; i++) {
  119. binary += String.fromCharCode(bytes[i])
  120. }
  121. const base64 = window.btoa(binary)
  122. console.log(base64)
  123. console.log('\n')
  124. let text = "-----BEGIN " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----\n" // 这里-----BEGIN和-----是固定的
  125. text += base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n") // 中间base64编码
  126. text += "\n-----END " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----" // 这里-----END和-----是固定的
  127. return text
  128. }
  129. //#endregion