rc5_rs/
lib.rs

1//! # RC5 Cipher implementation
2//!
3//! This algorithm is described in this paper:
4//! https://www.grc.com/r&d/rc5.pdf
5
6use {
7  crate::cipher::{encrypt_block, expand_key},
8  cipher::decrypt_block,
9  error::Error,
10  secrecy::{ExposeSecret, SecretVec, Zeroize},
11  std::mem::size_of,
12  word::Word,
13};
14
15pub mod cipher;
16pub mod error;
17pub mod word;
18
19/// RC5 Context
20///
21/// This struct holds the expanded key that the algorithm will use.
22/// Use this struct if you are going to encrypt or decrypt multiple buffers
23/// of data with the same key.
24///
25/// Otherwise you can use the shorthand free standing functions encrypt and
26/// decrypt.
27pub struct Context<W: Word = u32> {
28  expanded_key: SecretVec<W>,
29}
30
31impl<W: Word> Context<W> {
32  pub fn new(mut key: Vec<u8>, rounds: usize) -> Result<Self, Error> {
33    let expanded_key = expand_key::<W>(&key, rounds)?;
34    key.zeroize();
35
36    Ok(Self {
37      expanded_key: SecretVec::new(expanded_key),
38    })
39  }
40
41  /// Encrypts bytes using the RC5 context and returns the ciphertext.
42  /// The plaintext must be a multiple of the block size. Padding is not
43  /// implemented.
44  pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
45    let word_bytes = size_of::<W>();
46    let block_size = 2 * word_bytes;
47
48    if plaintext.len() % block_size != 0 {
49      return Err(Error::InvalidInputLength);
50    }
51
52    let mut ciphertext = Vec::with_capacity(plaintext.len());
53    for block in plaintext.chunks(block_size) {
54      let block = [
55        W::from_le_bytes(&block[0..word_bytes])?,
56        W::from_le_bytes(&block[word_bytes..block_size])?,
57      ];
58
59      ciphertext.extend(
60        encrypt_block::<W>(self.expanded_key.expose_secret(), block)?
61          .into_iter()
62          .map(|w| w.to_le_bytes())
63          .flatten(),
64      );
65    }
66
67    Ok(ciphertext)
68  }
69
70  pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
71    let word_bytes = size_of::<W>();
72    let block_size = 2 * word_bytes;
73
74    if ciphertext.len() % block_size != 0 {
75      return Err(Error::InvalidInputLength);
76    }
77
78    let mut plaintext = Vec::with_capacity(ciphertext.len());
79    for block in ciphertext.chunks(block_size) {
80      let block = [
81        W::from_le_bytes(&block[0..word_bytes])?,
82        W::from_le_bytes(&block[word_bytes..block_size])?,
83      ];
84
85      plaintext.extend(
86        decrypt_block::<W>(self.expanded_key.expose_secret(), block)?
87          .into_iter()
88          .map(|w| w.to_le_bytes())
89          .flatten(),
90      );
91    }
92
93    Ok(plaintext)
94  }
95}
96
97/// Given a key and plaintext, returns the ciphertext using a parametrized RC5.
98///
99/// This is the generic RC5 implementation, which uses a generic word size and
100/// rounds count.
101///
102/// The word size is specified by using a type parameter, which must implement
103/// Word trait. The key size is specified by the length of the key slice.
104/// The rounds count is specified by the rounds parameter.
105///
106/// Usage example:
107///
108/// ```
109/// use rc5_rs::encrypt;
110/// let key = [
111///   0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10,
112///   0x48, 0x81, 0xFF, 0x48,
113/// ];
114///
115/// let pt = vec![0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84];
116/// let ct = vec![0x11, 0xE4, 0x3B, 0x86, 0xD2, 0x31, 0xEA, 0x64];
117/// let res = encrypt::<u32>(&key, &pt, 12).unwrap();
118/// assert_eq!(ct, res);
119/// ```
120pub fn encrypt<W: Word>(
121  key: &[u8],
122  plaintext: &[u8],
123  rounds: usize,
124) -> Result<Vec<u8>, Error> {
125  Context::<W>::new(key.to_vec(), rounds)?.encrypt(plaintext)
126}
127
128/// Given a key and ciphertext, returns the plaintext using a parametrized RC5.
129///
130/// This is the generic RC5 implementation, which uses a generic word size and
131/// rounds count.
132///
133/// The word size is specified by using a type parameter, which must implement
134/// Word trait. The key size is specified by the length of the key slice.
135/// The rounds count is specified by the rounds parameter.
136///
137/// Usage example:
138///
139/// ```
140/// use rc5_rs::decrypt;
141/// let key = [
142///   0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10,
143///   0x48, 0x81, 0xFF, 0x48,
144/// ];
145///
146/// let pt = vec![0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84];
147/// let ct = vec![0x11, 0xE4, 0x3B, 0x86, 0xD2, 0x31, 0xEA, 0x64];
148/// let res = decrypt::<u32>(&key, &ct, 12).unwrap();
149/// assert_eq!(pt, res);
150/// ```
151pub fn decrypt<W: Word>(
152  key: &[u8],
153  ciphertext: &[u8],
154  rounds: usize,
155) -> Result<Vec<u8>, Error> {
156  Context::<W>::new(key.to_vec(), rounds)?.decrypt(ciphertext)
157}
158
159/// Given a key and plaintext, return the ciphertext using RC5/32/12/16.
160///
161/// This is the default RC5 implementation, which uses 32-bit words and 12
162/// rounds and a key size of 16 bytes.
163///
164/// Usage example:
165///
166/// ```
167/// use rc5_rs::encrypt_default;
168/// let key = [
169///   0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10,
170///   0x48, 0x81, 0xFF, 0x48,
171/// ];
172///
173/// let pt = vec![0xEA, 0x02, 0x47, 0x14, 0xAD, 0x5C, 0x4D, 0x84];
174/// let ct = vec![0x11, 0xE4, 0x3B, 0x86, 0xD2, 0x31, 0xEA, 0x64];
175/// let res = encrypt_default(key, &pt).unwrap();
176/// assert_eq!(ct, res);
177/// ```
178pub fn encrypt_default(
179  key: [u8; 16],
180  plaintext: &[u8],
181) -> Result<Vec<u8>, Error> {
182  encrypt::<u32>(&key, plaintext, 12)
183}
184
185/// Given a key and ciphertext, return the plaintext using RC5/32/12/16
186///
187/// Usage example:
188///
189/// ```
190/// use rc5_rs::decrypt_default;
191/// let key = [
192///   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
193///   0x0C, 0x0D, 0x0E, 0x0F,
194/// ];
195///
196/// let pt = vec![0x96, 0x95, 0x0D, 0xDA, 0x65, 0x4A, 0x3D, 0x62];
197/// let ct = vec![0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77];
198/// let res = decrypt_default(key, &ct).unwrap();
199/// assert_eq!(pt, res);
200/// ```
201pub fn decrypt_default(
202  key: [u8; 16],
203  ciphertext: &[u8],
204) -> Result<Vec<u8>, Error> {
205  decrypt::<u32>(&key, ciphertext, 12)
206}