payload-encryptor
v2.0.0
Published
Secure client-server payload encryption using X25519 key exchange and ChaCha20-Poly1305 (native crypto, zero dependencies)
Maintainers
Readme
🔐 payload-encryptor
Secure hybrid encryption for client-server communication using ECIES pattern.
Works everywhere: Browsers, Node.js, Bun, Deno, Cloudflare Workers.
✨ Features
- 🔒 ECIES Hybrid Encryption - X25519 ECDH + ChaCha20-Poly1305
- 🔄 Two-Way Encryption - Both request and response encrypted
- 🌍 Universal - Works everywhere, zero configuration
- 🔑 Forward Secrecy - New ephemeral keys for every message
- 📦 Zero Config - No webpack/bundler setup needed
- 🛡️ No Secrets Over Wire - Only public keys transmitted
📦 Installation
# Clone and build
git clone https://github.com/yourusername/payload-encryptor.git
cd payload-encryptor
# Build WASM and embed it (requires Zig 0.11+)
zig build wasm
bun run scripts/embed-wasm.ts
# Install dependencies
cd payload-encryptor && bun install🚀 Quick Start
Server
import { PayloadServer } from "payload-encryptor";
const server = await PayloadServer.create();
// Endpoint 1: Give clients the public key
app.get("/session", () => server.createSession());
// Endpoint 2: Receive encrypted request, send encrypted response
app.post("/data", async (req) => {
const encrypted = await req.json();
const decrypted = server.decrypt(encrypted);
// Encrypt response back to client
const response = server.encryptResponse(encrypted.clientEphemeralPublic, {
result: "success",
token: "secret-token",
});
return response;
});Client
import { PayloadClient } from "payload-encryptor";
const client = await PayloadClient.create();
// Step 1: Get session
const session = await fetch("/session").then((r) => r.json());
client.setSession(session);
// Step 2: Encrypt and send
const encrypted = client.encrypt({ username: "john", password: "secret" });
const encryptedResponse = await fetch("/data", {
method: "POST",
body: JSON.stringify(encrypted),
}).then((r) => r.json());
// Step 3: Decrypt response
const response = client.decryptResponse(encryptedResponse);
console.log(response); // { result: "success", token: "secret-token" }Browser Usage
<script type="module">
import { PayloadClient } from "./payload-encryptor/src/index.js";
const client = await PayloadClient.create();
// ... same API as above
</script>📚 API Reference
PayloadClient
class PayloadClient {
static create(): Promise<PayloadClient>;
setSession(session: SessionInit): void;
getSession(): SessionInit | null;
hasSession(): boolean;
encrypt(payload: string | object): EncryptedPayload;
decryptResponse<T>(response: EncryptedResponse): T; // NEW!
}PayloadServer
class PayloadServer {
static create(): Promise<PayloadServer>;
createSession(): SessionInit;
decrypt<T>(payload: EncryptedPayload): T;
encryptResponse(clientEphemeralPublic: string, data: any): EncryptedResponse; // NEW!
}🔧 Use With Any HTTP Client
With Axios
import axios from "axios";
const { data: session } = await axios.get("/session");
client.setSession(session);
const encrypted = client.encrypt(data);
await axios.post("/data", encrypted);With Got
import got from "got";
const session = await got("/session").json();
client.setSession(session);
const encrypted = client.encrypt(data);
await got.post("/data", { json: encrypted });With WebSocket
ws.on("session", (session) => {
client.setSession(session);
});
const encrypted = client.encrypt(data);
ws.send(JSON.stringify(encrypted));🛡️ Security
| Feature | Implementation | | --------------- | -------------------------- | | Key Exchange | X25519 (Curve25519) | | Encryption | ChaCha20-Poly1305 AEAD | | Key Derivation | HKDF-SHA256 | | Forward Secrecy | Ephemeral keys per message | | Authentication | Poly1305 MAC |
What's Transmitted
| Data | Transmitted? | | ------------------------ | ------------ | | Server Private Key | ❌ Never | | Server Public Key | ✅ Safe | | Client Ephemeral Private | ❌ Never | | Client Ephemeral Public | ✅ Safe | | Session Key | ❌ Encrypted | | Payload | ❌ Encrypted |
📄 License
MIT © 2024
Made with 🔐 for secure communications
