1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Block-cipher modes of operation: ECB, CBC, CFB, OFB and CTR.
//!
//! Each mode wraps an engine that implements the [`tc_block_cipher`] traits
//! and is itself a block cipher: initialize it with
//! [`BlockCipherInit::init`](tc_block_cipher::BlockCipherInit::init), then
//! transform one segment per call with
//! [`BlockCipher::process_block`](tc_block_cipher::BlockCipher::process_block).
//! [`BlockCipherMode`] adds [`reset`](BlockCipherMode::reset) and access to
//! the wrapped engine. Import the traits from `tc_block_cipher`.
//!
//! # Example
//!
//! AES-128 in CBC mode, encrypting and decrypting a two-block message:
//!
//! ```
//! use tc_aes::AesEngine;
//! use tc_block_cipher::{BlockCipher, BlockCipherInit, CipherDirection};
//! use tc_block_modes::{FixedCbcBlockCipher, KeyWithIvRef};
//!
//! let key = [0x42; 16];
//! // Use a fresh, unpredictable IV for every message.
//! let iv = [0x24; 16];
//! let params = KeyWithIvRef::new(&key, &iv);
//! let message = *b"two blocks of exactly 32 bytes!!";
//!
//! let mut mode = FixedCbcBlockCipher::<_, 16>::new(AesEngine::new());
//! mode.init(CipherDirection::Encrypt, ¶ms)?;
//! let mut ciphertext = [0; 32];
//! for (block, out) in message.chunks_exact(16).zip(ciphertext.chunks_exact_mut(16)) {
//! mode.process_block(block, out)?;
//! }
//!
//! mode.init(CipherDirection::Decrypt, ¶ms)?;
//! let mut recovered = [0; 32];
//! for (block, out) in ciphertext.chunks_exact(16).zip(recovered.chunks_exact_mut(16)) {
//! mode.process_block(block, out)?;
//! }
//! assert_eq!(recovered, message);
//! # Ok::<(), Box<dyn core::error::Error>>(())
//! ```
//!
//! # Choosing a mode
//!
//! - [`EcbBlockCipher`]: every block independently. Equal plaintext blocks
//! give equal ciphertext blocks, so use it only for single blocks or as a
//! building block.
//! - [`FixedCbcBlockCipher`] and `CbcBlockCipher`: CBC. Whole blocks only;
//! the IV must be unpredictable for every message.
//! - [`FixedCfbBlockCipher`] and `CfbBlockCipher`: CFB with a segment from one
//! byte (CFB8) up to one block (CFB128 for AES). The IV must be
//! unpredictable for every message.
//! - [`FixedOfbBlockCipher`] and `OfbBlockCipher`: OFB. The IV must never
//! repeat under one key.
//! - [`FixedCtrBlockCipher`] and `CtrBlockCipher`: CTR. A counter block must
//! never repeat under one key.
//!
//! The `Fixed*` forms take the block size `N` (and, for CFB and OFB, the
//! segment size `S` in bytes) as const generics, keep their state inline and
//! need no allocator; initialization rejects an engine whose block size is not
//! `N`. The runtime-sized forms, available with the `alloc` feature, size
//! their state from the engine and take the CFB and OFB feedback size in bits.
//!
//! # Parameters
//!
//! A mode accepts any parameter type that the engine accepts and that also
//! provides the IV through [`IvParams`]. The mode checks the IV and passes the
//! same value on to the engine's `init`.
//!
//! - [`KeyWithIvRef`] borrows a key and an IV without copying or wiping them.
//! - [`KeyWithIvFixed`] owns fixed-size arrays and wipes them on drop.
//! - `KeyWithIvOwned`, available with the `alloc` feature, owns vectors and
//! wipes them on drop.
//!
//! IV rules depend on the mode:
//!
//! - CBC: exactly one block.
//! - CFB and OFB: at most one block. A shorter IV is right-aligned over zeros,
//! as in FIPS 81, so an empty IV is all zeros.
//! - CTR: required. The IV fills the leading bytes of the counter block and
//! the rest start at zero; it may leave at most `min(8, block / 2)` bytes of
//! counter, so AES needs 8 to 16 bytes. The counter spans the whole block
//! and carries into the IV bytes, so keep each message below
//! `2^(8 * counter bytes)` blocks: 64 GiB for AES with a 12-byte IV.
//!
//! A fixed or all-zero IV defeats the confidentiality of every mode here.
//!
//! # Processing
//!
//! [`block_size`](tc_block_cipher::BlockCipher::block_size) returns the
//! segment each call transforms: the engine block for ECB, CBC and CTR, the
//! feedback segment for CFB and OFB. `process_block` transforms the first
//! segment of `input` into `output`, returns its length and leaves any longer
//! tail of `output` untouched. It returns [`BlockModeError::NotInitialised`]
//! before a successful `init` and [`BlockModeError::BufferTooShort`] when
//! either buffer is shorter than a segment; both leave the mode unchanged.
//!
//! There is no padding. ECB and CBC process whole blocks only. CFB, OFB and
//! CTR report [`is_partial_block_okay`](BlockCipherMode::is_partial_block_okay):
//! to finish with a partial segment, copy it into a segment-sized buffer,
//! process that, and keep the matching prefix of the output.
//!
//! A rejected `init` leaves the IV and chaining state of the previous
//! initialization in place; the engine's own state after a rejection is
//! defined by the engine. CFB, OFB and CTR always initialize the engine for
//! encryption, and OFB and CTR ignore the requested direction.
//!
//! # Security
//!
//! None of these modes authenticates: ciphertext can be altered without
//! detection. Protect messages with an authenticated-encryption construction,
//! or add a MAC over the ciphertext.
//!
//! The modes add only data-independent XORs, copies and a branch-free counter
//! increment, so each call is constant time exactly when the engine is.
//! `tc_aes::AesEngine`, for example, is constant time with AES-NI or its
//! `rustcrypto` feature and variable time otherwise.
//!
//! Each mode wipes its IV, its feedback register or counter, and its last
//! chaining or keystream block on drop; the engine wipes its key schedule as
//! its documentation states. Neither erases the caller's buffers or temporary
//! copies left in registers or on the stack.
//!
//! # Features
//!
//! The crate is `no_std` and requires no allocator by default. Enable `alloc`
//! for the runtime-sized modes and `KeyWithIvOwned`; this does not require the
//! standard library.
extern crate alloc;
pub use CbcBlockCipher;
pub use FixedCbcBlockCipher;
pub use CfbBlockCipher;
pub use FixedCfbBlockCipher;
pub use CtrBlockCipher;
pub use FixedCtrBlockCipher;
pub use EcbBlockCipher;
pub use BlockModeError;
pub use BlockModeInitError;
pub use FixedOfbBlockCipher;
pub use OfbBlockCipher;
pub use KeyWithIvOwned;
pub use ;
pub use BlockCipherMode;
pub use IvParams;