Skip to content

Instantly share code, notes, and snippets.

@FeernandoOFF
Created September 3, 2025 14:02
Show Gist options
  • Select an option

  • Save FeernandoOFF/c18031b42f8eae8342856592cc1f4b69 to your computer and use it in GitHub Desktop.

Select an option

Save FeernandoOFF/c18031b42f8eae8342856592cc1f4b69 to your computer and use it in GitHub Desktop.
// First Attempt (throws DOMException [NotSupportedError]: Unable to import RSA key with format raw)
const { subtle } = require('crypto').webcrypto;
async function generateKey() {
const algoritm = { name: "AES-CBC", length: 256 };
const exportable = true;
const usage = ['encrypt', 'decrypt'];
return await subtle.generateKey(algoritm, exportable, usage);
}
async function encryptAesKey(aesKey) {
let rawRsaPublicKey = Buffer.from("-----BEGIN PUBLIC KEY-----.(KEY)..-----END PUBLIC KEY----", 'hex');
const format = "raw";
const exportable = false;
const usage = ["wrapKey"];
let rsaPublicKey = await subtle.importKey(format, rawRsaPublicKey, {
name : "RSASSA-PKCS1-v1_5",
hash : "SHA-256"
}, exportable, usage);
let wrappedKey = await subtle.wrapKey(format, aesKey, rsaPublicKey, { name: "RSA-OAEP" });
return wrappedKey.toString('base64');
}
const key = generateKey();
const encryptedKey = encryptAesKey(key);
console.log(encryptedKey);
// Second Attempt
const {webcrypto} = require('crypto');
const {subtle} = webcrypto;
function pemToDer(pem) {
const b64 = pem
.replace(/-----BEGIN PUBLIC KEY-----/g, '')
.replace(/-----END PUBLIC KEY-----/g, '')
.replace(/\s+/g, '');
return Buffer.from(b64, 'base64');
}
async function generateAesKey() {
return subtle.generateKey(
{name: 'AES-CBC', length: 256},
/* extractable */ true, // must be true for wrapKey to export it
['encrypt', 'decrypt']
);
}
async function importRsaOaepPublicKeyFromPem(pem) {
const spkiDer = pemToDer(pem);
return subtle.importKey(
'spki',
spkiDer, // Buffer is fine (ArrayBufferView)
{
name: 'RSA-OAEP',
hash: 'SHA-256',
},
/* extractable */ false,
['wrapKey']
);
}
async function wrapAesKeyWithRsaOaep(aesKey, rsaPublicKey) {
const wrapped = await subtle.wrapKey(
// Export format for the AES key being wrapped:
'raw', // could also use 'jwk' if you prefer
aesKey,
rsaPublicKey,
{name: 'RSA-OAEP'} // OAEP with SHA-256 per the imported key
);
return Buffer.from(new Uint8Array(wrapped)).toString('base64');
}
// Example usage:
(async () => {
const rsaPublicKeyPem = `
-----BEGIN PUBLIC KEY-----
(KEY)
-----END PUBLIC KEY-----`.trim();
let aesKey = await generateAesKey();
const rsaPub = await importRsaOaepPublicKeyFromPem(rsaPublicKeyPem);
let wrappedBase64 = await wrapAesKeyWithRsaOaep(aesKey, rsaPub);
console.log('AES key:', aesKey);
console.log('Wrapped AES key (base64):', wrappedBase64);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment