crypto加密-实战篇之对称加密

服务端生成密钥

需要主要的是 对称加密只会产出一个密钥文件,也就是加密和解密都用这个密钥,不分公钥和私钥!

// 对称加密
const genKeyPair = () => {
  // 生成的对称密钥,以 Buffer 格式表示。
  const aesKey = crypto.randomBytes(32); // 32字节 = 256位
  // 将密钥转换为十六进制字符串,便于查看和存储。
  const aesKeyHex = aesKey.toString('hex');
  fs.outputFileSync("aes-keys/aesKey.hex", aesKeyHex);
}

客户端加密数据

获取密钥

  // 从hex字符串生成AES密钥
  const genAESKeyFromHex = async (hexKeyText) => {
    // 将hex字符串转换为ArrayBuffer
    const keyBuffer = new Uint8Array(
      hexKeyText.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
    );

    // 导入AES密钥
    return await crypto.subtle.importKey(
      "raw",
      keyBuffer,
      {
        name: "AES-GCM",
      },
      false,
      ["encrypt", "decrypt"]
    );
  };

// 封装一个通用方法,加载文件
const loadFile = (filePath) => {
  const response = fetch(filePath).then((res) => res.text());
  return response;
};

const hexKeyStr = await loadFile("./aes-keys/aesKey.hex");
const aesKey = await genAESKeyFromHex(hexKeyStr);

加密数据

// 使用AES密钥加密
const encrypt = async (data, aesKey) => {
  // 将内容字符串转换为ArrayBuffer
  const encoder = new TextEncoder();
  const dataBuffer = encoder.encode(data);

  // 生成随机IV(初始化向量)
  const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM推荐12字节IV

  // 加密
  const encrypted = await crypto.subtle.encrypt(
    {
      name: "AES-GCM",
      iv: iv,
    },
    aesKey,
    dataBuffer
  );

  // 将IV和加密数据合并,然后转换为Base64
  const encryptedArray = new Uint8Array(encrypted);
  const combined = new Uint8Array(iv.length + encryptedArray.length);
  combined.set(iv);
  combined.set(encryptedArray, iv.length);

  const base64String = btoa(String.fromCharCode(...combined));
  return base64String;
};

看看效果

 <input type="text" />
    <button>加密数据</button>

    <div class="encrypted-data">
      <p>加密后的数据:</p>
      <p class="encrypted-data-content" style="word-break: break-all"></p>
    </div>

    <script>
      // ...省略上诉代码

      const input = document.querySelector("input");
      const button = document.querySelector("button");
      const encryptedDataContent = document.querySelector(
        ".encrypted-data-content"
      );

      button.addEventListener("click", async () => {
        // 从文件加载hex密钥(假设密钥文件包含hex字符串)
        const hexKeyStr = await loadFile("./key-pair/aes-key.hex");
        const hexKey = hexKeyStr.trim(); // 移除可能的换行符

        const aesKey = await genAESKeyFromHex(hexKey);
        const content = input.value;
        const encryptedData = await encrypt(content, aesKey);
        encryptedDataContent.innerText = encryptedData;
      });
    </script>

400

服务端解密

// 使用AES密钥解密(对称加密)
export const decrypt = (encryptedData: string) => {
  // 读取hex格式的AES密钥
  const aesKeyHex = fs.readFileSync("aes-keys/aesKey.hex", "utf8").trim();
  const aesKey = Buffer.from(aesKeyHex, 'hex');

  // 将Base64编码的加密数据转换为Buffer
  const encryptedBuffer = Buffer.from(encryptedData, 'base64');

  // AES-GCM格式:IV(12字节) + 密文 + 认证标签(16字节)
  const iv = encryptedBuffer.subarray(0, 12);
  const authTag = encryptedBuffer.subarray(-16); // authTag由crypto.subtle.encrypt方法生成,并且包含在加密后的数据中。
  const cipherText = encryptedBuffer.subarray(12, -16);

  // 创建解密器
  const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, iv);
  decipher.setAuthTag(authTag);

  // 解密数据
  let decrypted = decipher.update(cipherText, undefined, 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
};


const content = "AzULO8EToCvznlMt0qndPsoMZc2DOqQi/DBwU7odng==";
console.log(decrypt(content));

image

posted @ 2025-08-25 14:29  丁少华  阅读(29)  评论(0)    收藏  举报