【问题标题】:JS SubtleCrypto RSA Encrypt and DecryptJS SubtleCrypto RSA 加密和解密
【发布时间】:2021-08-17 06:34:49
【问题描述】:

所以我正在尝试实现一些方法来加密然后解密一些数据。我没有这方面的任何经验,我尝试在网上关注一些关于如何解决这个问题的帖子。

当我将加密的“你好”传递给解密函数时,我得到了这个:

let a = importPublicKeyAndEncrypt('hello')

CryptoKey {type: "public", extractable: true, algorithm: {…}, usages: Array(1)} W29iamVjdCBBcnJheUJ1ZmZlcl0=

importPrivateKeyAndDecrypt(a)
Promise {<pending>}

DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
at importPrivateKeyAndDecrypt (<anonymous>:26:60)

当我使用我看到的 PKCS#8 帖子中的加密消息时,解密功能可以正常工作,但当我生成自己的密钥时却不能。

这里是代码 我做错了什么?

// PEM encoded X.509 key
const publicKey = `
-----BEGIN PUBLIC KEY-----
    <removed for space>
-----END PUBLIC KEY-----`;

// PEM encoded PKCS#8 key
const privateKey = `
-----BEGIN PRIVATE KEY-----
    <removed for space>
-----END PRIVATE KEY-----`;

async function importPublicKeyAndEncrypt(str) {
  try {
    const pub = await importPublicKey(publicKey);
    console.log(pub);
    const encrypted = await encryptRSA(pub, new TextEncoder().encode(str));
    const encryptedBase64 = window.btoa(ab2str(encrypted));
    console.log(encryptedBase64.replace(/(.{64})/g, '$1\n'));
  } catch (error) {
    console.log(error);
  }
}

async function importPrivateKeyAndDecrypt(str) {
  try {
    const priv = await importPrivateKey(privateKey);
    const decrypted = await decryptRSA(priv, str2ab(window.atob(str)));
    console.log(decrypted);
  } catch (error) {
    console.log(error);
  }
}

async function importPublicKey(spkiPem) {
  return await window.crypto.subtle.importKey(
    'spki',
    getSpkiDer(spkiPem),
    {
      name: 'RSA-OAEP',
      hash: 'SHA-256',
    },
    true,
    ['encrypt']
  );
}

async function importPrivateKey(pkcs8Pem) {
  return await window.crypto.subtle.importKey(
    'pkcs8',
    getPkcs8DerDecode(pkcs8Pem),
    {
      name: 'RSA-OAEP',
      hash: 'SHA-256',
    },
    true,
    ['decrypt']
  );
}

async function encryptRSA(key, plaintext) {
  let encrypted = await window.crypto.subtle.encrypt(
    {
      name: 'RSA-OAEP',
    },
    key,
    plaintext
  );
  return encrypted;
}

async function decryptRSA(key, ciphertext) {
  let decrypted = await window.crypto.subtle.decrypt(
    {
      name: 'RSA-OAEP',
    },
    key,
    ciphertext
  );
  return new TextDecoder().decode(decrypted);
}

function getSpkiDer(spkiPem) {
  const pemHeader = '-----BEGIN PUBLIC KEY-----';
  const pemFooter = '-----END PUBLIC KEY-----';
  var pemContents = spkiPem.substring(
    pemHeader.length,
    spkiPem.length - pemFooter.length
  );
  var binaryDerString = window.atob(pemContents);
  return str2ab(binaryDerString);
}

function getPkcs8DerDecode(pkcs8Pem) {
  const pemHeader = '-----BEGIN PRIVATE KEY-----';
  const pemFooter = '-----END PRIVATE KEY-----';
  var pemContents = pkcs8Pem.substring(
    pemHeader.length,
    pkcs8Pem.length - pemFooter.length
  );
  var binaryDerString = window.atob(pemContents);
  return str2ab(binaryDerString);
}

function str2ab(str) {
  const buf = new ArrayBuffer(str.length);
  const bufView = new Uint8Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

function ab2str(buf) {
  return String.fromCharCode.apply(null, new Uint8Array(buf));
}

【问题讨论】:

    标签: javascript encryption rsa cryptojs subtlecrypto


    【解决方案1】:

    只有两个小缺陷。

    首先,importPublicKeyAndEncrypt()importPrivateKeyAndDecrypt() 中缺少 return 语句(尽管后者对于当前代码 sn-p 不是必需的)。

    另外,需要等待importPublicKeyAndEncrypt()的promise才能调用importPrivateKeyAndDecrypt()

    通过这些修复,代码可以正常工作:

    // PEM encoded X.509 key
    const publicKey = `-----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT
    5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E
    bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw
    KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x
    H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4
    OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i
    GwIDAQAB
    -----END PUBLIC KEY-----`;
    
    // PEM encoded PKCS#8 key
    const privateKey = `-----BEGIN PRIVATE KEY-----
    MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6cXloNrocJ8sw
    wj8xktPmEOTfTgJT7KkUwWIGOjBB1QxApgdn5+SUHsakvEJq3Fgn+FnuuN8cfcqW
    rbT9jURtgNGinJNJ+StPM/PCxfhSv+XbkK11CV2EcJMyDB/8S/9u4E2ht/N1kT4O
    F2/mVDAq2MjjeUMq8CLmQR63ZMXB8lwmsGJEl4Rwt9WBZNcZFCfuCeBYrKRS7mtL
    zd4BTXEf0UuiNB/KJrz38TKSI47v/dRbB34wBNn0cuNLHb8t/eDaOvzV6J8SZgOW
    uL85mng6Fm77QGjUteWgJN76+YhDZgJfsRq1Q67JAy3ZXDHi5X538DcM/o+0wYEq
    kXxK3iIbAgMBAAECggEASlJj0ExIomKmmBhG8q8SM1s2sWG6gdQMjs6MEeluRT/1
    c2v79cq2Dum5y/+UBl8x8TUKPKSLpCLs+GXkiVKgHXrFlqoN+OYQArG2EUWzuODw
    czdYPhhupBXwR3oX4g41k/BsYfQfZBVzBFEJdWrIDLyAUFWNlfdGIj2BTiAoySfy
    qmamvmW8bsvc8coiGlZ28UC85/Xqx9wOzjeGoRkCH7PcTMlc9F7SxSthwX/k1VBX
    mNOHa+HzGOgO/W3k1LDqJbq2wKjZTW3iVEg2VodjxgBLMm0MueSGoI6IuaZSPMyF
    EM3gGvC2+cDBI2SL/amhiTUa/VDlTVw/IKbSuar9uQKBgQDd76M0Po5Lqh8ZhQ3o
    bhFqkfO5EBXy7HUL15cw51kVtwF6Gf/J2HNHjwsg9Nb0eJETTS6bbuVd9bn884Jo
    RS986nVTFNZ4dnjEgKjjQ8GjfzdkpbUxsRLWiIxuOQSpIUZGdMi2ctTTtspvMsDs
    jRRYdYIQCe/SDsdHGT3vcUCybwKBgQDXDz6iVnY84Fh5iDDVrQOR4lYoxCL/ikCD
    JjC6y1mjR0eVFdBPQ4j1dDSPU9lahBLby0VyagQCDp/kxQOl0z2zBLRI4I8jUtz9
    /9KW6ze7U7dQJ7OTfumd5I97OyQOG9XZwKUkRgfyb/PAMBSUSLgosi38f+OC3IN3
    qlvHFzvxFQKBgQCITpUDEmSczih5qQGIvolN1cRF5j5Ey7t7gXbnXz+Umah7kJpM
    IvdyfMVOAXJABgi8PQwiBLM0ySXo2LpARjXLV8ilNUggBktYDNktc8DrJMgltaya
    j3HNd2IglD5rjfc2cKWRgOd7/GlKcHaTEnbreYhfR2sWrWLxJOyoMfuVWwKBgFal
    CbMV6qU0LfEo8aPlBN8ttVDPVNpntP4h0NgxPXgPK8Pg+gA1UWSy4MouGg/hzkdH
    aj9ifyLlCX598a5JoT4S0x/ZeVHd/LNI8mtjcRzD6cMde7gdFbpLb5NSjIAyrsIA
    X4hxvpnqiOYRePkVIz0iLGziiaMbfMwlkrxvm/LRAoGBALPRbtSbE2pPgvOHKHTG
    Pr7gKbmsWVbOcQA8rG801T38W/UPe1XtynMEjzzQ29OaVeQwvUN9+DxFXJ6Yvwj6
    ih4Wdq109i7Oo1fDnMczOQN9DKch2eNAHrNSOMyLDCBm++wbyHAsS2T0VO8+gzLA
    BviZm5AFCQWfke4LZo5mOS10
    -----END PRIVATE KEY-----`;
    
    async function importPublicKeyAndEncrypt(str) {
      try {
        const pub = await importPublicKey(publicKey);
        //console.log(pub);
        const encrypted = await encryptRSA(pub, new TextEncoder().encode(str));
        const encryptedBase64 = window.btoa(ab2str(encrypted));
        //console.log(encryptedBase64.replace(/(.{64})/g, '$1\n'));
        return encryptedBase64;
      } catch (error) {
        console.log(error);
      }
    }
    
    async function importPrivateKeyAndDecrypt(str) {
      try {
        const priv = await importPrivateKey(privateKey);
        const decrypted = await decryptRSA(priv, str2ab(window.atob(str)));
        //console.log(decrypted);
        return decrypted;
      } catch (error) {
        console.log(error);
      }
    }
    
    async function importPublicKey(spkiPem) {
      return await window.crypto.subtle.importKey(
        'spki',
        getSpkiDer(spkiPem),
        {
          name: 'RSA-OAEP',
          hash: 'SHA-256',
        },
        true,
        ['encrypt']
      );
    }
    
    async function importPrivateKey(pkcs8Pem) {
      return await window.crypto.subtle.importKey(
        'pkcs8',
        getPkcs8DerDecode(pkcs8Pem),
        {
          name: 'RSA-OAEP',
          hash: 'SHA-256',
        },
        true,
        ['decrypt']
      );
    }
    
    async function encryptRSA(key, plaintext) {
      let encrypted = await window.crypto.subtle.encrypt(
        {
          name: 'RSA-OAEP',
        },
        key,
        plaintext
      );
      return encrypted;
    }
    
    async function decryptRSA(key, ciphertext) {
      let decrypted = await window.crypto.subtle.decrypt(
        {
          name: 'RSA-OAEP',
        },
        key,
        ciphertext
      );
      return new TextDecoder().decode(decrypted);
    }
    
    function getSpkiDer(spkiPem) {
      const pemHeader = '-----BEGIN PUBLIC KEY-----';
      const pemFooter = '-----END PUBLIC KEY-----';
      var pemContents = spkiPem.substring(
        pemHeader.length,
        spkiPem.length - pemFooter.length
      );
      var binaryDerString = window.atob(pemContents);
      return str2ab(binaryDerString);
    }
    
    function getPkcs8DerDecode(pkcs8Pem) {
      const pemHeader = '-----BEGIN PRIVATE KEY-----';
      const pemFooter = '-----END PRIVATE KEY-----';
      var pemContents = pkcs8Pem.substring(
        pemHeader.length,
        pkcs8Pem.length - pemFooter.length
      );
      var binaryDerString = window.atob(pemContents);
      return str2ab(binaryDerString);
    }
    
    function str2ab(str) {
      const buf = new ArrayBuffer(str.length);
      const bufView = new Uint8Array(buf);
      for (let i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
      }
      return buf;
    }
    
    function ab2str(buf) {
      return String.fromCharCode.apply(null, new Uint8Array(buf));
    }
    
    (async () => {
        let ciphertext = await importPublicKeyAndEncrypt('hello');
        console.log("Ciphertext:\n", ciphertext.replace(/(.{48})/g, '$1\n'));
        let decryptedData = await importPrivateKeyAndDecrypt(ciphertext);
        console.log("Decrypted data:", decryptedData);
    })();

    【讨论】:

    • 太好了,这正是我所需要的。有效!
    • 对 SO 表示感谢的最佳方式是投票/接受答案。答案旁边的向上箭头和 V 标记也应该在那里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    • 2012-06-02
    相关资源
    最近更新 更多