1use crate::{Cipher, Error, Result};
4use cipher::{Block, BlockCipherEncrypt, KeyIvInit};
5use core::fmt::{self, Debug};
6
7#[cfg(any(feature = "aes-cbc", feature = "aes-ctr"))]
8use aes::{Aes128, Aes192, Aes256};
9#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
10use cipher::block::BlockModeEncrypt;
11#[cfg(feature = "tdes")]
12use des::TdesEde3;
13#[cfg(feature = "aes-ctr")]
14use {
15 crate::Ctr128BE,
16 cipher::{BlockSizeUser, StreamCipherCore, array::sizes::U16},
17};
18
19pub struct Encryptor {
24 inner: Inner,
26}
27
28enum Inner {
30 #[cfg(feature = "aes-cbc")]
31 Aes128Cbc(cbc::Encryptor<Aes128>),
32 #[cfg(feature = "aes-cbc")]
33 Aes192Cbc(cbc::Encryptor<Aes192>),
34 #[cfg(feature = "aes-cbc")]
35 Aes256Cbc(cbc::Encryptor<Aes256>),
36 #[cfg(feature = "aes-ctr")]
37 Aes128Ctr(Ctr128BE<Aes128>),
38 #[cfg(feature = "aes-ctr")]
39 Aes192Ctr(Ctr128BE<Aes192>),
40 #[cfg(feature = "aes-ctr")]
41 Aes256Ctr(Ctr128BE<Aes256>),
42 #[cfg(feature = "tdes")]
43 TDesCbc(cbc::Encryptor<TdesEde3>),
44}
45
46impl Encryptor {
47 pub fn new(cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self> {
55 cipher.check_key_and_iv(key, iv)?;
56
57 let inner = match cipher {
58 #[cfg(feature = "aes-cbc")]
59 Cipher::Aes128Cbc => cbc::Encryptor::new_from_slices(key, iv).map(Inner::Aes128Cbc),
60 #[cfg(feature = "aes-cbc")]
61 Cipher::Aes192Cbc => cbc::Encryptor::new_from_slices(key, iv).map(Inner::Aes192Cbc),
62 #[cfg(feature = "aes-cbc")]
63 Cipher::Aes256Cbc => cbc::Encryptor::new_from_slices(key, iv).map(Inner::Aes256Cbc),
64 #[cfg(feature = "aes-ctr")]
65 Cipher::Aes128Ctr => Ctr128BE::new_from_slices(key, iv).map(Inner::Aes128Ctr),
66 #[cfg(feature = "aes-ctr")]
67 Cipher::Aes192Ctr => Ctr128BE::new_from_slices(key, iv).map(Inner::Aes192Ctr),
68 #[cfg(feature = "aes-ctr")]
69 Cipher::Aes256Ctr => Ctr128BE::new_from_slices(key, iv).map(Inner::Aes256Ctr),
70 #[cfg(feature = "tdes")]
71 Cipher::TDesCbc => cbc::Encryptor::new_from_slices(key, iv).map(Inner::TDesCbc),
72 _ => return Err(cipher.unsupported()),
73 }
74 .map_err(|_| Error::Length)?;
75
76 Ok(Self { inner })
77 }
78
79 #[must_use]
81 pub fn cipher(&self) -> Cipher {
82 match &self.inner {
83 #[cfg(feature = "aes-cbc")]
84 Inner::Aes128Cbc(_) => Cipher::Aes128Cbc,
85 #[cfg(feature = "aes-cbc")]
86 Inner::Aes192Cbc(_) => Cipher::Aes192Cbc,
87 #[cfg(feature = "aes-cbc")]
88 Inner::Aes256Cbc(_) => Cipher::Aes256Cbc,
89 #[cfg(feature = "aes-ctr")]
90 Inner::Aes128Ctr(_) => Cipher::Aes128Ctr,
91 #[cfg(feature = "aes-ctr")]
92 Inner::Aes192Ctr(_) => Cipher::Aes192Ctr,
93 #[cfg(feature = "aes-ctr")]
94 Inner::Aes256Ctr(_) => Cipher::Aes256Ctr,
95 #[cfg(feature = "tdes")]
96 Inner::TDesCbc(_) => Cipher::TDesCbc,
97 }
98 }
99
100 pub fn encrypt(&mut self, buffer: &mut [u8]) -> Result<()> {
106 match &mut self.inner {
107 #[cfg(feature = "aes-cbc")]
108 Inner::Aes128Cbc(cipher) => cbc_encrypt(cipher, buffer)?,
109 #[cfg(feature = "aes-cbc")]
110 Inner::Aes192Cbc(cipher) => cbc_encrypt(cipher, buffer)?,
111 #[cfg(feature = "aes-cbc")]
112 Inner::Aes256Cbc(cipher) => cbc_encrypt(cipher, buffer)?,
113 #[cfg(feature = "aes-ctr")]
114 Inner::Aes128Ctr(cipher) => ctr_encrypt(cipher, buffer)?,
115 #[cfg(feature = "aes-ctr")]
116 Inner::Aes192Ctr(cipher) => ctr_encrypt(cipher, buffer)?,
117 #[cfg(feature = "aes-ctr")]
118 Inner::Aes256Ctr(cipher) => ctr_encrypt(cipher, buffer)?,
119 #[cfg(feature = "tdes")]
120 Inner::TDesCbc(cipher) => cbc_encrypt(cipher, buffer)?,
121 }
122
123 Ok(())
124 }
125}
126
127impl Debug for Encryptor {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 f.debug_struct("Encryptor")
130 .field("cipher", &self.cipher())
131 .finish_non_exhaustive()
132 }
133}
134
135#[cfg(any(feature = "aes-cbc", feature = "tdes"))]
137fn cbc_encrypt<C>(encryptor: &mut cbc::Encryptor<C>, buffer: &mut [u8]) -> Result<()>
138where
139 C: BlockCipherEncrypt,
140{
141 let (blocks, remaining) = Block::<C>::slice_as_chunks_mut(buffer);
142
143 if !remaining.is_empty() {
145 return Err(Error::Length);
146 }
147
148 encryptor.encrypt_blocks(blocks);
149 Ok(())
150}
151
152#[cfg(feature = "aes-ctr")]
154pub(crate) fn ctr_encrypt<C>(encryptor: &mut Ctr128BE<C>, buffer: &mut [u8]) -> Result<()>
155where
156 C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
157{
158 let (blocks, remaining) = Block::<C>::slice_as_chunks_mut(buffer);
159
160 if !remaining.is_empty() {
162 return Err(Error::Length);
163 }
164
165 encryptor.apply_keystream_blocks(blocks);
166 Ok(())
167}