1use crate::err::Error;
5use libc::c_int;
6use nix::sys::socket;
7use nix::sys::socket::SetSockOpt;
8use nix::unistd;
9use std::io::IoSlice;
10use std::os::unix::io::RawFd;
11
12#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
13fn logical_cpus() -> usize {
14 let mut set: libc::cpu_set_t = unsafe { std::mem::zeroed() };
15 if unsafe { libc::sched_getaffinity(0, std::mem::size_of::<libc::cpu_set_t>(), &mut set) } == 0
16 {
17 let mut count: u32 = 0;
18 for i in 0..libc::CPU_SETSIZE as usize {
19 if unsafe { libc::CPU_ISSET(i, &set) } {
20 count += 1
21 }
22 }
23 count as usize
24 } else {
25 let cpus = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) };
26 if cpus < 1 {
27 1
28 } else {
29 cpus as usize
30 }
31 }
32}
33
34lazy_static::lazy_static! {
35 static ref PARALLEL_JOBS: usize = logical_cpus();
36}
37
38#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
39fn get_page_size() -> usize {
40 let sysconf_val = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
41 if sysconf_val == -1 {
42 4096
44 } else {
45 sysconf_val as usize
46 }
47}
48
49lazy_static::lazy_static! {
50 static ref PAGE_SIZE: usize = get_page_size();
51}
52
53#[derive(Debug, Clone)]
54pub enum Direction {
56 Encrypt,
58 Decrypt,
60}
61
62impl Into<c_int> for Direction {
63 fn into(self) -> c_int {
64 match self {
65 Direction::Encrypt => 1,
66 Direction::Decrypt => 0,
67 }
68 }
69}
70
71#[derive(Debug, Clone, PartialEq)]
73pub enum DataPos {
74 More,
76 Last,
78}
79
80impl Into<nix::fcntl::SpliceFFlags> for DataPos {
81 fn into(self) -> nix::fcntl::SpliceFFlags {
82 match self {
83 DataPos::More => nix::fcntl::SpliceFFlags::SPLICE_F_MORE,
84 DataPos::Last => nix::fcntl::SpliceFFlags::empty(),
85 }
86 }
87}
88
89impl Into<socket::MsgFlags> for DataPos {
90 fn into(self) -> socket::MsgFlags {
91 match self {
92 DataPos::More => unsafe { socket::MsgFlags::from_bits_unchecked(libc::MSG_MORE) },
93 DataPos::Last => socket::MsgFlags::empty(),
94 }
95 }
96}
97
98pub struct KcApi {
102 fd: RawFd,
103 opfd: RawFd,
104}
105
106impl Drop for KcApi {
107 fn drop(&mut self) {
108 if nix::fcntl::fcntl(self.opfd, nix::fcntl::FcntlArg::F_GETFD).is_ok() {
109 let _ = unistd::close(self.opfd);
110 }
111 if nix::fcntl::fcntl(self.fd, nix::fcntl::FcntlArg::F_GETFD).is_ok() {
112 let _ = unistd::close(self.fd);
113 }
114 }
115}
116
117impl KcApi {
118 pub fn new(alg_type: &str, alg_name: &str) -> Result<Self, Error> {
124 let adr = socket::AlgAddr::new(alg_type, alg_name);
125 let fd = socket::socket(
126 socket::AddressFamily::Alg,
127 socket::SockType::SeqPacket,
128 socket::SockFlag::empty(),
129 None,
130 )
131 .map_err(|e| {
132 log::debug!(
133 "Socket creation failed for type {} and name {} with error {}",
134 alg_type,
135 alg_name,
136 e
137 );
138 e
139 })?;
140 socket::bind(fd, &adr).map_err(|e| {
141 log::debug!(
142 "Socket bind failed for type {} and name {} with error {}",
143 alg_type,
144 alg_name,
145 e
146 );
147 e
148 })?;
149 log::debug!(
150 "Bind success for type {} and name {}, fd={}",
151 alg_type,
152 alg_name,
153 fd
154 );
155 Ok(Self { fd, opfd: -1 })
156 }
157
158 pub fn set_key<T>(&self, key: &T) -> Result<(), Error>
164 where
165 T: AsRef<[u8]> + Clone,
166 {
167 let opt = socket::sockopt::AlgSetKey::<T>::default();
168 opt.set(self.fd, key).map_err(|e| {
169 log::debug!(
170 "setsockopt ALG_SET_KEY failed with error {} for fd {} ",
171 e,
172 self.fd
173 );
174 e
175 })?;
176 Ok(())
177 }
178
179 pub fn set_aead_auth_size(&self, size: usize) -> Result<(), Error> {
185 socket::sockopt::AlgSetAeadAuthSize
186 .set(self.fd, &size)
187 .map_err(|e| {
188 log::debug!(
189 "setsockopt ALG_SET_AEAD_AUTHSIZE failed with error {} for fd {} ",
190 e,
191 self.fd
192 );
193 e
194 })?;
195 Ok(())
196 }
197
198 pub fn init(&mut self) -> Result<(), Error> {
204 if nix::fcntl::fcntl(self.opfd, nix::fcntl::FcntlArg::F_GETFD).is_ok() {
205 unistd::close(self.opfd).map_err(|e| {
206 log::debug!("close failed with error {} for fd {} ", e, self.fd);
207 e
208 })?;
209 }
210
211 self.opfd = socket::accept(self.fd).map_err(|e| {
212 log::debug!("accept failed with error {} for fd {} ", e, self.fd);
213 e
214 })?;
215
216 log::debug!("accept OK for fd {} : opdf={} ", self.fd, self.opfd);
217
218 Ok(())
219 }
220
221 pub fn finish(&mut self) -> Result<(), Error> {
227 unistd::close(self.opfd)?;
228 self.opfd = -1;
229 Ok(())
230 }
231
232 pub fn set_option(
240 &self,
241 iv: Option<&[u8]>,
242 aad: Option<u32>,
243 dir: Option<Direction>,
244 ) -> Result<(), Error> {
245 let mut message: Vec<socket::ControlMessage> = Vec::new();
246 #[allow(unused_assignments)]
247 let (mut aad_len, mut direction) = (0, 0);
248 if let Some(d) = iv {
249 message.push(socket::ControlMessage::AlgSetIv(d));
250 }
251 if let Some(d) = aad {
252 aad_len = d;
253 message.push(socket::ControlMessage::AlgSetAeadAssoclen(&aad_len));
254 }
255 if let Some(d) = dir {
256 direction = d.into();
257 message.push(socket::ControlMessage::AlgSetOp(&direction));
258 }
259 socket::sendmsg::<()>(
260 self.opfd,
261 &[],
262 message.as_slice(),
263 socket::MsgFlags::empty(),
264 None,
265 )
266 .map_err(|e| {
267 log::debug!(
268 "sendmsg failed with error {} for fd {}, opdf={} ",
269 e,
270 self.fd,
271 self.opfd
272 );
273 e
274 })?;
275 Ok(())
276 }
277
278 pub fn read(&self, out: &mut [u8]) -> Result<usize, Error> {
283 Ok(unistd::read(self.opfd, out).map_err(|e| {
284 log::debug!(
285 "read failed with error {} for fd {}, opdf={} ",
286 e,
287 self.fd,
288 self.opfd
289 );
290 e
291 })?)
292 }
293
294 pub fn send_data_with_option(
299 &self,
300 iv: Option<&[u8]>,
301 aad: Option<u32>,
302 dir: Option<Direction>,
303 data: &[u8],
304 more_data: DataPos,
305 ) -> Result<usize, Error> {
306 let mut message: Vec<socket::ControlMessage> = Vec::new();
307 #[allow(unused_assignments)]
308 let (mut aad_len, mut direction) = (0, 0);
309 if let Some(d) = iv {
310 message.push(socket::ControlMessage::AlgSetIv(d));
311 }
312 if let Some(d) = aad {
313 aad_len = d;
314 message.push(socket::ControlMessage::AlgSetAeadAssoclen(&aad_len));
315 }
316 if let Some(d) = dir {
317 direction = d.into();
318 message.push(socket::ControlMessage::AlgSetOp(&direction));
319 }
320
321 let r = socket::sendmsg::<()>(
322 self.opfd,
323 &[IoSlice::new(data)],
324 message.as_slice(),
325 more_data.into(),
326 None,
327 )
328 .map_err(|e| {
329 log::debug!(
330 "sendmsg failed with error {} for fd {}, opdf={} ",
331 e,
332 self.fd,
333 self.opfd
334 );
335 e
336 })?;
337 Ok(r)
338 }
339
340 pub fn send_data(&self, data: &[u8], more_data: DataPos) -> Result<usize, Error> {
345 let r = socket::send(self.opfd, data, more_data.into()).map_err(|e| {
346 log::debug!(
347 "send failed with error {} for fd {}, opdf={} ",
348 e,
349 self.fd,
350 self.opfd
351 );
352 e
353 })?;
354 Ok(r)
355 }
356
357 pub fn send_data_no_copy(&self, data: &[u8], more_data: DataPos) -> Result<usize, Error> {
362 let mut osize = 0;
363 let (pipe0, pipe1) = unistd::pipe()?;
364
365 let flag = more_data.into();
366
367 let mut chunks = data.chunks(*PAGE_SIZE).peekable();
369 while let Some(chunk) = chunks.next() {
370 let iov = [IoSlice::new(chunk)];
371 let more_flag = flag
372 | if chunks.peek().is_some() {
373 nix::fcntl::SpliceFFlags::SPLICE_F_MORE
374 } else {
375 nix::fcntl::SpliceFFlags::empty()
376 };
377 let sz =
378 nix::fcntl::vmsplice(pipe1, &iov, nix::fcntl::SpliceFFlags::SPLICE_F_GIFT | flag)
379 .map_err(|e| {
380 log::debug!(
381 "vmsplice failed with error {} for fd {}, opdf={} ",
382 e,
383 self.fd,
384 self.opfd
385 );
386 e
387 })?;
388
389 osize +=
390 nix::fcntl::splice(pipe0, None, self.opfd, None, sz, more_flag).map_err(|e| {
391 log::debug!(
392 "splice failed with error {} for fd {}, opdf={} ",
393 e,
394 self.fd,
395 self.opfd
396 );
397 e
398 })?;
399 }
400 unistd::close(pipe0)?;
401 unistd::close(pipe1)?;
402 Ok(osize)
403 }
404}
405
406#[cfg(test)]
407mod tests {
408 use super::*;
409 const MAX_PAGES: usize = 16;
410
411 fn init() {
412 let _ = env_logger::builder().is_test(true).try_init();
413 }
414
415 #[test]
416 fn new() {
417 init();
418 let good = KcApi::new("rng", "stdrng");
419 let bad = KcApi::new("badtype", "stdrng");
420 assert!(good.is_ok());
421 assert!(bad.is_err());
422 }
423
424 #[test]
425 fn lazy_static_init() {
426 println!("Number of CPU : {} ", *PARALLEL_JOBS);
427 println!("Page size : {} ", *PAGE_SIZE);
428 }
429
430 const MAX_TEST_READ_LEN: usize = 128;
432
433 #[test]
434 fn init_close() -> Result<(), Error> {
435 init();
436 let mut rng = KcApi::new("rng", "stdrng")?;
437
438 assert!(rng.finish().is_err());
439 rng.init()?;
440 assert!(rng.finish().is_ok());
441 Ok(())
442 }
443
444 #[test]
445 fn set_key() -> Result<(), Error> {
446 init();
447 let mut rng = KcApi::new("rng", "stdrng")?;
448 let mut dst = [0_u8; 16];
449 rng.init()?;
450 assert!(rng.read(&mut dst).is_err());
451
452 rng.finish()?;
453 rng.set_key(&[0_u8; 16])?;
454 rng.init()?;
455 assert!(rng.read(&mut dst).is_ok());
456
457 Ok(())
458 }
459
460 #[test]
461 fn read() -> Result<(), Error> {
462 init();
463 let mut rng = KcApi::new("rng", "stdrng")?;
464 let zero = [0_u8; MAX_TEST_READ_LEN];
465 rng.set_key(&[0_u8; 16])?;
467 rng.init()?;
468 for read_len in 4..=MAX_TEST_READ_LEN {
469 let reference = &zero[0..read_len];
470 let mut dst = Vec::from(reference);
471 rng.read(dst.as_mut_slice())?;
472 assert_ne!(reference, dst.as_slice());
473 }
474 Ok(())
475 }
476
477 #[test]
478 fn set_option() -> Result<(), Error> {
479 init();
480 let mut cip = KcApi::new("aead", "gcm(aes)")?;
481 let zero = [0_u8; 32];
482 let mut dst = [0_u8; 32];
483
484 cip.set_key(&[0_u8; 16])?;
486
487 cip.init()?;
489 cip.send_data(&zero, DataPos::Last)?;
490 assert!(cip.read(&mut dst).is_err());
491
492 cip.set_option(None, None, Some(Direction::Encrypt))?;
494 cip.send_data(&zero, DataPos::Last)?;
495 assert!(cip.read(&mut dst).is_ok());
496
497 assert_ne!(zero, dst);
499
500 Ok(())
501 }
502
503 #[test]
504 fn write() -> Result<(), Error> {
505 init();
506 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
507 let mut zero = Vec::new();
508
509 let mut dst = Vec::new();
510
511 let long_len = MAX_PAGES * *PAGE_SIZE * 3;
512
513 cip.set_key(&[0_u8; 16])?;
515 cip.init()?;
516 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
517
518 zero.resize(long_len, 0);
520 dst.resize(long_len, 0);
521 cip.send_data(&zero, DataPos::Last)?;
522 let read_res = cip.read(&mut dst);
523 assert!(read_res.is_ok());
524 assert_eq!(long_len, read_res.unwrap());
525
526 zero.resize(16, 0);
528 dst.resize(16, 0);
529 assert_eq!(16, cip.send_data(&zero, DataPos::Last).unwrap());
530 let read_res = cip.read(&mut dst);
531 assert!(read_res.is_ok());
532 assert_eq!(16, read_res.unwrap());
533
534 Ok(())
535 }
536
537 #[test]
538 fn more_data() -> Result<(), Error> {
539 init();
540 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
541 let mut zero = Vec::new();
542
543 let mut dst = Vec::new();
544 let mut dst_spl = Vec::new();
545
546 let len = 256;
547
548 cip.set_key(&[0_u8; 16])?;
550 cip.init()?;
551 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
552
553 zero.resize(len, 0);
554 dst.resize(len, 0);
555 dst_spl.resize(len, 0);
556 assert_eq!(len, cip.send_data(&zero, DataPos::Last)?);
557 let read_res = cip.read(&mut dst);
558 assert!(read_res.is_ok());
559 assert_eq!(len, read_res.unwrap());
560
561 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
562 assert_eq!(len / 2, cip.send_data(&zero[..len / 2], DataPos::More)?);
563 assert_eq!(len / 2, cip.send_data(&zero[len / 2..], DataPos::Last)?);
564 let read_res = cip.read(&mut dst_spl);
565 assert!(read_res.is_ok());
566 assert_eq!(len, read_res.unwrap());
567
568 assert_eq!(dst, dst_spl);
569
570 assert_eq!(
571 len / 2,
572 cip.send_data_with_option(
573 Some(&[0_u8; 16]),
574 None,
575 Some(Direction::Encrypt),
576 &zero[..len / 2],
577 DataPos::More
578 )?
579 );
580 assert_eq!(len / 2, cip.send_data(&zero[len / 2..], DataPos::Last)?);
581 let read_res = cip.read(&mut dst_spl);
582 assert!(read_res.is_ok());
583 assert_eq!(len, read_res.unwrap());
584
585 assert_eq!(dst, dst_spl);
586
587 Ok(())
588 }
589
590 #[test]
591 fn more_data_zero_copy() -> Result<(), Error> {
592 init();
593 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
594 let mut zero = Vec::new();
595
596 let mut dst = Vec::new();
597 let mut dst_spl = Vec::new();
598
599 let len = 256;
600
601 cip.set_key(&[0_u8; 16])?;
603 cip.init()?;
604 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
605
606 zero.resize(len, 0);
607 dst.resize(len, 0);
608 dst_spl.resize(len, 0);
609 assert_eq!(len, cip.send_data(&zero, DataPos::Last)?);
610 let read_res = cip.read(&mut dst);
611 assert!(read_res.is_ok());
612 assert_eq!(len, read_res.unwrap());
613
614 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
615 assert_eq!(
616 len / 2,
617 cip.send_data_no_copy(&zero[..len / 2], DataPos::More)?
618 );
619 assert_eq!(
620 len / 2,
621 cip.send_data_no_copy(&zero[len / 2..], DataPos::Last)?
622 );
623 let read_res = cip.read(&mut dst_spl);
624 assert!(read_res.is_ok());
625 assert_eq!(len, read_res.unwrap());
626
627 assert_eq!(dst, dst_spl);
628
629 Ok(())
630 }
631
632 #[test]
633 fn write_long() -> Result<(), Error> {
634 init();
635 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
636 let mut zero = Vec::new();
637
638 let mut dst = Vec::new();
639
640 let long_len = MAX_PAGES * *PAGE_SIZE * 3;
641
642 cip.set_key(&[0_u8; 16])?;
644 cip.init()?;
645 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
646
647 zero.resize(long_len, 0);
648 dst.resize(long_len, 0);
649 assert_eq!(long_len, cip.send_data(&zero, DataPos::Last)?);
650 let read_res = cip.read(&mut dst);
651 assert!(read_res.is_ok());
652 assert_eq!(long_len, read_res.unwrap());
653
654 Ok(())
655 }
656
657 #[test]
658 fn send_data_no_copy() -> Result<(), Error> {
659 init();
660 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
661 let mut zero = Vec::new();
662
663 let mut dst = Vec::new();
664
665 let long_len = MAX_PAGES * *PAGE_SIZE * 3;
666
667 cip.set_key(&[0_u8; 16])?;
669 cip.init()?;
670 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
671
672 zero.resize(long_len, 0);
673 dst.resize(long_len, 0);
674 assert_eq!(long_len, cip.send_data_no_copy(&zero, DataPos::Last)?);
675 let read_res = cip.read(&mut dst);
676 assert!(read_res.is_ok());
677 assert_eq!(long_len, read_res.unwrap());
678
679 Ok(())
680 }
681
682 const BENCH_TEST_SZ: usize = 32;
683 #[repr(C)]
684 pub struct Aligned([u8; BENCH_TEST_SZ]);
685
686 fn new_aligned() -> Aligned {
687 Aligned([0; BENCH_TEST_SZ])
688 }
689
690 use std::time::SystemTime;
691
692 #[test]
693 #[ignore]
694 fn bench_send_data_no_copy() -> Result<(), Error> {
695 init();
696 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
697 let zero = new_aligned();
698 let mut dst = [0; 32];
699
700 cip.set_key(&[0_u8; 16])?;
702 cip.init()?;
703 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
704
705 let mut duration = 0;
706
707 for _ in 0..4096 {
708 let now = SystemTime::now();
709 cip.send_data_no_copy(&zero.0, DataPos::Last)?;
710 cip.read(&mut dst)?;
711 duration += now.elapsed().unwrap().as_micros()
712 }
713 println!("Elapsed {} microsec", duration);
714 Ok(())
715 }
716
717 #[test]
718 fn bench_write() -> Result<(), Error> {
719 init();
720 let mut cip = KcApi::new("skcipher", "ctr(aes)")?;
721 let zero = new_aligned();
722 let mut dst = [0; 32];
723
724 cip.set_key(&[0_u8; 16])?;
726 cip.init()?;
727 cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
728
729 let mut duration = 0;
730
731 for _ in 0..4096 {
732 let now = SystemTime::now();
733 cip.send_data(&zero.0, DataPos::Last)?;
734 cip.read(&mut dst)?;
735 duration += now.elapsed().unwrap().as_micros()
736 }
737 println!("Elapsed {}", duration);
738 Ok(())
739 }
740}