Skip to content

aman-eth/ephy-rsa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

19 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Ephy-RSA

Ephy-RSA is a lightweight encryption library for securely exchanging data between a frontend application and a backend server. It generates ephemeral RSA key pairs in browser memory, ensuring that sensitive data is encrypted before transmission and that no keys are persistently stored. This prevents plaintext exposure in browser network logs and enhances security.

tl;dr

Below is a Sequence Diagram illustrating the encryption and decryption process:

Sequence Diagram

πŸš€ Features

  • πŸ” Ephemeral RSA Key Pairs – No keys are stored persistently on the frontend.
  • πŸ”„ Client-Side Encryption – Data is encrypted before leaving the browser.
  • πŸš€ Easy Integration – Works seamlessly with JSON Web Encryption (JWE) using jose.
  • πŸ”’ No Plaintext Exposure – Data remains encrypted in transit.

πŸ— Installation

npm install ephy-rsa

OR

yarn add ephy-rsa

πŸ›  Usage

πŸ–₯ Frontend (Client-Side)

1️⃣ Initialize the Library and Generate an Ephemeral Key Pair

import RSAKeyService from "ephy-rsa";

(async () => {
  const rsaService = await RSAKeyService();
  console.log("Public Key:", rsaService.getPublicKey());
})();

2️⃣ Encrypt Request Payload with the Server's Public Key

(async () => {
  const rsaService = await RSAKeyService();

  const serverPublicKey = "your-server-public-key-in-JWK-or-PEM-format";
  const encryptedData = await rsaService.encryptWithServerPublicKey(
    "Sensitive Data",
    serverPublicKey,
  );
  console.log("Encrypted Data:", encryptedData);
})();

3️⃣ Decrypt Response Data with the Ephemeral Private Key

(async () => {
  const rsaService = await RSAKeyService();

  const encryptedData = "..."; // Encrypted string received from backend
  const decryptedData = await rsaService.decryptWithPrivateKey(encryptedData);

  console.log("Decrypted Data:", decryptedData);
})();

πŸ–₯ Backend (Server-Side)

The backend should:

  1. Generate an RSA Key Pair and expose the public key to the frontend.
  2. Decrypt incoming encrypted messages using the private key.
  3. Encrypt responses using client's public key.

Example Backend Code (Node.js using jose)

import * as jose from "jose";
import fs from "fs";

// Load RSA Private Key (PEM format)
const privateKeyPem = fs.readFileSync("./private.pem", "utf8");
const privateKey = await jose.importPKCS8(privateKeyPem, "RSA-OAEP");

// Load RSA Public Key (PEM format)
const publicKeyPem = fs.readFileSync("./public.pem", "utf8");
const publicKey = await jose.importSPKI(publicKeyPem, "RSA-OAEP");

// Decrypt received encrypted data
async function decryptData(encryptedData) {
  const decrypted = await jose.compactDecrypt(encryptedData, privateKey);
  console.log("Decrypted Data:", new TextDecoder().decode(decrypted.plaintext));
}

// Encrypt responses
async function encryptResponse(response, clientPublicKey) {
  const encrypted = await jose.compactEncrypt(
    JSON.stringify(response),
    clientPublicKey,
  );
  console.log("Encrypted Response:", new TextDecoder().decode(encrypted));
}

export { publicKey, decryptData, encryptResponse };

The public key should be exposed via an API endpoint, so the frontend can retrieve it and use it for encryption.


πŸ”€ API Reference

RSAKeyService(algorithm?: RsaHashedKeyGenParams): Promise<RSAKeyService>

Creates an instance of RSAKeyService. You can optionally specify an RSA key generation algorithm.

getPublicKey(): string | null

Returns the Base64-encoded PEM public key of the generated RSA key pair.

encryptWithServerPublicKey(data: string, jwkPublicKey: JsonWebKey | string, alg?: "RSA-OAEP" | "RSA-OAEP-256", enc?: "A128GCM" | "A256GCM"): Promise<string>

Encrypts the given data using the server’s public key. The key can be in JWK or PEM/Base64 format.

decryptWithPrivateKey(encryptedData: string): Promise<string>

Decrypts the given encrypted data using the ephemeral private key stored in memory.


πŸ”’ Security Considerations

  • Frontend:

    • Private keys are never stored persistently – They exist only in memory and are lost when the page refreshes.
    • Protect against XSS attacks – Since in-memory keys can be accessed if malicious scripts are injected.
    • Use HTTPS – To prevent man-in-the-middle attacks.
    • Implement a strong Content Security Policy (CSP) – To restrict script execution and mitigate injection risks.
  • Backend:

    • Store the private key securely.
    • Restrict access to the decryption endpoint.
    • Ensure proper authentication and authorization before decrypting data.

πŸ“– TypeScript Interface

interface RSAKeyService {
  getPublicKey(): string | null;
  encryptWithServerPublicKey(
    data: string,
    jwkPublicKey: JsonWebKey | string,
    alg?: "RSA-OAEP" | "RSA-OAEP-256",
    enc?: "A128GCM" | "A256GCM",
  ): Promise<string>;
  decryptWithPrivateKey(encryptedData: string): Promise<string>;
}

πŸ“š Additional Resources


🏷 Keywords

reactjs, nextjs, RSA, AES, encryption, decryption, hybrid, jose, cryptography, browser, secure, ephemeral


πŸ“ License

This project is licensed under the MIT License


❀️ Contributing

Contributions are welcome! Feel free to open issues or pull requests or reach out to me via GitHub Issues.

About

A lightweight, secure encryption library for client-side RSA encryption with ephemeral private keys. Ensures end-to-end encryption without exposing plaintext data in network traffic. πŸš€πŸ”

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors