Browse Source

fix: 修复之前的rsa-oaep在http下不能使用的问题,用了jsrsasign库来实现

yanglzh 1 year ago
parent
commit
90cf0c7c1f
5 changed files with 171 additions and 155 deletions
  1. 1 1
      package.json
  2. 1 0
      plugins.d.ts
  3. 155 0
      src/utils/rsa-https.ts
  4. 9 149
      src/utils/rsa.ts
  5. 5 5
      yarn.lock

+ 1 - 1
package.json

@@ -33,8 +33,8 @@
     "echarts-wordcloud": "^2.0.0",
     "element-plus": "2.2.28",
     "event-source-polyfill": "^1.0.31",
-    "jsencrypt": "^3.3.2",
     "jsplumb": "^2.15.6",
+    "jsrsasign": "^10.8.6",
     "mitt": "^3.0.0",
     "nprogress": "^0.2.0",
     "pako": "^1.0.11",

+ 1 - 0
plugins.d.ts

@@ -3,3 +3,4 @@ declare module 'qrcodejs2-fixes';
 declare module 'splitpanes';
 declare module 'vue3-json-viewer';
 declare module 'vform3-builds';
+declare module 'jsrsasign';

+ 155 - 0
src/utils/rsa-https.ts

@@ -0,0 +1,155 @@
+const PUBLIC_KEY = import.meta.env.VITE_PUBLIC_KEY
+const PRIVATE_KEY = import.meta.env.VITE_PRIVATE_KEY
+
+let publicKey: CryptoKey
+let privateKey: CryptoKey
+
+async function setPublicKey() {
+  const publicKeyBuffer = pemToBuffer(PUBLIC_KEY);
+  publicKey = await window.crypto.subtle.importKey(
+    "spki", // 这边如果私钥则是pkcs8
+    publicKeyBuffer,
+    {
+      name: "RSA-OAEP",
+      hash: { name: 'SHA-256' },
+    },
+    true,
+    ["encrypt"] // 用于加密所以是公钥,私钥就是 decrypt
+  )
+  // console.log(publicKey)
+}
+
+async function setPrivateKey() {
+  const privateBuffer = pemToBuffer(PRIVATE_KEY);
+  privateKey = await window.crypto.subtle.importKey(
+    "pkcs8", // 这边如果私钥则是pkcs8
+    privateBuffer,
+    {
+      name: "RSA-OAEP",
+      hash: { name: 'SHA-256' },
+    },
+    true,
+    ["decrypt"] // 用于加密所以是公钥,私钥就是 decrypt
+  )
+  // console.log(privateKey)
+}
+
+setPublicKey()
+// setPrivateKey()
+
+// setTimeout(() => {
+//   // encrypt('asdfasdf').then(res => {
+//   //   console.log(res)
+//   // })
+//   decrypt('uts03JfyTGh/l8ivwQX/n9a6UpaVpfGgLaelrPfyMMdbslJmj79UNnv30NqktM7E6LhOyp4Ebt+EoJ8ss1FPyMlKpxwPHCFIanaClyR/aTCzeQGxVH2kZKJuZu02vrX1m2qXjn0Z1aV43GV5bNB40qPHzUZsMzMBHOqCAvqYO2zZwGpmFRFRu/93CPgpxgbhsbH7dCwOqJt9I7DMx9KaiiJmnPlbDSI4HG/wP/J2L1GHnZPK9zq+ccHm7WUYeVhf2xVYvma+hSzLWSiuwT1n5vRMIUKwjlT66usKJkEVhIiLTPmR6KLqEmWN21a/p6Dus/MCkFlA5hAURBalDqlnMQ==').then(res => {
+//     console.log(res)
+//   })
+// }, 300)
+
+export function encrypt(str: string) {
+  const enc = new TextEncoder()
+  const data = enc.encode(str) // 这边将要加密的字符串转为utf-8的Uint8Array
+  return new Promise(async (resolve) => {
+    const buffer = await window.crypto.subtle.encrypt(
+      {
+        name: "RSA-OAEP"
+      },
+      publicKey, // 生成或者导入的CryptoKey对象
+      data
+    )
+    const resStr = window.btoa(String.fromCharCode(...new Uint8Array(buffer)))
+    resolve(resStr)
+  })
+}
+
+export function decrypt(base64String: string) {
+  return new Promise(async (resolve) => {
+    const buffer = await window.crypto.subtle.decrypt(
+      {
+        name: "RSA-OAEP"
+      },
+      privateKey,
+      base64ToUint8Array(base64String)
+    )
+    const resStr = new TextDecoder().decode(buffer);
+    resolve(resStr)
+  })
+}
+
+function pemToBuffer(pem: string) {
+  const lines = pem.split('\n');
+  const encoded = lines.slice(1, -1).join('');
+  const decoded = window.atob(encoded);
+  const buffer = new Uint8Array(decoded.length);
+  for (let i = 0; i < decoded.length; ++i) {
+    buffer[i] = decoded.charCodeAt(i);
+  }
+  return buffer.buffer
+}
+
+function base64ToUint8Array(base64String: string) {
+  const padding = '='.repeat((4 - base64String.length % 4) % 4)
+  const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/')
+
+  const rawData = window.atob(base64)
+  const outputArray = new Uint8Array(rawData.length)
+
+  for (let i = 0; i < rawData.length; ++i) {
+    outputArray[i] = rawData.charCodeAt(i)
+  }
+  return outputArray
+}
+
+//#region 生成公钥私钥
+
+// generateKey()
+
+function generateKey() {
+  window.crypto.subtle.generateKey(
+    {
+      name: "RSA-OAEP",
+      modulusLength: 2048,
+      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+      hash: {
+        name: "SHA-256" // 这边如果后端使用公钥加密,要注意与前端一致
+      },
+    },
+    true,
+    ["encrypt", "decrypt"] // must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
+  ).then(key => {
+    getPemText('spki', key.publicKey)
+    getPemText('pkcs8', key.privateKey)
+  })
+}
+
+
+function getPemText(type: "pkcs8" | "spki", key: CryptoKey) {
+  // 导出私钥
+  window.crypto.subtle.exportKey(type, key).then(function (res) {
+    const key = RSA2text(res, type) // 私钥pem
+    console.log(key)
+    console.log(key.length)
+  }).catch(function (err) {
+    console.error(err)
+  })
+}
+
+// pem格式文本
+function RSA2text(buffer: ArrayBuffer, type: "pkcs8" | "spki") {
+  const isPrivate = type === 'pkcs8'
+  let binary = ''
+  const bytes = new Uint8Array(buffer)
+  const len = bytes.byteLength
+  for (let i = 0; i < len; i++) {
+    binary += String.fromCharCode(bytes[i])
+  }
+  const base64 = window.btoa(binary)
+  console.log(base64)
+  console.log('\n')
+  let text = "-----BEGIN " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----\n" // 这里-----BEGIN和-----是固定的
+  text += base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n") // 中间base64编码
+  text += "\n-----END " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----" // 这里-----END和-----是固定的
+  return text
+}
+
+//#endregion

