1 use crate::errors::*;
2 
3 use libsodium_sys::*;
4 use siphasher::sip::SipHasher13;
5 use std::ffi::CStr;
6 use std::hash::Hasher;
7 use std::ptr;
8 
9 #[derive(Derivative)]
10 #[derivative(Default)]
11 pub struct Signature(
12     #[derivative(Default(value = "[0u8; crypto_sign_BYTES as usize]"))]
13     [u8; crypto_sign_BYTES as usize],
14 );
15 
16 impl Signature {
as_bytes(&self) -> &[u8; crypto_sign_BYTES as usize]17     pub fn as_bytes(&self) -> &[u8; crypto_sign_BYTES as usize] {
18         &self.0
19     }
20 
from_bytes(bytes: [u8; crypto_sign_BYTES as usize]) -> Self21     pub fn from_bytes(bytes: [u8; crypto_sign_BYTES as usize]) -> Self {
22         Signature(bytes)
23     }
24 }
25 
26 big_array! { BigArray; crypto_sign_SECRETKEYBYTES as usize }
27 
28 #[derive(Serialize, Deserialize, Derivative, Clone)]
29 #[derivative(Default)]
30 pub struct SignSK(
31     #[serde(with = "BigArray")]
32     #[derivative(Default(value = "[0u8; crypto_sign_SECRETKEYBYTES as usize]"))]
33     [u8; crypto_sign_SECRETKEYBYTES as usize],
34 );
35 
36 impl SignSK {
as_bytes(&self) -> &[u8; crypto_sign_SECRETKEYBYTES as usize]37     pub fn as_bytes(&self) -> &[u8; crypto_sign_SECRETKEYBYTES as usize] {
38         &self.0
39     }
40 
from_bytes(bytes: [u8; crypto_sign_SECRETKEYBYTES as usize]) -> Self41     pub fn from_bytes(bytes: [u8; crypto_sign_SECRETKEYBYTES as usize]) -> Self {
42         SignSK(bytes)
43     }
44 
sign(&self, bytes: &[u8]) -> Signature45     pub fn sign(&self, bytes: &[u8]) -> Signature {
46         let mut signature = Signature::default();
47         let ret = unsafe {
48             crypto_sign_detached(
49                 signature.0.as_mut_ptr(),
50                 ptr::null_mut(),
51                 bytes.as_ptr(),
52                 bytes.len() as _,
53                 self.as_bytes().as_ptr(),
54             )
55         };
56         assert_eq!(ret, 0);
57         signature
58     }
59 }
60 
61 #[derive(Debug, Serialize, Deserialize, Default, Clone)]
62 pub struct SignPK([u8; crypto_sign_PUBLICKEYBYTES as usize]);
63 
64 impl SignPK {
as_bytes(&self) -> &[u8; crypto_sign_PUBLICKEYBYTES as usize]65     pub fn as_bytes(&self) -> &[u8; crypto_sign_PUBLICKEYBYTES as usize] {
66         &self.0
67     }
68 
from_bytes(bytes: [u8; crypto_sign_PUBLICKEYBYTES as usize]) -> Self69     pub fn from_bytes(bytes: [u8; crypto_sign_PUBLICKEYBYTES as usize]) -> Self {
70         SignPK(bytes)
71     }
72 
as_string(&self) -> String73     pub fn as_string(&self) -> String {
74         bin2hex(self.as_bytes())
75     }
76 }
77 
78 #[derive(Derivative, Serialize, Deserialize, Clone)]
79 #[derivative(Debug, Default)]
80 pub struct SignKeyPair {
81     #[derivative(Debug = "ignore")]
82     pub sk: SignSK,
83     pub pk: SignPK,
84 }
85 
86 impl SignKeyPair {
new() -> Self87     pub fn new() -> Self {
88         let mut kp = SignKeyPair::default();
89         unsafe { crypto_sign_keypair(kp.pk.0.as_mut_ptr(), kp.sk.0.as_mut_ptr()) };
90         kp
91     }
92 }
93 
94 #[derive(Debug, Default, Clone, Serialize, Deserialize)]
95 pub struct CryptSK([u8; crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES as usize]);
96 
97 impl CryptSK {
as_bytes( &self, ) -> &[u8; crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES as usize]98     pub fn as_bytes(
99         &self,
100     ) -> &[u8; crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES as usize] {
101         &self.0
102     }
103 
from_bytes( bytes: [u8; crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES as usize], ) -> Self104     pub fn from_bytes(
105         bytes: [u8; crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES as usize],
106     ) -> Self {
107         CryptSK(bytes)
108     }
109 }
110 
111 #[derive(Debug, Default, Clone, Serialize, Deserialize)]
112 pub struct CryptPK([u8; crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES as usize]);
113 
114 impl CryptPK {
as_bytes( &self, ) -> &[u8; crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES as usize]115     pub fn as_bytes(
116         &self,
117     ) -> &[u8; crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES as usize] {
118         &self.0
119     }
120 
from_bytes( bytes: [u8; crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES as usize], ) -> Self121     pub fn from_bytes(
122         bytes: [u8; crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES as usize],
123     ) -> Self {
124         CryptPK(bytes)
125     }
126 }
127 
128 #[derive(Debug, Default, Clone, Serialize, Deserialize)]
129 pub struct CryptKeyPair {
130     pub sk: CryptSK,
131     pub pk: CryptPK,
132 }
133 
134 impl CryptKeyPair {
from_seed( seed: [u8; crypto_box_curve25519xchacha20poly1305_SEEDBYTES as usize], ) -> Self135     pub fn from_seed(
136         seed: [u8; crypto_box_curve25519xchacha20poly1305_SEEDBYTES as usize],
137     ) -> Self {
138         let mut kp = CryptKeyPair::default();
139         unsafe {
140             crypto_box_curve25519xchacha20poly1305_seed_keypair(
141                 kp.pk.0.as_mut_ptr(),
142                 kp.sk.0.as_mut_ptr(),
143                 seed.as_ptr(),
144             )
145         };
146         kp
147     }
148 
compute_shared_key(&self, pk: &[u8]) -> Result<SharedKey, Error>149     pub fn compute_shared_key(&self, pk: &[u8]) -> Result<SharedKey, Error> {
150         let mut shared_key = SharedKey::default();
151         let res = unsafe {
152             crypto_box_curve25519xchacha20poly1305_beforenm(
153                 shared_key.0.as_mut_ptr(),
154                 pk.as_ptr(),
155                 self.sk.0.as_ptr(),
156             )
157         };
158         ensure!(res == 0, "Weak public key");
159         Ok(shared_key)
160     }
161 }
162 
163 #[derive(Debug, Clone, Default)]
164 pub struct SharedKey([u8; crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES as usize]);
165 
166 impl SharedKey {
decrypt(&self, nonce: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error>167     pub fn decrypt(&self, nonce: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
168         let encrypted_len = encrypted.len();
169         let mut decrypted =
170             vec![0u8; encrypted_len - crypto_box_curve25519xchacha20poly1305_MACBYTES as usize];
171         let res = unsafe {
172             libsodium_sys::crypto_box_curve25519xchacha20poly1305_open_easy_afternm(
173                 decrypted.as_mut_ptr(),
174                 encrypted.as_ptr(),
175                 encrypted_len as _,
176                 nonce.as_ptr(),
177                 self.0.as_ptr(),
178             )
179         };
180         ensure!(res == 0, "Unable to decrypt");
181         let idx = decrypted
182             .iter()
183             .rposition(|x| *x != 0x00)
184             .ok_or_else(|| anyhow!("Padding error"))?;
185         ensure!(decrypted[idx] == 0x80, "Padding error");
186         decrypted.truncate(idx);
187         Ok(decrypted)
188     }
189 
encrypt_into( &self, target: &mut Vec<u8>, nonce: &[u8], client_nonce: &[u8], plaintext: Vec<u8>, max_target_size: usize, ) -> Result<(), Error>190     pub fn encrypt_into(
191         &self,
192         target: &mut Vec<u8>,
193         nonce: &[u8],
194         client_nonce: &[u8],
195         plaintext: Vec<u8>,
196         max_target_size: usize,
197     ) -> Result<(), Error> {
198         ensure!(
199             max_target_size >= crypto_box_curve25519xchacha20poly1305_MACBYTES as usize,
200             "Max target size too small"
201         );
202         let plaintext_len = plaintext.len();
203         let max_padded_plaintext_len =
204             max_target_size - crypto_box_curve25519xchacha20poly1305_MACBYTES as usize;
205         let mut hasher = SipHasher13::new();
206         hasher.write(&self.0);
207         hasher.write(client_nonce);
208         let pad_size: usize = 1 + (hasher.finish() as usize & 0xff);
209         let mut padded_plaintext_len = (plaintext_len + pad_size) & !63;
210         if padded_plaintext_len < plaintext_len {
211             padded_plaintext_len += 256;
212         }
213         if padded_plaintext_len > max_padded_plaintext_len {
214             padded_plaintext_len = max_padded_plaintext_len;
215         }
216         ensure!(padded_plaintext_len > plaintext_len, "No room for padding");
217         let mut padded_plaintext = plaintext;
218         padded_plaintext.push(0x80);
219         while padded_plaintext.len() != padded_plaintext_len {
220             padded_plaintext.push(0x00);
221         }
222         let padded_plaintext_len = padded_plaintext.len();
223         let target_header_len = target.len();
224         target.resize(
225             target_header_len
226                 + padded_plaintext_len
227                 + crypto_box_curve25519xchacha20poly1305_MACBYTES as usize,
228             0,
229         );
230         let encrypted = &mut target[target_header_len..];
231         let res = unsafe {
232             libsodium_sys::crypto_box_curve25519xchacha20poly1305_easy_afternm(
233                 encrypted.as_mut_ptr(),
234                 padded_plaintext.as_ptr(),
235                 padded_plaintext_len as _,
236                 nonce.as_ptr(),
237                 self.0.as_ptr(),
238             )
239         };
240         ensure!(res == 0, "Unable to encrypt");
241         Ok(())
242     }
243 }
244 
bin2hex(bin: &[u8]) -> String245 pub fn bin2hex(bin: &[u8]) -> String {
246     let bin_len = bin.len();
247     let hex_len = bin_len * 2 + 1;
248     let mut hex = vec![0u8; hex_len];
249     unsafe {
250         sodium_bin2hex(hex.as_mut_ptr() as *mut _, hex_len, bin.as_ptr(), bin_len);
251     }
252     CStr::from_bytes_with_nul(&hex)
253         .unwrap()
254         .to_str()
255         .unwrap()
256         .to_string()
257 }
258 
init() -> Result<(), Error>259 pub fn init() -> Result<(), Error> {
260     let res = unsafe { sodium_init() };
261     ensure!(res >= 0, "Unable to initialize libsodium");
262     Ok(())
263 }
264