Skip to content

Commit f4fdb5c

Browse files
committed
ocb3: migrate internals to use inout
1 parent a09f3d2 commit f4fdb5c

3 files changed

Lines changed: 79 additions & 66 deletions

File tree

Cargo.lock

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

ocb3/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dbl = "0.4.0-rc.2"
2323
subtle = { version = "2", default-features = false }
2424
aead-stream = { version = "=0.6.0-pre", optional = true, default-features = false }
2525
zeroize = { version = "1", optional = true, default-features = false }
26+
inout = { version = "0.2.0-rc.4", default-features = false }
2627

2728
[dev-dependencies]
2829
aead = { version = "0.6.0-rc.0", features = ["dev"], default-features = false }

ocb3/src/lib.rs

Lines changed: 77 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
html_logo_url = "https://github.com/RustCrypto/meta/master/logo.svg",
66
html_favicon_url = "https://github.com/RustCrypto/meta/master/logo.svg"
77
)]
8-
#![deny(unsafe_code)]
8+
//#![deny(unsafe_code)]
99
#![warn(missing_docs, rust_2018_idioms)]
1010

1111
/// Constants used, reexported for convenience.
@@ -21,11 +21,12 @@ pub use aead::{
2121
use aead::{PostfixTagged, array::ArraySize};
2222
use cipher::{
2323
BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser,
24-
consts::{U12, U16},
24+
consts::{U2, U12, U16},
2525
typenum::Unsigned,
2626
};
27-
use core::marker::PhantomData;
27+
use core::{marker::PhantomData, ops::Mul};
2828
use dbl::Dbl;
29+
use inout::{InOut, InOutBuf};
2930
use subtle::ConstantTimeEq;
3031

3132
/// Number of L values to be precomputed. Precomputing m values, allows
@@ -55,7 +56,9 @@ pub type Nonce<NonceSize> = Array<u8, NonceSize>;
5556
/// OCB3 tag
5657
pub type Tag<TagSize> = Array<u8, TagSize>;
5758

58-
pub(crate) type Block = Array<u8, U16>;
59+
type BlockSize = U16;
60+
pub(crate) type Block = Array<u8, BlockSize>;
61+
type DoubleBlock = Array<u8, <BlockSize as Mul<U2>>::Output>;
5962

6063
mod sealed {
6164
use aead::array::{
@@ -210,34 +213,36 @@ where
210213
associated_data: &[u8],
211214
buffer: &mut [u8],
212215
) -> aead::Result<aead::Tag<Self>> {
216+
let buffer = InOutBuf::from(buffer);
213217
if (buffer.len() > P_MAX) || (associated_data.len() > A_MAX) {
214218
unimplemented!()
215219
}
216220

217221
// First, try to process many blocks at once.
218-
let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer);
222+
let (tail, index, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer);
219223

220-
let mut i = (processed_bytes / 16) + 1;
224+
let mut i = index;
221225

222226
// Then, process the remaining blocks.
223-
for p_i in Block::slice_as_chunks_mut(&mut buffer[processed_bytes..]).0 {
227+
let (blocks, mut tail): (InOutBuf<'_, '_, Block>, _) = tail.into_chunks();
228+
229+
for p_i in blocks {
224230
// offset_i = offset_{i-1} xor L_{ntz(i)}
225231
inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
226232
// checksum_i = checksum_{i-1} xor p_i
227-
inplace_xor(&mut checksum_i, p_i);
233+
inplace_xor(&mut checksum_i, p_i.get_in());
228234
// c_i = offset_i xor ENCIPHER(K, p_i xor offset_i)
229-
let c_i = p_i;
230-
inplace_xor(c_i, &offset_i);
231-
self.cipher.encrypt_block(c_i);
232-
inplace_xor(c_i, &offset_i);
235+
let mut c_i = p_i;
236+
c_i.xor_in2out(&offset_i);
237+
self.cipher.encrypt_block(c_i.get_out());
238+
inplace_xor(c_i.get_out(), &offset_i);
233239

234240
i += 1;
235241
}
236242

237243
// Process any partial blocks.
238-
if (buffer.len() % 16) != 0 {
239-
let processed_bytes = (i - 1) * 16;
240-
let remaining_bytes = buffer.len() - processed_bytes;
244+
if !tail.is_empty() {
245+
let remaining_bytes = tail.len();
241246

242247
// offset_* = offset_m xor L_*
243248
inplace_xor(&mut offset_i, &self.ll_star);
@@ -247,11 +252,11 @@ where
247252
self.cipher.encrypt_block(&mut pad);
248253
// checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
249254
let checksum_rhs = &mut [0u8; 16];
250-
checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]);
255+
checksum_rhs[..remaining_bytes].copy_from_slice(tail.get_in());
251256
checksum_rhs[remaining_bytes] = 0b1000_0000;
252257
inplace_xor(&mut checksum_i, checksum_rhs.as_ref());
253258
// C_* = P_* xor Pad[1..bitlen(P_*)]
254-
let p_star = &mut buffer[processed_bytes..];
259+
let p_star = tail.get_out();
255260
let pad = &mut pad[..p_star.len()];
256261
for (aa, bb) in p_star.iter_mut().zip(pad) {
257262
*aa ^= *bb;
@@ -295,32 +300,32 @@ where
295300
if (buffer.len() > C_MAX) || (associated_data.len() > A_MAX) {
296301
unimplemented!()
297302
}
303+
let buffer = InOutBuf::from(buffer);
298304

299305
// First, try to process many blocks at once.
300-
let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer);
306+
let (tail, index, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer);
301307

302-
let mut i = (processed_bytes / 16) + 1;
308+
let mut i = index;
303309

304310
// Then, process the remaining blocks.
305-
let (blocks, _remaining) = Block::slice_as_chunks_mut(&mut buffer[processed_bytes..]);
311+
let (blocks, mut tail): (InOutBuf<'_, '_, Block>, _) = tail.into_chunks();
306312
for c_i in blocks {
307313
// offset_i = offset_{i-1} xor L_{ntz(i)}
308314
inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
309315
// p_i = offset_i xor DECIPHER(K, c_i xor offset_i)
310-
let p_i = c_i;
311-
inplace_xor(p_i, &offset_i);
312-
self.cipher.decrypt_block(p_i);
313-
inplace_xor(p_i, &offset_i);
316+
let mut p_i = c_i;
317+
p_i.xor_in2out(&offset_i);
318+
self.cipher.decrypt_block(p_i.get_out());
319+
inplace_xor(p_i.get_out(), &offset_i);
314320
// checksum_i = checksum_{i-1} xor p_i
315-
inplace_xor(&mut checksum_i, p_i);
321+
inplace_xor(&mut checksum_i, p_i.get_out());
316322

317323
i += 1;
318324
}
319325

320326
// Process any partial blocks.
321-
if (buffer.len() % 16) != 0 {
322-
let processed_bytes = (i - 1) * 16;
323-
let remaining_bytes = buffer.len() - processed_bytes;
327+
if !tail.is_empty() {
328+
let remaining_bytes = tail.len();
324329

325330
// offset_* = offset_m xor L_*
326331
inplace_xor(&mut offset_i, &self.ll_star);
@@ -329,14 +334,12 @@ where
329334
inplace_xor(&mut pad, &offset_i);
330335
self.cipher.encrypt_block(&mut pad);
331336
// P_* = C_* xor Pad[1..bitlen(C_*)]
332-
let c_star = &mut buffer[processed_bytes..];
337+
let c_star = tail.get_in();
333338
let pad = &mut pad[..c_star.len()];
334-
for (aa, bb) in c_star.iter_mut().zip(pad) {
335-
*aa ^= *bb;
336-
}
339+
tail.xor_in2out(pad);
337340
// checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
338341
let checksum_rhs = &mut [0u8; 16];
339-
checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]);
342+
checksum_rhs[..remaining_bytes].copy_from_slice(tail.get_out());
340343
checksum_rhs[remaining_bytes] = 0b1000_0000;
341344
inplace_xor(&mut checksum_i, checksum_rhs.as_ref());
342345
}
@@ -347,20 +350,24 @@ where
347350
/// Encrypts plaintext in groups of two.
348351
///
349352
/// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c
350-
fn wide_encrypt(&self, nonce: &Nonce<NonceSize>, buffer: &mut [u8]) -> (usize, Block, Block) {
353+
fn wide_encrypt<'i, 'o>(
354+
&self,
355+
nonce: &Nonce<NonceSize>,
356+
buffer: InOutBuf<'i, 'o, u8>,
357+
) -> (InOutBuf<'i, 'o, u8>, usize, Block, Block) {
351358
const WIDTH: usize = 2;
352359

353360
let mut i = 1;
354361

355362
let mut offset_i = [Block::default(); WIDTH];
356363
offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
357364
let mut checksum_i = Block::default();
358-
for wide_blocks in buffer.chunks_exact_mut(<Block as AssocArraySize>::Size::USIZE * WIDTH) {
359-
let p_i = split_into_two_blocks(wide_blocks);
360365

361-
// checksum_i = checksum_{i-1} xor p_i
366+
let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks();
367+
for wide_block in wide_blocks.into_iter() {
368+
let mut p_i = split_into_two_blocks(wide_block);
362369
for p_ij in &p_i {
363-
inplace_xor(&mut checksum_i, p_ij);
370+
inplace_xor(&mut checksum_i, p_ij.get_in());
364371
}
365372

366373
// offset_i = offset_{i-1} xor L_{ntz(i)}
@@ -373,32 +380,36 @@ where
373380

374381
// c_i = offset_i xor ENCIPHER(K, p_i xor offset_i)
375382
for j in 0..p_i.len() {
376-
inplace_xor(p_i[j], &offset_i[j]);
377-
self.cipher.encrypt_block(p_i[j]);
378-
inplace_xor(p_i[j], &offset_i[j])
383+
p_i[j].xor_in2out(&offset_i[j]);
384+
self.cipher.encrypt_block(p_i[j].get_out());
385+
inplace_xor(p_i[j].get_out(), &offset_i[j]);
379386
}
380387

381388
i += WIDTH;
382389
}
383390

384-
let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16);
385-
386-
(processed_bytes, offset_i[offset_i.len() - 1], checksum_i)
391+
(tail, i, offset_i[offset_i.len() - 1], checksum_i)
387392
}
388393

389394
/// Decrypts plaintext in groups of two.
390395
///
391396
/// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c
392-
fn wide_decrypt(&self, nonce: &Nonce<NonceSize>, buffer: &mut [u8]) -> (usize, Block, Block) {
397+
fn wide_decrypt<'i, 'o>(
398+
&self,
399+
nonce: &Nonce<NonceSize>,
400+
buffer: InOutBuf<'i, 'o, u8>,
401+
) -> (InOutBuf<'i, 'o, u8>, usize, Block, Block) {
393402
const WIDTH: usize = 2;
394403

395404
let mut i = 1;
396405

397406
let mut offset_i = [Block::default(); WIDTH];
398407
offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
399408
let mut checksum_i = Block::default();
400-
for wide_blocks in buffer.chunks_exact_mut(16 * WIDTH) {
401-
let c_i = split_into_two_blocks(wide_blocks);
409+
410+
let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks();
411+
for wide_block in wide_blocks.into_iter() {
412+
let mut c_i = split_into_two_blocks(wide_block);
402413

403414
// offset_i = offset_{i-1} xor L_{ntz(i)}
404415
offset_i[0] = offset_i[offset_i.len() - 1];
@@ -411,17 +422,16 @@ where
411422
// p_i = offset_i xor DECIPHER(K, c_i xor offset_i)
412423
// checksum_i = checksum_{i-1} xor p_i
413424
for j in 0..c_i.len() {
414-
inplace_xor(c_i[j], &offset_i[j]);
415-
self.cipher.decrypt_block(c_i[j]);
416-
inplace_xor(c_i[j], &offset_i[j]);
417-
inplace_xor(&mut checksum_i, c_i[j]);
425+
c_i[j].xor_in2out(&offset_i[j]);
426+
self.cipher.decrypt_block(c_i[j].get_out());
427+
inplace_xor(c_i[j].get_out(), &offset_i[j]);
428+
inplace_xor(&mut checksum_i, c_i[j].get_out());
418429
}
419430

420431
i += WIDTH;
421432
}
422433

423-
let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16);
424-
(processed_bytes, offset_i[offset_i.len() - 1], checksum_i)
434+
(tail, i, offset_i[offset_i.len() - 1], checksum_i)
425435
}
426436

427437
/// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1
@@ -580,11 +590,20 @@ pub(crate) fn ntz(n: usize) -> usize {
580590
}
581591

582592
#[inline]
583-
pub(crate) fn split_into_two_blocks(two_blocks: &mut [u8]) -> [&mut Block; 2] {
584-
const BLOCK_SIZE: usize = 16;
585-
debug_assert_eq!(two_blocks.len(), BLOCK_SIZE * 2);
586-
let (b0, b1) = two_blocks.split_at_mut(BLOCK_SIZE);
587-
[b0.try_into().unwrap(), b1.try_into().unwrap()]
593+
pub(crate) fn split_into_two_blocks<'i, 'o>(
594+
two_blocks: InOut<'i, 'o, DoubleBlock>,
595+
) -> [InOut<'i, 'o, Block>; 2] {
596+
let (input, output) = two_blocks.into_raw();
597+
598+
let (bi0, bi1) = unsafe { input.as_ref() }
599+
.unwrap()
600+
.split_at(BlockSize::USIZE);
601+
let (bi0, bi1): (&Block, &Block) = (bi0.try_into().unwrap(), bi1.try_into().unwrap());
602+
let (bo0, bo1) = unsafe { output.as_mut() }
603+
.unwrap()
604+
.split_at_mut(BlockSize::USIZE);
605+
let (bo0, bo1): (&mut Block, &mut Block) = (bo0.try_into().unwrap(), bo1.try_into().unwrap());
606+
[InOut::from((bi0, bo0)), InOut::from((bi1, bo1))]
588607
}
589608

590609
#[cfg(test)]

0 commit comments

Comments
 (0)