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
//! Block cipher padding schemes: PKCS#7, ISO 7816-4, ANSI X9.23, TBC, zero
//! byte and, with the `rand_core` feature, ISO 10126.
//!
//! ECB and CBC encrypt whole blocks only. A padding scheme fills the end of a
//! message's final block before encryption and, after decryption, reports how
//! many trailing bytes to remove. Every scheme implements
//! [`BlockCipherPadding`] and works on one block at a time; none of them
//! touches a cipher, so they pair with any block mode.
//!
//! # Example
//!
//! AES-128 in CBC mode with PKCS#7, for a 20-byte message:
//!
//! ```
//! use tc_aes::AesEngine;
//! use tc_block_cipher::{BlockCipher, BlockCipherInit, CipherDirection};
//! use tc_block_modes::{FixedCbcBlockCipher, KeyWithIvRef};
//! use tc_block_padding::{BlockCipherPadding, Pkcs7Padding};
//!
//! let (key, iv) = ([0x42; 16], [0x24; 16]);
//! let params = KeyWithIvRef::new(&key, &iv);
//! let message = b"twenty byte message!";
//!
//! // Pad the final partial block: bytes 16..20 hold the message, 12 bytes of
//! // padding follow.
//! let mut data = [0u8; 32];
//! data[..message.len()].copy_from_slice(message);
//! Pkcs7Padding::new().add_padding(&mut data[16..], message.len() - 16)?;
//!
//! let mut cbc = FixedCbcBlockCipher::<_, 16>::new(AesEngine::new());
//! cbc.init(CipherDirection::Encrypt, ¶ms)?;
//! let mut ciphertext = [0u8; 32];
//! for (block, out) in data.chunks_exact(16).zip(ciphertext.chunks_exact_mut(16)) {
//! cbc.process_block(block, out)?;
//! }
//!
//! // Authenticate the ciphertext before this point in real code.
//! cbc.init(CipherDirection::Decrypt, ¶ms)?;
//! let mut plaintext = [0u8; 32];
//! for (block, out) in ciphertext.chunks_exact(16).zip(plaintext.chunks_exact_mut(16)) {
//! cbc.process_block(block, out)?;
//! }
//! let count = Pkcs7Padding::new().pad_count(&plaintext[16..])?;
//! assert_eq!(&plaintext[..32 - count], message);
//! # Ok::<(), Box<dyn core::error::Error>>(())
//! ```
//!
//! # Choosing a scheme
//!
//! - [`Pkcs7Padding`]: PKCS#7, the common default. Every padding byte holds
//! the count, and removal checks all of them.
//! - [`Iso7816d4Padding`]: ISO 7816-4, a `0x80` marker then zeros, used by
//! smart cards and several MACs.
//! - [`X923Padding`]: ANSI X9.23, zeros then the count. Only the count is
//! checked on removal.
//! - `Iso10126Padding`, with the `rand_core` feature: ISO 10126, random bytes
//! then the count. Only the count is checked. The standard is withdrawn; use
//! it for compatibility.
//! - [`TbcPadding`]: trailing bit complement, filled with the complement of
//! the message's last bit.
//! - [`ZeroBytePadding`]: zeros. It cannot tell padding from a message that
//! itself ends in `0x00`, so use it only where message lengths are known
//! some other way.
//!
//! # Padding a message
//!
//! Pad only the final block, at the offset where the message ends in it. Every
//! scheme except zero-byte padding must add at least one byte, so when the
//! message fills its last block exactly, append one more block and pad it
//! from offset 0; passing the block length instead returns
//! [`PaddingError::BlockFull`]. After decryption, `pad_count` on the final
//! block gives the number of bytes to drop. PKCS#7, X9.23 and ISO 10126 store
//! the count in one byte and reject blocks of 256 bytes or more.
//!
//! # Security
//!
//! Padding does not authenticate. Deciding whether decrypted data carries
//! valid padding and acting on the answer, even by returning a different
//! error, turns CBC into a padding oracle that recovers plaintext without the
//! key. Authenticate the ciphertext before removing padding, for example with
//! a MAC over it, or use an authenticated-encryption construction instead of
//! a padded mode.
//!
//! Every scheme adds and checks padding in constant time with respect to the
//! block contents. What `pad_count` returns, the count and whether the padding
//! was valid, is revealed by its result; that is inherent to removing padding
//! and is why the ciphertext must be authenticated first.
//!
//! # Features
//!
//! The crate is `no_std`, needs no allocator and has no dependencies by
//! default. The `rand_core` feature adds `Iso10126Padding` and a dependency on
//! `rand_core`, through which the caller supplies the generator.
pub use Iso7816d4Padding;
pub use Iso10126Padding;
pub use PaddingError;
pub use Pkcs7Padding;
pub use TbcPadding;
pub use BlockCipherPadding;
pub use X923Padding;
pub use ZeroBytePadding;