vue+koa中使用aes和rsa混合加密

31 篇文章 4 订阅

首先需要了解以下内容:

Vue中使用crypto-js进行AES对称加密:https://blog.csdn.net/qq_40323256/article/details/123688626

Vue中使用jsencrypt进行RSA非对称加密:https://blog.csdn.net/qq_40323256/article/details/124006449 

生成RSA密钥对在线工具:http://web.chacuo.net/netrsakeypair

RSA公钥加密解密:http://tool.chacuo.net/cryptrsapubkey

AES加密解密:http://tool.chacuo.net/cryptaes 

混合加密流程:

  1. 前端每次请求都要随机生成一个秘钥字符串key_aes(秘钥字符串length推荐为16,可大小写+数字)。然后AES用这个秘钥key_aes加密明文data。
  2. 请求服务端获取公钥的接口,获取服务端通过RSA生成的公钥。(服务端只需要生成一次公钥和私钥,然后持久保存在服务端即可,不用每次都生成,否则多了难以维护)
  3. 前端使用获取到的公钥通过RSA对key_aes进行非对称加密。
  4. 前端将对称加密后的data和非对称加密后的秘钥key_aes传输到服务端
  5. 服务端用刚刚通过RSA生成的私钥解密key_aes,获取解密后的key_aes。再用解密后的key_aes通过AES解密data,获取data明文
  6. 经过一轮以上步骤,此时前后端都保存有相同的秘钥key_aes。服务端给前端响应数据时,就可用该秘钥AES加密响应的数据,前端AES解密数据即可。

整个过程,需要服务端提供2个接口,一个是获取公钥的接口,一个是传送数据的接口 (包括对称加密的明文data数据和非对称加密的aes秘钥)

随机生成aes密钥:

密钥字符串的length最好为16。当然也可以为32,但是在工作中发现用32的话,后端可能会因为密钥长度相对较长而导致密钥被截断一部分,因此选择用16

    //生成指定长度随机字符串
    generateRandomStr(strLength = 16) {
      let code = '';
      const chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
      const charsArr = chars.split('');
 
      for (let i = 0; i < strLength; i++) {
        const num = Math.floor(Math.random() * charsArr.length);
        code += charsArr[num];
      }
      return code;
    }

 客户端:

<!--main-->
<template>
  <div>
    <el-button @click="test()">test</el-button>
  </div>
</template>
<script>
import { JSEncrypt } from "jsencrypt";
import CryptoJS from "crypto-js";
import axios from "axios";
export default {
  methods: {
    async test() {
      //待加密传输的data数据
      const data = {
        username: "李疆",
        password: 123,
      };
      console.log("aes加密前的data数据:", data);

      //aes密钥
      let key_aes = "385f33cb91484b04a177828829081ab7";
      console.log("aes密钥:", key_aes);

      //aes加密data数据
      const data_encrypted_by_aes = CryptoJS.AES.encrypt(
        JSON.stringify(data),
        CryptoJS.enc.Utf8.parse(key_aes),
        {
          mode: CryptoJS.mode.ECB,
          padding: CryptoJS.pad.Pkcs7,
        }
      ).ciphertext.toString();
      console.log("aes加密后的data数据:", data_encrypted_by_aes);

      //从服务端获取公钥
      let { data: publicKey } = await axios.get("/api/test/publicKey");
      console.log("从服务端获取的rsa公钥:", publicKey);

      //rsa公钥加密aes密钥
      let encryptor = new JSEncrypt();
      encryptor.setPublicKey(publicKey);
      let aeskey_encrypted_by_rsa = encryptor.encrypt(key_aes);
      console.log("被rsa公钥加密后的aes密钥:", aeskey_encrypted_by_rsa);

      //发送aes加密后的data数据和被rsa公钥加密的aes密钥到服务端
      let result = await axios.post("/api/test/decryption", {
        data_encrypted_by_aes,
        aeskey_encrypted_by_rsa,
      });
      console.log("result:", result);
    },
  },
};
</script>

