1use chacha20poly1305::aead::{rand_core::RngCore, OsRng};
2use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Error as CryptoError, Key, KeyInit, Nonce, Tag, XChaCha20Poly1305, XNonce};
3
4use crate::{ENCODED_PACKET_TAG_BYTES, NETCODE_MAC_BYTES};
5
6pub fn decode_and_check_buffer(buffer: &[u8], protocol_id: u64) -> Result<(), ()> {
7 let (_, buffer_tag) = buffer.split_at(buffer.len() - ENCODED_PACKET_TAG_BYTES);
8 let protocol_tag = u64::from_le_bytes(buffer_tag.try_into().unwrap());
9
10 if protocol_tag != protocol_id {
11 return Err(());
12 }
13
14 Ok(())
15}
16
17pub fn dencrypted_in_place(buffer: &mut [u8], sequence: u64, private_key: &[u8; 32], aad: &[u8]) -> Result<(), CryptoError> {
18 let mut nonce = [0; 12];
19 nonce[4..12].copy_from_slice(&sequence.to_le_bytes());
20 let nonce = Nonce::from(nonce);
21 let (buffer, tag) = buffer.split_at_mut(buffer.len() - NETCODE_MAC_BYTES);
22 let tag = Tag::from_slice(tag);
23
24 let key = Key::from_slice(private_key);
25 let cipher = ChaCha20Poly1305::new(key);
26
27 cipher.decrypt_in_place_detached(&nonce, aad, buffer, tag)
28}
29
30pub fn dencrypted_in_place_xnonce(buffer: &mut [u8], xnonce: &[u8; 24], private_key: &[u8; 32], aad: &[u8]) -> Result<(), CryptoError> {
31 let xnonce = XNonce::from_slice(xnonce);
32 let (buffer, tag) = buffer.split_at_mut(buffer.len() - NETCODE_MAC_BYTES);
33 let tag = Tag::from_slice(tag);
34
35 let key = Key::from_slice(private_key);
36 let cipher = XChaCha20Poly1305::new(key);
37
38 cipher.decrypt_in_place_detached(xnonce, aad, buffer, tag)
39}
40
41pub fn encode_in_place(buffer: &mut [u8], protocol_id: u64) {
42 let (_, buffer_tag) = buffer.split_at_mut(buffer.len() - ENCODED_PACKET_TAG_BYTES);
43 buffer_tag.copy_from_slice(&protocol_id.to_le_bytes());
44}
45
46pub fn encrypt_in_place(buffer: &mut [u8], sequence: u64, key: &[u8; 32], aad: &[u8]) -> Result<(), CryptoError> {
47 let mut nonce = [0; 12];
48 nonce[4..12].copy_from_slice(&sequence.to_le_bytes());
49 let nonce = Nonce::from(nonce);
50 let (buffer, buffer_tag) = buffer.split_at_mut(buffer.len() - NETCODE_MAC_BYTES);
51
52 let key = Key::from_slice(key);
53 let cipher = ChaCha20Poly1305::new(key);
54 let tag = cipher.encrypt_in_place_detached(&nonce, aad, buffer)?;
55 buffer_tag.copy_from_slice(&tag);
56
57 Ok(())
58}
59
60pub fn encrypt_in_place_xnonce(buffer: &mut [u8], xnonce: &[u8; 24], key: &[u8; 32], aad: &[u8]) -> Result<(), CryptoError> {
61 let (buffer, buffer_tag) = buffer.split_at_mut(buffer.len() - NETCODE_MAC_BYTES);
62
63 let xnonce = XNonce::from_slice(xnonce);
64 let key = Key::from_slice(key);
65 let cipher = XChaCha20Poly1305::new(key);
66 let tag = cipher.encrypt_in_place_detached(xnonce, aad, buffer)?;
67 buffer_tag.copy_from_slice(&tag);
68
69 Ok(())
70}
71
72pub fn generate_random_bytes<const N: usize>() -> [u8; N] {
77 let mut bytes = [0; N];
78 OsRng.fill_bytes(&mut bytes);
79 bytes
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_encode_decode_in_place() {
88 let protocol_id = 42;
89
90 let mut data = b"some packet data".to_vec();
91 let data_len = data.len();
92 data.extend_from_slice(&[0u8; ENCODED_PACKET_TAG_BYTES]);
93
94 encode_in_place(&mut data, protocol_id);
95 decode_and_check_buffer(&data, protocol_id).unwrap();
96 assert_eq!(&data[..data_len], b"some packet data");
97 }
98
99 #[test]
100 fn test_encrypt_decrypt_in_place() {
101 let key = b"an example very very secret key."; let sequence = 2;
103 let aad = b"test";
104
105 let mut data = b"some packet data".to_vec();
106 let data_len = data.len();
107 data.extend_from_slice(&[0u8; NETCODE_MAC_BYTES]);
108
109 encrypt_in_place(&mut data, sequence, key, aad).unwrap();
110 dencrypted_in_place(&mut data, sequence, key, aad).unwrap();
111 assert_eq!(&data[..data_len], b"some packet data");
112 }
113}