+ 9 - 149
src/utils/rsa.ts

@@ -1,155 +1,15 @@
-const PUBLIC_KEY = import.meta.env.VITE_PUBLIC_KEY
-const PRIVATE_KEY = import.meta.env.VITE_PRIVATE_KEY
-
-let publicKey: CryptoKey
-let privateKey: CryptoKey
+import jsrsasign from 'jsrsasign'
 
-async function setPublicKey() {
-  const publicKeyBuffer = pemToBuffer(PUBLIC_KEY);
-  publicKey = await window.crypto.subtle.importKey(
-    "spki", // 这边如果私钥则是pkcs8
-    publicKeyBuffer,
-    {
-      name: "RSA-OAEP",
-      hash: { name: 'SHA-256' },
-    },
-    true,
-    ["encrypt"] // 用于加密所以是公钥,私钥就是 decrypt
-  )
-  // console.log(publicKey)
-}
+const PUBLIC_KEY = import.meta.env.VITE_PUBLIC_KEY
 
-async function setPrivateKey() {
-  const privateBuffer = pemToBuffer(PRIVATE_KEY);
-  privateKey = await window.crypto.subtle.importKey(
-    "pkcs8", // 这边如果私钥则是pkcs8
-    privateBuffer,
-    {
-      name: "RSA-OAEP",
-      hash: { name: 'SHA-256' },
-    },
-    true,
-    ["decrypt"] // 用于加密所以是公钥,私钥就是 decrypt
-  )
-  // console.log(privateKey)
-}
+// 初始化RSA密钥对象
+const publicKey = jsrsasign.KEYUTIL.getKey(PUBLIC_KEY);
 
-setPublicKey()
-// setPrivateKey()
+console.log(publicKey)
 