服务端:

const router = require('koa-router')()
const CryptoJS = require("crypto-js");
const NodeRSA = require('node-rsa');

router.prefix('/test')

router.get('/', (ctx, next) => {
    ctx.body = 'this is a users response!'
})

const key_rsa = new NodeRSA({ b: 1024 });//密钥长度1024位
key_rsa.setOptions({ encryptionScheme: 'pkcs1' });//指定加密格式.不改格式得话可能会报错
router.get('/publicKey', async (ctx, next) => {
    let publicKey = key_rsa.exportKey('public');//生成公钥
    // let privateKey = key_rsa.exportKey('private');//生成私钥
    ctx.body = publicKey;
});
router.post('/decryption', async (ctx, next) => {
    let { data_encrypted_by_aes, aeskey_encrypted_by_rsa, } = ctx.request.body;

    console.log("aes加密后的data数据:", data_encrypted_by_aes)
    console.log("被rsa公钥加密的aes密钥:", aeskey_encrypted_by_rsa)

    //rsa私钥解密出aes密钥
    const aeskey_decrypted_by_rsa = key_rsa.decrypt(aeskey_encrypted_by_rsa, 'utf8');
    console.log('被rsa私钥解密出的aes密钥: ', aeskey_decrypted_by_rsa);

    // aes密钥解密出data数据
    let data_decrypted_by_aes = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
        CryptoJS.format.Hex.parse(data_encrypted_by_aes),
        CryptoJS.enc.Utf8.parse(aeskey_decrypted_by_rsa),
        {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        }
    )))
    console.log('被aes密钥解密出的data数据:', data_decrypted_by_aes);

    ctx.body = { message: "success" };

});

module.exports = router

结果:

上面的公钥和私钥是通过node-rsa生成的,如果想自己手动指定公钥和私钥,可通过如下方式:(客户端代码不变,只需要改服务端代码)

const router = require('koa-router')()
const CryptoJS = require("crypto-js");
const NodeRSA = require('node-rsa');

router.prefix('/test')

router.get('/', (ctx, next) => {
    ctx.body = 'this is a users response!'
})

