Skip to content

Commit 557d864

Browse files
authored
deoxys: rewrite the internals to use inout (#666)
This is to prepare the migration to `AeadInOut`, following RustCrypto/traits#1793 Note: there is a strong chance this could actually use the StreamCipherCore api, but I couldn't not make it fit.
1 parent c667162 commit 557d864

File tree

4 files changed

+277
-126
lines changed

4 files changed

+277
-126
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deoxys/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ rust-version = "1.85"
2020
[dependencies]
2121
aead = { version = "0.6.0-rc.0", default-features = false }
2222
aes = { version = "=0.9.0-pre.3", features = ["hazmat"], default-features = false }
23+
inout = { version = "0.2.0-rc.4", default-features = false }
2324
subtle = { version = "2", default-features = false }
2425
zeroize = { version = "1", optional = true, default-features = false }
2526

deoxys/src/lib.rs

Lines changed: 129 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ use aead::{
118118
consts::U16,
119119
};
120120
use core::marker::PhantomData;
121+
use inout::{InOut, InOutBuf};
121122

122123
/// Deoxys-I with 128-bit keys
123124
pub type DeoxysI128 = Deoxys<modes::DeoxysI<deoxys_bc::DeoxysBc256>, deoxys_bc::DeoxysBc256>;
@@ -156,19 +157,19 @@ where
156157

157158
/// Encrypts the data in place with the specified parameters
158159
/// Returns the tag
159-
fn encrypt_in_place(
160+
fn encrypt_inout(
160161
nonce: &Array<u8, Self::NonceSize>,
161162
associated_data: &[u8],
162-
buffer: &mut [u8],
163+
buffer: InOutBuf<'_, '_, u8>,
163164
subkeys: &Array<DeoxysKey, B::SubkeysSize>,
164165
) -> Tag;
165166

166167
/// Decrypts the data in place with the specified parameters
167168
/// Returns an error if the tag verification fails
168-
fn decrypt_in_place(
169+
fn decrypt_inout(
169170
nonce: &Array<u8, Self::NonceSize>,
170171
associated_data: &[u8],
171-
buffer: &mut [u8],
172+
buffer: InOutBuf<'_, '_, u8>,
172173
tag: &Tag,
173174
subkeys: &Array<DeoxysKey, B::SubkeysSize>,
174175
) -> Result<(), aead::Error>;
@@ -184,44 +185,40 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal {
184185
fn precompute_subkeys(key: &Array<u8, Self::KeySize>) -> Array<DeoxysKey, Self::SubkeysSize>;
185186

186187
/// Encrypts a block of data in place.
187-
fn encrypt_in_place(
188-
block: &mut Block,
188+
fn encrypt_inout(
189+
mut block: InOut<'_, '_, Block>,
189190
tweak: &Tweak,
190191
subkeys: &Array<DeoxysKey, Self::SubkeysSize>,
191192
) {
192193
let keys = Self::key_schedule(tweak, subkeys);
193194

194-
for (b, k) in block.iter_mut().zip(keys[0].iter()) {
195-
*b ^= k;
196-
}
195+
block.xor_in2out(&keys[0]);
197196

198197
for k in &keys[1..] {
199-
aes::hazmat::cipher_round(block, k);
198+
aes::hazmat::cipher_round(block.get_out(), k);
200199
}
201200
}
202201

203202
/// Decrypts a block of data in place.
204-
fn decrypt_in_place(
205-
block: &mut Block,
203+
fn decrypt_inout(
204+
mut block: InOut<'_, '_, Block>,
206205
tweak: &Tweak,
207206
subkeys: &Array<DeoxysKey, Self::SubkeysSize>,
208207
) {
209208
let mut keys = Self::key_schedule(tweak, subkeys);
210209

211210
let r = keys.len();
212211

213-
for (b, k) in block.iter_mut().zip(keys[r - 1].iter()) {
214-
*b ^= k;
215-
}
212+
block.xor_in2out(&keys[r - 1]);
216213

217-
aes::hazmat::inv_mix_columns(block);
214+
aes::hazmat::inv_mix_columns(block.get_out());
218215

219216
for k in keys[..r - 1].iter_mut().rev() {
220217
aes::hazmat::inv_mix_columns(k);
221-
aes::hazmat::equiv_inv_cipher_round(block, k);
218+
aes::hazmat::equiv_inv_cipher_round(block.get_out(), k);
222219
}
223220

224-
aes::hazmat::mix_columns(block);
221+
aes::hazmat::mix_columns(block.get_out());
225222
}
226223
}
227224

@@ -285,10 +282,10 @@ where
285282
associated_data: &[u8],
286283
buffer: &mut [u8],
287284
) -> Result<Tag, Error> {
288-
Ok(Tag::from(M::encrypt_in_place(
285+
Ok(Tag::from(M::encrypt_inout(
289286
nonce,
290287
associated_data,
291-
buffer,
288+
buffer.into(),
292289
&self.subkeys,
293290
)))
294291
}
@@ -300,7 +297,7 @@ where
300297
buffer: &mut [u8],
301298
tag: &Tag,
302299
) -> Result<(), Error> {
303-
M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys)
300+
M::decrypt_inout(nonce, associated_data, buffer.into(), tag, &self.subkeys)
304301
}
305302
}
306303

@@ -327,3 +324,114 @@ where
327324
B: DeoxysBcType,
328325
{
329326
}
327+
328+
#[cfg(test)]
329+
mod tests {
330+
//! this module is here to test the inout behavior which is not currently exposed.
331+
//! it will be once we port over to the API made in RustCrypto/traits#1793.
332+
//!
333+
//! This is to drop once https://github.com/RustCrypto/traits/pull/1797 is made available.
334+
//!
335+
//! It duplicates test vectors from `tests/deoxys_i_128.rs` and provides a mock buffer backing
336+
//! for InOut.
337+
338+
use hex_literal::hex;
339+
340+
use super::*;
341+
342+
struct MockBuffer {
343+
in_buf: [u8; 33],
344+
out_buf: [u8; 33],
345+
}
346+
347+
impl From<&[u8]> for MockBuffer {
348+
fn from(buf: &[u8]) -> Self {
349+
let mut in_buf = [0u8; 33];
350+
in_buf.copy_from_slice(buf);
351+
Self {
352+
in_buf,
353+
out_buf: [0u8; 33],
354+
}
355+
}
356+
}
357+
358+
impl MockBuffer {
359+
/// Get an [`InOutBuf`] from a [`MockBuffer`]
360+
pub fn to_in_out_buf(&mut self) -> InOutBuf<'_, '_, u8> {
361+
InOutBuf::new(self.in_buf.as_slice(), self.out_buf.as_mut_slice())
362+
.expect("Invariant violation")
363+
}
364+
}
365+
366+
impl AsRef<[u8]> for MockBuffer {
367+
fn as_ref(&self) -> &[u8] {
368+
&self.out_buf
369+
}
370+
}
371+
372+
#[test]
373+
fn test_deoxys_i_128_5() {
374+
let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4");
375+
let mut buffer = MockBuffer::from(&plaintext[..]);
376+
377+
let aad = [];
378+
379+
let key = hex!("101112131415161718191a1b1c1d1e1f");
380+
let key = Array(key);
381+
382+
let nonce = hex!("202122232425262728292a2b2c2d2e2f");
383+
let nonce = Array::try_from(&nonce[..8]).unwrap();
384+
385+
let ciphertext_expected =
386+
hex!("cded5a43d3c76e942277c2a1517530ad66037897c985305ede345903ed7585a626");
387+
388+
let tag_expected: [u8; 16] = hex!("cbf5faa6b8398c47f4278d2019161776");
389+
390+
type M = modes::DeoxysI<deoxys_bc::DeoxysBc256>;
391+
let cipher = DeoxysI128::new(&key);
392+
let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys);
393+
394+
let ciphertext = buffer.as_ref();
395+
assert_eq!(ciphertext, ciphertext_expected);
396+
assert_eq!(tag, tag_expected);
397+
398+
let mut buffer = MockBuffer::from(buffer.as_ref());
399+
M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys)
400+
.expect("decryption failed");
401+
402+
assert_eq!(&plaintext[..], buffer.as_ref());
403+
}
404+
405+
#[test]
406+
fn test_deoxys_ii_128_5() {
407+
let plaintext = hex!("06ac1756eccece62bd743fa80c299f7baa3872b556130f52265919494bdc136db3");
408+
let mut buffer = MockBuffer::from(&plaintext[..]);
409+
410+
let aad = [];
411+
412+
let key = hex!("101112131415161718191a1b1c1d1e1f");
413+
let key = Array(key);
414+
415+
let nonce = hex!("202122232425262728292a2b2c2d2e2f");
416+
let nonce = Array::try_from(&nonce[..15]).unwrap();
417+
418+
let ciphertext_expected =
419+
hex!("82bf241958b324ed053555d23315d3cc20935527fc970ff34a9f521a95e302136d");
420+
421+
let tag_expected: [u8; 16] = hex!("0eadc8612d5208c491e93005195e9769");
422+
423+
type M = modes::DeoxysII<deoxys_bc::DeoxysBc256>;
424+
let cipher = DeoxysII128::new(&key);
425+
let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys);
426+
427+
let ciphertext = buffer.as_ref();
428+
assert_eq!(ciphertext, ciphertext_expected);
429+
assert_eq!(tag, tag_expected);
430+
431+
let mut buffer = MockBuffer::from(buffer.as_ref());
432+
M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys)
433+
.expect("decryption failed");
434+
435+
assert_eq!(&plaintext[..], buffer.as_ref());
436+
}
437+
}

0 commit comments

Comments
 (0)