title: Web Crypto API: how to import RSA private key
body: <p>I have 2 different web software.
  At one of them I want to encrypt user's data in browser using public key from the server and store encrypted user's data at database.
  After that I want to have possibility to decrypt those data on server side or browser.</p>
  <p>I tried to create proof of concept - It works with keys that were generated by Web Cypto API itself but fail with keys from another source.</p>
  <h2>How to reproduce:</h2>
  <p>I've create  RSA keys using OpenSSL Ruby standard library</p>
  <pre class="lang-rb prettyprint-override"><code>require 'openssl'
  
  rsa = OpenSSL::PKey::RSA.new(2048)
  puts rsa.to_s
  puts rsa.public_key.to_s
  </code></pre>
  <p>I'm trying to use them to encrypt/decrypt messages via Web Crypto API.
  However I've encountered and error while importing private key.
  In DevTools I see it as <code>Error</code> without a backtrace.</p>
  <p>Could someone advice How can I achieve by goal?</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>function arrayBufferToString(buf) {
    let bytes = new Uint8Array(buf);
    return bytes.reduce((str, byte) =&gt; str + String.fromCharCode(byte), "");
  }
  
  function stringToArrayBuffer(str) {
    let buf = new ArrayBuffer(str.length);
    let bufView = new Uint8Array(buf);
    for (var i = 0, strLen = str.length; i &lt; strLen; i++) {
      bufView[i] = str.charCodeAt(i);
    }
    return buf;
  }
  
  function base64ToBinary(str) {
    return atob(str);
  }
  
  function binaryToBase64(str) {
    return btoa(str);
  }
  
  (async function main() {
    console.clear();
    var content = "hello world!"; //+ Math.random();
    console.log("content: ", content);
  
    let algorithmOptions = {
      name: "RSA-OAEP",
      modulusLength: 2048,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256"
    };
  
    let rsaPrivate =
      "-----BEGIN RSA PRIVATE KEY-----\n" +
      "MIIEogIBAAKCAQEAqnXo4TWhiUaDpiQBArFq5B22JB2ebKlAvQMbDrOakK8Tactj\n" +
      "zg64ZTXwZhadVcfPwFvoS45O6LkIZL+o7F9N7WnlRiT5SXgwkPzQ75l2EcGqZKgK\n" +
      "lyCl5THuD2RRMOTJI1bzmx8DO/f7LMHr3xUGtdHXzqICxIUwa5B0RTvHG/j6Wirk\n" +
      "Z51ArwQa5ZrtyGXJoupgws0LZRuadJBkbIRUaaujv1pA25Dmzu7pODr3S2XWqIYy\n" +
      "cfJqxgIGvNJ7LHTEPLBWh1xCc0MNf3C9cZNEsVmDgGCYS4oeKuBbUoqF6eirQHC6\n" +
      "rkW+4KwE/Rvo6LZVrtl1vh6vI+rVt6wvoWydYQIDAQABAoIBAB+xZogg6ZTVaHrG\n" +
      "bO2sQPyCza+vVhpL6b56ylgUaqOF+a0M5NSWBhDDU5wXjk85pFXWgL0zi1ZXuMjK\n" +
      "ncS8/4cpzjgZfcP8NcNvTgWOWdZ5VI38dGOe7VlMzD9OXo4hq4gHjamEvZwzwh6T\n" +
      "O6CxjxrVFjPUCYGyZctKA2Qv9hgsB9Nq7EV5z/VErN33OI1edHeMIdZ0tvahQNrY\n" +
      "2It26hKsxSKAowm7H+NG0fJsVUmN0m1Ou0od9tqzX6XwOgycUvvdr5iHrECHFMDe\n" +
      "be5iZ19evzai8gdxr4ZkWdF5P7+VltI7vlKpHKUvx/I/mO/XWq4yo4efEoLYWjfe\n" +
      "Vz8OG7ECgYEA2yAesiDs3buYAQ8nEVje6sn/jr2PgtXXo6TXHbd3NNCnvbt71LWw\n" +
      "5P8dUqqiIwKskjargEU0HphQKmUubnSdYdl+rLpwcCsRn/0kBX1+89vv7XWnn20i\n" +
      "j07IUtsHev40xK3joJcJ1eHsHjkljJaMsRvGilo8V7eh5p8WkfDA4jUCgYEAxyVR\n" +
      "DQSc0U/O9++euv9LVUxqISaSG866/k9HP++IKhcN3Gh3gcJJcMETgtH0sEa5ut9K\n" +
      "AzC61OTZqpB+t1bVOpdzj2h4K0YVy2FVAB/wpZcoslrD4hC6Zh7tcUlfrdo3Pj+i\n" +
      "1cJzqaqZDVv0Rtxwz9ekWkBi9V+pPWohntZas/0CgYBRTS2WcdjwvDW9zt1z9kFf\n" +
      "Y+tKDtM8fBMySGr4P6YfFnvmTbW4SmGD1ZQPo/fcfZWB+n7PbN3VrDWyRTBhEyuB\n" +
      "rqztcY9eTtyPO+EtmE6ONEBlHo4+/MMh4N06wMGZxM/XWZ1nbCLeFKEC5bkk3Ib+\n" +
      "/4s+shRJh3yukMBTDbzDMQKBgH7Rtc7LfC4TW+MqdnPxNgEo+4EG9g69VPm0dNQz\n" +
      "bwwWyF3vLQO2PVyPqCQsHl3PfGGT5qcndiMzZaYoBHou0vVQE2hlB/nO1PxCjIXa\n" +
      "0T4yh9kk0g95xapY0a7OIh8tkvaSQdlMzqlimbsXLvWdVj4VvnU3AY3vEHCq0KQ9\n" +
      "L1/lAoGAbRAVMic9JDVqjpxfjAeL1E9w30m59vDCIEjJdMGX5BHOea7iVbQshilb\n" +
      "yo+1s+QfWVNT0jOTzo4VPRomRNbdEIMb5W/M3zv+cUAmnCJymHUBiBP0N+ZO8+g8\n" +
      "lEB3MJBdfsiKxMiX69jcoU1fB8tAwwE3hWSmkNKuvvzjOgxhtgQ=\n" +
      "-----END RSA PRIVATE KEY-----";
    let rsaPrivateBase64String = rsaPrivate.split("\n").slice(1, -1).join("");
    // console.log("rsaPrivateString", rsaPrivateBase64String);
  
    let rsaPublic =
      "-----BEGIN PUBLIC KEY-----\n" +
      "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqnXo4TWhiUaDpiQBArFq\n" +
      "5B22JB2ebKlAvQMbDrOakK8Tactjzg64ZTXwZhadVcfPwFvoS45O6LkIZL+o7F9N\n" +
      "7WnlRiT5SXgwkPzQ75l2EcGqZKgKlyCl5THuD2RRMOTJI1bzmx8DO/f7LMHr3xUG\n" +
      "tdHXzqICxIUwa5B0RTvHG/j6WirkZ51ArwQa5ZrtyGXJoupgws0LZRuadJBkbIRU\n" +
      "aaujv1pA25Dmzu7pODr3S2XWqIYycfJqxgIGvNJ7LHTEPLBWh1xCc0MNf3C9cZNE\n" +
      "sVmDgGCYS4oeKuBbUoqF6eirQHC6rkW+4KwE/Rvo6LZVrtl1vh6vI+rVt6wvoWyd\n" +
      "YQIDAQAB\n" +
      "-----END PUBLIC KEY-----";
    let rsaPublicBase64String = rsaPublic.split("\n").slice(1, -1).join("");
    // console.log("rsaPublicBase64String", rsaPublicBase64String);
  
    let pubKey = await crypto.subtle.importKey(
      "spki",
      stringToArrayBuffer(base64ToBinary(rsaPublicBase64String)),
      algorithmOptions,
      false, ["encrypt"]
    );
    console.log("pubKey", pubKey);
  
    // &gt;&gt; ERROR IS ON STATEMENT BELOW
    let privKey = await crypto.subtle.importKey(
      "pkcs8",
      stringToArrayBuffer(base64ToBinary(rsaPrivateBase64String)),
      algorithmOptions,
      false, ["decrypt"]
    );
    console.log("privKey", privKey);
  
    let encryptedBuf = await crypto.subtle.encrypt({
        name: "RSA-OAEP"
      },
      pubKey,
      stringToArrayBuffer(content)
    );
    let encrypted = arrayBufferToString(encryptedBuf);
    console.log("encrypted", binaryToBase64(encrypted));
  
    let decryptedBuf = await crypto.subtle.decrypt({
        name: "RSA-OAEP"
      },
      privKey,
      stringToArrayBuffer(encrypted)
    );
    let decrypted = arrayBufferToString(decryptedBuf);
    console.log("decrypted", decrypted);
  })().catch(error =&gt; console.error(error));</code></pre>
  </div>
  </div>
  </p>
  <p>Here's <a href="https://codesandbox.io/s/subtle-import-key-failed-64120268-wicif" rel="nofollow noreferrer">code sandbox link</a></p>