In today’s digital landscape, ensuring secure communication is more critical than ever. This article explores how to implement the RSA-OAEP algorithm using the Web Cryptography API in JavaScript to safeguard data transmission.
1. Generating a Key Pair
The first step in establishing secure communication is generating a key pair. The generateKeyPair
function utilizes the RSA-OAEP algorithm with a modulus length of 1024 bits and employs SHA-256 for hashing. Both public and private keys are marked as extractable, enabling their export for future use. The keys are then exported in SPKI (for the public key) and PKCS8 (for the private key) formats before being returned .
async function generateKeyPair() {
const keyPair = await crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 1024,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: "SHA-256",
},
true,
["encrypt", "decrypt"],
);
const publicKeyJwk = await crypto.subtle.exportKey("spki", keyPair.publicKey);
const privateKeyJwk = await crypto.subtle.exportKey(
"pkcs8",
keyPair.privateKey,
);
return { publicKeyJwk, privateKeyJwk };
}
2. Encrypting a Message
To securely transmit messages, we employ the encrypt
function, which takes a public key and a message string. It imports the public key and proceeds to encrypt the message using the RSA-OAEP algorithm .
async function encrypt(publicKeyJwk, message) {
const importedPublicKey = await crypto.subtle.importKey(
"spki",
publicKeyJwk,
{
name: "RSA-OAEP",
hash: "SHA-256",
},
true,
["encrypt"],
);
const encrypted = await crypto.subtle.encrypt(
{ name: "RSA-OAEP" },
importedPublicKey,
new TextEncoder().encode(message),
);
return encrypted;
}
3. Decrypting an Encrypted Message
For the recipient to read the encrypted message, the decrypt
function comes into play. It accepts a private key and an encrypted message, importing the private key before decrypting the message with RSA-OAEP .
async function decrypt(privateKeyJwk, message) {
const importedPrivateKey = await crypto.subtle.importKey(
"pkcs8",
privateKeyJwk,
{
name: "RSA-OAEP",
hash: "SHA-256",
},
true,
["decrypt"],
);
const decrypted = await crypto.subtle.decrypt(
{ name: "RSA-OAEP" },
importedPrivateKey,
message,
);
return decrypted;
}
4. Running the Code
The example usage demonstrates the process by generating a key pair, encrypting a message, and subsequently decrypting it:
(async () => {
const { publicKeyJwk, privateKeyJwk } = await generateKeyPair();
console.log("generateKeyPair: ", publicKeyJwk, privateKeyJwk);
const encrypted = await encrypt(publicKeyJwk, "hello");
console.log("encrypted: ", encrypted);
const decrypted = await decrypt(privateKeyJwk, encrypted);
console.log("decrypted: ", decrypted, new TextDecoder().decode(decrypted));
})();
Important Considerations
- Key Management: Effective key management is vital. Ensure private keys are stored securely and refrain from transmitting them over insecure channels .
- Error Handling: This example lacks comprehensive error handling. Implement robust error management practices for production environments to address potential issues effectively.
Conclusion
By adopting secure communication techniques like those discussed here, you can significantly enhance the confidentiality and integrity of your data, particularly when handling sensitive information. For further exploration, consider understanding and implementing ECDSA in JavaScript cryptography .