1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![allow(clippy::unwrap_used, reason = "todo: convert to expect")]
9
10pub use cipher;
11
12pub use cipher::{KeyInit, KeyIvInit};
13
14mod cbc_cs1;
15mod cbc_cs2;
16mod cbc_cs3;
17mod ecb_cs1;
18mod ecb_cs2;
19mod ecb_cs3;
20
21pub use cbc_cs1::CbcCs1;
22pub use cbc_cs2::CbcCs2;
23pub use cbc_cs3::CbcCs3;
24pub use ecb_cs1::EcbCs1;
25pub use ecb_cs2::EcbCs2;
26pub use ecb_cs3::EcbCs3;
27
28use cipher::{
29 Block, BlockCipherDecBackend, BlockCipherEncBackend,
30 array::{Array, ArraySize},
31 inout::InOutBuf,
32 typenum::Unsigned,
33};
34
35#[derive(Copy, Clone, Debug)]
37pub struct Error;
38
39pub trait Encrypt: Sized {
41 fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error>;
46
47 fn encrypt(self, buf: &mut [u8]) -> Result<(), Error> {
52 self.encrypt_inout(buf.into())
53 }
54
55 fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), Error> {
60 InOutBuf::new(in_buf, out_buf)
61 .map_err(|_| Error)
62 .and_then(|buf| self.encrypt_inout(buf))
63 }
64}
65
66pub trait Decrypt: Sized {
68 fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error>;
73
74 fn decrypt(self, buf: &mut [u8]) -> Result<(), Error> {
79 self.decrypt_inout(buf.into())
80 }
81
82 fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), Error> {
87 InOutBuf::new(in_buf, out_buf)
88 .map_err(|_| Error)
89 .and_then(|buf| self.decrypt_inout(buf))
90 }
91}
92
93fn ecb_enc<B: BlockCipherEncBackend>(cipher: &B, mut blocks: InOutBuf<'_, '_, Block<B>>) {
94 if B::ParBlocksSize::USIZE > 1 {
95 let (par_blocks, rem_blocks) = blocks.into_chunks();
96 blocks = rem_blocks;
97 for blocks in par_blocks {
98 cipher.encrypt_par_blocks(blocks);
99 }
100 }
101 for block in blocks {
102 cipher.encrypt_block(block);
103 }
104}
105
106fn ecb_dec<B: BlockCipherDecBackend>(cipher: &B, mut blocks: InOutBuf<'_, '_, Block<B>>) {
107 if B::ParBlocksSize::USIZE > 1 {
108 let (par_blocks, rem_blocks) = blocks.into_chunks();
109 blocks = rem_blocks;
110 for blocks in par_blocks {
111 cipher.decrypt_par_blocks(blocks);
112 }
113 }
114 for block in blocks {
115 cipher.decrypt_block(block);
116 }
117}
118
119fn cbc_enc<B: BlockCipherEncBackend>(
120 cipher: &B,
121 iv: &mut Block<B>,
122 mut blocks: InOutBuf<'_, '_, Block<B>>,
123) {
124 for mut block in blocks.reborrow() {
125 let mut t = block.clone_in();
126 xor(&mut t, iv);
127 cipher.encrypt_block_inplace(&mut t);
128 *iv = t.clone();
129 *block.get_out() = t;
130 }
131}
132
133fn cbc_dec<B: BlockCipherDecBackend>(
134 cipher: &B,
135 iv: &mut Block<B>,
136 mut blocks: InOutBuf<'_, '_, Block<B>>,
137) {
138 if B::ParBlocksSize::USIZE > 1 {
139 let (par_blocks, rem_blocks) = blocks.into_chunks();
140 blocks = rem_blocks;
141
142 for mut blocks in par_blocks {
143 let in_blocks = blocks.clone_in();
144 let mut t = blocks.clone_in();
145
146 cipher.decrypt_par_blocks_inplace(&mut t);
147 let n = t.len();
148 xor(&mut t[0], iv);
149 for i in 1..n {
150 xor(&mut t[i], &in_blocks[i - 1]);
151 }
152 *blocks.get_out() = t;
153 *iv = in_blocks[n - 1].clone();
154 }
155 }
156
157 for mut block in blocks {
158 let in_block = block.clone_in();
159 let mut t = block.clone_in();
160 cipher.decrypt_block_inplace(&mut t);
161 xor(&mut t, iv);
162 *block.get_out() = t;
163 *iv = in_block;
164 }
165}
166
167#[inline(always)]
168fn xor<N: ArraySize>(out: &mut Array<u8, N>, buf: &Array<u8, N>) {
169 for (a, b) in out.iter_mut().zip(buf) {
170 *a ^= *b;
171 }
172}