Crypto in vc
This commit is contained in:
Generated
+137
-3
@@ -8,6 +8,16 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common 0.2.2",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.5"
|
version = "1.1.5"
|
||||||
@@ -319,6 +329,15 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
|
||||||
|
dependencies = [
|
||||||
|
"hybrid-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -508,6 +527,29 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures 0.3.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20poly1305"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b89e1c441e926b9c82a8d023f6e1b7ae0adcfaa7d621814e4d60789bac751cb"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"chacha20",
|
||||||
|
"cipher",
|
||||||
|
"poly1305",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.45"
|
version = "0.4.45"
|
||||||
@@ -520,6 +562,23 @@ dependencies = [
|
|||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer 0.12.1",
|
||||||
|
"crypto-common 0.2.2",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cmov"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -642,6 +701,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -676,6 +744,17 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.4.3",
|
||||||
|
"hybrid-array",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.36.0"
|
version = "0.36.0"
|
||||||
@@ -715,6 +794,15 @@ version = "0.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctutils"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
|
||||||
|
dependencies = [
|
||||||
|
"cmov",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.23.0"
|
version = "0.23.0"
|
||||||
@@ -833,8 +921,8 @@ version = "0.10.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer 0.10.4",
|
||||||
"crypto-common",
|
"crypto-common 0.1.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -994,6 +1082,7 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
|||||||
name = "enclave"
|
name = "enclave"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chacha20poly1305",
|
||||||
"cpal",
|
"cpal",
|
||||||
"ringbuf",
|
"ringbuf",
|
||||||
"rubato",
|
"rubato",
|
||||||
@@ -1392,6 +1481,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi 6.0.0",
|
"r-efi 6.0.0",
|
||||||
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1627,6 +1717,15 @@ version = "1.10.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hybrid-array"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
@@ -1846,6 +1945,15 @@ dependencies = [
|
|||||||
"cfb",
|
"cfb",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
|
||||||
|
dependencies = [
|
||||||
|
"hybrid-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.12.1"
|
version = "2.12.1"
|
||||||
@@ -2807,6 +2915,16 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "poly1305"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e2d0073b297041425c7c3df6eb4792d598a15323fe63346852b092eca02904c"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures 0.3.1",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
@@ -2944,6 +3062,12 @@ version = "6.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-handle"
|
name = "raw-window-handle"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -3398,7 +3522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures 0.2.17",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4396,6 +4520,16 @@ version = "1.13.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common 0.2.2",
|
||||||
|
"ctutils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.8"
|
version = "2.5.8"
|
||||||
|
|||||||
@@ -25,4 +25,5 @@ serde_json = "1"
|
|||||||
cpal = "0.18.2"
|
cpal = "0.18.2"
|
||||||
ringbuf = "0.5.1"
|
ringbuf = "0.5.1"
|
||||||
rubato = "5.0.0"
|
rubato = "5.0.0"
|
||||||
|
chacha20poly1305 = "0.11.0"
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use chacha20poly1305::{aead::KeyInit, ChaCha20Poly1305, Key};
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
use ringbuf::{
|
use ringbuf::{
|
||||||
storage::Heap,
|
storage::Heap,
|
||||||
@@ -17,11 +18,10 @@ use ringbuf::{
|
|||||||
};
|
};
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
use crate::commands::config::ConfigState;
|
use crate::{commands::config::ConfigState, crypto::SessionCipher};
|
||||||
|
|
||||||
const TARGET_SAMPLE_RATE: u32 = 48_000;
|
const TARGET_SAMPLE_RATE: u32 = 48_000;
|
||||||
const PACKET_SAMPLES: usize = 960; // 20ms @ 48kHz mono
|
const PACKET_SAMPLES: usize = 960;
|
||||||
const HEADER_SIZE: usize = 4;
|
|
||||||
const MAX_PACKET_SIZE: usize = 4096;
|
const MAX_PACKET_SIZE: usize = 4096;
|
||||||
|
|
||||||
const INITIAL_PACKET_CUSHION: usize = 3;
|
const INITIAL_PACKET_CUSHION: usize = 3;
|
||||||
@@ -345,11 +345,15 @@ pub fn disconnect_from_vc(voice_state: State<'_, VoiceState>) -> Result<(), Stri
|
|||||||
pub fn connect_to_vc(
|
pub fn connect_to_vc(
|
||||||
hostname: String,
|
hostname: String,
|
||||||
pin: u64,
|
pin: u64,
|
||||||
|
shared_secret: Vec<u8>, // output of js `x25519.getSharedSecret`
|
||||||
config_state: State<'_, ConfigState>,
|
config_state: State<'_, ConfigState>,
|
||||||
voice_state: State<'_, VoiceState>,
|
voice_state: State<'_, VoiceState>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
disconnect_from_vc(voice_state.clone())?;
|
disconnect_from_vc(voice_state.clone())?;
|
||||||
|
|
||||||
|
let key = Key::try_from(shared_secret.as_slice()).map_err(|v| v.to_string())?;
|
||||||
|
let cipher = Arc::new(Mutex::new(SessionCipher::new(ChaCha20Poly1305::new(&key))));
|
||||||
|
|
||||||
let config = config_state.0.lock().unwrap().clone();
|
let config = config_state.0.lock().unwrap().clone();
|
||||||
let state_inner = Arc::clone(&voice_state.inner);
|
let state_inner = Arc::clone(&voice_state.inner);
|
||||||
|
|
||||||
@@ -444,10 +448,10 @@ pub fn connect_to_vc(
|
|||||||
{
|
{
|
||||||
let input_socket = socket.clone();
|
let input_socket = socket.clone();
|
||||||
let shutdown = shutdown.clone();
|
let shutdown = shutdown.clone();
|
||||||
|
let cipher = cipher.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut sequence = 0u32;
|
let mut sequence = 0u32;
|
||||||
let mut net_packet = vec![0u8; HEADER_SIZE + PACKET_SAMPLES * 2];
|
|
||||||
let mut frame_buf = vec![0.0f32; PACKET_SAMPLES];
|
let mut frame_buf = vec![0.0f32; PACKET_SAMPLES];
|
||||||
let mut hangover_counter = 0;
|
let mut hangover_counter = 0;
|
||||||
|
|
||||||
@@ -469,13 +473,21 @@ pub fn connect_to_vc(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if is_speaking {
|
if is_speaking {
|
||||||
net_packet[0..4].copy_from_slice(&sequence.to_be_bytes());
|
// sequence goes INSIDE the plaintext now, prefixed before the PCM
|
||||||
for (i, sample) in frame_buf.iter().enumerate() {
|
let mut plaintext = Vec::with_capacity(4 + PACKET_SAMPLES * 2);
|
||||||
|
plaintext.extend_from_slice(&sequence.to_be_bytes());
|
||||||
|
|
||||||
|
for sample in frame_buf.iter() {
|
||||||
let pcm = (sample.clamp(-1.0, 1.0) * 32767.0) as i16;
|
let pcm = (sample.clamp(-1.0, 1.0) * 32767.0) as i16;
|
||||||
let offset = HEADER_SIZE + i * 2;
|
plaintext.extend_from_slice(&pcm.to_be_bytes());
|
||||||
net_packet[offset..offset + 2].copy_from_slice(&pcm.to_be_bytes());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Ok(net_packet) = cipher.lock().unwrap().encrypt(&plaintext) else {
|
||||||
|
eprintln!("[vc] failed to encrypt outgoing packet");
|
||||||
|
sequence = sequence.wrapping_add(1);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
let _ = input_socket.send(&net_packet);
|
let _ = input_socket.send(&net_packet);
|
||||||
sequence = sequence.wrapping_add(1);
|
sequence = sequence.wrapping_add(1);
|
||||||
}
|
}
|
||||||
@@ -490,6 +502,7 @@ pub fn connect_to_vc(
|
|||||||
{
|
{
|
||||||
let socket = socket.clone();
|
let socket = socket.clone();
|
||||||
let shutdown = shutdown.clone();
|
let shutdown = shutdown.clone();
|
||||||
|
let cipher = cipher.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut packets: BTreeMap<u32, Vec<f32>> = BTreeMap::new();
|
let mut packets: BTreeMap<u32, Vec<f32>> = BTreeMap::new();
|
||||||
@@ -501,15 +514,25 @@ pub fn connect_to_vc(
|
|||||||
|
|
||||||
while !shutdown.load(Ordering::Relaxed) {
|
while !shutdown.load(Ordering::Relaxed) {
|
||||||
if let Ok(len) = socket.recv(&mut udp_buffer) {
|
if let Ok(len) = socket.recv(&mut udp_buffer) {
|
||||||
if len > HEADER_SIZE {
|
match cipher.lock().unwrap().decrypt(&udp_buffer[..len]) {
|
||||||
let seq = u32::from_be_bytes(udp_buffer[0..4].try_into().unwrap());
|
Ok(plaintext) => {
|
||||||
let pcm = &udp_buffer[HEADER_SIZE..len];
|
if plaintext.len() < 4 {
|
||||||
let samples: Vec<f32> = pcm
|
eprintln!("[vc] dropped packet: too short after decrypt");
|
||||||
.chunks_exact(2)
|
} else {
|
||||||
.map(|c| i16::from_be_bytes([c[0], c[1]]) as f32 / 32768.0)
|
let seq = u32::from_be_bytes(plaintext[..4].try_into().unwrap());
|
||||||
.collect();
|
let pcm = &plaintext[4..];
|
||||||
|
|
||||||
packets.insert(seq, samples);
|
let samples: Vec<f32> = pcm
|
||||||
|
.chunks_exact(2)
|
||||||
|
.map(|c| i16::from_be_bytes([c[0], c[1]]) as f32 / 32768.0)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
packets.insert(seq, samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("[vc] dropped packet: decryption failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, Nonce};
|
||||||
|
|
||||||
|
pub struct SessionCipher {
|
||||||
|
cipher: ChaCha20Poly1305,
|
||||||
|
send_counter: u64,
|
||||||
|
recv_counter: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionCipher {
|
||||||
|
pub fn new(cipher: ChaCha20Poly1305) -> Self {
|
||||||
|
Self {
|
||||||
|
cipher,
|
||||||
|
send_counter: 0,
|
||||||
|
recv_counter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_send_nonce(&mut self) -> [u8; 12] {
|
||||||
|
let mut nonce = [0u8; 12];
|
||||||
|
nonce[..8].copy_from_slice(&self.send_counter.to_be_bytes());
|
||||||
|
// top bit distinguishes "send" direction from "recv" direction,
|
||||||
|
// so client-send and server-send counters never collide even if
|
||||||
|
// both happened to reach the same numeric value
|
||||||
|
nonce[11] |= 0b1000_0000;
|
||||||
|
self.send_counter += 1;
|
||||||
|
nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_recv_nonce(&mut self) -> [u8; 12] {
|
||||||
|
let mut nonce = [0u8; 12];
|
||||||
|
nonce[..8].copy_from_slice(&self.recv_counter.to_be_bytes());
|
||||||
|
self.recv_counter += 1;
|
||||||
|
nonce
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encrypt(&mut self, plaintext: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
|
let nonce_bytes = self.next_send_nonce();
|
||||||
|
let nonce = Nonce::try_from(nonce_bytes).map_err(|v| v.to_string())?;
|
||||||
|
|
||||||
|
let ciphertext = self
|
||||||
|
.cipher
|
||||||
|
.encrypt(&nonce, plaintext)
|
||||||
|
.map_err(|v| v.to_string())?;
|
||||||
|
|
||||||
|
// prepend the nonce so the other side can reconstruct it on decrypt
|
||||||
|
let mut out = nonce_bytes.to_vec();
|
||||||
|
out.extend(ciphertext);
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decrypt(&mut self, data: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
|
if data.len() < 12 {
|
||||||
|
return Err("message too short to contain a nonce".to_string());
|
||||||
|
}
|
||||||
|
let (nonce_bytes, ciphertext) = data.split_at(12);
|
||||||
|
let nonce = Nonce::try_from(nonce_bytes).map_err(|v| v.to_string())?;
|
||||||
|
|
||||||
|
self.cipher
|
||||||
|
.decrypt(&nonce, ciphertext)
|
||||||
|
.map_err(|v| v.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ use std::sync::Mutex;
|
|||||||
use crate::commands::config::ConfigState;
|
use crate::commands::config::ConfigState;
|
||||||
|
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
pub mod crypto;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
|
|||||||
+5
-1
@@ -171,7 +171,11 @@ export default class Enclave<P = Page> {
|
|||||||
if (!server || channel.kind !== "voice") return;
|
if (!server || channel.kind !== "voice") return;
|
||||||
|
|
||||||
server.voiceJoin = (pin, channelId) => {
|
server.voiceJoin = (pin, channelId) => {
|
||||||
invoke("connect_to_vc", { hostname: server.hostname, pin, channelId })
|
invoke("connect_to_vc", {
|
||||||
|
hostname: server.hostname,
|
||||||
|
pin,
|
||||||
|
sharedSecret: server.websocket?.sharedSecret,
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
server.isInVoiceChat = true;
|
server.isInVoiceChat = true;
|
||||||
server.voiceChannelId = channelId;
|
server.voiceChannelId = channelId;
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ export default class EnclaveWebSocket {
|
|||||||
|
|
||||||
private sendCounter = 0n;
|
private sendCounter = 0n;
|
||||||
private recvCounter = 0n;
|
private recvCounter = 0n;
|
||||||
private sharedSecret: Uint8Array | null = null;
|
public sharedSecret: Uint8Array | null = null;
|
||||||
|
|
||||||
private readonly handshakeReady: Promise<void>;
|
private readonly handshakeReady: Promise<void>;
|
||||||
private resolveHandshake!: () => void;
|
private resolveHandshake!: () => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user