Js RSA非对称加密

复制代码
    // RSA 加密
    async function encryptData(publicKeyStr, data) {
      const publicKey = await importPublicKey(publicKeyStr);
      const encoder = new TextEncoder();
      const encrypted = await window.crypto.subtle.encrypt(
        {
          name: "RSA-OAEP"
        },
        publicKey,
        encoder.encode(data)
      );
      return arrayBufferToBase64(encrypted);
    }

    // RSA 解密
    async function decryptData(privateKeyStr, encryptedData) {
      const privateKey = await importPrivateKey(privateKeyStr);
      const encryptedBuffer = base64ToArrayBuffer(encryptedData);
      const decrypted = await window.crypto.subtle.decrypt(
        {
          name: "RSA-OAEP"
        },
        privateKey,
        encryptedBuffer
      );
      const decoder = new TextDecoder();
      return decoder.decode(decrypted);
    }

    // 导入公钥根据公钥字符串
    async function importPublicKey(pemString) {
      const keyData = pemToArrayBuffer(pemString);

      const publicKey = await window.crypto.subtle.importKey(
        "spki",
        keyData,
        {
          name: "RSA-OAEP",
          hash: "SHA-256"
        },
        true, // extractable
        ["encrypt"]
      );

      return publicKey;
    }

    // 导入私钥根据私钥字符串
    async function importPrivateKey(pemString) {
      const keyData = pemToArrayBuffer(pemString);

      const privateKey = await window.crypto.subtle.importKey(
        "pkcs8",
        keyData,
        {
          name: "RSA-OAEP",
          hash: "SHA-256"
        },
        true, // extractable
        ["decrypt"]
      );

      return privateKey;
    }

    // PEM 转 ArrayBuffer(清理 PEM 头尾并解码 Base64)
    function pemToArrayBuffer(pem) {
      const PEM_REGEX = /-----BEGIN [A-Z0-9 ]+KEY-----([^-]+)-----END [A-Z0-9 ]+KEY-----/g;
      const base64Der = pem.replace(PEM_REGEX, '$1').replace(/\s/g, '');
      const binaryString = atob(base64Der);
      const len = binaryString.length;
      const bytes = new Uint8Array(len);
      for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
      }
      return bytes.buffer;
    }

    // 格式化 PEM 字符串为每行指定长度
    function formatPEM(str, chunkSize = 64) {
      return str.match(new RegExp('.{1,' + chunkSize + '}', 'g')).join('\n');
    }

    // 将 ArrayBuffer 转换为 Base64 字符串
    function arrayBufferToBase64(buffer) {
      let binary = '';
      const bytes = new Uint8Array(buffer);
      for (let i = 0; i < bytes.byteLength; i++) {
        binary += String.fromCharCode(bytes[i]);
      }
      return window.btoa(binary);
    }

    // 将 Base64 字符串转换为 ArrayBuffer
    function base64ToArrayBuffer(base64) {
      const binaryString = window.atob(base64);
      const len = binaryString.length;
      const bytes = new Uint8Array(len);
      for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
      }
      return bytes.buffer;
    }

    console.log("😊😊😊 RSA Begin");
    const keyPair = await generateRsaKeyPair();
    console.log("GenerateRsaKey:", keyPair);
    const publicKeyStr = await exportPublicKey(keyPair.publicKey);
    const privateKeyStr = await exportPrivateKey(keyPair.privateKey);
    console.log("PrivateKeyStr:", privateKeyStr);
    console.log("PublicKeyStr:", publicKeyStr);

    const testData = "Hello, World!";
    console.log("Test Data:", testData);
    const encryptStr = await encryptData(publicKeyStr, testData);
    console.log("EncryptStr:", encryptStr);
    const decryptStr = await decryptData(privateKeyStr, encryptStr);
    console.log("DecryptStr:", decryptStr);
    console.log("😊😊😊 RSA End");

注意

Node.js 不支持 window.crypto,因为 window 对象是浏览器环境特有的,代表了浏览器中的全局对象,而 Node.js 运行在一个独立的环境中,没有浏览器相关的全局对象如 window。

如果你希望在 Node.js 中使用类似于浏览器环境中 window.crypto 提供的功能(例如加密操作),你可以利用 Node.js 自带的 crypto 模块来实现。或者使用其他的三方组件库,如"webcrypto"等