1 #![no_std]
2 pub extern crate byteorder;
3 pub extern crate block_padding;
4 pub extern crate generic_array;
5 extern crate byte_tools;
6 
7 use byteorder::{ByteOrder, BE};
8 use byte_tools::zero;
9 use block_padding::{Padding, PadError};
10 use generic_array::{GenericArray, ArrayLength};
11 use core::slice;
12 
13 /// Buffer for block processing of data
14 #[derive(Clone, Default)]
15 pub struct BlockBuffer<BlockSize: ArrayLength<u8>>  {
16     buffer: GenericArray<u8, BlockSize>,
17     pos: usize,
18 }
19 
20 #[inline(always)]
cast<N: ArrayLength<u8>>(block: &[u8]) -> &GenericArray<u8, N>21 unsafe fn cast<N: ArrayLength<u8>>(block: &[u8]) -> &GenericArray<u8, N> {
22     debug_assert_eq!(block.len(), N::to_usize());
23     &*(block.as_ptr() as *const GenericArray<u8, N>)
24 }
25 
26 
27 
28 impl<BlockSize: ArrayLength<u8>> BlockBuffer<BlockSize> {
29     /// Process data in `input` in blocks of size `BlockSize` using function `f`.
30     #[inline]
input<F>(&mut self, mut input: &[u8], mut f: F) where F: FnMut(&GenericArray<u8, BlockSize>)31     pub fn input<F>(&mut self, mut input: &[u8], mut f: F)
32         where F: FnMut(&GenericArray<u8, BlockSize>)
33     {
34         // If there is already data in the buffer, process it if we have
35         // enough to complete the chunk.
36         let rem = self.remaining();
37         if self.pos != 0 && input.len() >= rem {
38             let (l, r) = input.split_at(rem);
39             input = r;
40             self.buffer[self.pos..].copy_from_slice(l);
41             self.pos = 0;
42             f(&self.buffer);
43         }
44 
45         // While we have at least a full buffer size chunks's worth of data,
46         // process that data without copying it into the buffer
47         while input.len() >= self.size() {
48             let (block, r) = input.split_at(self.size());
49             input = r;
50             f(unsafe { cast(block) });
51         }
52 
53         // Copy any remaining data into the buffer.
54         self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input);
55         self.pos += input.len();
56     }
57 
58     /*
59     /// Process data in `input` in blocks of size `BlockSize` using function `f`, which accepts
60     /// slice of blocks.
61     #[inline]
62     pub fn input2<F>(&mut self, mut input: &[u8], mut f: F)
63         where F: FnMut(&[GenericArray<u8, BlockSize>])
64     {
65         // If there is already data in the buffer, process it if we have
66         // enough to complete the chunk.
67         let rem = self.remaining();
68         if self.pos != 0 && input.len() >= rem {
69             let (l, r) = input.split_at(rem);
70             input = r;
71             self.buffer[self.pos..].copy_from_slice(l);
72             self.pos = 0;
73             f(slice::from_ref(&self.buffer));
74         }
75 
76         // While we have at least a full buffer size chunks's worth of data,
77         // process it data without copying into the buffer
78         let n_blocks = input.len()/self.size();
79         let (left, right) = input.split_at(n_blocks*self.size());
80         // safe because we guarantee that `blocks` does not point outside of `input`
81         let blocks = unsafe {
82             slice::from_raw_parts(
83                 left.as_ptr() as *const GenericArray<u8, BlockSize>,
84                 n_blocks,
85             )
86         };
87         f(blocks);
88 
89         // Copy remaining data into the buffer.
90         self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right);
91         self.pos += right.len();
92     }
93     */
94 
95     /// Variant that doesn't flush the buffer until there's additional
96     /// data to be processed. Suitable for tweakable block ciphers
97     /// like Threefish that need to know whether a block is the *last*
98     /// data block before processing it.
99     #[inline]
input_lazy<F>(&mut self, mut input: &[u8], mut f: F) where F: FnMut(&GenericArray<u8, BlockSize>)100     pub fn input_lazy<F>(&mut self, mut input: &[u8], mut f: F)
101         where F: FnMut(&GenericArray<u8, BlockSize>)
102     {
103         let rem = self.remaining();
104         if self.pos != 0 && input.len() > rem {
105             let (l, r) = input.split_at(rem);
106             input = r;
107             self.buffer[self.pos..].copy_from_slice(l);
108             self.pos = 0;
109             f(&self.buffer);
110         }
111 
112         while input.len() > self.size() {
113             let (block, r) = input.split_at(self.size());
114             input = r;
115             f(unsafe { cast(block) });
116         }
117 
118         self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input);
119         self.pos += input.len();
120     }
121 
122     /// Pad buffer with `prefix` and make sure that internall buffer
123     /// has at least `up_to` free bytes. All remaining bytes get
124     /// zeroed-out.
125     #[inline]
digest_pad<F>(&mut self, up_to: usize, f: &mut F) where F: FnMut(&GenericArray<u8, BlockSize>)126     fn digest_pad<F>(&mut self, up_to: usize, f: &mut F)
127         where F: FnMut(&GenericArray<u8, BlockSize>)
128     {
129         if self.pos == self.size() {
130             f(&self.buffer);
131             self.pos = 0;
132         }
133         self.buffer[self.pos] = 0x80;
134         self.pos += 1;
135 
136         zero(&mut self.buffer[self.pos..]);
137 
138         if self.remaining() < up_to {
139             f(&self.buffer);
140             zero(&mut self.buffer[..self.pos]);
141         }
142     }
143 
144     /// Pad message with 0x80, zeros and 64-bit message length
145     /// in a byte order specified by `B`
146     #[inline]
len64_padding<B, F>(&mut self, data_len: u64, mut f: F) where B: ByteOrder, F: FnMut(&GenericArray<u8, BlockSize>)147     pub fn len64_padding<B, F>(&mut self, data_len: u64, mut f: F)
148         where B: ByteOrder, F: FnMut(&GenericArray<u8, BlockSize>)
149     {
150         // TODO: replace `F` with `impl Trait` on MSRV bump
151         self.digest_pad(8, &mut f);
152         let s = self.size();
153         B::write_u64(&mut self.buffer[s-8..], data_len);
154         f(&self.buffer);
155         self.pos = 0;
156     }
157 
158 
159     /// Pad message with 0x80, zeros and 128-bit message length
160     /// in the big-endian byte order
161     #[inline]
len128_padding_be<F>(&mut self, hi: u64, lo: u64, mut f: F) where F: FnMut(&GenericArray<u8, BlockSize>)162     pub fn len128_padding_be<F>(&mut self, hi: u64, lo: u64, mut f: F)
163         where F: FnMut(&GenericArray<u8, BlockSize>)
164     {
165         // TODO: on MSRV bump replace `F` with `impl Trait`, use `u128`, add `B`
166         self.digest_pad(16, &mut f);
167         let s = self.size();
168         BE::write_u64(&mut self.buffer[s-16..s-8], hi);
169         BE::write_u64(&mut self.buffer[s-8..], lo);
170         f(&self.buffer);
171         self.pos = 0;
172     }
173 
174     /// Pad message with a given padding `P`
175     ///
176     /// Returns `PadError` if internall buffer is full, which can only happen if
177     /// `input_lazy` was used.
178     #[inline]
pad_with<P: Padding>(&mut self) -> Result<&mut GenericArray<u8, BlockSize>, PadError>179     pub fn pad_with<P: Padding>(&mut self)
180         -> Result<&mut GenericArray<u8, BlockSize>, PadError>
181     {
182         P::pad_block(&mut self.buffer[..], self.pos)?;
183         self.pos = 0;
184         Ok(&mut self.buffer)
185     }
186 
187     /// Return size of the internall buffer in bytes
188     #[inline]
size(&self) -> usize189     pub fn size(&self) -> usize {
190         BlockSize::to_usize()
191     }
192 
193     /// Return current cursor position
194     #[inline]
position(&self) -> usize195     pub fn position(&self) -> usize {
196         self.pos
197     }
198 
199     /// Return number of remaining bytes in the internall buffer
200     #[inline]
remaining(&self) -> usize201     pub fn remaining(&self) -> usize {
202         self.size() - self.pos
203     }
204 
205     /// Reset buffer by setting cursor position to zero
206     #[inline]
reset(&mut self)207     pub fn reset(&mut self)  {
208         self.pos = 0
209     }
210 }
211