diff options
author | metamuffin <metamuffin@disroot.org> | 2022-09-09 11:42:06 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-09-09 11:42:06 +0200 |
commit | b6d93e0f322901dfc1fee23f3d396a68e61e1b29 (patch) | |
tree | 01ba855cf41fb53f84cd6eb504c4f4ba0134fdfa /client-web/source/protocol | |
parent | afed94bb4609bd796102c9184f13fa29c5f92a48 (diff) | |
download | keks-meet-b6d93e0f322901dfc1fee23f3d396a68e61e1b29.tar keks-meet-b6d93e0f322901dfc1fee23f3d396a68e61e1b29.tar.bz2 keks-meet-b6d93e0f322901dfc1fee23f3d396a68e61e1b29.tar.zst |
crypto stuff
Diffstat (limited to 'client-web/source/protocol')
-rw-r--r-- | client-web/source/protocol/crypto.ts | 80 | ||||
-rw-r--r-- | client-web/source/protocol/mod.ts | 15 |
2 files changed, 93 insertions, 2 deletions
diff --git a/client-web/source/protocol/crypto.ts b/client-web/source/protocol/crypto.ts new file mode 100644 index 0000000..6cd2ba3 --- /dev/null +++ b/client-web/source/protocol/crypto.ts @@ -0,0 +1,80 @@ +import { log } from "../logger.ts"; + +//! I am not a crypto expert at all! Please read carefully and report any issues to me. + +export async function crypto_seeded_key(seed: string): Promise<CryptoKey> { + log("crypto", "importing seed…") + const seed_key = await window.crypto.subtle.importKey( + "raw", + new TextEncoder().encode(seed), + "PBKDF2", + false, + ["deriveKey"] + ) + //? TODO is it possible to use a unique seed per session here? + // const salt = window.crypto.getRandomValues(new Uint8Array(16)); + const salt = base64_to_buf("thisisagoodsaltAAAAAAA==") // valid "unique" 16-byte base-64 string + log("crypto", "deriving key…") + const key = await window.crypto.subtle.deriveKey( + { + name: "PBKDF2", + salt, + iterations: 250000, + hash: "SHA-256", + }, + seed_key, + { name: "AES-GCM", length: 256 }, + false, + ["encrypt", "decrypt"] + ) + console.log(key); + log("crypto", "ready") + return key +} + +export async function crypto_encrypt(key: CryptoKey, data: string): Promise<string> { + const iv = window.crypto.getRandomValues(new Uint8Array(12)); + const ciphertext = new Uint8Array(await window.crypto.subtle.encrypt( + { name: "AES-GCM", iv }, + key, + new TextEncoder().encode(data) + )); + const buf = new Uint8Array(iv.byteLength + ciphertext.byteLength); + buf.set(iv, 0); + buf.set(ciphertext, iv.byteLength); + const b64 = buf_to_base64(buf); + return b64; +} + +export async function crypt_decrypt(key: CryptoKey, data: string): Promise<string> { + const buf = base64_to_buf(data); + const iv = buf.slice(0, 12); + const ciphertext = buf.slice(12); + const decryptedContent = await window.crypto.subtle.decrypt( + { name: "AES-GCM", iv }, + key, + ciphertext + ); + const plain = new TextDecoder().decode(decryptedContent); + return plain +} + +// const buf_to_base64 = (buf: Uint8Array) => btoa(String.fromCharCode.apply(null, buf)); +// const base64_to_buf = (b64: string) => Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)); + +export function base64_to_buf(data: string): Uint8Array { + const binary_string = globalThis.atob(data); + const bytes = new Uint8Array(binary_string.length); + for (let i = 0; i < binary_string.length; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; +} + +export function buf_to_base64(bytes: Uint8Array): string { + let binary = ''; + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]); + } + return globalThis.btoa(binary); +}
\ No newline at end of file diff --git a/client-web/source/protocol/mod.ts b/client-web/source/protocol/mod.ts index 76b1290..f86e96f 100644 --- a/client-web/source/protocol/mod.ts +++ b/client-web/source/protocol/mod.ts @@ -1,6 +1,17 @@ +import { crypto_seeded_key } from "./crypto.ts" export class SignalingConnection { - constructor(room: string) { - + room!: string + websocket!: WebSocket + signaling_id!: string + key!: CryptoKey + + constructor() { } + async connect(room: string): Promise<SignalingConnection> { + this.key = await crypto_seeded_key(room) + const ws_url = new URL(`${window.location.protocol.endsWith("s:") ? "wss" : "ws"}://${window.location.host}/signaling/${encodeURIComponent(this.signaling_id)}`) + this.websocket = new WebSocket(ws_url) + await new Promise(r => this.websocket!.onopen = r) + return this } } |