diff --git a/block-buffer/Cargo.toml b/block-buffer/Cargo.toml index d94e7a15..0e18fcc4 100644 --- a/block-buffer/Cargo.toml +++ b/block-buffer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block-buffer" -version = "0.8.0" +version = "0.9.0-pre" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" description = "Fixed size buffer for block processing of data" @@ -8,12 +8,8 @@ documentation = "https://docs.rs/block-buffer" repository = "https://github.com/RustCrypto/utils" keywords = ["block", "buffer"] categories = ["cryptography", "no-std"] +edition = "2018" [dependencies] -byteorder = { version = "1.1", default-features = false } -byte-tools = "0.3" -block-padding = "0.1" +block-padding = { version = "0.2.0-pre", path = "../block-padding", optional = true } generic-array = "0.14" - -[badges] -travis-ci = { repository = "RustCrypto/utils" } diff --git a/block-buffer/src/lib.rs b/block-buffer/src/lib.rs index edfd981a..bebc9715 100644 --- a/block-buffer/src/lib.rs +++ b/block-buffer/src/lib.rs @@ -1,13 +1,12 @@ #![no_std] -pub extern crate byteorder; -pub extern crate block_padding; -pub extern crate generic_array; -extern crate byte_tools; +pub use generic_array; +#[cfg(feature = "block-padding")] +pub use block_padding; -use byteorder::{ByteOrder, BE}; -use byte_tools::zero; -use block_padding::{Padding, PadError}; +use core::{slice, convert::TryInto}; use generic_array::{GenericArray, ArrayLength}; +#[cfg(feature = "block-padding")] +use block_padding::{Padding, PadError}; /// Buffer for block processing of data #[derive(Clone, Default)] @@ -16,56 +15,52 @@ pub struct BlockBuffer> { pos: usize, } -#[inline(always)] -unsafe fn cast>(block: &[u8]) -> &GenericArray { - debug_assert_eq!(block.len(), N::to_usize()); - &*(block.as_ptr() as *const GenericArray) -} - - - impl> BlockBuffer { /// Process data in `input` in blocks of size `BlockSize` using function `f`. #[inline] - pub fn input(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&GenericArray) - { - // If there is already data in the buffer, process it if we have - // enough to complete the chunk. - let rem = self.remaining(); - if self.pos != 0 && input.len() >= rem { - let (l, r) = input.split_at(rem); + pub fn input_block( + &mut self, mut input: &[u8], mut f: impl FnMut(&GenericArray), + ) { + let r = self.remaining(); + if input.len() < r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() >= r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; f(&self.buffer); } - // While we have at least a full buffer size chunks's worth of data, - // process that data without copying it into the buffer - while input.len() >= self.size() { - let (block, r) = input.split_at(self.size()); - input = r; - f(unsafe { cast(block) }); + let mut chunks_iter = input.chunks_exact(self.size()); + for chunk in &mut chunks_iter { + f(chunk.try_into().unwrap()); } + let rem = chunks_iter.remainder(); // Copy any remaining data into the buffer. - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); + self.buffer[..rem.len()].copy_from_slice(rem); + self.pos = rem.len(); } - /* /// Process data in `input` in blocks of size `BlockSize` using function `f`, which accepts /// slice of blocks. #[inline] - pub fn input2(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&[GenericArray]) - { - // If there is already data in the buffer, process it if we have - // enough to complete the chunk. - let rem = self.remaining(); - if self.pos != 0 && input.len() >= rem { - let (l, r) = input.split_at(rem); + pub fn input_blocks( + &mut self, mut input: &[u8], mut f: impl FnMut(&[GenericArray]), + ) { + let r = self.remaining(); + if input.len() < r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() >= r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); self.pos = 0; @@ -73,10 +68,10 @@ impl> BlockBuffer { } // While we have at least a full buffer size chunks's worth of data, - // process it data without copying into the buffer + // process its data without copying into the buffer let n_blocks = input.len()/self.size(); let (left, right) = input.split_at(n_blocks*self.size()); - // safe because we guarantee that `blocks` does not point outside of `input` + // SAFETY: we guarantee that `blocks` does not point outside of `input` let blocks = unsafe { slice::from_raw_parts( left.as_ptr() as *const GenericArray, @@ -86,10 +81,10 @@ impl> BlockBuffer { f(blocks); // Copy remaining data into the buffer. - self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right); - self.pos += right.len(); + let n = right.len(); + self.buffer[..n].copy_from_slice(right); + self.pos = n; } - */ /// Variant that doesn't flush the buffer until there's additional /// data to be processed. Suitable for tweakable block ciphers @@ -99,32 +94,37 @@ impl> BlockBuffer { pub fn input_lazy(&mut self, mut input: &[u8], mut f: F) where F: FnMut(&GenericArray) { - let rem = self.remaining(); - if self.pos != 0 && input.len() > rem { - let (l, r) = input.split_at(rem); + let r = self.remaining(); + if input.len() <= r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() > r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; f(&self.buffer); } while input.len() > self.size() { let (block, r) = input.split_at(self.size()); input = r; - f(unsafe { cast(block) }); + f(block.try_into().unwrap()); } - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); + self.buffer[..input.len()].copy_from_slice(input); + self.pos = input.len(); } /// Pad buffer with `prefix` and make sure that internall buffer /// has at least `up_to` free bytes. All remaining bytes get /// zeroed-out. #[inline] - fn digest_pad(&mut self, up_to: usize, f: &mut F) - where F: FnMut(&GenericArray) - { + fn digest_pad( + &mut self, up_to: usize, mut f: impl FnMut(&GenericArray), + ) { if self.pos == self.size() { f(&self.buffer); self.pos = 0; @@ -132,40 +132,52 @@ impl> BlockBuffer { self.buffer[self.pos] = 0x80; self.pos += 1; - zero(&mut self.buffer[self.pos..]); + set_zero(&mut self.buffer[self.pos..]); if self.remaining() < up_to { f(&self.buffer); - zero(&mut self.buffer[..self.pos]); + set_zero(&mut self.buffer[..self.pos]); } } /// Pad message with 0x80, zeros and 64-bit message length - /// in a byte order specified by `B` + /// using big-endian byte order #[inline] - pub fn len64_padding(&mut self, data_len: u64, mut f: F) - where B: ByteOrder, F: FnMut(&GenericArray) - { - // TODO: replace `F` with `impl Trait` on MSRV bump + pub fn len64_padding_be( + &mut self, data_len: u64, mut f: impl FnMut(&GenericArray), + ) { self.digest_pad(8, &mut f); - let s = self.size(); - B::write_u64(&mut self.buffer[s-8..], data_len); + let b = data_len.to_be_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); f(&self.buffer); self.pos = 0; } + /// Pad message with 0x80, zeros and 64-bit message length + /// using little-endian byte order + #[inline] + pub fn len64_padding_le( + &mut self, data_len: u64, mut f: impl FnMut(&GenericArray), + ) { + self.digest_pad(8, &mut f); + let b = data_len.to_le_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); + f(&self.buffer); + self.pos = 0; + } /// Pad message with 0x80, zeros and 128-bit message length - /// in the big-endian byte order + /// using big-endian byte order #[inline] - pub fn len128_padding_be(&mut self, hi: u64, lo: u64, mut f: F) - where F: FnMut(&GenericArray) - { - // TODO: on MSRV bump replace `F` with `impl Trait`, use `u128`, add `B` + pub fn len128_padding_be( + &mut self, data_len: u128, mut f: impl FnMut(&GenericArray), + ) { self.digest_pad(16, &mut f); - let s = self.size(); - BE::write_u64(&mut self.buffer[s-16..s-8], hi); - BE::write_u64(&mut self.buffer[s-8..], lo); + let b = data_len.to_be_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); f(&self.buffer); self.pos = 0; } @@ -174,6 +186,7 @@ impl> BlockBuffer { /// /// Returns `PadError` if internall buffer is full, which can only happen if /// `input_lazy` was used. + #[cfg(feature = "block-padding")] #[inline] pub fn pad_with(&mut self) -> Result<&mut GenericArray, PadError> @@ -207,3 +220,14 @@ impl> BlockBuffer { self.pos = 0 } } + +/// Sets all bytes in `dst` to zero +#[inline(always)] +fn set_zero(dst: &mut [u8]) { + // SAFETY: we overwrite valid memory behind `dst` + // note: loop is not used here because it produces + // unnecessary branch which tests for zero-length slices + unsafe { + core::ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len()); + } +} diff --git a/block-padding/Cargo.toml b/block-padding/Cargo.toml index 3999ff59..6797b118 100644 --- a/block-padding/Cargo.toml +++ b/block-padding/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "block-padding" -version = "0.1.5" +version = "0.2.0-pre" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" description = "Padding and unpadding of messages divided into blocks." @@ -8,9 +8,4 @@ documentation = "https://docs.rs/block-padding" repository = "https://github.com/RustCrypto/utils" keywords = ["padding", "pkcs7", "ansix923", "iso7816"] categories = ["cryptography", "no-std"] - -[dependencies] -byte-tools = "0.3" - -[badges] -travis-ci = { repository = "RustCrypto/utils" } +edition = "2018" diff --git a/block-padding/src/lib.rs b/block-padding/src/lib.rs index 5c4c8c3b..09d82400 100644 --- a/block-padding/src/lib.rs +++ b/block-padding/src/lib.rs @@ -6,9 +6,6 @@ #![no_std] #![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] -extern crate byte_tools; - -use byte_tools::{zero, set}; /// Error for indicating failed padding operation #[derive(Clone, Copy, Debug)] @@ -80,7 +77,7 @@ pub enum ZeroPadding{} impl Padding for ZeroPadding { fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> { if pos > block.len() { Err(PadError)? } - zero(&mut block[pos..]); + set(&mut block[pos..], 0); Ok(()) } @@ -212,7 +209,7 @@ impl Padding for AnsiX923 { if block.len() > 255 { Err(PadError)? } if pos >= block.len() { Err(PadError)? } let bs = block.len(); - zero(&mut block[pos..bs-1]); + set(&mut block[pos..bs-1], 0); block[bs-1] = (bs - pos) as u8; Ok(()) } @@ -260,7 +257,7 @@ impl Padding for Iso7816 { fn pad_block(block: &mut [u8], pos: usize) -> Result<(), PadError> { if pos >= block.len() { Err(PadError)? } block[pos] = 0x80; - zero(&mut block[pos+1..]); + set(&mut block[pos+1..], 0); Ok(()) } @@ -321,3 +318,14 @@ impl Padding for NoPadding { Ok(data) } } + +/// Sets all bytes in `dst` equal to `value` +#[inline(always)] +fn set(dst: &mut [u8], value: u8) { + // SAFETY: we overwrite valid memory behind `dst` + // note: loop is not used here because it produces + // unnecessary branch which tests for zero-length slices + unsafe { + core::ptr::write_bytes(dst.as_mut_ptr(), value, dst.len()); + } +}