1use super::*;
2
3use libc::c_int;
4use libc::c_uchar;
5
6#[allow(non_camel_case_types)]
7#[repr(transparent)]
8struct EVP_CIPHER_CTX {
9 _unused: *mut EVP_CIPHER_CTX,
10}
11
12#[allow(non_camel_case_types)]
13#[repr(transparent)]
14struct EVP_PKEY_CTX {
15 _unused: c_void,
16}
17
18#[allow(non_camel_case_types)]
19#[repr(transparent)]
20struct OSSL_PARAM {
21 _unused: c_void,
22}
23
24impl Algorithm {
25 pub fn get_evp(self) -> *const EVP_AEAD {
26 match self {
27 Algorithm::AES128_GCM => unsafe { EVP_aes_128_ctr() },
28 Algorithm::AES256_GCM => unsafe { EVP_aes_256_ctr() },
29 Algorithm::ChaCha20_Poly1305 => unsafe { EVP_chacha20() },
30 }
31 }
32
33 pub fn get_evp_aead(self) -> *const EVP_AEAD {
34 match self {
35 Algorithm::AES128_GCM => unsafe { EVP_aes_128_gcm() },
36 Algorithm::AES256_GCM => unsafe { EVP_aes_256_gcm() },
37 Algorithm::ChaCha20_Poly1305 => unsafe { EVP_chacha20_poly1305() },
38 }
39 }
40}
41
42pub(crate) struct PacketKey {
43 alg: Algorithm,
44
45 ctx: *mut EVP_CIPHER_CTX,
46
47 nonce: Vec<u8>,
48
49 key: Vec<u8>,
53}
54
55impl PacketKey {
56 pub fn new(
57 alg: Algorithm, key: Vec<u8>, iv: Vec<u8>, enc: u32,
58 ) -> Result<Self> {
59 Ok(Self {
60 alg,
61 ctx: make_evp_cipher_ctx_basic(alg, true, enc)?,
62 nonce: iv,
63 key,
64 })
65 }
66
67 pub fn from_secret(aead: Algorithm, secret: &[u8], enc: u32) -> Result<Self> {
68 let key_len = aead.key_len();
69 let nonce_len = aead.nonce_len();
70
71 let mut key = vec![0; key_len];
72 let mut iv = vec![0; nonce_len];
73
74 derive_pkt_key(aead, secret, &mut key)?;
75 derive_pkt_iv(aead, secret, &mut iv)?;
76
77 Self::new(aead, key, iv, enc)
78 }
79
80 pub fn open_with_u64_counter(
81 &self, counter: u64, ad: &[u8], buf: &mut [u8],
82 ) -> Result<usize> {
83 let tag_len = self.alg.tag_len();
84
85 let in_buf = buf.to_owned(); let mut cipher_len = buf.len();
88
89 let nonce = make_nonce(&self.nonce, counter);
90
91 const EVP_CTRL_AEAD_SET_IVLEN: i32 = 0x9;
93 let mut rc = unsafe {
94 EVP_CIPHER_CTX_ctrl(
95 self.ctx,
96 EVP_CTRL_AEAD_SET_IVLEN,
97 nonce.len() as i32,
98 std::ptr::null_mut(),
99 )
100 };
101 if rc != 1 {
102 return Err(Error::CryptoFail);
103 }
104
105 rc = unsafe {
106 EVP_CipherInit_ex2(
107 self.ctx,
108 std::ptr::null_mut(), self.key.as_ptr(),
110 nonce[..].as_ptr(),
111 Open::DECRYPT as i32,
112 std::ptr::null(),
113 )
114 };
115
116 if rc != 1 {
117 return Err(Error::CryptoFail);
118 }
119
120 let mut olen: i32 = 0;
121
122 if !ad.is_empty() {
123 rc = unsafe {
124 EVP_CipherUpdate(
125 self.ctx,
126 std::ptr::null_mut(),
127 &mut olen,
128 ad.as_ptr(),
129 ad.len() as i32,
130 )
131 };
132
133 if rc != 1 {
134 return Err(Error::CryptoFail);
135 }
136 }
137
138 if cipher_len < tag_len {
139 return Err(Error::CryptoFail);
140 }
141
142 cipher_len -= tag_len;
143
144 rc = unsafe {
145 EVP_CipherUpdate(
146 self.ctx,
147 buf.as_mut_ptr(),
148 &mut olen,
149 in_buf.as_ptr(),
150 cipher_len as i32,
151 )
152 };
153
154 if rc != 1 {
155 return Err(Error::CryptoFail);
156 }
157
158 let plaintext_len = olen as usize;
159
160 const EVP_CTRL_AEAD_SET_TAG: i32 = 0x11;
161 rc = unsafe {
162 EVP_CIPHER_CTX_ctrl(
163 self.ctx,
164 EVP_CTRL_AEAD_SET_TAG,
165 tag_len as i32,
166 buf[cipher_len..].as_mut_ptr() as *mut c_void,
167 )
168 };
169
170 if rc != 1 {
171 return Err(Error::CryptoFail);
172 }
173
174 rc = unsafe {
175 EVP_CipherFinal_ex(
176 self.ctx,
177 buf[plaintext_len..].as_mut_ptr(),
178 &mut olen,
179 )
180 };
181
182 if rc != 1 {
183 return Err(Error::CryptoFail);
184 }
185
186 Ok(plaintext_len + olen as usize)
187 }
188
189 pub fn seal_with_u64_counter(
190 &self, counter: u64, ad: &[u8], buf: &mut [u8], in_len: usize,
191 _extra_in: Option<&[u8]>,
192 ) -> Result<usize> {
193 let tag_len = self.alg.tag_len();
194
195 let in_buf = buf.to_owned();
197
198 let nonce = make_nonce(&self.nonce, counter);
199
200 const EVP_CTRL_AEAD_SET_IVLEN: i32 = 0x9;
202 let mut rc = unsafe {
203 EVP_CIPHER_CTX_ctrl(
204 self.ctx,
205 EVP_CTRL_AEAD_SET_IVLEN,
206 nonce.len() as i32,
207 std::ptr::null_mut(),
208 )
209 };
210
211 if rc != 1 {
212 return Err(Error::CryptoFail);
213 }
214
215 rc = unsafe {
216 EVP_CipherInit_ex2(
217 self.ctx,
218 std::ptr::null_mut(), self.key.as_ptr(),
220 nonce[..].as_ptr(),
221 Seal::ENCRYPT as i32,
222 std::ptr::null(),
223 )
224 };
225 if rc != 1 {
226 return Err(Error::CryptoFail);
227 }
228
229 let mut olen: i32 = 0;
230 let mut rc;
231
232 if !ad.is_empty() {
233 rc = unsafe {
234 EVP_CipherUpdate(
235 self.ctx,
236 std::ptr::null_mut(),
237 &mut olen,
238 ad.as_ptr(),
239 ad.len() as i32,
240 )
241 };
242
243 if rc != 1 {
244 return Err(Error::CryptoFail);
246 }
247 }
248
249 let mut ciphertext_len: usize = 0;
250
251 rc = unsafe {
252 EVP_CipherUpdate(
253 self.ctx,
254 buf.as_mut_ptr(),
255 &mut olen,
256 in_buf.as_ptr(),
257 in_len as i32,
258 )
259 };
260
261 if rc != 1 {
262 return Err(Error::CryptoFail);
263 };
264
265 ciphertext_len += olen as usize;
266
267 let len = olen as usize;
268 rc = unsafe {
269 EVP_CipherFinal_ex(self.ctx, buf[len..].as_mut_ptr(), &mut olen)
270 };
271
272 if rc != 1 {
273 return Err(Error::CryptoFail);
274 }
275
276 ciphertext_len += olen as usize;
277
278 const EVP_CTRL_AEAD_GET_TAG: i32 = 0x10;
279 rc = unsafe {
280 EVP_CIPHER_CTX_ctrl(
281 self.ctx,
282 EVP_CTRL_AEAD_GET_TAG,
283 tag_len as i32,
284 buf[ciphertext_len..].as_mut_ptr() as *mut c_void,
285 )
286 };
287
288 if rc != 1 {
289 return Err(Error::CryptoFail);
290 }
291
292 Ok(in_len + tag_len)
293 }
294}
295
296impl Drop for PacketKey {
297 fn drop(&mut self) {
298 unsafe { EVP_CIPHER_CTX_free(self.ctx) }
299 }
300}
301
302unsafe impl std::marker::Send for PacketKey {}
303unsafe impl std::marker::Sync for PacketKey {}
304
305pub(crate) struct HeaderProtectionKey {
306 ctx: *mut EVP_CIPHER_CTX,
307
308 key: Vec<u8>,
309}
310
311impl HeaderProtectionKey {
312 pub fn new(alg: Algorithm, hp_key: Vec<u8>) -> Result<Self> {
313 Ok(Self {
314 ctx: make_evp_cipher_ctx_basic(alg, false, 1)?,
315 key: hp_key,
316 })
317 }
318
319 pub fn new_mask(&self, sample: &[u8]) -> Result<HeaderProtectionMask> {
320 const PLAINTEXT: &[u8; 5] = &[0_u8; 5];
321
322 let mut new_mask = HeaderProtectionMask::default();
323
324 let rc = unsafe {
326 EVP_CipherInit_ex2(
327 self.ctx,
328 std::ptr::null_mut(), self.key.as_ptr(),
330 sample.as_ptr(),
331 -1,
332 std::ptr::null(),
333 )
334 };
335
336 if rc != 1 {
337 return Err(Error::CryptoFail);
338 }
339
340 let mut out_len: i32 = 0;
341
342 let rc = unsafe {
343 EVP_CipherUpdate(
344 self.ctx,
345 new_mask.as_mut_ptr(),
346 &mut out_len,
347 PLAINTEXT.as_ptr(),
348 PLAINTEXT.len() as i32,
349 )
350 };
351
352 if rc != 1 {
353 return Err(Error::CryptoFail);
354 };
355
356 let rc = unsafe {
357 EVP_CipherFinal_ex(
358 self.ctx,
359 new_mask[out_len as usize..].as_mut_ptr(),
360 &mut out_len,
361 )
362 };
363
364 if rc != 1 {
365 return Err(Error::CryptoFail);
366 }
367
368 Ok(new_mask)
369 }
370}
371
372impl Clone for HeaderProtectionKey {
373 fn clone(&self) -> Self {
374 let ctx = unsafe { EVP_CIPHER_CTX_dup(self.ctx) };
375
376 Self {
377 ctx,
378 key: self.key.clone(),
379 }
380 }
381}
382
383impl Drop for HeaderProtectionKey {
384 fn drop(&mut self) {
385 unsafe { EVP_CIPHER_CTX_free(self.ctx) }
386 }
387}
388
389unsafe impl std::marker::Send for HeaderProtectionKey {}
390unsafe impl std::marker::Sync for HeaderProtectionKey {}
391
392fn make_evp_cipher_ctx_basic(
393 alg: Algorithm, aead: bool, enc: u32,
394) -> Result<*mut EVP_CIPHER_CTX> {
395 let ctx: *mut EVP_CIPHER_CTX = unsafe {
396 let cipher: *const EVP_AEAD = if aead {
397 alg.get_evp_aead()
398 } else {
399 alg.get_evp()
400 };
401
402 let ctx = EVP_CIPHER_CTX_new();
403
404 if ctx.is_null() {
405 return Err(Error::CryptoFail);
406 }
407
408 let rc = EVP_CipherInit_ex2(
409 ctx,
410 cipher,
411 std::ptr::null_mut(),
412 std::ptr::null_mut(),
413 enc as c_int, std::ptr::null(),
415 );
416
417 if rc != 1 {
418 return Err(Error::CryptoFail);
419 }
420
421 ctx
422 };
423
424 Ok(ctx)
425}
426
427pub(crate) fn hkdf_extract(
428 alg: Algorithm, out: &mut [u8], secret: &[u8], salt: &[u8],
429) -> Result<()> {
430 let mut out_len = out.len();
431
432 unsafe {
433 let prf = alg.get_evp_digest();
434
435 let ctx = EVP_PKEY_CTX_new_id(
436 1036, std::ptr::null_mut(),
438 );
439
440 if EVP_PKEY_derive_init(ctx) != 1 ||
441 EVP_PKEY_CTX_set_hkdf_mode(
442 ctx, 1, ) != 1 ||
444 EVP_PKEY_CTX_set_hkdf_md(ctx, prf) != 1 ||
445 EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt.as_ptr(), salt.len()) != 1 ||
446 EVP_PKEY_CTX_set1_hkdf_key(ctx, secret.as_ptr(), secret.len()) != 1 ||
447 EVP_PKEY_derive(ctx, out.as_mut_ptr(), &mut out_len) != 1
448 {
449 EVP_PKEY_CTX_free(ctx);
450 return Err(Error::CryptoFail);
451 }
452
453 EVP_PKEY_CTX_free(ctx);
454 }
455
456 Ok(())
457}
458
459pub(crate) fn hkdf_expand(
460 alg: Algorithm, out: &mut [u8], secret: &[u8], info: &[u8],
461) -> Result<()> {
462 let mut out_len = out.len();
463
464 unsafe {
465 let prf = alg.get_evp_digest();
466
467 let ctx = EVP_PKEY_CTX_new_id(
468 1036, std::ptr::null_mut(),
470 );
471
472 if EVP_PKEY_derive_init(ctx) != 1 ||
473 EVP_PKEY_CTX_set_hkdf_mode(
474 ctx, 2, ) != 1 ||
476 EVP_PKEY_CTX_set_hkdf_md(ctx, prf) != 1 ||
477 EVP_PKEY_CTX_set1_hkdf_key(ctx, secret.as_ptr(), secret.len()) != 1 ||
478 EVP_PKEY_CTX_add1_hkdf_info(ctx, info.as_ptr(), info.len()) != 1 ||
479 EVP_PKEY_derive(ctx, out.as_mut_ptr(), &mut out_len) != 1
480 {
481 EVP_PKEY_CTX_free(ctx);
482 return Err(Error::CryptoFail);
483 }
484
485 EVP_PKEY_CTX_free(ctx);
486 }
487
488 Ok(())
489}
490
491extern "C" {
492 fn EVP_aes_128_ctr() -> *const EVP_AEAD;
494 fn EVP_aes_128_gcm() -> *const EVP_AEAD;
495
496 fn EVP_aes_256_ctr() -> *const EVP_AEAD;
497 fn EVP_aes_256_gcm() -> *const EVP_AEAD;
498
499 fn EVP_chacha20() -> *const EVP_AEAD;
500 fn EVP_chacha20_poly1305() -> *const EVP_AEAD;
501
502 fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX;
504
505 fn EVP_CIPHER_CTX_dup(ctx: *const EVP_CIPHER_CTX) -> *mut EVP_CIPHER_CTX;
506
507 fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX);
508
509 fn EVP_CipherInit_ex2(
510 ctx: *mut EVP_CIPHER_CTX, cipher: *const EVP_AEAD, key: *const c_uchar,
511 iv: *const c_uchar, enc: c_int, params: *const OSSL_PARAM,
512 ) -> c_int;
513
514 fn EVP_CIPHER_CTX_ctrl(
515 ctx: *mut EVP_CIPHER_CTX, type_: i32, arg: i32, ptr: *mut c_void,
516 ) -> c_int;
517
518 fn EVP_CipherUpdate(
519 ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int,
520 in_: *const c_uchar, inl: i32,
521 ) -> c_int;
522
523 fn EVP_CipherFinal_ex(
524 ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int,
525 ) -> c_int;
526
527 fn EVP_PKEY_CTX_new_id(id: c_int, e: *mut c_void) -> *mut EVP_PKEY_CTX;
529
530 fn EVP_PKEY_CTX_set_hkdf_mode(ctx: *mut EVP_PKEY_CTX, mode: c_int) -> c_int;
531 fn EVP_PKEY_CTX_set_hkdf_md(
532 ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD,
533 ) -> c_int;
534 fn EVP_PKEY_CTX_set1_hkdf_salt(
535 ctx: *mut EVP_PKEY_CTX, salt: *const u8, salt_len: usize,
536 ) -> c_int;
537 fn EVP_PKEY_CTX_set1_hkdf_key(
538 ctx: *mut EVP_PKEY_CTX, key: *const u8, key_len: usize,
539 ) -> c_int;
540 fn EVP_PKEY_CTX_add1_hkdf_info(
541 ctx: *mut EVP_PKEY_CTX, info: *const u8, info_len: usize,
542 ) -> c_int;
543
544 fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
545
546 fn EVP_PKEY_derive(
547 ctx: *mut EVP_PKEY_CTX, key: *mut u8, key_len: *mut usize,
548 ) -> c_int;
549
550 fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX);
551}