title: CryptoKey ArrayBuffer to base64 and Back
body: <p>I was wondering how do I solve this problem. I generate RSA-OAEP keypair using WebCrypto API, then I export private key in pkcs8 from the keypair which exports as ArrayBuffer and I want to encode this ArrayBuffer into base64 so I can store it as a PEM.</p>
  
  <p>In this testing example I am exporting key as pkcs8 and importing this pkcs8 back to CryptoKey. The problem is that sometimes it works and sometimes it does not.</p>
  
  <p>These are results of the code:
  NOTE: Only happens one of these states not all at once.
  NOTE2: This example does not contain -----BEGIN PRIVATE KEY----- prefix and suffix I am only encoding the key.</p>
  
  <p>Case1: Uncaught (in promise) URIError: URI malformed(…)b64DecodeUnicode @ try.php:20b64toab @ try.php:70wayBack @ try.php:66(anonymous function) @ try.php:56</p>
  
  <p>Case2: undefined:1 Uncaught (in promise) DOMException</p>
  
  <p>Case3: OK - works all the way back.</p>
  
  <p>I don't know what causes the errors but I think it has something to do with base64 encoding. As I said sometimes private key generates OK and sometimes not.</p>
  
  <p>Thank you very much for every help in advance.</p>
  
  <pre><code>function b64EncodeUnicode(str) {
      return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
          return String.fromCharCode('0x' + p1);
      }));
  }
  
  function b64DecodeUnicode(str) {
      return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) {
          return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
      }).join(''));
  }
  
  function addNewLines(str) {
      var finalString = '';
      for(var i=0; i &lt; str.length; i++) {
          finalString += str.substring(0, 64) + '\n';
          str = str.substring(64);
      }
  
       return finalString;
  }
  
  window.crypto.subtle.generateKey(
      {
          name: "RSA-OAEP",
          modulusLength: 2048,
          publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
          hash: {name: "SHA-256"}
      },
      true,
      ["encrypt", "decrypt"]
  ).then(function(keyPair) {
      window.crypto.subtle.exportKey(
          "pkcs8",
          keyPair.privateKey
      ).then(function(exportedPrivateKey) {
          var byteArray = new Uint8Array(exportedPrivateKey);
          console.log(byteArray);
          var byteString = '';
          for(var i=0; i &lt; byteArray.byteLength; i++) {
              byteString += String.fromCodePoint(byteArray[i]);
          }
  
          wayBack(addNewLines(b64EncodeUnicode(byteString)));
      });
  });
  
  function wayBack(pem) {
      var lines = pem.split('\n');
      var encodedString = '';
      for(var i=0; i &lt; lines.length; i++) {
          encodedString += lines[i].trim();
      }
      b64toab(encodedString);
  }
  
  function b64toab(b64) {
      var byteString = b64DecodeUnicode(b64);
      console.log(byteString);
      var byteArray = new Uint8Array(byteString.length);
      for(var i=0; i &lt; byteString.length; i++) {
          byteArray[i] = byteString.codePointAt(i);
      }
      console.log(byteArray);
  
      window.crypto.subtle.importKey(
          "pkcs8",
          byteArray,
          {
              name: "RSA-OAEP",
              hash: {name: "SHA-256"}
          },
          true,
          ["decrypt"]
      ).then(function(importedPrivateKey) {
          console.log(importedPrivateKey);
      });
  }
  </code></pre>