Kaynağa Gözat

feat: 增加oaep的加密验证

yanglzh 1 yıl önce
ebeveyn
işleme
4051b31085

+ 1 - 1
.env

@@ -28,4 +28,4 @@ VITE_MODBUS_API = '/base-api/modbus'
 VITE_ICE104_API = '/base-api/ice104'
 
 # 加密公钥, 用双引号,换行符用 \n
-VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBCgKCAQEA2GHtfmjFVCi5pcjsv6ppyeEmESN4FpID8WHLtvXXRm3wexonVmhO\n2GUEl/T8PonnYYuUHARFVBmTEF0SvFUwfTab88HznL8KDW8yPDEz8E8daV59BzAx\nVWP389PUxv0AAwLWNa5dy5cIG4eKvrgRjHtMn/c12Ba5R6OfvWX/lX9YkOIDfeca\n2X1eOhgtfqVr4iG6R4UHAf0NzKleNvPbwQjXUN/wMFIF7bNmYebn5kSBDkFb2DLP\npEb8iQ6CQzQM/Z6HVGM2XokJ2oPhvUFpI7BVQce0gIg7rq00Dexz7IJxCU/khkFY\nR6fjPEkL0hoaae2MXtv22gJPwOhlh7kFhQIDAQAB\n-----END PUBLIC KEY-----"
+VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwrJzCAJ0aart82Y2B5qo\nsZRv8p1dGX2oLFr1sArJxevW3a1v7cVA0U4WVFJdifDVFpsuich9nsfhUp7CNOZn\na+rNveglzYlrtMhqynYU+bKUBBAmYaVyDHOpxkp86fhp0q7qoX8YoeSvYRaVaPoF\nHRYeahy0d3L+gL8pRhr0k70RZMraC3zzXbuUcM7GNibiKbFiQllhlGlfbV0bmOH8\nLZcwWwv40Ptdd4x2gihn5vmzGdQ1OAf3D6YmtsXf7iMj0H1g5svyHs17ncSN7h9i\nWTrVKcNDxrl1dm4BRsxDJsWenwrIM1WUHuonlbE6OoIJEO25T3ucymzWDzMSWxe3\nsQIDAQAB\n-----END PUBLIC KEY-----"

+ 3 - 9
.env.development

@@ -1,17 +1,11 @@
 # VITE_SERVER_PROTOCOL = 'http:'
 # VITE_SERVER_HOSTNAME = '127.0.0.1:8200'
+
 VITE_SERVER_PROTOCOL = 'https:'
 VITE_SERVER_HOSTNAME = 'zhgy.sagoo.cn'
 
 # VITE_SERVER_PROTOCOL = 'http:'
-# VITE_SERVER_HOSTNAME = 'iot.server.mydig.net'
-
+# VITE_SERVER_HOSTNAME = 'wg.server.mydig.net'
 
 # VITE_SERVER_PROTOCOL = 'http:'
-# VITE_SERVER_HOSTNAME = 'liangzi.server.mydig.net'
-
-# VITE_SERVER_PROTOCOL = 'http:'
-# VITE_SERVER_HOSTNAME = 'pg.server.mydig.net'
-
-# 加密公钥, 用双引号,换行符用 \n
-VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBCgKCAQEA2GHtfmjFVCi5pcjsv6ppyeEmESN4FpID8WHLtvXXRm3wexonVmhO\n2GUEl/T8PonnYYuUHARFVBmTEF0SvFUwfTab88HznL8KDW8yPDEz8E8daV59BzAx\nVWP389PUxv0AAwLWNa5dy5cIG4eKvrgRjHtMn/c12Ba5R6OfvWX/lX9YkOIDfeca\n2X1eOhgtfqVr4iG6R4UHAf0NzKleNvPbwQjXUN/wMFIF7bNmYebn5kSBDkFb2DLP\npEb8iQ6CQzQM/Z6HVGM2XokJ2oPhvUFpI7BVQce0gIg7rq00Dexz7IJxCU/khkFY\nR6fjPEkL0hoaae2MXtv22gJPwOhlh7kFhQIDAQAB\n-----END PUBLIC KEY-----"
+# VITE_SERVER_HOSTNAME = 'pg.server.mydig.net'

+ 1 - 5
.env.open

@@ -1,8 +1,4 @@
 VITE_SERVER_PROTOCOL = ''
 VITE_SERVER_HOSTNAME = ''
 # 开源标识
-VITE_ISOPEN = true
-
-# 加密公钥, 用双引号,换行符用 \n
-
-VITE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBCgKCAQEA2GHtfmjFVCi5pcjsv6ppyeEmESN4FpID8WHLtvXXRm3wexonVmhO\n2GUEl/T8PonnYYuUHARFVBmTEF0SvFUwfTab88HznL8KDW8yPDEz8E8daV59BzAx\nVWP389PUxv0AAwLWNa5dy5cIG4eKvrgRjHtMn/c12Ba5R6OfvWX/lX9YkOIDfeca\n2X1eOhgtfqVr4iG6R4UHAf0NzKleNvPbwQjXUN/wMFIF7bNmYebn5kSBDkFb2DLP\npEb8iQ6CQzQM/Z6HVGM2XokJ2oPhvUFpI7BVQce0gIg7rq00Dexz7IJxCU/khkFY\nR6fjPEkL0hoaae2MXtv22gJPwOhlh7kFhQIDAQAB\n-----END PUBLIC KEY-----"
+VITE_ISOPEN = true

+ 146 - 115
src/utils/rsa.ts

@@ -1,124 +1,155 @@
-import JSEncrypt from 'jsencrypt'
-
-export function encrypt(value: string) {
-  const crypt = new JSEncrypt();
-  crypt.setPublicKey(import.meta.env.VITE_PUBLIC_KEY);
-  return crypt.encrypt(value)
+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)
 }
 
-export function decrypt(value: string) {
-  const crypt = new JSEncrypt();
-  crypt.setPrivateKey(import.meta.env.VITE_PRIVATE_KEY);
-  return crypt.decrypt(value)
+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)
 }
 
-
-// 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()
+setPublicKey()
 // setPrivateKey()
 
-// 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
-// }
-
-// export function encrypt(str: string) {
-//   return str
-// }
-
-
-
-// //#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)
+// 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 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
+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

+ 3 - 2
src/views/login/component/account.vue

@@ -114,13 +114,14 @@ export default defineComponent({
 		const onSignIn = () => {
 			// 验证表单
 			proxy.$refs.loginForm
-				.validate((valid: boolean) => {
+				.validate(async (valid: boolean) => {
 					if (valid) {
 						state.loading.signIn = true;
+						const password = await encrypt(state.ruleForm.password)
 						api.login
 							.login({
 								...state.ruleForm,
-								password: encrypt(state.ruleForm.password)
+								password
 							})
 							.then(async (res: any) => {
 								// 检查是否需要更换密码

+ 5 - 2
src/views/login/component/changePwd.vue

@@ -52,10 +52,13 @@ const formRules = computed(() => ({
 async function onSubmit() {
 	await formRef.value.validate()
 
+	const oldUserPassword = await encrypt(ruleForm.oldUserPassword)
+	const userPassword = await encrypt(ruleForm.userPassword)
+
 	api.login.editPassword({
 		userName: ruleForm.userName,
-		oldUserPassword: encrypt(ruleForm.oldUserPassword),
-		userPassword: encrypt(ruleForm.userPassword)
+		oldUserPassword,
+		userPassword,
 	}).then(() => {
 		show.value = false
 		ElMessage.success('修改成功')