-// setTimeout(() => {
-//   // encrypt('asdfasdf').then(res => {
-//   //   console.log(res)
-//   // })
-//   decrypt('uts03JfyTGh/l8ivwQX/n9a6UpaVpfGgLaelrPfyMMdbslJmj79UNnv30NqktM7E6LhOyp4Ebt+EoJ8ss1FPyMlKpxwPHCFIanaClyR/aTCzeQGxVH2kZKJuZu02vrX1m2qXjn0Z1aV43GV5bNB40qPHzUZsMzMBHOqCAvqYO2zZwGpmFRFRu/93CPgpxgbhsbH7dCwOqJt9I7DMx9KaiiJmnPlbDSI4HG/wP/J2L1GHnZPK9zq+ccHm7WUYeVhf2xVYvma+hSzLWSiuwT1n5vRMIUKwjlT66usKJkEVhIiLTPmR6KLqEmWN21a/p6Dus/MCkFlA5hAURBalDqlnMQ==').then(res => {
-//     console.log(res)
-//   })
-// }, 300)
 
 export function encrypt(str: string) {
-  const enc = new TextEncoder()
-  const data = enc.encode(str) // 这边将要加密的字符串转为utf-8的Uint8Array
-  return new Promise(async (resolve) => {
-    const buffer = await window.crypto.subtle.encrypt(
-      {
-        name: "RSA-OAEP"
-      },
-      publicKey, // 生成或者导入的CryptoKey对象
-      data
-    )
-    const resStr = window.btoa(String.fromCharCode(...new Uint8Array(buffer)))
-    resolve(resStr)
-  })
-}
-
-export function decrypt(base64String: string) {
-  return new Promise(async (resolve) => {
-    const buffer = await window.crypto.subtle.decrypt(
-      {
-        name: "RSA-OAEP"
-      },
-      privateKey,
-      base64ToUint8Array(base64String)
-    )
-    const resStr = new TextDecoder().decode(buffer);
-    resolve(resStr)
-  })
-}
-
-function pemToBuffer(pem: string) {
-  const lines = pem.split('\n');
-  const encoded = lines.slice(1, -1).join('');
-  const decoded = window.atob(encoded);
-  const buffer = new Uint8Array(decoded.length);
-  for (let i = 0; i < decoded.length; ++i) {
-    buffer[i] = decoded.charCodeAt(i);
-  }
-  return buffer.buffer
-}
-
-function base64ToUint8Array(base64String: string) {
-  const padding = '='.repeat((4 - base64String.length % 4) % 4)
-  const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/')
-
-  const rawData = window.atob(base64)
-  const outputArray = new Uint8Array(rawData.length)
-
-  for (let i = 0; i < rawData.length; ++i) {
-    outputArray[i] = rawData.charCodeAt(i)
-  }
-  return outputArray
-}
-
-//#region 生成公钥私钥
-
-// generateKey()
-
-function generateKey() {
-  window.crypto.subtle.generateKey(
-    {
-      name: "RSA-OAEP",
-      modulusLength: 2048,
-      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
-      hash: {
-        name: "SHA-256" // 这边如果后端使用公钥加密,要注意与前端一致
-      },
-    },
-    true,
-    ["encrypt", "decrypt"] // must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
-  ).then(key => {
-    getPemText('spki', key.publicKey)
-    getPemText('pkcs8', key.privateKey)
-  })
-}
-
-
-function getPemText(type: "pkcs8" | "spki", key: CryptoKey) {
-  // 导出私钥
-  window.crypto.subtle.exportKey(type, key).then(function (res) {
-    const key = RSA2text(res, type) // 私钥pem
-    console.log(key)
-    console.log(key.length)
-  }).catch(function (err) {
-    console.error(err)
-  })
-}
-
-// pem格式文本
-function RSA2text(buffer: ArrayBuffer, type: "pkcs8" | "spki") {
-  const isPrivate = type === 'pkcs8'
-  let binary = ''
-  const bytes = new Uint8Array(buffer)
-  const len = bytes.byteLength
-  for (let i = 0; i < len; i++) {
-    binary += String.fromCharCode(bytes[i])
-  }
-  const base64 = window.btoa(binary)
-  console.log(base64)
-  console.log('\n')
-  let text = "-----BEGIN " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----\n" // 这里-----BEGIN和-----是固定的
-  text += base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n") // 中间base64编码
-  text += "\n-----END " + (isPrivate ? "PRIVATE" : "PUBLIC") + " KEY-----" // 这里-----END和-----是固定的
-  return text
-}
-
-//#endregion
+  const encrypted = jsrsasign.KJUR.crypto.Cipher.encrypt(str, publicKey, 'RSAOAEP256');
+  const resStr = jsrsasign.hextob64(encrypted)
+  return resStr
+}

+ 5 - 5
yarn.lock

@@ -2096,11 +2096,6 @@ js-yaml@^4.1.0:
   dependencies:
     argparse "^2.0.1"
 
-jsencrypt@^3.3.2:
-  version "3.3.2"
-  resolved "https://registry.yarnpkg.com/jsencrypt/-/jsencrypt-3.3.2.tgz#b0f1a2278810c7ba1cb8957af11195354622df7c"
-  integrity sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==
-
 json-schema-traverse@^0.4.1:
   version "0.4.1"
   resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
@@ -2132,6 +2127,11 @@ jsplumb@^2.15.6:
   resolved "https://registry.npmmirror.com/jsplumb/-/jsplumb-2.15.6.tgz"
   integrity sha512-sIpbpz5eMVM+vV+MQzFCidlaa1RsknrQs6LOTKYDjYUDdTAi2AN2bFi94TxB33TifcIsRNV1jebcaxg0tCoPzg==
 
+jsrsasign@^10.8.6:
+  version "10.8.6"
+  resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-10.8.6.tgz#ebf7f3c812c6517af84f0d8a10115e0dbfabe145"
+  integrity sha512-bQmbVtsfbgaKBTWCKiDCPlUPbdlRIK/FzSwT3BzIgZl/cU6TqXu6pZJsCI/dJVrZ9Gir5GC4woqw9shH/v7MBw==
+
 kind-of@^3.0.2:
   version "3.2.2"
   resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz"