// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
+use io;
#[cfg(not(feature = "fuzztarget"))]
mod real_chacha {
- use std::cmp;
- use util::byte_utils::{slice_to_le32, le32_to_array};
+ use core::cmp;
+ use core::convert::TryInto;
#[derive(Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
struct u32x4(pub u32, pub u32, pub u32, pub u32);
- impl ::std::ops::Add for u32x4 {
+ impl ::core::ops::Add for u32x4 {
type Output = u32x4;
fn add(self, rhs: u32x4) -> u32x4 {
u32x4(self.0.wrapping_add(rhs.0),
self.3.wrapping_add(rhs.3))
}
}
- impl ::std::ops::Sub for u32x4 {
+ impl ::core::ops::Sub for u32x4 {
type Output = u32x4;
fn sub(self, rhs: u32x4) -> u32x4 {
u32x4(self.0.wrapping_sub(rhs.0),
self.3.wrapping_sub(rhs.3))
}
}
- impl ::std::ops::BitXor for u32x4 {
+ impl ::core::ops::BitXor for u32x4 {
type Output = u32x4;
fn bitxor(self, rhs: u32x4) -> u32x4 {
u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
}
}
- impl ::std::ops::Shr<u32x4> for u32x4 {
+ impl ::core::ops::Shr<u32x4> for u32x4 {
type Output = u32x4;
fn shr(self, rhs: u32x4) -> u32x4 {
u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3)
}
}
- impl ::std::ops::Shl<u32x4> for u32x4 {
+ impl ::core::ops::Shl<u32x4> for u32x4 {
type Output = u32x4;
fn shl(self, rhs: u32x4) -> u32x4 {
u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3)
}
}
+ impl u32x4 {
+ fn from_bytes(bytes: &[u8]) -> Self {
+ assert_eq!(bytes.len(), 4*4);
+ Self (
+ u32::from_le_bytes(bytes[0*4..1*4].try_into().expect("len is 4")),
+ u32::from_le_bytes(bytes[1*4..2*4].try_into().expect("len is 4")),
+ u32::from_le_bytes(bytes[2*4..3*4].try_into().expect("len is 4")),
+ u32::from_le_bytes(bytes[3*4..4*4].try_into().expect("len is 4")),
+ )
+ }
+ }
+
+ const BLOCK_SIZE: usize = 64;
#[derive(Clone,Copy)]
struct ChaChaState {
#[derive(Copy)]
pub struct ChaCha20 {
state : ChaChaState,
- output : [u8; 64],
+ output : [u8; BLOCK_SIZE],
offset : usize,
}
d1,d2,d3,d4
];
for i in 0..lens.len() {
- $output[i*4..(i+1)*4].copy_from_slice(&le32_to_array(lens[i]));
+ $output[i*4..(i+1)*4].copy_from_slice(&lens[i].to_le_bytes());
}
}}
}
assert!(key.len() == 16 || key.len() == 32);
assert!(nonce.len() == 8 || nonce.len() == 12);
- ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; 64], offset: 64 }
+ ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 }
}
fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
_ => unreachable!(),
};
ChaChaState {
- a: u32x4(
- slice_to_le32(&constant[0..4]),
- slice_to_le32(&constant[4..8]),
- slice_to_le32(&constant[8..12]),
- slice_to_le32(&constant[12..16])
- ),
- b: u32x4(
- slice_to_le32(&key[0..4]),
- slice_to_le32(&key[4..8]),
- slice_to_le32(&key[8..12]),
- slice_to_le32(&key[12..16])
- ),
+ a: u32x4::from_bytes(&constant[0..16]),
+ b: u32x4::from_bytes(&key[0..16]),
c: if key.len() == 16 {
- u32x4(
- slice_to_le32(&key[0..4]),
- slice_to_le32(&key[4..8]),
- slice_to_le32(&key[8..12]),
- slice_to_le32(&key[12..16])
- )
+ u32x4::from_bytes(&key[0..16])
} else {
- u32x4(
- slice_to_le32(&key[16..20]),
- slice_to_le32(&key[20..24]),
- slice_to_le32(&key[24..28]),
- slice_to_le32(&key[28..32])
- )
+ u32x4::from_bytes(&key[16..32])
},
d: if nonce.len() == 16 {
- u32x4(
- slice_to_le32(&nonce[0..4]),
- slice_to_le32(&nonce[4..8]),
- slice_to_le32(&nonce[8..12]),
- slice_to_le32(&nonce[12..16])
- )
+ u32x4::from_bytes(&nonce[0..16])
} else if nonce.len() == 12 {
- u32x4(
- 0,
- slice_to_le32(&nonce[0..4]),
- slice_to_le32(&nonce[4..8]),
- slice_to_le32(&nonce[8..12])
- )
+ let mut nonce4 = [0; 4*4];
+ nonce4[4..].copy_from_slice(nonce);
+ u32x4::from_bytes(&nonce4)
} else {
- u32x4(
- 0,
- 0,
- slice_to_le32(&nonce[0..4]),
- slice_to_le32(&nonce[4..8])
- )
+ let mut nonce4 = [0; 4*4];
+ nonce4[8..].copy_from_slice(nonce);
+ u32x4::from_bytes(&nonce4)
}
}
}
- // put the the next 64 keystream bytes into self.output
+ // put the the next BLOCK_SIZE keystream bytes into self.output
fn update(&mut self) {
let mut state = self.state;
while i < len {
// If there is no keystream available in the output buffer,
// generate the next block.
- if self.offset == 64 {
+ if self.offset == BLOCK_SIZE {
self.update();
}
// Process the min(available keystream, remaining input length).
- let count = cmp::min(64 - self.offset, len - i);
+ let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
// explicitly assert lengths to avoid bounds checks:
assert!(output.len() >= i + count);
assert!(input.len() >= i + count);
self.offset += count;
}
}
+
+ pub fn process_in_place(&mut self, input_output: &mut [u8]) {
+ let len = input_output.len();
+ let mut i = 0;
+ while i < len {
+ // If there is no keystream available in the output buffer,
+ // generate the next block.
+ if self.offset == BLOCK_SIZE {
+ self.update();
+ }
+
+ // Process the min(available keystream, remaining input length).
+ let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
+ // explicitly assert lengths to avoid bounds checks:
+ assert!(input_output.len() >= i + count);
+ assert!(self.output.len() >= self.offset + count);
+ for j in 0..count {
+ input_output[i + j] ^= self.output[self.offset + j];
+ }
+ i += count;
+ self.offset += count;
+ }
+ }
}
}
#[cfg(not(feature = "fuzztarget"))]
pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
output.copy_from_slice(input);
}
+
+ pub fn process_in_place(&mut self, _input_output: &mut [u8]) {}
}
}
#[cfg(feature = "fuzztarget")]
pub use self::fuzzy_chacha::ChaCha20;
+pub(crate) struct ChaChaReader<'a, R: io::Read> {
+ pub chacha: &'a mut ChaCha20,
+ pub read: R,
+}
+impl<'a, R: io::Read> io::Read for ChaChaReader<'a, R> {
+ fn read(&mut self, dest: &mut [u8]) -> Result<usize, io::Error> {
+ let res = self.read.read(dest)?;
+ if res > 0 {
+ self.chacha.process_in_place(&mut dest[0..res]);
+ }
+ Ok(res)
+ }
+}
+
#[cfg(test)]
mod test {
- use std::iter::repeat;
+ use prelude::*;
+ use core::iter::repeat;
use super::ChaCha20;
key: [u8; 32],
nonce: [u8; 8],
keystream: Vec<u8>,
- };
+ }
// taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
let test_vectors = vec!(
TestVector{
key: [u8; 32],
nonce: [u8; 12],
keystream: Vec<u8>,
- };
+ }
// taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
let test_vectors = vec!(
TestVector{