diff --git a/src/app.js b/src/app.js index 09526ab..5c94c1e 100644 --- a/src/app.js +++ b/src/app.js @@ -51,11 +51,11 @@ io.on('connection', async (socket) => { socket.on('disconnect', () => { console.log('User disconnected'); }); - socket.on('chat message', async (msg, room) => { + socket.on('chat message', async (msg, room, tag, iv, nonce) => { const roomid = room.substring(5); const members = await database.getRoomMembers(roomid); members.forEach(memberRoom => { - socket.to(memberRoom).emit('chat message', msg, roomid, session.publicKey); + socket.to(memberRoom).emit('chat message', msg, roomid, tag, iv, nonce); }); console.log('message: ' + msg + ', sender: ' + session.id); console.log(session.publicKey); diff --git a/src/controllers/main.js b/src/controllers/main.js index bf3170f..c35956a 100644 --- a/src/controllers/main.js +++ b/src/controllers/main.js @@ -6,7 +6,8 @@ const mainController = { let pubKeyHex = req.session.publicKey; let isLoggedIn = typeof pubKeyHex !== 'undefined'; let pubKey = isLoggedIn ? stringutils.hexToPem(pubKeyHex).replaceAll('\n','') : null; - res.render('index', {isLoggedIn, pubKey}); + let hex = `key-${pubKeyHex}` + res.render('index', {isLoggedIn, pubKey, hex}); } }; diff --git a/src/public/chat.js b/src/public/chat.js index 10440d3..be33d8f 100644 --- a/src/public/chat.js +++ b/src/public/chat.js @@ -31,12 +31,16 @@ function init_ratchets(order, user_pubkey) { } -socket.on('chat message', (msg, room) => { +socket.on('chat message', (msg, room, tag_received, iv, nonce) => { console.log(`received: ${msg}`); - console.log(sharedsecret); - const item = document.createElement('li'); - item.textContent = msg; const messages = document.getElementById(`messages-${room}`); + const associated_data = fromHexString(Array.from((document.getElementById('pubkey')).classList).find(className => className.startsWith('key-')).replace('key-', '')); + const pubkey = Array.from(messages.classList).find(className => className.startsWith('key-')).replace('key-', ''); + const item = document.createElement('li'); + let {plaintext, tag} = decrypt_message(msg, pubkey, fromHexString(iv), fromHexString(nonce), associated_data); + item.textContent = plaintext + console.log(tag); + console.log(tag_received); messages.appendChild(item); window.scrollTo(0, document.body.scrollHeight); }); @@ -69,12 +73,55 @@ export function create_listener(form, input) { form.addEventListener('submit', function(e) { e.preventDefault(); if (input.value) { - socket.emit('chat message', input.value, form.id); + const pubkey = Array.from(form.classList).find(className => className.startsWith('key-')).replace('key-', ''); + let {cipher, tag, iv, nonce} = encrypt_message(input.value, pubkey) + socket.emit('chat message', cipher, form.id, tag, iv, nonce); input.value = ''; } }); } +function encrypt_message(message, user_pubkey) { + let encryption_key = sending_ratchets[user_pubkey].next(); + let encoded_msg = (new TextEncoder()).encode(message); + let iv = generateRandomUint8Array(); + let nonce = generateRandomUint8Array(); + let associated_data = fromHexString(user_pubkey); + let {cipher, tag} = keccakAEAD.encrypt(encryption_key, encoded_msg, iv, associated_data, nonce); + console.log(iv) + console.log(nonce) + console.log(associated_data) + console.log(encryption_key) + console.log(encoded_msg) + console.log(cipher) + return {cipher: toHexString(cipher), + tag: toHexString(tag), + iv: toHexString(iv), + nonce: toHexString(nonce) + }; +} + +function decrypt_message(cipher, user_pubkey, iv, nonce, associated_data) { + let decryption_key = receiving_ratchets[user_pubkey].next(); + let cipher_array = fromHexString(cipher); + let {plaintext, tag} = keccakAEAD.decrypt(decryption_key, cipher_array, iv, associated_data, nonce); + console.log(iv) + console.log(nonce) + console.log(associated_data) + console.log(decryption_key) + console.log(plaintext) + console.log(cipher_array) + return {plaintext: (new TextDecoder('utf-8')).decode(plaintext), + tag: toHexString(tag) + }; +} + +function generateRandomUint8Array(length = 16) { + const randomArray = new Uint8Array(length); + window.crypto.getRandomValues(randomArray); + return randomArray; +} + const fromHexString = (hexString) => Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))); diff --git a/src/public/kdf.js b/src/public/kdf.js index 4a57272..131daa5 100644 --- a/src/public/kdf.js +++ b/src/public/kdf.js @@ -2,7 +2,7 @@ import { concatUint8Arrays } from './arrayutils.js'; import { keccak } from './keccak.js'; class keccakKDF { - constructor(encryptionKeyLength = 32, privateKeyLength = 32) { + constructor(encryptionKeyLength = 16, privateKeyLength = 32) { this.encryptionKeyLength = encryptionKeyLength; this.privateKeyLength = privateKeyLength; } @@ -19,7 +19,7 @@ class keccakKDF { this.currentKey = initialKey; return this.kdf(salt); } - next(salt) { + next(salt=(new Uint8Array(0))) { if (!this.currentKey) throw new Error("KDF not initialized"); return this.kdf(salt); } diff --git a/src/public/rooms.js b/src/public/rooms.js index f24326d..2f67363 100644 --- a/src/public/rooms.js +++ b/src/public/rooms.js @@ -18,6 +18,7 @@ function render_rooms(room_info) { roomDiv.classList.add(`key-${pubkey}`); const messagesUl = document.createElement('ul'); messagesUl.id = `messages-${roomId}`; + messagesUl.classList.add(`key-${pubkey}`); const form = document.createElement('form'); form.id = `form-${roomId}`; form.classList.add(`key-${pubkey}`); diff --git a/src/views/index.pug b/src/views/index.pug index 69e1a9f..928fcd1 100644 --- a/src/views/index.pug +++ b/src/views/index.pug @@ -57,7 +57,7 @@ html(lang="en-US") .d-flex.mb-3 - input#pubkey.form-control(type="text", value=pubKey, readonly, style="border-right: 0;") + input#pubkey.form-control(type="text", value=pubKey, class=hex, readonly, style="border-right: 0;") button#copyPubKey.btn.btn-outline-secondary(type="button") Copy #rooms