React + Express 传输加密以及不可逆加密

发布于:2025-07-09 ⋅ 阅读:(13) ⋅ 点赞:(0)

一、传输加密

这里用 对称加密模式 ASE实现。

React 前端


const CryptoJS = require("crypto-js");

// 示例1:ECB模式(无需IV)
const encryptECB = (plainText, key) => {
  return CryptoJS.AES.encrypt(plainText, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  }).toString();
};

const decryptECB = (cipherText, key) => {
  const bytes = CryptoJS.AES.decrypt(cipherText, key, {
    mode: CryptoJS.mode.ECB
  });
  return bytes.toString(CryptoJS.enc.Utf8);
};

// 示例2:CBC模式(需要IV)
const encryptCBC = (plainText, key, iv) => {
  return CryptoJS.AES.encrypt(plainText, key, {
    iv: CryptoJS.enc.Utf8.parse(iv),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  }).toString();
};

const decryptCBC = (cipherText, key, iv) => {
  const bytes = CryptoJS.AES.decrypt(cipherText, key, {
    iv: CryptoJS.enc.Utf8.parse(iv)
  });
  return bytes.toString(CryptoJS.enc.Utf8);
};

// 测试用例
const key = "my-secret-key-123"; // 16/24/32字节
const iv = "1234567890123456";   // 16字节
const text = "Hello AES!";

// ECB模式
const ecbEncrypted = encryptECB(text, key);
console.log("ECB加密结果:", ecbEncrypted);
console.log("ECB解密结果:", decryptECB(ecbEncrypted, key));

// CBC模式
const cbcEncrypted = encryptCBC(text, key, iv);
console.log("CBC加密结果:", cbcEncrypted);
console.log("CBC解密结果:", decryptCBC(cbcEncrypted, key, iv));

Express 中间件

解密中间件封装

创建 AES_decrypt.js 中间件文件,处理请求体的加密数据:

const { AES_decrypt } = require('../utils/AES');
const decryptMiddleware = (req, res, next) => {
  if (req.body?.content && req.body?.iv) {
    try {
      const decrypted = AES_decrypt(req.body.content, req.body.iv);
      req.decryptedData = JSON.parse(decrypted); // 存储解密结果到请求对象
      next();
    } catch (err) {
      res.status(400).json({ error: "解密失败" });
    }
  } else {
    next(); // 非加密请求跳过
  }
};
module.exports = decryptMiddleware;

引用自实际中间件解密实现‌

在 utils/AES.js 中定义解密函数,需与前端 CryptoJS 的 CBC 模式配置一致:

const crypto = require('crypto');
const secretKey = '1234567890123456'; // 16字节密钥

function AES_decrypt(encryptedText, ivHex) {
  const decipher = crypto.createDecipheriv(
    'aes-128-cbc',
    Buffer.from(secretKey),
    Buffer.from(ivHex, 'hex')
  );
  let decrypted = decipher.update(encryptedText, 'base64', 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
}
module.exports = { AES_decrypt };

下面是ECB(无vi模式)


const crypto = require('crypto');
const secretKey = process.env.AES_KEY || 'default16byteskey!'; // 16字节密钥

module.exports = (req, res, next) => {
  if (req.body?.encryptedData) {
    try {
      const decipher = crypto.createDecipheriv(
        'aes-128-ecb', 
        Buffer.from(secretKey),
        null // ECB模式无需IV
      );
      let decrypted = decipher.update(req.body.encryptedData, 'base64', 'utf8');
      decrypted += decipher.final('utf8');
      req.decryptedBody = JSON.parse(decrypted);
      next();
    } catch (err) {
      res.status(400).json({ error: "ECB解密失败", details: err.message });
    }
  } else {
    next(); // 非加密请求跳过
  }
};

二、不可逆加密

这里用bcryptjs实现

import bcrypt from 'bcryptjs';

/**
 * 加密(不可逆转加密)
 * @param rawData 
 */
export const getHashedData = (rawData: string): string => {
    const salt = bcrypt.genSaltSync(10); // 成本因子推荐10-12
    const hashedData = bcrypt.hashSync(rawData, salt); 
    return hashedData;
}

/**
 * 匹配不可逆转加密方式生成的数据
 * @param rawData 
 * @param hashedData 
 * @returns 
 */
export const matchHashDataAndRawData = (rawData: string, hashedData: string): boolean => {
   return bcrypt.compareSync(rawData, hashedData);
} 

调用

加密

 const hashedPassword = getHashedData(password);

比对数据 

matchHashDataAndRawData(newPassword, password);


网站公告

今日签到

点亮在社区的每一天
去签到