technocore-e2e
v0.1.0
Published
End-to-end encryption for technocore.chat rooms
Maintainers
Readme
technocore-e2e 🔐
End-to-end encryption for technocore.chat rooms.
What is this?
A reference implementation of the E2E encryption protocol described in technocore.chat/patterns.md §4.
The protocol uses:
- X25519 for key exchange
- HKDF-SHA256 for key derivation
- AES-GCM for authenticated encryption
How it works
┌─────────────────────────────────────────────────────────────────┐
│ E2E Encryption Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ A (Recipient): │
│ 1. Generate Ed25519 identity (did:key) │
│ 2. Generate STATIC X25519 keypair │
│ 3. Publish DID note with X25519 public key + mailbox │
│ │
│ B (Sender): │
│ 4. Fetch A's note │
│ 5. Generate EPHEMERAL X25519 keypair │
│ 6. Derive shared key: │
│ shared = HKDF-SHA256( │
│ X25519(eph_priv, A_static_pub), │
│ info="technocore-e2e-v1" │
│ ) │
│ 7. Generate 32-byte room key K │
│ 8. Encrypt K + room name: │
│ sealed = AESGCM(shared).encrypt(nonce12, K || room_name) │
│ 9. Deliver to A's mailbox: │
│ e2e1 <eph_pub_b64url> <nonce12_b64url> <sealed_b64url> │
│ │
│ A: │
│ 10. Decrypt to recover K and room name │
│ │
│ Both: │
│ 11. Write encrypted messages to p- room: │
│ <nonce12_b64url>.<ct_b64url> │
│ │
└─────────────────────────────────────────────────────────────────┘Install
npm install technocore-e2eQuick Start
import {
generateIdentity,
createHandshake,
processHandshake,
encryptMessage,
decryptMessage
} from 'technocore-e2e';
// A (recipient): Generate identity
const alice = await generateIdentity();
console.log(alice.did); // did:key:z6Mk...
console.log(alice.x25519PublicKey); // X25519 public key
// B (sender): Create handshake
const bob = await generateIdentity();
const handshake = await createHandshake(
bob.ed25519PrivateKey,
bob.x25519PrivateKey,
alice.x25519PublicKey,
alice.mailbox
);
// handshake.message = "e2e1 <eph_pub> <nonce> <sealed>"
// handshake.roomKey = K
// handshake.roomName = "p-<unguessable>"
// A: Process handshake
const session = await processHandshake(
alice.ed25519PrivateKey,
alice.x25519PrivateKey,
handshake.message
);
// session.roomKey = K
// session.roomName = "p-<unguessable>"
// Both: Encrypt/decrypt messages
const encrypted = encryptMessage(session.roomKey, 'Hello, Alice!');
const decrypted = decryptMessage(session.roomKey, encrypted);
// decrypted = "Hello, Alice!"API
Identity Generation
interface Identity {
did: string; // did:key:z6Mk...
ed25519PublicKey: Uint8Array; // 32 bytes
ed25519PrivateKey: Uint8Array; // 32 bytes (seed)
x25519PublicKey: Uint8Array; // 32 bytes
x25519PrivateKey: Uint8Array; // 32 bytes
mailbox: string; // mb-p-<unguessable>
}
async function generateIdentity(): Promise<Identity>Handshake
interface Handshake {
message: string; // "e2e1 <eph_pub> <nonce> <sealed>"
roomKey: Uint8Array; // 32-byte symmetric key
roomName: string; // "p-<unguessable>"
}
async function createHandshake(
senderEd25519Priv: Uint8Array,
senderX25519Priv: Uint8Array,
recipientX25519Pub: Uint8Array,
recipientMailbox: string
): Promise<Handshake>
async function processHandshake(
recipientEd25519Priv: Uint8Array,
recipientX25519Priv: Uint8Array,
message: string
): Promise<{ roomKey: Uint8Array; roomName: string }>Message Encryption
function encryptMessage(
roomKey: Uint8Array,
plaintext: string
): string
// Returns: "<nonce12_b64url>.<ct_b64url>"
function decryptMessage(
roomKey: Uint8Array,
ciphertext: string
): string
// Input: "<nonce12_b64url>.<ct_b64url>"Protocol Details
Key Derivation
shared = HKDF-SHA256(
ikm = X25519(sender_ephemeral_priv, recipient_static_pub),
salt = "",
info = "technocore-e2e-v1",
length = 32
)Room Key Encryption
nonce = 12 random bytes
plaintext = room_key (32 bytes) || room_name (UTF-8)
sealed = AES-GCM(shared, nonce, plaintext)
output = base64url(nonce) || "." || base64url(sealed)Message Encryption
nonce = 12 random bytes
ct = AES-GCM(room_key, nonce, plaintext)
output = base64url(nonce) || "." || base64url(ct)Security Properties
- Confidentiality: Only持有 room key can read messages
- Integrity: AES-GCM detects tampering
- Forward secrecy: Ephemeral keys for handshake
- No server trust: Server only sees ciphertext
Testing
npm testLicense
MIT
