0

I am writing a script to decode a cipher text using a private key. The original text is Hello World. I used this website to generate the public private key pair, as well as testing the encryption: https://www.devglan.com/online-tools/rsa-encryption-decryption I chose the cipher type as RSA.

However, when I implemented this algorithm in JS, although I can import the private key, I always get an uncaught error as I try to decode the cipher text using the private key (i.e. window.crypto.subtle.decrypt()).

However, if I create the cipher text using the imported public key, I can decrypt it successfully. I suspect something is not right with how I converted string to uint8 array but I couldn't figure it out.

Using external JS library is not an option due to requirements. So as using public API endpoint for encryption/decryption. The script is going to be ran in a service worker.

Here is the code snippet

async function run(){

    const publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApTsMkYN8ehigb/rHQSRm45kf6yPzxuMvihf6sx02+Kt7qCKCzfxETHG/bmczvK+j3GqBjgkYXSQ9pNtaXF5s5Bz9rk/4v/5GwYwk9WzH9GBc4XvLObQ84AQakG5UmnY5F6SWefgyWsPBkAIsaVUuTgV0iG8g6ubPXeOnINoRy5TxChTaKa1gyl0cqNG9QpKIfDfn7E7247Mb8+Yq1fjLTwnIYilhTuOOH3iVCGpaMDE9JcVIh6UojBFBRlcZcThJr1Ul3q9wLvmPhzTJ+AY5XMdqVULJNtnAi0SyfHkC82zf+WfW3s50B5RN3JfvR5qmO05wFTZn9aLOEflvTR3KcwIDAQAB"
    const privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQClOwyRg3x6GKBv+sdBJGbjmR/rI/PG4y+KF/qzHTb4q3uoIoLN/ERMcb9uZzO8r6PcaoGOCRhdJD2k21pcXmzkHP2uT/i//kbBjCT1bMf0YFzhe8s5tDzgBBqQblSadjkXpJZ5+DJaw8GQAixpVS5OBXSIbyDq5s9d46cg2hHLlPEKFNoprWDKXRyo0b1Ckoh8N+fsTvbjsxvz5irV+MtPCchiKWFO444feJUIalowMT0lxUiHpSiMEUFGVxlxOEmvVSXer3Au+Y+HNMn4Bjlcx2pVQsk22cCLRLJ8eQLzbN/5Z9beznQHlE3cl+9HmqY7TnAVNmf1os4R+W9NHcpzAgMBAAECggEAMiOEAdgDes1kSfawZh0Ut7XskJ79R3oDIAV8xsNzvevTf0bRqI4Hb6cIrwjUE0q9D5KmM6Kg6QqpRhBmECd7JZGCjVWpJyGS+QJ86JiU6JwhMy8skRsXaeb05KUGOUTsuDbyjpp5NT+3yepO7buybGyNWyVVuNJHVLdTLM3fnoXb56Qx8KkDE9tHSpYXW5swRFMB/dO93m+rU+EOzMYUKcc3sQwHYw0q1BLvYru0efHWYuXpOQyxpbaiF+I78tBj5IYvVjz1yZb9fpayF5FDHVzD6aW9HjZhZuOM9W8XayWInJiLp8DZcR2icHGi5MkAtUXR/Fx10PbrhWeoumxOmQKBgQDUjrzeJojdcyyBboKMxMFc5bo7SWTETfk5r//UhR9sIBb8tHhfCd5N2VgqGuL5TWD8jxsdhzRFqxhPrTb4CunfJGGGFMA1pJMCEZsZ9omLlkw8nSp7usJwrgrJReAHzwGtH+RG/XKwPi1vuo11iEwl0rp7U5j7kxAoZjO5DM0fjQKBgQDHABybn4VsHq/WqbR8VCDNd/3r20MgV4fw0TYtkBt2EqzM78VRAtWszQKZOPLwt6+QbbnBWxDpO5Et3JMMKLS4NH9VbjMX5+k1r4ZyaAodl7qco1yH+qLvQDfXJyznShkMSALr7epuRgwox+r/Vcb/M4xiMquepcjmQx1cUj8R/wKBgQCPwCDXFLSHH7c/qZ882Gv1CaBTLCWr5Rfh/bdE4OsJUwJ40Qx/KctgVtcbUqeh9sTayWWLKL8fRsDgUcLVKXxVXuNdrHb5UF3jjkiY3HTVJEZWz+vFVd7eGbZNvKXwYf0+Ok1F/W4s50APSdkVXaIyCjv33+ecbC8HQ2dDhPbMmQKBgGhZEac07aR1LuUUFdT/1DeJjPdpAPjrjRfkzFD1+MBgKIZJ0CCbqOm0koE/0HwTBZdpQfc2xlZWatkuiVjd222f8YkdgOMvMyV4hbpl/a/oyOyr6LBQ57Em7mD+ZNhfDWVYOVf3aG8sgeG8eugq1W8qW5l+UmmdKww68yFe6z2HAoGBALtXTjn4/2sgbhD/nmwCQA8lJjJvIacX1t+q0f7IfPMwXCUeCy9zhWeL0pd645bIlaVZhSq1Ul+R0GXB0L0eBaIh9uPgsE3A6kCNHyO0zAWG1X/aGLwXscpJGuH9gaAyUqBHMa6He49tS0b6hanvwkAe8uzwans36hTXLGHehWgq"
    const ciphertext = "CaLtZdaxgk55DMlExKyJvNa1S2CvN7yfb0txNViQvB9hX9YjhfmIyV/HAbAsdmM82Y27sQmF5VTe5XpFyt0fwxNVGarXGosbbtY3BEWk1fT15dWeVtgJ5Dmxf1cZ2fVVGNK9dtRcXpEdo0IUZqRi21u9ZC/wSEdbSHvHKx0UVO7Bq866LFv2E2F8/SNHCO6tCxPPPvI0RWSKDtA/Rj3lHkkMyUhcvjNhZbvr4jk40QlHhYfqh/hgCnNGVjDx1osTNe/OoRntFVILTPhlPSTTHKtw/UVIwulN4e8QApooDJGJYpK2daYh6BTN+XldWGcDEXP+YElKbF6mvEm5SRo+WQ=="

    const publicKeyCrypto = await importPublicKey(publicKey);
    const privateKeyCrypto = await importPrivateKey(privateKey);

    const dec = new TextDecoder()
    let cipherTextArr = fromBase64(ciphertext);
  

    decrypted = await window.crypto.subtle.decrypt(
      { 
        name: "RSA-OAEP"
      },
      privateKeyCrypto,
      cipherTextArr
    );
    console.log(dec.decode(decrypted))
}



const fromBase64 = base64String => Uint8Array.from(atob(base64String), c => c.charCodeAt(0));

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

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

Here is the error. The script is ran when I pressed the press me button. (https://i.stack.imgur.com/KlRVq.png)

Appreciate any help from the community!

mkc210593
  • 1
  • 1
  • Selecting *RSA* as *Cipher Type* on the linked web site applies PKCS#1 v1.5 as padding whereas in your WebCrypto code OAEP is used as padding (with SHA256 as OAEP and MGF1 digest). So both are incompatible, which is why the ciphertext of the website cannot be decrypted with the WebCrypto code. – Topaco Dec 05 '22 at 20:55
  • Note that WebCrypto does not support PKCS#1 v1.5 padding for encryption, but only OAEP, s. [here](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto#supported_algorithms). The web site applies OAEP (with SHA-1 as OAEP and MGF1 digest) when *RSA/ECB/OAEPWithSHA-1AndMGF1Padding* is selected as *Cipher Type*. To make your WebCrypto code compatible, you must change SHA-256 to SHA-1 in both of your `importKey()` calls (btw SHA-1 is not considered insecure when used with OAEP, see [here](https://security.stackexchange.com/a/112032)). – Topaco Dec 05 '22 at 21:18

1 Answers1

0

@Topaco Thank you very much for pointing that out! You are correct that I was using the wrong padding. After switching the Cipher Type to ESA/ECB/OAEPWithSHA-1AndMGF1Padding and changing the hash to 'SHA-1', The problem is resolved.

async function importPrivateKey(key){
return window.crypto.subtle.importKey(
    "pkcs8",
    fromBase64(key),
    {
      name: "RSA-OAEP",
      hash: "SHA-1",
    },
    true,
    ["decrypt"]
    );
}
mkc210593
  • 1
  • 1