36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
import nacl from 'tweetnacl'
|
|
|
|
export type E2EEState = {
|
|
sharedKey: Uint8Array
|
|
deviceToken: string | null
|
|
authenticated: boolean
|
|
}
|
|
|
|
export function deriveSharedKey(ourSecret: Uint8Array, peerPublic: Uint8Array): Uint8Array {
|
|
return nacl.box.before(peerPublic, ourSecret)
|
|
}
|
|
|
|
export function e2eeEncrypt(plaintext: string, sharedKey: Uint8Array): string {
|
|
const nonce = nacl.randomBytes(nacl.box.nonceLength)
|
|
const msg = new TextEncoder().encode(plaintext)
|
|
const ciphertext = nacl.box.after(msg, nonce, sharedKey)
|
|
const bundle = new Uint8Array(nonce.length + ciphertext.length)
|
|
bundle.set(nonce)
|
|
bundle.set(ciphertext, nonce.length)
|
|
return Buffer.from(bundle).toString('base64')
|
|
}
|
|
|
|
export function e2eeDecrypt(encrypted: string, sharedKey: Uint8Array): string | null {
|
|
const bundle = Uint8Array.from(Buffer.from(encrypted, 'base64'))
|
|
if (bundle.length < nacl.box.nonceLength + nacl.box.overheadLength) {
|
|
return null
|
|
}
|
|
const nonce = bundle.slice(0, nacl.box.nonceLength)
|
|
const ciphertext = bundle.slice(nacl.box.nonceLength)
|
|
const plaintext = nacl.box.open.after(ciphertext, nonce, sharedKey)
|
|
if (!plaintext) {
|
|
return null
|
|
}
|
|
return new TextDecoder().decode(plaintext)
|
|
}
|