So I am trying to implement some methods to encrypt then decrypt some data. I don't have any experience with this, and I've tried to follow along with some posts online on how to go about this.
When i pass the encrypted 'hello' into the decrypt function, i get this:
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)
The decrypt function works correctly when i use an encrypted messages from one of the posts i saw for PKCS#8 but not when i generate my own keys.
Here is the code What am i doing wrong?
// 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));
}