I am trying to create the following flow:
- Create a keypair on the client
- Send the public key to the server (nodejs)
- Encrypt a string on the server using a WebCryptoAPI polyfill https://github.com/PeculiarVentures/node-webcrypto-ossl
- Send the encrypted data back to the client for decryption
I am struggling (for a long time time) with the data types.
Below is the code, first to generate the keys (client):
// some reusable settings objects const crypto = window.crypto.subtle; let publicKeyToExport = {}; let privateKeyToStore = {}; // function called to create a keypair const generateKeypair = () => { crypto.generateKey({ name : 'RSA-OAEP', modulusLength : 2048, //can be 1024, 2048, or 4096 publicExponent : new Uint8Array([0x01, 0x00, 0x01]), hash : {name: 'SHA-256'}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" }, true, ['encrypt', 'decrypt'] ).then((key) => { publicKeyToExport = key.publicKey; privateKeyToStore = key.privateKey; console.log(key); }).catch((err) => { console.error(err); }); }; Then to export:
// function to export the generate publicKey const exportPublicKey = (publicKey) => { crypto.exportKey('jwk', publicKey) .then((keydata) => { fetch('/key2', { method : 'POST', mode : 'cors', body : JSON.stringify(keydata), headers : new Headers({ 'Content-Type' : 'application/json' }) }).then(res => res.json()) .catch(err => console.error(err)) .then(res => console.log(res)); console.log(keydata); }) .catch((err) => { console.log(err); }); }; Save the key:
app.post('/key2', (req, res) => { webcrypto.subtle.importKey( 'jwk', req.body, { name : 'RSA-OAEP', hash : {name : 'SHA-256'}, }, false, ['encrypt'] ).then((publicKey) => { keyStorage.setItem('alicePubKey', publicKey); if(publicKey == keyStorage.getItem('alicePubKey')); res.json({ 'success' : 'key received and saved' }); console.log('saved key from client: ' + publicKey); return; }) .catch((err) => { console.error(err); }); }); Encrypt on server:
app.get('/challenge', (req, res) => { let challengeFromServer = null; let key = keyStorage.getItem('alicePubKey'); let buf = new Buffer.from('decryptthis!'); webcrypto.subtle.encrypt( { name : 'RSA-OAEP' }, key, buf ) .then((encrypted) => { console.log('challenge created: ' + encrypted); res.json({'challenge' : new Uint8Array(encrypted) }) }) .catch((err) => { console.error(err); }) Get encrypted data and decrypt - not working :)
const requestChallenge = () => { fetch('/challenge') .then((res) => { return res.json(); }) .then((data) => { console.log(data); console.log(ArrayBuffer.isView(data.challenge)) console.log(new ArrayBuffer(data.challenge)) crypto.decrypt({ name : 'RSA-OAEP' }, privateKeyToStore, new ArrayBuffer(data.challenge)) .then((decrypted)=>{ console.log(decrypted) }) .catch(err => console.error(err)); }) .catch(err => console.error(err)); }; The following lines are the issue I think!
console.log(ArrayBuffer.isView(data.challenge)) // false console.log(new ArrayBuffer(data.challenge)) // empty Small update:
res.json( {'challenge' : encrypted , // {} empty 'uint' : new Uint8Array(encrypted), // {0: 162, 1: 252, 2: 113, 3: 38, ....... 'stringify' : JSON.stringify(encrypted), // "{}" empty 'toString' : encrypted.toString() // "[object ArrayBuffer]" });