encrypt and decrypt messages in browser
This commit is contained in:
		| @@ -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); | ||||
|   | ||||
| @@ -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}); | ||||
|     } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -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))); | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|   | ||||
| @@ -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}`); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user