UNPKG

oidc-spa

Version:

Openidconnect client for Single Page Applications

85 lines 3.55 kB
const INFO_LABEL = "oidc-spa/tools/asymmetricEncryption"; export async function generateKeys() { const keyPair = await crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, ["deriveKey", "deriveBits"]); const publicKeyRaw = await crypto.subtle.exportKey("jwk", keyPair.publicKey); const privateKeyRaw = await crypto.subtle.exportKey("jwk", keyPair.privateKey); return { publicKey: btoa(JSON.stringify(publicKeyRaw)), privateKey: btoa(JSON.stringify(privateKeyRaw)) }; } export async function asymmetricEncrypt(params) { const { publicKey, message } = params; const importedPublicKey = await crypto.subtle.importKey("jwk", JSON.parse(atob(publicKey)), { name: "ECDH", namedCurve: "P-256" }, false, []); const ephemeralKeyPair = await crypto.subtle.generateKey({ name: "ECDH", namedCurve: "P-256" }, true, ["deriveKey", "deriveBits"]); const sharedSecret = await crypto.subtle.deriveBits({ name: "ECDH", public: importedPublicKey }, ephemeralKeyPair.privateKey, 256); const salt = crypto.getRandomValues(new Uint8Array(16)); const infoBytes = new TextEncoder().encode(INFO_LABEL); const hkdfKey = await crypto.subtle.importKey("raw", sharedSecret, "HKDF", false, ["deriveKey"]); const derivedKey = await crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", salt, info: infoBytes }, hkdfKey, { name: "AES-GCM", length: 256 }, false, ["encrypt"]); const iv = crypto.getRandomValues(new Uint8Array(12)); const encodedMessage = new TextEncoder().encode(message); const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, derivedKey, encodedMessage); const ephemeralPubKeyRaw = await crypto.subtle.exportKey("jwk", ephemeralKeyPair.publicKey); const payload = { ephemeralPubKey: ephemeralPubKeyRaw, iv: Array.from(iv), salt: Array.from(salt), ciphertext: Array.from(new Uint8Array(ciphertext)) }; return { encryptedMessage: btoa(JSON.stringify(payload)) }; } export async function asymmetricDecrypt(params) { const { privateKey, encryptedMessage } = params; const { ephemeralPubKey, iv, salt, ciphertext } = JSON.parse(atob(encryptedMessage)); const importedPrivateKey = await crypto.subtle.importKey("jwk", JSON.parse(atob(privateKey)), { name: "ECDH", namedCurve: "P-256" }, false, ["deriveKey", "deriveBits"]); const importedEphemeralPubKey = await crypto.subtle.importKey("jwk", ephemeralPubKey, { name: "ECDH", namedCurve: "P-256" }, false, []); const sharedSecret = await crypto.subtle.deriveBits({ name: "ECDH", public: importedEphemeralPubKey }, importedPrivateKey, 256); const infoBytes = new TextEncoder().encode(INFO_LABEL); const hkdfKey = await crypto.subtle.importKey("raw", sharedSecret, "HKDF", false, ["deriveKey"]); const derivedKey = await crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", salt: new Uint8Array(salt), info: infoBytes }, hkdfKey, { name: "AES-GCM", length: 256 }, false, ["decrypt"]); const decryptedBuffer = await crypto.subtle.decrypt({ name: "AES-GCM", iv: new Uint8Array(iv) }, derivedKey, new Uint8Array(ciphertext)); return { message: new TextDecoder().decode(decryptedBuffer) }; } //# sourceMappingURL=asymmetricEncryption.js.map