linux_kcapi/
internal.rs

1//! This module is mainly intended for internal usage, as it provides function without particular input checking.
2//! It is exposed for being able to use any algorithm which may not be exposed by a convenient API from this crate.
3//!
4use 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        // return default value
43        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)]
54/// Encryption direction
55pub enum Direction {
56    /// Perform encryption
57    Encrypt,
58    /// Perform decryption
59    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/// Whether this respresents the last message or not
72#[derive(Debug, Clone, PartialEq)]
73pub enum DataPos {
74    /// There is more messages to send  
75    More,
76    /// Last message to send
77    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
98/// Entry structure to linux kernel crypto api.
99/// All method low level (i.e. libc calls) errors are logued at debug level to allow investigation in case of unexpected error.
100///
101pub 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    /// New from algorithm name and type.
119    ///
120    /// # Errors
121    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
122    ///    See `man 2 socket` and `man 2 bind`
123    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    /// Set Cipher key.
159    /// See [KCAPI setsockopt](https://www.kernel.org/doc/html/v4.10/crypto/userspace-if.html#setsockopt-interface)
160    /// # Errors
161    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
162    ///    See `man 2 setsockopt`
163    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    /// Set authentication tag size for AEAD ciphers.
180    /// See [KCAPI setsockopt](https://www.kernel.org/doc/html/v4.10/crypto/userspace-if.html#setsockopt-interface)
181    /// # Errors
182    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
183    ///    See `man 2 setsockopt`
184    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    /// Accept connexion to get operation socket
199    /// Eventually close current connexion
200    /// # Errors
201    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
202    ///    See `man 2 close` and `man 2 accept`
203    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    /// Close current connexion.
222    ///
223    /// # Errors
224    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
225    ///    See `man 2 close`
226    pub fn finish(&mut self) -> Result<(), Error> {
227        unistd::close(self.opfd)?;
228        self.opfd = -1;
229        Ok(())
230    }
231
232    /// Set cipher option.
233    /// See [KCAPI symmetric-cipher-api](https://www.kernel.org/doc/html/v4.10/crypto/userspace-if.html#symmetric-cipher-api)
234    /// and
235    /// See [KCAPI aead-cipher-api](https://www.kernel.org/doc/html/v4.10/crypto/userspace-if.html#aead-cipher-api)
236    /// # Errors
237    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
238    ///    See `man 2 sendmsg`
239    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    /// Get processed data.
279    /// # Errors
280    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
281    ///    See `man 2 read`
282    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    /// Send data to be processed.
295    /// # Errors
296    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
297    ///    See `man 2 sendmsg`
298    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    /// Send data to be processed.
341    /// # Errors
342    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
343    ///    See `man 2 send`
344    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    /// Send data to be processed.
358    /// # Errors
359    ///  - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys)  in case of low level error.
360    ///    See `man 2 vmsplice`, `man 2 splice`, `man 2 close`
361    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        // kernel processes input data with max size of one page
368        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    // The kernel generates at most 128 bytes in one call.
431    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        // for tests, rng must be seeded
466        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        // cipher must be keyed
485        cip.set_key(&[0_u8; 16])?;
486
487        // error shall occur if no direction  is set
488        cip.init()?;
489        cip.send_data(&zero, DataPos::Last)?;
490        assert!(cip.read(&mut dst).is_err());
491
492        // if set, shall be ok
493        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        // dst shall be non zero
498        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        // cipher must be keyed
514        cip.set_key(&[0_u8; 16])?;
515        cip.init()?;
516        cip.set_option(Some(&[0_u8; 16]), None, Some(Direction::Encrypt))?;
517
518        // iov split at block size ok
519        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        // iov not split at block size
527        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        // cipher must be keyed
549        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        // cipher must be keyed
602        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        // cipher must be keyed
643        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        // cipher must be keyed
668        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        // cipher must be keyed
701        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        // cipher must be keyed
725        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}