encrypt and decrypt messages in browser
This commit is contained in:
parent
744e1fae29
commit
b7907c94ae
@ -51,11 +51,11 @@ io.on('connection', async (socket) => {
|
|||||||
socket.on('disconnect', () => {
|
socket.on('disconnect', () => {
|
||||||
console.log('User disconnected');
|
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 roomid = room.substring(5);
|
||||||
const members = await database.getRoomMembers(roomid);
|
const members = await database.getRoomMembers(roomid);
|
||||||
members.forEach(memberRoom => {
|
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('message: ' + msg + ', sender: ' + session.id);
|
||||||
console.log(session.publicKey);
|
console.log(session.publicKey);
|
||||||
|
@ -6,7 +6,8 @@ const mainController = {
|
|||||||
let pubKeyHex = req.session.publicKey;
|
let pubKeyHex = req.session.publicKey;
|
||||||
let isLoggedIn = typeof pubKeyHex !== 'undefined';
|
let isLoggedIn = typeof pubKeyHex !== 'undefined';
|
||||||
let pubKey = isLoggedIn ? stringutils.hexToPem(pubKeyHex).replaceAll('\n','') : null;
|
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(`received: ${msg}`);
|
||||||
console.log(sharedsecret);
|
|
||||||
const item = document.createElement('li');
|
|
||||||
item.textContent = msg;
|
|
||||||
const messages = document.getElementById(`messages-${room}`);
|
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);
|
messages.appendChild(item);
|
||||||
window.scrollTo(0, document.body.scrollHeight);
|
window.scrollTo(0, document.body.scrollHeight);
|
||||||
});
|
});
|
||||||
@ -69,12 +73,55 @@ export function create_listener(form, input) {
|
|||||||
form.addEventListener('submit', function(e) {
|
form.addEventListener('submit', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (input.value) {
|
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 = '';
|
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) =>
|
const fromHexString = (hexString) =>
|
||||||
Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
|
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';
|
import { keccak } from './keccak.js';
|
||||||
|
|
||||||
class keccakKDF {
|
class keccakKDF {
|
||||||
constructor(encryptionKeyLength = 32, privateKeyLength = 32) {
|
constructor(encryptionKeyLength = 16, privateKeyLength = 32) {
|
||||||
this.encryptionKeyLength = encryptionKeyLength;
|
this.encryptionKeyLength = encryptionKeyLength;
|
||||||
this.privateKeyLength = privateKeyLength;
|
this.privateKeyLength = privateKeyLength;
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ class keccakKDF {
|
|||||||
this.currentKey = initialKey;
|
this.currentKey = initialKey;
|
||||||
return this.kdf(salt);
|
return this.kdf(salt);
|
||||||
}
|
}
|
||||||
next(salt) {
|
next(salt=(new Uint8Array(0))) {
|
||||||
if (!this.currentKey) throw new Error("KDF not initialized");
|
if (!this.currentKey) throw new Error("KDF not initialized");
|
||||||
return this.kdf(salt);
|
return this.kdf(salt);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ function render_rooms(room_info) {
|
|||||||
roomDiv.classList.add(`key-${pubkey}`);
|
roomDiv.classList.add(`key-${pubkey}`);
|
||||||
const messagesUl = document.createElement('ul');
|
const messagesUl = document.createElement('ul');
|
||||||
messagesUl.id = `messages-${roomId}`;
|
messagesUl.id = `messages-${roomId}`;
|
||||||
|
messagesUl.classList.add(`key-${pubkey}`);
|
||||||
const form = document.createElement('form');
|
const form = document.createElement('form');
|
||||||
form.id = `form-${roomId}`;
|
form.id = `form-${roomId}`;
|
||||||
form.classList.add(`key-${pubkey}`);
|
form.classList.add(`key-${pubkey}`);
|
||||||
|
@ -57,7 +57,7 @@ html(lang="en-US")
|
|||||||
|
|
||||||
|
|
||||||
.d-flex.mb-3
|
.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
|
button#copyPubKey.btn.btn-outline-secondary(type="button") Copy
|
||||||
|
|
||||||
#rooms
|
#rooms
|
||||||
|
Loading…
x
Reference in New Issue
Block a user