Encrypted, ephemeral, private memos on atproto
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(crypto): mitigate public key Uint8Array mutation

+54 -1
+3 -1
packages/crypto/src/encrypt.ts
··· 8 8 publicKey: Uint8Array, 9 9 text: string, 10 10 ): EncryptedPayload { 11 - const { cipherText, sharedSecret } = XWing.encapsulate(publicKey); 11 + // Create a copy of the public key to prevent mutation by XWing.encapsulate 12 + const publicKeyCopy = new Uint8Array(publicKey); 13 + const { cipherText, sharedSecret } = XWing.encapsulate(publicKeyCopy); 12 14 const nonce = randomBytes(24); 13 15 const contentBytes = new TextEncoder().encode(text); 14 16 const cipher = xchacha20poly1305(sharedSecret, nonce);
+51
packages/crypto/src/integration.test.ts
··· 1 + import { expect } from "@std/expect"; 2 + import { generateKeys } from "./keys.ts"; 3 + import { encryptText } from "./encrypt.ts"; 4 + import { decryptText } from "./decrypt.ts"; 5 + 6 + Deno.test({ 7 + name: "encrypts and decrypts multiple messages with the same keypair", 8 + fn() { 9 + const keys = generateKeys(); 10 + 11 + const text1 = "First message"; 12 + const text2 = "Second message"; 13 + const text3 = "Third message"; 14 + 15 + const encrypted1 = encryptText(keys.publicKey, text1); 16 + const encrypted2 = encryptText(keys.publicKey, text2); 17 + const encrypted3 = encryptText(keys.publicKey, text3); 18 + 19 + expect(encrypted1.content.length).toBeGreaterThan(0); 20 + expect(encrypted2.content.length).toBeGreaterThan(0); 21 + expect(encrypted3.content.length).toBeGreaterThan(0); 22 + 23 + const decrypted1 = decryptText(keys.secretKey, encrypted1); 24 + const decrypted2 = decryptText(keys.secretKey, encrypted2); 25 + const decrypted3 = decryptText(keys.secretKey, encrypted3); 26 + 27 + expect(decrypted1).toEqual(text1); 28 + expect(decrypted2).toEqual(text2); 29 + expect(decrypted3).toEqual(text3); 30 + }, 31 + }); 32 + 33 + Deno.test({ 34 + name: "encrypts messages with reused public key reference", 35 + fn() { 36 + const keys = generateKeys(); 37 + const publicKey = keys.publicKey; 38 + 39 + const encrypted1 = encryptText(publicKey, "Message 1"); 40 + const encrypted2 = encryptText(publicKey, "Message 2"); 41 + const encrypted3 = encryptText(publicKey, "Message 3"); 42 + 43 + expect(encrypted1.cipherText).not.toEqual(encrypted2.cipherText); 44 + expect(encrypted2.cipherText).not.toEqual(encrypted3.cipherText); 45 + expect(encrypted1.cipherText).not.toEqual(encrypted3.cipherText); 46 + 47 + expect(decryptText(keys.secretKey, encrypted1)).toEqual("Message 1"); 48 + expect(decryptText(keys.secretKey, encrypted2)).toEqual("Message 2"); 49 + expect(decryptText(keys.secretKey, encrypted3)).toEqual("Message 3"); 50 + }, 51 + });