portal_lib/protocol/
encrypted.rs1use crate::errors::PortalError::*;
2use serde::{Deserialize, Serialize};
3use std::convert::TryInto;
4use std::error::Error;
5
6use rand::Rng;
8
9#[cfg(not(feature = "ring-backend"))]
11use chacha20poly1305::{aead::AeadInPlace, aead::NewAead, ChaCha20Poly1305, Key, Nonce, Tag};
12
13#[cfg(feature = "ring-backend")]
14use ring::aead::{Aad, LessSafeKey, Nonce, Tag, UnboundKey, CHACHA20_POLY1305};
15
16const NONCE_SIZE: usize = 12;
18const TAG_SIZE: usize = 16;
19
20#[derive(PartialEq, Eq, Debug)]
24pub struct NonceSequence([u8; TAG_SIZE]);
25
26#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)]
28pub struct EncryptedMessage {
29 pub nonce: [u8; NONCE_SIZE],
31 pub tag: [u8; TAG_SIZE],
33 pub len: usize,
36}
37
38#[cfg(not(feature = "ring-backend"))]
39impl EncryptedMessage {
40 pub fn encrypt(
43 key: &[u8],
44 nseq: &mut NonceSequence,
45 data: &mut [u8],
46 ) -> Result<Self, Box<dyn Error>> {
47 let mut state = Self {
49 nonce: nseq.next_unique()?,
50 ..Default::default()
51 };
52
53 let nonce = Nonce::from_slice(&state.nonce);
55
56 let cha_key = Key::from_slice(key);
58 let cipher = ChaCha20Poly1305::new(cha_key);
59
60 state.len = data.len();
62
63 let tag = cipher
65 .encrypt_in_place_detached(nonce, b"", data)
66 .or(Err(EncryptError))?;
67
68 state.tag = tag.into();
70 Ok(state)
71 }
72
73 pub fn decrypt(&mut self, key: &[u8], data: &mut [u8]) -> Result<usize, Box<dyn Error>> {
75 let cha_key = Key::from_slice(key);
77 let cipher = ChaCha20Poly1305::new(cha_key);
78
79 let nonce = Nonce::from_slice(&self.nonce);
81 let tag = Tag::from_slice(&self.tag);
82
83 cipher
85 .decrypt_in_place_detached(nonce, b"", data, tag)
86 .or(Err(DecryptError))?;
87
88 Ok(data.len())
89 }
90}
91
92#[cfg(feature = "ring-backend")]
93impl EncryptedMessage {
94 pub fn encrypt(
97 key: &[u8],
98 nseq: &mut NonceSequence,
99 data: &mut [u8],
100 ) -> Result<Self, Box<dyn Error>> {
101 let mut state = Self::default();
103
104 let ring_key_chacha20 =
106 LessSafeKey::new(UnboundKey::new(&CHACHA20_POLY1305, key).or(Err(CryptoError))?);
107
108 state.nonce = nseq.next()?;
110 let ring_nonce = Nonce::assume_unique_for_key(state.nonce);
111
112 state.len = data.len();
114
115 let tag = ring_key_chacha20
117 .seal_in_place_separate_tag(ring_nonce, Aad::empty(), data)
118 .or(Err(EncryptError))?;
119
120 state.tag = tag.as_ref().try_into().or(Err(EncryptError))?;
122 Ok(state)
123 }
124
125 pub fn decrypt(&mut self, key: &[u8], data: &mut [u8]) -> Result<usize, Box<dyn Error>> {
127 let ring_key_chacha20 =
129 LessSafeKey::new(UnboundKey::new(&CHACHA20_POLY1305, key).or(Err(CryptoError))?);
130
131 let ring_tag: Tag = self.tag.try_into().or(Err(DecryptError))?;
133 let ring_nonce = Nonce::assume_unique_for_key(self.nonce);
134
135 ring_key_chacha20
137 .open_in_place_separate_tag(ring_nonce, Aad::empty(), ring_tag, data, 0..)
138 .or(Err(DecryptError))?;
139
140 Ok(data.len())
141 }
142}
143
144impl Default for NonceSequence {
145 fn default() -> Self {
146 Self::new()
147 }
148}
149
150impl NonceSequence {
151 pub fn new() -> Self {
153 let mut rng = rand::thread_rng();
154 Self(rng.gen::<[u8; 16]>())
155 }
156
157 pub fn next_unique(&mut self) -> Result<[u8; NONCE_SIZE], Box<dyn Error>> {
160 let old = self.0;
162
163 let new = u128::from_be_bytes(self.0).wrapping_shr(32);
165 self.0 = new.wrapping_add(1).wrapping_shl(32).to_be_bytes();
166
167 Ok(old[..NONCE_SIZE].try_into().or(Err(CryptoError))?)
169 }
170}