router.get('/publicKey', async (ctx, next) => {
    let publicKey = `-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDARcNxlvPXZQSup9yPV6iVzqMI
    eBr2Rztd4zxYUCwL2pqaig3ZP17eFpzfiI+aBf2F4qp/QHPMVnEQmx33/fGlssvc
    cqplP7gvk7BKporUWtnyqYKqy/fAE07c/Yxpe5WZoMo2pRyaBDMLMZ49MpfAzHXS
    pTzUY9W4F49C0Y8SPQIDAQAB
    -----END PUBLIC KEY-----`
    ctx.body = publicKey;
});
router.post('/decryption', async (ctx, next) => {
    let { data_encrypted_by_aes, aeskey_encrypted_by_rsa, } = ctx.request.body;

    console.log("aes加密后的data数据:", data_encrypted_by_aes)
    console.log("被rsa公钥加密的aes密钥:", aeskey_encrypted_by_rsa)

    let privateKey = `-----BEGIN PRIVATE KEY-----
    MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMBFw3GW89dlBK6n
    3I9XqJXOowh4GvZHO13jPFhQLAvampqKDdk/Xt4WnN+Ij5oF/YXiqn9Ac8xWcRCb
    Hff98aWyy9xyqmU/uC+TsEqmitRa2fKpgqrL98ATTtz9jGl7lZmgyjalHJoEMwsx
    nj0yl8DMddKlPNRj1bgXj0LRjxI9AgMBAAECgYEAsjd34y+yMTKXVnSNQehUgRcZ
    kt4Qz7pS0sGvy4P0b8BekWPpVjcg7eYz3hYsVO28gn8I3g6Vxw9Qmb3N13HwqrPt
    1z6pGkr54FtgsxPDaS0Cu86gt9G+MfAHMbYHtCd3VEhfXmj17/NeV/nFUG0mlgGZ
    bZY0wLlDNYX6t+clYQECQQDphC6/5xhdWr1yelNO5fybt/1p9Cp5q3nRR1NjEwCY
    77WE1VMwbdSYkj9whSL9EcnEGFL6/PgcWjkXuY4Jpg9hAkEA0sj79IVYt7L0xnTO
    tNg6RBoF9vnt9T0HUAqU0Q9YHbV+SzEMUOKepMW5XwSlPomeOpOQEYot7SmXuUL5
    aBj8XQJBAKNj+dIMwN+RPj17mg76nWXXt1kLnyzC7tmgLpiEE0bvcvMe0LZyIu8e
    ZYU1ouWwLJ0o5+b2WiR8fLY8/0WBDAECQQCa7mXbfiQOqjgmovbIkGKLagFWXrBc
    YKY+W/i0ja278IpK5FtkHJ51CGxPfg+jnu2xqoLrkYBeYQMHhkXiEPN1AkEAmjlL
    3AWqcl6I0vsvt1cK4XiQmez8L6JomMddjF9vi96mNy8Be8+7OCxWv+aZ2P8AhZKD
    WrHvhaHSs389XzS3HQ==
    -----END PRIVATE KEY-----
    `
    const key_rsa = new NodeRSA(privateKey);
    key_rsa.setOptions({ encryptionScheme: 'pkcs1' }); // 因为jsencrypt自身使用的是pkcs1加密方案, nodejs需要修改成pkcs1。
    const aeskey_decrypted_by_rsa = key_rsa.decrypt(aeskey_encrypted_by_rsa, 'utf8');
    console.log('被rsa私钥解密出的aes密钥: ', aeskey_decrypted_by_rsa);

    let data_decrypted_by_aes = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
        CryptoJS.format.Hex.parse(data_encrypted_by_aes),
        CryptoJS.enc.Utf8.parse(aeskey_decrypted_by_rsa),
        {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        }
    )))
    console.log('被aes密钥解密出的data数据:', data_decrypted_by_aes);

    ctx.body = { message: "success" };
});

module.exports = router

注意:我尝试过代码中不直接展示公钥和私钥,而是通过fs.readFile()的方式读取本地的公钥和私钥文件,虽然可以读取,但是最后加密解密失败。

把公钥私钥文件放到public/files文件夹中,这样读取路径是可以的:fs.readFile('public/files/xxx.txt',(err,data)=>{})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现最简单的注册登录功能,可以借助VueKoa2进行开发。 首先,在Vue创建两个页面组件,一个是注册页面,一个是登录页面。注册页面通过表单收集用户的注册信息,包括用户名和密码,并发送POST请求给后端。登录页面同理,收集用户的登录信息,并发送POST请求给后端。 在Koa2,需要使用koa-router间件来处理路由,监听前端发送的注册和登录请求。对于注册请求,需要将用户提供的用户名和密码存储到数据库。对于登录请求,需要从数据库查询用户提供的用户名和密码是否匹配。 数据库可以选择使用MySQL、MongoDB等,具体可以根据实际需求选择。在Koa2可以使用相应的数据库连接库进行连接和操作。 在注册和登录过程,需要对用户的密码进行加密存储,可以使用bcyrpt等密码加密库进行加密。 另外,为了实现用户登录状态的保持,可以使用session或者token进行用户身份验证。当用户注册或登录成功后,将相应的用户信息存储到session或者token。在后续用户的请求,通过校验session或者token来验证用户的身份和权限。 当用户注册或登录成功后,可以在前端页面进行相应的提示或跳转,同时可以通过路由守卫等方式限制未登录用户的访问权限。 总的来说,VueKoa2可以很好地配合实现最简单的注册登录功能。具体实现过程可以根据项目需求和技术栈的选择进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值