use crate::onion_message::packet::ControlTlvs;
use crate::prelude::*;
use crate::sign::{NodeSigner, Recipient};
-use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter;
+use crate::crypto::streams::ChaChaPolyReadAdapter;
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer};
use core::mem;
use crate::ln::msgs::DecodeError;
use crate::ln::onion_utils;
use crate::onion_message::messenger::Destination;
-use crate::util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
+use crate::crypto::streams::ChaChaPolyWriteAdapter;
use crate::util::ser::{Readable, Writeable};
use crate::io;
preimages_slice_to_htlcs!($preimages_slice).into_iter().map(|(htlc, _)| (htlc, None)).collect()
}
}
- let dummy_sig = crate::util::crypto::sign(&secp_ctx,
+ let dummy_sig = crate::crypto::utils::sign(&secp_ctx,
&bitcoin::secp256k1::Message::from_slice(&[42; 32]).unwrap(),
&SecretKey::from_slice(&[42; 32]).unwrap());
--- /dev/null
+// This file was stolen from rust-crypto.
+// 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.
+
+#[cfg(not(fuzzing))]
+mod real_chacha {
+ 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 ::core::ops::Add for u32x4 {
+ type Output = u32x4;
+ #[inline]
+ fn add(self, rhs: u32x4) -> u32x4 {
+ u32x4(self.0.wrapping_add(rhs.0),
+ self.1.wrapping_add(rhs.1),
+ self.2.wrapping_add(rhs.2),
+ self.3.wrapping_add(rhs.3))
+ }
+ }
+ impl ::core::ops::Sub for u32x4 {
+ type Output = u32x4;
+ #[inline]
+ fn sub(self, rhs: u32x4) -> u32x4 {
+ u32x4(self.0.wrapping_sub(rhs.0),
+ self.1.wrapping_sub(rhs.1),
+ self.2.wrapping_sub(rhs.2),
+ self.3.wrapping_sub(rhs.3))
+ }
+ }
+ impl ::core::ops::BitXor for u32x4 {
+ type Output = u32x4;
+ #[inline]
+ fn bitxor(self, rhs: u32x4) -> u32x4 {
+ u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
+ }
+ }
+ impl ::core::ops::Shr<u8> for u32x4 {
+ type Output = u32x4;
+ #[inline]
+ fn shr(self, shr: u8) -> u32x4 {
+ u32x4(self.0 >> shr, self.1 >> shr, self.2 >> shr, self.3 >> shr)
+ }
+ }
+ impl ::core::ops::Shl<u8> for u32x4 {
+ type Output = u32x4;
+ #[inline]
+ fn shl(self, shl: u8) -> u32x4 {
+ u32x4(self.0 << shl, self.1 << shl, self.2 << shl, self.3 << shl)
+ }
+ }
+ impl u32x4 {
+ #[inline]
+ 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 {
+ a: u32x4,
+ b: u32x4,
+ c: u32x4,
+ d: u32x4
+ }
+
+ #[derive(Copy)]
+ pub struct ChaCha20 {
+ state : ChaChaState,
+ output : [u8; BLOCK_SIZE],
+ offset : usize,
+ }
+
+ impl Clone for ChaCha20 { fn clone(&self) -> ChaCha20 { *self } }
+
+ macro_rules! swizzle {
+ ($b: expr, $c: expr, $d: expr) => {{
+ let u32x4(b10, b11, b12, b13) = $b;
+ $b = u32x4(b11, b12, b13, b10);
+ let u32x4(c10, c11, c12, c13) = $c;
+ $c = u32x4(c12, c13,c10, c11);
+ let u32x4(d10, d11, d12, d13) = $d;
+ $d = u32x4(d13, d10, d11, d12);
+ }}
+ }
+
+ macro_rules! state_to_buffer {
+ ($state: expr, $output: expr) => {{
+ let u32x4(a1, a2, a3, a4) = $state.a;
+ let u32x4(b1, b2, b3, b4) = $state.b;
+ let u32x4(c1, c2, c3, c4) = $state.c;
+ let u32x4(d1, d2, d3, d4) = $state.d;
+ let lens = [
+ a1,a2,a3,a4,
+ b1,b2,b3,b4,
+ c1,c2,c3,c4,
+ d1,d2,d3,d4
+ ];
+ for i in 0..lens.len() {
+ $output[i*4..(i+1)*4].copy_from_slice(&lens[i].to_le_bytes());
+ }
+ }}
+ }
+
+ macro_rules! round{
+ ($state: expr) => {{
+ $state.a = $state.a + $state.b;
+ rotate!($state.d, $state.a, 16);
+ $state.c = $state.c + $state.d;
+ rotate!($state.b, $state.c, 12);
+ $state.a = $state.a + $state.b;
+ rotate!($state.d, $state.a, 8);
+ $state.c = $state.c + $state.d;
+ rotate!($state.b, $state.c, 7);
+ }}
+ }
+
+ macro_rules! rotate {
+ ($a: expr, $b: expr, $rot: expr) => {{
+ let v = $a ^ $b;
+ let r = 32 - $rot;
+ let right = v >> r;
+ $a = (v << $rot) ^ right
+ }}
+ }
+
+ impl ChaCha20 {
+ pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
+ assert!(key.len() == 16 || key.len() == 32);
+ assert!(nonce.len() == 8 || nonce.len() == 12);
+
+ ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 }
+ }
+
+ /// Get one block from a ChaCha stream.
+ pub fn get_single_block(key: &[u8; 32], nonce: &[u8; 16]) -> [u8; 32] {
+ let mut chacha = ChaCha20 { state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 };
+ let mut chacha_bytes = [0; 32];
+ chacha.process_in_place(&mut chacha_bytes);
+ chacha_bytes
+ }
+
+ /// Encrypts `src` into `dest` using a single block from a ChaCha stream. Passing `dest` as
+ /// `src` in a second call will decrypt it.
+ pub fn encrypt_single_block(
+ key: &[u8; 32], nonce: &[u8; 16], dest: &mut [u8], src: &[u8]
+ ) {
+ debug_assert_eq!(dest.len(), src.len());
+ debug_assert!(dest.len() <= 32);
+
+ let block = ChaCha20::get_single_block(key, nonce);
+ for i in 0..dest.len() {
+ dest[i] = block[i] ^ src[i];
+ }
+ }
+
+ /// Same as `encrypt_single_block` only operates on a fixed-size input in-place.
+ pub fn encrypt_single_block_in_place(
+ key: &[u8; 32], nonce: &[u8; 16], bytes: &mut [u8; 32]
+ ) {
+ let block = ChaCha20::get_single_block(key, nonce);
+ for i in 0..bytes.len() {
+ bytes[i] = block[i] ^ bytes[i];
+ }
+ }
+
+ fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
+ let constant = match key.len() {
+ 16 => b"expand 16-byte k",
+ 32 => b"expand 32-byte k",
+ _ => unreachable!(),
+ };
+ ChaChaState {
+ a: u32x4::from_bytes(&constant[0..16]),
+ b: u32x4::from_bytes(&key[0..16]),
+ c: if key.len() == 16 {
+ u32x4::from_bytes(&key[0..16])
+ } else {
+ u32x4::from_bytes(&key[16..32])
+ },
+ d: if nonce.len() == 16 {
+ u32x4::from_bytes(&nonce[0..16])
+ } else if nonce.len() == 12 {
+ let mut nonce4 = [0; 4*4];
+ nonce4[4..].copy_from_slice(nonce);
+ u32x4::from_bytes(&nonce4)
+ } else {
+ let mut nonce4 = [0; 4*4];
+ nonce4[8..].copy_from_slice(nonce);
+ u32x4::from_bytes(&nonce4)
+ }
+ }
+ }
+
+ // put the the next BLOCK_SIZE keystream bytes into self.output
+ fn update(&mut self) {
+ let mut state = self.state;
+
+ for _ in 0..10 {
+ round!(state);
+ swizzle!(state.b, state.c, state.d);
+ round!(state);
+ swizzle!(state.d, state.c, state.b);
+ }
+ state.a = state.a + self.state.a;
+ state.b = state.b + self.state.b;
+ state.c = state.c + self.state.c;
+ state.d = state.d + self.state.d;
+
+ state_to_buffer!(state, self.output);
+
+ self.state.d = self.state.d + u32x4(1, 0, 0, 0);
+ let u32x4(c12, _, _, _) = self.state.d;
+ if c12 == 0 {
+ // we could increment the other counter word with an 8 byte nonce
+ // but other implementations like boringssl have this same
+ // limitation
+ panic!("counter is exhausted");
+ }
+
+ self.offset = 0;
+ }
+
+ #[inline] // Useful cause input may be 0s on stack that should be optimized out
+ pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
+ assert!(input.len() == output.len());
+ let len = input.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!(output.len() >= i + count);
+ assert!(input.len() >= i + count);
+ assert!(self.output.len() >= self.offset + count);
+ for j in 0..count {
+ output[i + j] = input[i + j] ^ self.output[self.offset + j];
+ }
+ 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(test)]
+ pub fn seek_to_block(&mut self, block_offset: u32) {
+ self.state.d.0 = block_offset;
+ self.update();
+ }
+ }
+}
+#[cfg(not(fuzzing))]
+pub use self::real_chacha::ChaCha20;
+
+#[cfg(fuzzing)]
+mod fuzzy_chacha {
+ pub struct ChaCha20 {}
+
+ impl ChaCha20 {
+ pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
+ assert!(key.len() == 16 || key.len() == 32);
+ assert!(nonce.len() == 8 || nonce.len() == 12);
+ Self {}
+ }
+
+ pub fn get_single_block(_key: &[u8; 32], _nonce: &[u8; 16]) -> [u8; 32] {
+ [0; 32]
+ }
+
+ pub fn encrypt_single_block(
+ _key: &[u8; 32], _nonce: &[u8; 16], dest: &mut [u8], src: &[u8]
+ ) {
+ debug_assert_eq!(dest.len(), src.len());
+ debug_assert!(dest.len() <= 32);
+ }
+
+ pub fn encrypt_single_block_in_place(
+ _key: &[u8; 32], _nonce: &[u8; 16], _bytes: &mut [u8; 32]
+ ) {}
+
+ 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(fuzzing)]
+pub use self::fuzzy_chacha::ChaCha20;
+
+#[cfg(test)]
+mod test {
+ use alloc::vec;
+ use alloc::vec::{Vec};
+ use core::convert::TryInto;
+ use core::iter::repeat;
+
+ use super::ChaCha20;
+
+ #[test]
+ fn test_chacha20_256_tls_vectors() {
+ struct TestVector {
+ 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: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+ keystream: vec!(
+ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
+ 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
+ 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
+ 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
+ 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
+ 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
+ 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
+ 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+ keystream: vec!(
+ 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
+ 0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
+ 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
+ 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
+ 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
+ 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
+ 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
+ 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
+ keystream: vec!(
+ 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
+ 0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
+ 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
+ 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
+ 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
+ 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
+ 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
+ 0x44, 0x5f, 0x41, 0xe3,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ nonce: [ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+ keystream: vec!(
+ 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
+ 0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
+ 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
+ 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
+ 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
+ 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
+ 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
+ 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ ],
+ nonce: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
+ keystream: vec!(
+ 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
+ 0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
+ 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
+ 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
+ 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
+ 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
+ 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
+ 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
+ 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
+ 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
+ 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
+ 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
+ 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
+ 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
+ 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
+ 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
+ 0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
+ 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
+ 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
+ 0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
+ 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
+ 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
+ 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
+ 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
+ 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
+ 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
+ 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
+ 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
+ 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
+ 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
+ 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
+ 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
+ ),
+ },
+ );
+
+ for tv in test_vectors.iter() {
+ let mut c = ChaCha20::new(&tv.key, &tv.nonce);
+ let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
+ let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
+ c.process(&input[..], &mut output[..]);
+ assert_eq!(output, tv.keystream);
+ }
+ }
+
+ #[test]
+ fn test_chacha20_256_tls_vectors_96_nonce() {
+ struct 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{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+ keystream: vec!(
+ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
+ 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
+ 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
+ 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
+ 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
+ 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
+ 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
+ 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+ keystream: vec!(
+ 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
+ 0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
+ 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
+ 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
+ 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
+ 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
+ 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
+ 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
+ keystream: vec!(
+ 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
+ 0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
+ 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
+ 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
+ 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
+ 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
+ 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
+ 0x44, 0x5f, 0x41, 0xe3,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ nonce: [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
+ keystream: vec!(
+ 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
+ 0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
+ 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
+ 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
+ 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
+ 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
+ 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
+ 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
+ ),
+ }, TestVector{
+ key: [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ ],
+ nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
+ keystream: vec!(
+ 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
+ 0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
+ 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
+ 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
+ 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
+ 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
+ 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
+ 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
+ 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
+ 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
+ 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
+ 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
+ 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
+ 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
+ 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
+ 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
+ 0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
+ 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
+ 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
+ 0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
+ 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
+ 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
+ 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
+ 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
+ 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
+ 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
+ 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
+ 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
+ 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
+ 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
+ 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
+ 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
+ ),
+ },
+ );
+
+ for tv in test_vectors.iter() {
+ let mut c = ChaCha20::new(&tv.key, &tv.nonce);
+ let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
+ let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
+ c.process(&input[..], &mut output[..]);
+ assert_eq!(output, tv.keystream);
+ }
+ }
+
+ #[test]
+ fn get_single_block() {
+ // Test that `get_single_block` (which takes a 16-byte nonce) is equivalent to getting a block
+ // using a 12-byte nonce, with the block starting at the counter offset given by the remaining 4
+ // bytes.
+ let key = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ ];
+ let nonce_16bytes = [
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ ];
+ let counter_pos = &nonce_16bytes[..4];
+ let nonce_12bytes = &nonce_16bytes[4..];
+
+ // Initialize a ChaCha20 instance with its counter starting at 0.
+ let mut chacha20 = ChaCha20::new(&key, nonce_12bytes);
+ // Seek its counter to the block at counter_pos.
+ chacha20.seek_to_block(u32::from_le_bytes(counter_pos.try_into().unwrap()));
+ let mut block_bytes = [0; 32];
+ chacha20.process_in_place(&mut block_bytes);
+
+ assert_eq!(ChaCha20::get_single_block(&key, &nonce_16bytes), block_bytes);
+ }
+
+ #[test]
+ fn encrypt_single_block() {
+ let key = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ ];
+ let nonce = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ ];
+ let bytes = [1; 32];
+
+ let mut encrypted_bytes = [0; 32];
+ ChaCha20::encrypt_single_block(&key, &nonce, &mut encrypted_bytes, &bytes);
+
+ let mut decrypted_bytes = [0; 32];
+ ChaCha20::encrypt_single_block(&key, &nonce, &mut decrypted_bytes, &encrypted_bytes);
+
+ assert_eq!(bytes, decrypted_bytes);
+ }
+
+ #[test]
+ fn encrypt_single_block_in_place() {
+ let key = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ ];
+ let nonce = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ ];
+ let unencrypted_bytes = [1; 32];
+ let mut bytes = unencrypted_bytes;
+
+ ChaCha20::encrypt_single_block_in_place(&key, &nonce, &mut bytes);
+ assert_ne!(bytes, unencrypted_bytes);
+
+ ChaCha20::encrypt_single_block_in_place(&key, &nonce, &mut bytes);
+ assert_eq!(bytes, unencrypted_bytes);
+ }
+}
--- /dev/null
+// ring has a garbage API so its use is avoided, but rust-crypto doesn't have RFC-variant poly1305
+// Instead, we steal rust-crypto's implementation and tweak it to match the RFC.
+//
+// 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.
+//
+// This is a port of Andrew Moons poly1305-donna
+// https://github.com/floodyberry/poly1305-donna
+
+#[cfg(not(fuzzing))]
+mod real_chachapoly {
+ use super::super::chacha20::ChaCha20;
+ use super::super::poly1305::Poly1305;
+ use super::super::fixed_time_eq;
+
+ #[derive(Clone, Copy)]
+ pub struct ChaCha20Poly1305RFC {
+ cipher: ChaCha20,
+ mac: Poly1305,
+ finished: bool,
+ data_len: usize,
+ aad_len: u64,
+ }
+
+ impl ChaCha20Poly1305RFC {
+ #[inline]
+ fn pad_mac_16(mac: &mut Poly1305, len: usize) {
+ if len % 16 != 0 {
+ mac.input(&[0; 16][0..16 - (len % 16)]);
+ }
+ }
+ pub fn new(key: &[u8], nonce: &[u8], aad: &[u8]) -> ChaCha20Poly1305RFC {
+ assert!(key.len() == 16 || key.len() == 32);
+ assert!(nonce.len() == 12);
+
+ // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant
+ assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0);
+
+ let mut cipher = ChaCha20::new(key, &nonce[4..]);
+ let mut mac_key = [0u8; 64];
+ let zero_key = [0u8; 64];
+ cipher.process(&zero_key, &mut mac_key);
+
+ let mut mac = Poly1305::new(&mac_key[..32]);
+ mac.input(aad);
+ ChaCha20Poly1305RFC::pad_mac_16(&mut mac, aad.len());
+
+ ChaCha20Poly1305RFC {
+ cipher,
+ mac,
+ finished: false,
+ data_len: 0,
+ aad_len: aad.len() as u64,
+ }
+ }
+
+ pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
+ assert!(input.len() == output.len());
+ assert!(self.finished == false);
+ self.cipher.process(input, output);
+ self.data_len += input.len();
+ self.mac.input(output);
+ ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
+ self.finished = true;
+ self.mac.input(&self.aad_len.to_le_bytes());
+ self.mac.input(&(self.data_len as u64).to_le_bytes());
+ self.mac.raw_result(out_tag);
+ }
+
+ pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
+ self.encrypt_in_place(input_output);
+ self.finish_and_get_tag(out_tag);
+ }
+
+ // Encrypt `input_output` in-place. To finish and calculate the tag, use `finish_and_get_tag`
+ // below.
+ pub(in super::super) fn encrypt_in_place(&mut self, input_output: &mut [u8]) {
+ debug_assert!(self.finished == false);
+ self.cipher.process_in_place(input_output);
+ self.data_len += input_output.len();
+ self.mac.input(input_output);
+ }
+
+ // If we were previously encrypting with `encrypt_in_place`, this method can be used to finish
+ // encrypting and calculate the tag.
+ pub(in super::super) fn finish_and_get_tag(&mut self, out_tag: &mut [u8]) {
+ debug_assert!(self.finished == false);
+ ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
+ self.finished = true;
+ self.mac.input(&self.aad_len.to_le_bytes());
+ self.mac.input(&(self.data_len as u64).to_le_bytes());
+ self.mac.raw_result(out_tag);
+ }
+
+ /// Decrypt the `input`, checking the given `tag` prior to writing the decrypted contents
+ /// into `output`. Note that, because `output` is not touched until the `tag` is checked,
+ /// this decryption is *variable time*.
+ pub fn variable_time_decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> Result<(), ()> {
+ assert!(input.len() == output.len());
+ assert!(self.finished == false);
+
+ self.finished = true;
+
+ self.mac.input(input);
+
+ self.data_len += input.len();
+ ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
+ self.mac.input(&self.aad_len.to_le_bytes());
+ self.mac.input(&(self.data_len as u64).to_le_bytes());
+
+ let mut calc_tag = [0u8; 16];
+ self.mac.raw_result(&mut calc_tag);
+ if fixed_time_eq(&calc_tag, tag) {
+ self.cipher.process(input, output);
+ Ok(())
+ } else {
+ Err(())
+ }
+ }
+
+ pub fn check_decrypt_in_place(&mut self, input_output: &mut [u8], tag: &[u8]) -> Result<(), ()> {
+ self.decrypt_in_place(input_output);
+ if self.finish_and_check_tag(tag) { Ok(()) } else { Err(()) }
+ }
+
+ /// Decrypt in place, without checking the tag. Use `finish_and_check_tag` to check it
+ /// later when decryption finishes.
+ ///
+ /// Should never be `pub` because the public API should always enforce tag checking.
+ pub(in super::super) fn decrypt_in_place(&mut self, input_output: &mut [u8]) {
+ debug_assert!(self.finished == false);
+ self.mac.input(input_output);
+ self.data_len += input_output.len();
+ self.cipher.process_in_place(input_output);
+ }
+
+ /// If we were previously decrypting with `just_decrypt_in_place`, this method must be used
+ /// to check the tag. Returns whether or not the tag is valid.
+ pub(in super::super) fn finish_and_check_tag(&mut self, tag: &[u8]) -> bool {
+ debug_assert!(self.finished == false);
+ self.finished = true;
+ ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
+ self.mac.input(&self.aad_len.to_le_bytes());
+ self.mac.input(&(self.data_len as u64).to_le_bytes());
+
+ let mut calc_tag = [0u8; 16];
+ self.mac.raw_result(&mut calc_tag);
+ if fixed_time_eq(&calc_tag, tag) {
+ true
+ } else {
+ false
+ }
+ }
+ }
+}
+#[cfg(not(fuzzing))]
+pub use self::real_chachapoly::ChaCha20Poly1305RFC;
+
+#[cfg(fuzzing)]
+mod fuzzy_chachapoly {
+ #[derive(Clone, Copy)]
+ pub struct ChaCha20Poly1305RFC {
+ tag: [u8; 16],
+ finished: bool,
+ }
+ impl ChaCha20Poly1305RFC {
+ pub fn new(key: &[u8], nonce: &[u8], _aad: &[u8]) -> ChaCha20Poly1305RFC {
+ assert!(key.len() == 16 || key.len() == 32);
+ assert!(nonce.len() == 12);
+
+ // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant
+ assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0);
+
+ let mut tag = [0; 16];
+ tag.copy_from_slice(&key[0..16]);
+
+ ChaCha20Poly1305RFC {
+ tag,
+ finished: false,
+ }
+ }
+
+ pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
+ assert!(input.len() == output.len());
+ assert!(self.finished == false);
+
+ output.copy_from_slice(&input);
+ out_tag.copy_from_slice(&self.tag);
+ self.finished = true;
+ }
+
+ pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
+ self.encrypt_in_place(input_output);
+ self.finish_and_get_tag(out_tag);
+ }
+
+ pub(in super::super) fn encrypt_in_place(&mut self, _input_output: &mut [u8]) {
+ assert!(self.finished == false);
+ }
+
+ pub(in super::super) fn finish_and_get_tag(&mut self, out_tag: &mut [u8]) {
+ assert!(self.finished == false);
+ out_tag.copy_from_slice(&self.tag);
+ self.finished = true;
+ }
+
+ pub fn variable_time_decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> Result<(), ()> {
+ assert!(input.len() == output.len());
+ assert!(self.finished == false);
+
+ if tag[..] != self.tag[..] { return Err(()); }
+ output.copy_from_slice(input);
+ self.finished = true;
+ Ok(())
+ }
+
+ pub fn check_decrypt_in_place(&mut self, input_output: &mut [u8], tag: &[u8]) -> Result<(), ()> {
+ self.decrypt_in_place(input_output);
+ if self.finish_and_check_tag(tag) { Ok(()) } else { Err(()) }
+ }
+
+ pub(in super::super) fn decrypt_in_place(&mut self, _input: &mut [u8]) {
+ assert!(self.finished == false);
+ }
+
+ pub(in super::super) fn finish_and_check_tag(&mut self, tag: &[u8]) -> bool {
+ if tag[..] != self.tag[..] { return false; }
+ self.finished = true;
+ true
+ }
+ }
+}
+#[cfg(fuzzing)]
+pub use self::fuzzy_chachapoly::ChaCha20Poly1305RFC;
--- /dev/null
+use bitcoin::hashes::cmp::fixed_time_eq;
+
+pub(crate) mod chacha20;
+#[cfg(not(fuzzing))]
+pub(crate) mod poly1305;
+pub(crate) mod chacha20poly1305rfc;
+pub(crate) mod streams;
+pub(crate) mod utils;
--- /dev/null
+// 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.
+
+// This is a port of Andrew Moons poly1305-donna
+// https://github.com/floodyberry/poly1305-donna
+
+use core::cmp::min;
+use core::convert::TryInto;
+
+#[derive(Clone, Copy)]
+pub struct Poly1305 {
+ r : [u32; 5],
+ h : [u32; 5],
+ pad : [u32; 4],
+ leftover : usize,
+ buffer : [u8; 16],
+ finalized : bool,
+}
+
+impl Poly1305 {
+ pub fn new(key: &[u8]) -> Poly1305 {
+ assert!(key.len() == 32);
+ let mut poly = Poly1305{ r: [0u32; 5], h: [0u32; 5], pad: [0u32; 4], leftover: 0, buffer: [0u8; 16], finalized: false };
+
+ // r &= 0xffffffc0ffffffc0ffffffc0fffffff
+ poly.r[0] = (u32::from_le_bytes(key[ 0.. 4].try_into().expect("len is 4")) ) & 0x3ffffff;
+ poly.r[1] = (u32::from_le_bytes(key[ 3.. 7].try_into().expect("len is 4")) >> 2) & 0x3ffff03;
+ poly.r[2] = (u32::from_le_bytes(key[ 6..10].try_into().expect("len is 4")) >> 4) & 0x3ffc0ff;
+ poly.r[3] = (u32::from_le_bytes(key[ 9..13].try_into().expect("len is 4")) >> 6) & 0x3f03fff;
+ poly.r[4] = (u32::from_le_bytes(key[12..16].try_into().expect("len is 4")) >> 8) & 0x00fffff;
+
+ poly.pad[0] = u32::from_le_bytes(key[16..20].try_into().expect("len is 4"));
+ poly.pad[1] = u32::from_le_bytes(key[20..24].try_into().expect("len is 4"));
+ poly.pad[2] = u32::from_le_bytes(key[24..28].try_into().expect("len is 4"));
+ poly.pad[3] = u32::from_le_bytes(key[28..32].try_into().expect("len is 4"));
+
+ poly
+ }
+
+ fn block(&mut self, m: &[u8]) {
+ let hibit : u32 = if self.finalized { 0 } else { 1 << 24 };
+
+ let r0 = self.r[0];
+ let r1 = self.r[1];
+ let r2 = self.r[2];
+ let r3 = self.r[3];
+ let r4 = self.r[4];
+
+ let s1 = r1 * 5;
+ let s2 = r2 * 5;
+ let s3 = r3 * 5;
+ let s4 = r4 * 5;
+
+ let mut h0 = self.h[0];
+ let mut h1 = self.h[1];
+ let mut h2 = self.h[2];
+ let mut h3 = self.h[3];
+ let mut h4 = self.h[4];
+
+ // h += m
+ h0 += (u32::from_le_bytes(m[ 0.. 4].try_into().expect("len is 4")) ) & 0x3ffffff;
+ h1 += (u32::from_le_bytes(m[ 3.. 7].try_into().expect("len is 4")) >> 2) & 0x3ffffff;
+ h2 += (u32::from_le_bytes(m[ 6..10].try_into().expect("len is 4")) >> 4) & 0x3ffffff;
+ h3 += (u32::from_le_bytes(m[ 9..13].try_into().expect("len is 4")) >> 6) & 0x3ffffff;
+ h4 += (u32::from_le_bytes(m[12..16].try_into().expect("len is 4")) >> 8) | hibit;
+
+ // h *= r
+ let d0 = (h0 as u64 * r0 as u64) + (h1 as u64 * s4 as u64) + (h2 as u64 * s3 as u64) + (h3 as u64 * s2 as u64) + (h4 as u64 * s1 as u64);
+ let mut d1 = (h0 as u64 * r1 as u64) + (h1 as u64 * r0 as u64) + (h2 as u64 * s4 as u64) + (h3 as u64 * s3 as u64) + (h4 as u64 * s2 as u64);
+ let mut d2 = (h0 as u64 * r2 as u64) + (h1 as u64 * r1 as u64) + (h2 as u64 * r0 as u64) + (h3 as u64 * s4 as u64) + (h4 as u64 * s3 as u64);
+ let mut d3 = (h0 as u64 * r3 as u64) + (h1 as u64 * r2 as u64) + (h2 as u64 * r1 as u64) + (h3 as u64 * r0 as u64) + (h4 as u64 * s4 as u64);
+ let mut d4 = (h0 as u64 * r4 as u64) + (h1 as u64 * r3 as u64) + (h2 as u64 * r2 as u64) + (h3 as u64 * r1 as u64) + (h4 as u64 * r0 as u64);
+
+ // (partial) h %= p
+ let mut c : u32;
+ c = (d0 >> 26) as u32; h0 = d0 as u32 & 0x3ffffff;
+ d1 += c as u64; c = (d1 >> 26) as u32; h1 = d1 as u32 & 0x3ffffff;
+ d2 += c as u64; c = (d2 >> 26) as u32; h2 = d2 as u32 & 0x3ffffff;
+ d3 += c as u64; c = (d3 >> 26) as u32; h3 = d3 as u32 & 0x3ffffff;
+ d4 += c as u64; c = (d4 >> 26) as u32; h4 = d4 as u32 & 0x3ffffff;
+ h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += c;
+
+ self.h[0] = h0;
+ self.h[1] = h1;
+ self.h[2] = h2;
+ self.h[3] = h3;
+ self.h[4] = h4;
+ }
+
+ pub fn finish(&mut self) {
+ if self.leftover > 0 {
+ self.buffer[self.leftover] = 1;
+ for i in self.leftover+1..16 {
+ self.buffer[i] = 0;
+ }
+ self.finalized = true;
+ let tmp = self.buffer;
+ self.block(&tmp);
+ }
+
+ // fully carry h
+ let mut h0 = self.h[0];
+ let mut h1 = self.h[1];
+ let mut h2 = self.h[2];
+ let mut h3 = self.h[3];
+ let mut h4 = self.h[4];
+
+ let mut c : u32;
+ c = h1 >> 26; h1 = h1 & 0x3ffffff;
+ h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
+ h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
+ h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
+ h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += c;
+
+ // compute h + -p
+ let mut g0 = h0.wrapping_add(5); c = g0 >> 26; g0 &= 0x3ffffff;
+ let mut g1 = h1.wrapping_add(c); c = g1 >> 26; g1 &= 0x3ffffff;
+ let mut g2 = h2.wrapping_add(c); c = g2 >> 26; g2 &= 0x3ffffff;
+ let mut g3 = h3.wrapping_add(c); c = g3 >> 26; g3 &= 0x3ffffff;
+ let mut g4 = h4.wrapping_add(c).wrapping_sub(1 << 26);
+
+ // select h if h < p, or h + -p if h >= p
+ let mut mask = (g4 >> (32 - 1)).wrapping_sub(1);
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = !mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ // h = h % (2^128)
+ h0 = ((h0 ) | (h1 << 26)) & 0xffffffff;
+ h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
+ h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+ h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
+
+ // h = mac = (h + pad) % (2^128)
+ let mut f : u64;
+ f = h0 as u64 + self.pad[0] as u64 ; h0 = f as u32;
+ f = h1 as u64 + self.pad[1] as u64 + (f >> 32); h1 = f as u32;
+ f = h2 as u64 + self.pad[2] as u64 + (f >> 32); h2 = f as u32;
+ f = h3 as u64 + self.pad[3] as u64 + (f >> 32); h3 = f as u32;
+
+ self.h[0] = h0;
+ self.h[1] = h1;
+ self.h[2] = h2;
+ self.h[3] = h3;
+ }
+
+ pub fn input(&mut self, data: &[u8]) {
+ assert!(!self.finalized);
+ let mut m = data;
+
+ if self.leftover > 0 {
+ let want = min(16 - self.leftover, m.len());
+ for i in 0..want {
+ self.buffer[self.leftover+i] = m[i];
+ }
+ m = &m[want..];
+ self.leftover += want;
+
+ if self.leftover < 16 {
+ return;
+ }
+
+ // self.block(self.buffer[..]);
+ let tmp = self.buffer;
+ self.block(&tmp);
+
+ self.leftover = 0;
+ }
+
+ while m.len() >= 16 {
+ self.block(&m[0..16]);
+ m = &m[16..];
+ }
+
+ for i in 0..m.len() {
+ self.buffer[i] = m[i];
+ }
+ self.leftover = m.len();
+ }
+
+ pub fn raw_result(&mut self, output: &mut [u8]) {
+ assert!(output.len() >= 16);
+ if !self.finalized{
+ self.finish();
+ }
+ output[0..4].copy_from_slice(&self.h[0].to_le_bytes());
+ output[4..8].copy_from_slice(&self.h[1].to_le_bytes());
+ output[8..12].copy_from_slice(&self.h[2].to_le_bytes());
+ output[12..16].copy_from_slice(&self.h[3].to_le_bytes());
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use core::iter::repeat;
+ use alloc::vec::Vec;
+
+ use super::Poly1305;
+
+ fn poly1305(key: &[u8], msg: &[u8], mac: &mut [u8]) {
+ let mut poly = Poly1305::new(key);
+ poly.input(msg);
+ poly.raw_result(mac);
+ }
+
+ #[test]
+ fn test_nacl_vector() {
+ let key = [
+ 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91,
+ 0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25,
+ 0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65,
+ 0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80,
+ ];
+
+ let msg = [
+ 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73,
+ 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce,
+ 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4,
+ 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a,
+ 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b,
+ 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72,
+ 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2,
+ 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38,
+ 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a,
+ 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae,
+ 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea,
+ 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda,
+ 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde,
+ 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3,
+ 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6,
+ 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74,
+ 0xe3,0x55,0xa5,
+ ];
+
+ let expected = [
+ 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5,
+ 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9,
+ ];
+
+ let mut mac = [0u8; 16];
+ poly1305(&key, &msg, &mut mac);
+ assert_eq!(&mac[..], &expected[..]);
+
+ let mut poly = Poly1305::new(&key);
+ poly.input(&msg[0..32]);
+ poly.input(&msg[32..96]);
+ poly.input(&msg[96..112]);
+ poly.input(&msg[112..120]);
+ poly.input(&msg[120..124]);
+ poly.input(&msg[124..126]);
+ poly.input(&msg[126..127]);
+ poly.input(&msg[127..128]);
+ poly.input(&msg[128..129]);
+ poly.input(&msg[129..130]);
+ poly.input(&msg[130..131]);
+ poly.raw_result(&mut mac);
+ assert_eq!(&mac[..], &expected[..]);
+ }
+
+ #[test]
+ fn donna_self_test() {
+ let wrap_key = [
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let wrap_msg = [
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ];
+
+ let wrap_mac = [
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let mut mac = [0u8; 16];
+ poly1305(&wrap_key, &wrap_msg, &mut mac);
+ assert_eq!(&mac[..], &wrap_mac[..]);
+
+ let total_key = [
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
+ 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let total_mac = [
+ 0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd,
+ 0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39,
+ ];
+
+ let mut tpoly = Poly1305::new(&total_key);
+ for i in 0..256 {
+ let key: Vec<u8> = repeat(i as u8).take(32).collect();
+ let msg: Vec<u8> = repeat(i as u8).take(256).collect();
+ let mut mac = [0u8; 16];
+ poly1305(&key[..], &msg[0..i], &mut mac);
+ tpoly.input(&mac);
+ }
+ tpoly.raw_result(&mut mac);
+ assert_eq!(&mac[..], &total_mac[..]);
+ }
+
+ #[test]
+ fn test_tls_vectors() {
+ // from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
+ let key = b"this is 32-byte key for Poly1305";
+ let msg = [0u8; 32];
+ let expected = [
+ 0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6,
+ 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07,
+ ];
+ let mut mac = [0u8; 16];
+ poly1305(key, &msg, &mut mac);
+ assert_eq!(&mac[..], &expected[..]);
+
+ let msg = b"Hello world!";
+ let expected= [
+ 0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16,
+ 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0,
+ ];
+ poly1305(key, msg, &mut mac);
+ assert_eq!(&mac[..], &expected[..]);
+ }
+}
--- /dev/null
+use crate::crypto::chacha20::ChaCha20;
+use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC;
+
+use crate::ln::msgs::DecodeError;
+use crate::util::ser::{FixedLengthReader, LengthRead, LengthReadableArgs, Readable, Writeable, Writer};
+use crate::io::{self, Read, Write};
+
+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)
+ }
+}
+
+/// Enables the use of the serialization macros for objects that need to be simultaneously encrypted and
+/// serialized. This allows us to avoid an intermediate Vec allocation.
+pub(crate) struct ChaChaPolyWriteAdapter<'a, W: Writeable> {
+ pub rho: [u8; 32],
+ pub writeable: &'a W,
+}
+
+impl<'a, W: Writeable> ChaChaPolyWriteAdapter<'a, W> {
+ #[allow(unused)] // This will be used for onion messages soon
+ pub fn new(rho: [u8; 32], writeable: &'a W) -> ChaChaPolyWriteAdapter<'a, W> {
+ Self { rho, writeable }
+ }
+}
+
+impl<'a, T: Writeable> Writeable for ChaChaPolyWriteAdapter<'a, T> {
+ // Simultaneously write and encrypt Self::writeable.
+ fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+ let mut chacha = ChaCha20Poly1305RFC::new(&self.rho, &[0; 12], &[]);
+ let mut chacha_stream = ChaChaPolyWriter { chacha: &mut chacha, write: w };
+ self.writeable.write(&mut chacha_stream)?;
+ let mut tag = [0 as u8; 16];
+ chacha.finish_and_get_tag(&mut tag);
+ tag.write(w)?;
+
+ Ok(())
+ }
+}
+
+/// Enables the use of the serialization macros for objects that need to be simultaneously decrypted and
+/// deserialized. This allows us to avoid an intermediate Vec allocation.
+pub(crate) struct ChaChaPolyReadAdapter<R: Readable> {
+ pub readable: R,
+}
+
+impl<T: Readable> LengthReadableArgs<[u8; 32]> for ChaChaPolyReadAdapter<T> {
+ // Simultaneously read and decrypt an object from a LengthRead, storing it in Self::readable.
+ // LengthRead must be used instead of std::io::Read because we need the total length to separate
+ // out the tag at the end.
+ fn read<R: LengthRead>(mut r: &mut R, secret: [u8; 32]) -> Result<Self, DecodeError> {
+ if r.total_bytes() < 16 { return Err(DecodeError::InvalidValue) }
+
+ let mut chacha = ChaCha20Poly1305RFC::new(&secret, &[0; 12], &[]);
+ let decrypted_len = r.total_bytes() - 16;
+ let s = FixedLengthReader::new(&mut r, decrypted_len);
+ let mut chacha_stream = ChaChaPolyReader { chacha: &mut chacha, read: s };
+ let readable: T = Readable::read(&mut chacha_stream)?;
+ chacha_stream.read.eat_remaining()?;
+
+ let mut tag = [0 as u8; 16];
+ r.read_exact(&mut tag)?;
+ if !chacha.finish_and_check_tag(&tag) {
+ return Err(DecodeError::InvalidValue)
+ }
+
+ Ok(Self { readable })
+ }
+}
+
+
+/// Enables simultaneously reading and decrypting a ChaCha20Poly1305RFC stream from a std::io::Read.
+struct ChaChaPolyReader<'a, R: Read> {
+ pub chacha: &'a mut ChaCha20Poly1305RFC,
+ pub read: R,
+}
+
+impl<'a, R: Read> Read for ChaChaPolyReader<'a, R> {
+ // Decrypt bytes from Self::read into `dest`.
+ // `ChaCha20Poly1305RFC::finish_and_check_tag` must be called to check the tag after all reads
+ // complete.
+ fn read(&mut self, dest: &mut [u8]) -> Result<usize, io::Error> {
+ let res = self.read.read(dest)?;
+ if res > 0 {
+ self.chacha.decrypt_in_place(&mut dest[0..res]);
+ }
+ Ok(res)
+ }
+}
+
+/// Enables simultaneously writing and encrypting a byte stream into a Writer.
+struct ChaChaPolyWriter<'a, W: Writer> {
+ pub chacha: &'a mut ChaCha20Poly1305RFC,
+ pub write: &'a mut W,
+}
+
+impl<'a, W: Writer> Writer for ChaChaPolyWriter<'a, W> {
+ // Encrypt then write bytes from `src` into Self::write.
+ // `ChaCha20Poly1305RFC::finish_and_get_tag` can be called to retrieve the tag after all writes
+ // complete.
+ fn write_all(&mut self, src: &[u8]) -> Result<(), io::Error> {
+ let mut src_idx = 0;
+ while src_idx < src.len() {
+ let mut write_buffer = [0; 8192];
+ let bytes_written = (&mut write_buffer[..]).write(&src[src_idx..]).expect("In-memory writes can't fail");
+ self.chacha.encrypt_in_place(&mut write_buffer[..bytes_written]);
+ self.write.write_all(&write_buffer[..bytes_written])?;
+ src_idx += bytes_written;
+ }
+ Ok(())
+ }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use crate::ln::msgs::DecodeError;
+ use super::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
+ use crate::util::ser::{self, FixedLengthReader, LengthReadableArgs, Writeable};
+
+ // Used for for testing various lengths of serialization.
+ #[derive(Debug, PartialEq, Eq)]
+ struct TestWriteable {
+ field1: Vec<u8>,
+ field2: Vec<u8>,
+ field3: Vec<u8>,
+ }
+ impl_writeable_tlv_based!(TestWriteable, {
+ (1, field1, required_vec),
+ (2, field2, required_vec),
+ (3, field3, required_vec),
+ });
+
+ #[test]
+ fn test_chacha_stream_adapters() {
+ // Check that ChaChaPolyReadAdapter and ChaChaPolyWriteAdapter correctly encode and decode an
+ // encrypted object.
+ macro_rules! check_object_read_write {
+ ($obj: expr) => {
+ // First, serialize the object, encrypted with ChaCha20Poly1305.
+ let rho = [42; 32];
+ let writeable_len = $obj.serialized_length() as u64 + 16;
+ let write_adapter = ChaChaPolyWriteAdapter::new(rho, &$obj);
+ let encrypted_writeable_bytes = write_adapter.encode();
+ let encrypted_writeable = &encrypted_writeable_bytes[..];
+
+ // Now deserialize the object back and make sure it matches the original.
+ let mut rd = FixedLengthReader::new(encrypted_writeable, writeable_len);
+ let read_adapter = <ChaChaPolyReadAdapter<TestWriteable>>::read(&mut rd, rho).unwrap();
+ assert_eq!($obj, read_adapter.readable);
+ };
+ }
+
+ // Try a big object that will require multiple write buffers.
+ let big_writeable = TestWriteable {
+ field1: vec![43],
+ field2: vec![44; 4192],
+ field3: vec![45; 4192 + 1],
+ };
+ check_object_read_write!(big_writeable);
+
+ // Try a small object that fits into one write buffer.
+ let small_writeable = TestWriteable {
+ field1: vec![43],
+ field2: vec![44],
+ field3: vec![45],
+ };
+ check_object_read_write!(small_writeable);
+ }
+
+ fn do_chacha_stream_adapters_ser_macros() -> Result<(), DecodeError> {
+ let writeable = TestWriteable {
+ field1: vec![43],
+ field2: vec![44; 4192],
+ field3: vec![45; 4192 + 1],
+ };
+
+ // First, serialize the object into a TLV stream, encrypted with ChaCha20Poly1305.
+ let rho = [42; 32];
+ let write_adapter = ChaChaPolyWriteAdapter::new(rho, &writeable);
+ let mut writer = ser::VecWriter(Vec::new());
+ encode_tlv_stream!(&mut writer, {
+ (1, write_adapter, required),
+ });
+
+ // Now deserialize the object back and make sure it matches the original.
+ let mut read_adapter: Option<ChaChaPolyReadAdapter<TestWriteable>> = None;
+ decode_tlv_stream!(&writer.0[..], {
+ (1, read_adapter, (option: LengthReadableArgs, rho)),
+ });
+ assert_eq!(writeable, read_adapter.unwrap().readable);
+
+ Ok(())
+ }
+
+ #[test]
+ fn chacha_stream_adapters_ser_macros() {
+ // Test that our stream adapters work as expected with the TLV macros.
+ // This also serves to test the `option: $trait` variant of the `_decode_tlv` ser macro.
+ do_chacha_stream_adapters_ser_macros().unwrap()
+ }
+}
--- /dev/null
+use bitcoin::hashes::{Hash, HashEngine};
+use bitcoin::hashes::hmac::{Hmac, HmacEngine};
+use bitcoin::hashes::sha256::Hash as Sha256;
+use bitcoin::secp256k1::{Message, Secp256k1, SecretKey, ecdsa::Signature, Signing};
+
+use crate::sign::EntropySource;
+
+use core::ops::Deref;
+
+macro_rules! hkdf_extract_expand {
+ ($salt: expr, $ikm: expr) => {{
+ let mut hmac = HmacEngine::<Sha256>::new($salt);
+ hmac.input($ikm);
+ let prk = Hmac::from_engine(hmac).to_byte_array();
+ let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
+ hmac.input(&[1; 1]);
+ let t1 = Hmac::from_engine(hmac).to_byte_array();
+ let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
+ hmac.input(&t1);
+ hmac.input(&[2; 1]);
+ (t1, Hmac::from_engine(hmac).to_byte_array(), prk)
+ }};
+ ($salt: expr, $ikm: expr, 2) => {{
+ let (k1, k2, _) = hkdf_extract_expand!($salt, $ikm);
+ (k1, k2)
+ }};
+ ($salt: expr, $ikm: expr, 5) => {{
+ let (k1, k2, prk) = hkdf_extract_expand!($salt, $ikm);
+
+ let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
+ hmac.input(&k2);
+ hmac.input(&[3; 1]);
+ let k3 = Hmac::from_engine(hmac).to_byte_array();
+
+ let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
+ hmac.input(&k3);
+ hmac.input(&[4; 1]);
+ let k4 = Hmac::from_engine(hmac).to_byte_array();
+
+ let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
+ hmac.input(&k4);
+ hmac.input(&[5; 1]);
+ let k5 = Hmac::from_engine(hmac).to_byte_array();
+
+ (k1, k2, k3, k4, k5)
+ }}
+}
+
+pub fn hkdf_extract_expand_twice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
+ hkdf_extract_expand!(salt, ikm, 2)
+}
+
+pub fn hkdf_extract_expand_5x(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32]) {
+ hkdf_extract_expand!(salt, ikm, 5)
+}
+
+#[inline]
+pub fn sign<C: Signing>(ctx: &Secp256k1<C>, msg: &Message, sk: &SecretKey) -> Signature {
+ #[cfg(feature = "grind_signatures")]
+ let sig = ctx.sign_ecdsa_low_r(msg, sk);
+ #[cfg(not(feature = "grind_signatures"))]
+ let sig = ctx.sign_ecdsa(msg, sk);
+ sig
+}
+
+#[inline]
+#[allow(unused_variables)]
+pub fn sign_with_aux_rand<C: Signing, ES: Deref>(
+ ctx: &Secp256k1<C>, msg: &Message, sk: &SecretKey, entropy_source: &ES
+) -> Signature where ES::Target: EntropySource {
+ #[cfg(feature = "grind_signatures")]
+ let sig = loop {
+ let sig = ctx.sign_ecdsa_with_noncedata(msg, sk, &entropy_source.get_secure_random_bytes());
+ if sig.serialize_compact()[0] < 0x80 {
+ break sig;
+ }
+ };
+ #[cfg(all(not(feature = "grind_signatures"), not(feature = "_test_vectors")))]
+ let sig = ctx.sign_ecdsa_with_noncedata(msg, sk, &entropy_source.get_secure_random_bytes());
+ #[cfg(all(not(feature = "grind_signatures"), feature = "_test_vectors"))]
+ let sig = sign(ctx, msg, sk);
+ sig
+}
pub mod blinded_path;
pub mod events;
+pub(crate) mod crypto;
+
#[cfg(feature = "std")]
/// Re-export of either `core2::io` or `std::io`, depending on the `std` feature flag.
pub use std::io;
use core::ops::Deref;
use crate::chain;
use crate::ln::features::ChannelTypeFeatures;
-use crate::util::crypto::{sign, sign_with_aux_rand};
+use crate::crypto::utils::{sign, sign_with_aux_rand};
use super::channel_keys::{DelayedPaymentBasepoint, DelayedPaymentKey, HtlcKey, HtlcBasepoint, RevocationKey, RevocationBasepoint};
/// Maximum number of one-way in-flight HTLC (protocol-level value).
use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
use crate::ln::msgs;
use crate::ln::msgs::MAX_VALUE_MSAT;
-use crate::util::chacha20::ChaCha20;
-use crate::util::crypto::hkdf_extract_expand_5x;
+use crate::crypto::chacha20::ChaCha20;
+use crate::crypto::utils::hkdf_extract_expand_5x;
use crate::util::errors::APIError;
use crate::util::logger::Logger;
use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, PaymentId, RecipientOnionFields};
use crate::ln::msgs::ChannelMessageHandler;
use crate::util::config::UserConfig;
-use crate::util::crypto::sign;
+use crate::crypto::utils::sign;
use crate::util::ser::Writeable;
use crate::util::scid_utils::block_from_scid;
use crate::util::test_utils;
use crate::io_extras::read_to_end;
use crate::events::{EventsProvider, MessageSendEventsProvider};
-use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter;
+use crate::crypto::streams::ChaChaPolyReadAdapter;
use crate::util::logger;
use crate::util::ser::{LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
use crate::util::base32;
use crate::routing::gossip::NetworkUpdate;
use crate::routing::router::{BlindedTail, Path, RouteHop};
use crate::sign::NodeSigner;
-use crate::util::chacha20::{ChaCha20, ChaChaReader};
+use crate::crypto::chacha20::ChaCha20;
+use crate::crypto::streams::ChaChaReader;
use crate::util::errors::{self, APIError};
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, LengthCalculatingWriter};
use crate::util::logger::Logger;
use hex::DisplayHex;
-use crate::util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
-use crate::util::crypto::hkdf_extract_expand_twice;
+use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC;
+use crate::crypto::utils::hkdf_extract_expand_twice;
use crate::util::ser::VecWriter;
use core::ops::Deref;
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h);
- if !chacha.decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]) {
+ if chacha.variable_time_decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]).is_err() {
return Err(LightningError{err: "Bad MAC".to_owned(), action: msgs::ErrorAction::DisconnectPeer{ msg: None }});
}
Ok(())
use crate::ln::onion_utils;
use super::messenger::CustomOnionMessageHandler;
use super::offers::OffersMessage;
-use crate::util::chacha20poly1305rfc::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
+use crate::crypto::streams::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
use crate::util::logger::Logger;
use crate::util::ser::{BigSize, FixedLengthReader, LengthRead, LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer};
use crate::sign::EntropySource;
use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer};
use crate::util::logger::{Level, Logger};
-use crate::util::chacha20::ChaCha20;
+use crate::crypto::chacha20::ChaCha20;
use crate::io;
use crate::prelude::*;
use crate::offers::invoice::BlindedPayInfo;
use crate::util::config::UserConfig;
use crate::util::test_utils as ln_test_utils;
- use crate::util::chacha20::ChaCha20;
+ use crate::crypto::chacha20::ChaCha20;
use crate::util::ser::{Readable, Writeable};
#[cfg(c_bindings)]
use crate::util::ser::Writer;
use bitcoin::{secp256k1, Sequence, Witness, Txid};
use crate::util::transaction_utils;
-use crate::util::crypto::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
+use crate::crypto::utils::{hkdf_extract_expand_twice, sign, sign_with_aux_rand};
use crate::util::ser::{Writeable, Writer, Readable, ReadableArgs};
use crate::chain::transaction::OutPoint;
use crate::ln::channel::ANCHOR_OUTPUT_VALUE_SATOSHI;
#[cfg(taproot)]
use crate::sign::taproot::TaprootChannelSigner;
use crate::util::atomic_counter::AtomicCounter;
-use crate::util::chacha20::ChaCha20;
+use crate::crypto::chacha20::ChaCha20;
use crate::util::invoice::construct_invoice_preimage;
pub(crate) mod type_resolver;
+++ /dev/null
-// This file was stolen from rust-crypto.
-// 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.
-
-use crate::io;
-
-#[cfg(not(fuzzing))]
-mod real_chacha {
- 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 ::core::ops::Add for u32x4 {
- type Output = u32x4;
- #[inline]
- fn add(self, rhs: u32x4) -> u32x4 {
- u32x4(self.0.wrapping_add(rhs.0),
- self.1.wrapping_add(rhs.1),
- self.2.wrapping_add(rhs.2),
- self.3.wrapping_add(rhs.3))
- }
- }
- impl ::core::ops::Sub for u32x4 {
- type Output = u32x4;
- #[inline]
- fn sub(self, rhs: u32x4) -> u32x4 {
- u32x4(self.0.wrapping_sub(rhs.0),
- self.1.wrapping_sub(rhs.1),
- self.2.wrapping_sub(rhs.2),
- self.3.wrapping_sub(rhs.3))
- }
- }
- impl ::core::ops::BitXor for u32x4 {
- type Output = u32x4;
- #[inline]
- fn bitxor(self, rhs: u32x4) -> u32x4 {
- u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
- }
- }
- impl ::core::ops::Shr<u8> for u32x4 {
- type Output = u32x4;
- #[inline]
- fn shr(self, shr: u8) -> u32x4 {
- u32x4(self.0 >> shr, self.1 >> shr, self.2 >> shr, self.3 >> shr)
- }
- }
- impl ::core::ops::Shl<u8> for u32x4 {
- type Output = u32x4;
- #[inline]
- fn shl(self, shl: u8) -> u32x4 {
- u32x4(self.0 << shl, self.1 << shl, self.2 << shl, self.3 << shl)
- }
- }
- impl u32x4 {
- #[inline]
- 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 {
- a: u32x4,
- b: u32x4,
- c: u32x4,
- d: u32x4
- }
-
- #[derive(Copy)]
- pub struct ChaCha20 {
- state : ChaChaState,
- output : [u8; BLOCK_SIZE],
- offset : usize,
- }
-
- impl Clone for ChaCha20 { fn clone(&self) -> ChaCha20 { *self } }
-
- macro_rules! swizzle {
- ($b: expr, $c: expr, $d: expr) => {{
- let u32x4(b10, b11, b12, b13) = $b;
- $b = u32x4(b11, b12, b13, b10);
- let u32x4(c10, c11, c12, c13) = $c;
- $c = u32x4(c12, c13,c10, c11);
- let u32x4(d10, d11, d12, d13) = $d;
- $d = u32x4(d13, d10, d11, d12);
- }}
- }
-
- macro_rules! state_to_buffer {
- ($state: expr, $output: expr) => {{
- let u32x4(a1, a2, a3, a4) = $state.a;
- let u32x4(b1, b2, b3, b4) = $state.b;
- let u32x4(c1, c2, c3, c4) = $state.c;
- let u32x4(d1, d2, d3, d4) = $state.d;
- let lens = [
- a1,a2,a3,a4,
- b1,b2,b3,b4,
- c1,c2,c3,c4,
- d1,d2,d3,d4
- ];
- for i in 0..lens.len() {
- $output[i*4..(i+1)*4].copy_from_slice(&lens[i].to_le_bytes());
- }
- }}
- }
-
- macro_rules! round{
- ($state: expr) => {{
- $state.a = $state.a + $state.b;
- rotate!($state.d, $state.a, 16);
- $state.c = $state.c + $state.d;
- rotate!($state.b, $state.c, 12);
- $state.a = $state.a + $state.b;
- rotate!($state.d, $state.a, 8);
- $state.c = $state.c + $state.d;
- rotate!($state.b, $state.c, 7);
- }}
- }
-
- macro_rules! rotate {
- ($a: expr, $b: expr, $rot: expr) => {{
- let v = $a ^ $b;
- let r = 32 - $rot;
- let right = v >> r;
- $a = (v << $rot) ^ right
- }}
- }
-
- impl ChaCha20 {
- pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 8 || nonce.len() == 12);
-
- ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 }
- }
-
- /// Get one block from a ChaCha stream.
- pub fn get_single_block(key: &[u8; 32], nonce: &[u8; 16]) -> [u8; 32] {
- let mut chacha = ChaCha20 { state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 };
- let mut chacha_bytes = [0; 32];
- chacha.process_in_place(&mut chacha_bytes);
- chacha_bytes
- }
-
- /// Encrypts `src` into `dest` using a single block from a ChaCha stream. Passing `dest` as
- /// `src` in a second call will decrypt it.
- pub fn encrypt_single_block(
- key: &[u8; 32], nonce: &[u8; 16], dest: &mut [u8], src: &[u8]
- ) {
- debug_assert_eq!(dest.len(), src.len());
- debug_assert!(dest.len() <= 32);
-
- let block = ChaCha20::get_single_block(key, nonce);
- for i in 0..dest.len() {
- dest[i] = block[i] ^ src[i];
- }
- }
-
- /// Same as `encrypt_single_block` only operates on a fixed-size input in-place.
- pub fn encrypt_single_block_in_place(
- key: &[u8; 32], nonce: &[u8; 16], bytes: &mut [u8; 32]
- ) {
- let block = ChaCha20::get_single_block(key, nonce);
- for i in 0..bytes.len() {
- bytes[i] = block[i] ^ bytes[i];
- }
- }
-
- fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
- let constant = match key.len() {
- 16 => b"expand 16-byte k",
- 32 => b"expand 32-byte k",
- _ => unreachable!(),
- };
- ChaChaState {
- a: u32x4::from_bytes(&constant[0..16]),
- b: u32x4::from_bytes(&key[0..16]),
- c: if key.len() == 16 {
- u32x4::from_bytes(&key[0..16])
- } else {
- u32x4::from_bytes(&key[16..32])
- },
- d: if nonce.len() == 16 {
- u32x4::from_bytes(&nonce[0..16])
- } else if nonce.len() == 12 {
- let mut nonce4 = [0; 4*4];
- nonce4[4..].copy_from_slice(nonce);
- u32x4::from_bytes(&nonce4)
- } else {
- let mut nonce4 = [0; 4*4];
- nonce4[8..].copy_from_slice(nonce);
- u32x4::from_bytes(&nonce4)
- }
- }
- }
-
- // put the the next BLOCK_SIZE keystream bytes into self.output
- fn update(&mut self) {
- let mut state = self.state;
-
- for _ in 0..10 {
- round!(state);
- swizzle!(state.b, state.c, state.d);
- round!(state);
- swizzle!(state.d, state.c, state.b);
- }
- state.a = state.a + self.state.a;
- state.b = state.b + self.state.b;
- state.c = state.c + self.state.c;
- state.d = state.d + self.state.d;
-
- state_to_buffer!(state, self.output);
-
- self.state.d = self.state.d + u32x4(1, 0, 0, 0);
- let u32x4(c12, _, _, _) = self.state.d;
- if c12 == 0 {
- // we could increment the other counter word with an 8 byte nonce
- // but other implementations like boringssl have this same
- // limitation
- panic!("counter is exhausted");
- }
-
- self.offset = 0;
- }
-
- #[inline] // Useful cause input may be 0s on stack that should be optimized out
- pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
- assert!(input.len() == output.len());
- let len = input.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!(output.len() >= i + count);
- assert!(input.len() >= i + count);
- assert!(self.output.len() >= self.offset + count);
- for j in 0..count {
- output[i + j] = input[i + j] ^ self.output[self.offset + j];
- }
- 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(test)]
- pub fn seek_to_block(&mut self, block_offset: u32) {
- self.state.d.0 = block_offset;
- self.update();
- }
- }
-}
-#[cfg(not(fuzzing))]
-pub use self::real_chacha::ChaCha20;
-
-#[cfg(fuzzing)]
-mod fuzzy_chacha {
- pub struct ChaCha20 {}
-
- impl ChaCha20 {
- pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 8 || nonce.len() == 12);
- Self {}
- }
-
- pub fn get_single_block(_key: &[u8; 32], _nonce: &[u8; 16]) -> [u8; 32] {
- [0; 32]
- }
-
- pub fn encrypt_single_block(
- _key: &[u8; 32], _nonce: &[u8; 16], dest: &mut [u8], src: &[u8]
- ) {
- debug_assert_eq!(dest.len(), src.len());
- debug_assert!(dest.len() <= 32);
- }
-
- pub fn encrypt_single_block_in_place(
- _key: &[u8; 32], _nonce: &[u8; 16], _bytes: &mut [u8; 32]
- ) {}
-
- 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(fuzzing)]
-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 crate::prelude::*;
- use core::iter::repeat;
-
- use super::ChaCha20;
- use std::convert::TryInto;
-
- #[test]
- fn test_chacha20_256_tls_vectors() {
- struct TestVector {
- 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: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
- keystream: vec!(
- 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
- 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
- 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
- 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
- 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
- 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
- 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
- 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
- ),
- }, TestVector{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
- keystream: vec!(
- 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
- 0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
- 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
- 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
- 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
- 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
- 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
- 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
- ),
- }, TestVector{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
- keystream: vec!(
- 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
- 0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
- 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
- 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
- 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
- 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
- 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
- 0x44, 0x5f, 0x41, 0xe3,
- ),
- }, TestVector{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
- keystream: vec!(
- 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
- 0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
- 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
- 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
- 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
- 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
- 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
- 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
- ),
- }, TestVector{
- key: [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ],
- nonce: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
- keystream: vec!(
- 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
- 0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
- 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
- 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
- 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
- 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
- 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
- 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
- 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
- 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
- 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
- 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
- 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
- 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
- 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
- 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
- 0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
- 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
- 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
- 0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
- 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
- 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
- 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
- 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
- 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
- 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
- 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
- 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
- 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
- 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
- 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
- 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
- ),
- },
- );
-
- for tv in test_vectors.iter() {
- let mut c = ChaCha20::new(&tv.key, &tv.nonce);
- let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
- let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
- c.process(&input[..], &mut output[..]);
- assert_eq!(output, tv.keystream);
- }
- }
-
- #[test]
- fn test_chacha20_256_tls_vectors_96_nonce() {
- struct 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{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
- keystream: vec!(
- 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
- 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
- 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
- 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
- 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
- 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
- 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
- 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
- ),
- }, TestVector{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
- keystream: vec!(
- 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96,
- 0xd7, 0x73, 0x6e, 0x7b, 0x20, 0x8e, 0x3c, 0x96,
- 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60,
- 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41,
- 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2,
- 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c,
- 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, 0x81,
- 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
- ),
- }, TestVector{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ],
- keystream: vec!(
- 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5,
- 0xe7, 0x86, 0xdc, 0x63, 0x97, 0x3f, 0x65, 0x3a,
- 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13,
- 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31,
- 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08, 0x45,
- 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b,
- 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e,
- 0x44, 0x5f, 0x41, 0xe3,
- ),
- }, TestVector{
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
- keystream: vec!(
- 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb,
- 0xf5, 0xcf, 0x35, 0xbd, 0x3d, 0xd3, 0x3b, 0x80,
- 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac,
- 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32,
- 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c,
- 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54,
- 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, 0x7d,
- 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
- ),
- }, TestVector{
- key: [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 ],
- keystream: vec!(
- 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69,
- 0x82, 0x10, 0x5f, 0xfb, 0x64, 0x0b, 0xb7, 0x75,
- 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93,
- 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1,
- 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46, 0x41,
- 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69,
- 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1,
- 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a,
- 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94,
- 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66,
- 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58,
- 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd,
- 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
- 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e,
- 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e,
- 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7,
- 0x9d, 0xb9, 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15,
- 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3,
- 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a,
- 0x97, 0xa5, 0xf5, 0x76, 0xfe, 0x06, 0x40, 0x25,
- 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5,
- 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69,
- 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c, 0xc9, 0xc4,
- 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7,
- 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79,
- 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
- 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a,
- 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2,
- 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a,
- 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09,
- 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a,
- 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
- ),
- },
- );
-
- for tv in test_vectors.iter() {
- let mut c = ChaCha20::new(&tv.key, &tv.nonce);
- let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
- let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
- c.process(&input[..], &mut output[..]);
- assert_eq!(output, tv.keystream);
- }
- }
-
- #[test]
- fn get_single_block() {
- // Test that `get_single_block` (which takes a 16-byte nonce) is equivalent to getting a block
- // using a 12-byte nonce, with the block starting at the counter offset given by the remaining 4
- // bytes.
- let key = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ];
- let nonce_16bytes = [
- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
- ];
- let counter_pos = &nonce_16bytes[..4];
- let nonce_12bytes = &nonce_16bytes[4..];
-
- // Initialize a ChaCha20 instance with its counter starting at 0.
- let mut chacha20 = ChaCha20::new(&key, nonce_12bytes);
- // Seek its counter to the block at counter_pos.
- chacha20.seek_to_block(u32::from_le_bytes(counter_pos.try_into().unwrap()));
- let mut block_bytes = [0; 32];
- chacha20.process_in_place(&mut block_bytes);
-
- assert_eq!(ChaCha20::get_single_block(&key, &nonce_16bytes), block_bytes);
- }
-
- #[test]
- fn encrypt_single_block() {
- let key = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ];
- let nonce = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- ];
- let bytes = [1; 32];
-
- let mut encrypted_bytes = [0; 32];
- ChaCha20::encrypt_single_block(&key, &nonce, &mut encrypted_bytes, &bytes);
-
- let mut decrypted_bytes = [0; 32];
- ChaCha20::encrypt_single_block(&key, &nonce, &mut decrypted_bytes, &encrypted_bytes);
-
- assert_eq!(bytes, decrypted_bytes);
- }
-
- #[test]
- fn encrypt_single_block_in_place() {
- let key = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ];
- let nonce = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- ];
- let unencrypted_bytes = [1; 32];
- let mut bytes = unencrypted_bytes;
-
- ChaCha20::encrypt_single_block_in_place(&key, &nonce, &mut bytes);
- assert_ne!(bytes, unencrypted_bytes);
-
- ChaCha20::encrypt_single_block_in_place(&key, &nonce, &mut bytes);
- assert_eq!(bytes, unencrypted_bytes);
- }
-}
+++ /dev/null
-// ring has a garbage API so its use is avoided, but rust-crypto doesn't have RFC-variant poly1305
-// Instead, we steal rust-crypto's implementation and tweak it to match the RFC.
-//
-// 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.
-//
-// This is a port of Andrew Moons poly1305-donna
-// https://github.com/floodyberry/poly1305-donna
-
-use crate::ln::msgs::DecodeError;
-use crate::util::ser::{FixedLengthReader, LengthRead, LengthReadableArgs, Readable, Writeable, Writer};
-use crate::io::{self, Read, Write};
-
-#[cfg(not(fuzzing))]
-mod real_chachapoly {
- use crate::util::chacha20::ChaCha20;
- use crate::util::poly1305::Poly1305;
- use bitcoin::hashes::cmp::fixed_time_eq;
-
- #[derive(Clone, Copy)]
- pub struct ChaCha20Poly1305RFC {
- cipher: ChaCha20,
- mac: Poly1305,
- finished: bool,
- data_len: usize,
- aad_len: u64,
- }
-
- impl ChaCha20Poly1305RFC {
- #[inline]
- fn pad_mac_16(mac: &mut Poly1305, len: usize) {
- if len % 16 != 0 {
- mac.input(&[0; 16][0..16 - (len % 16)]);
- }
- }
- pub fn new(key: &[u8], nonce: &[u8], aad: &[u8]) -> ChaCha20Poly1305RFC {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 12);
-
- // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant
- assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0);
-
- let mut cipher = ChaCha20::new(key, &nonce[4..]);
- let mut mac_key = [0u8; 64];
- let zero_key = [0u8; 64];
- cipher.process(&zero_key, &mut mac_key);
-
- let mut mac = Poly1305::new(&mac_key[..32]);
- mac.input(aad);
- ChaCha20Poly1305RFC::pad_mac_16(&mut mac, aad.len());
-
- ChaCha20Poly1305RFC {
- cipher,
- mac,
- finished: false,
- data_len: 0,
- aad_len: aad.len() as u64,
- }
- }
-
- pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
- assert!(input.len() == output.len());
- assert!(self.finished == false);
- self.cipher.process(input, output);
- self.data_len += input.len();
- self.mac.input(output);
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.finished = true;
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
- self.mac.raw_result(out_tag);
- }
-
- pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
- self.encrypt_in_place(input_output);
- self.finish_and_get_tag(out_tag);
- }
-
- // Encrypt `input_output` in-place. To finish and calculate the tag, use `finish_and_get_tag`
- // below.
- pub(super) fn encrypt_in_place(&mut self, input_output: &mut [u8]) {
- debug_assert!(self.finished == false);
- self.cipher.process_in_place(input_output);
- self.data_len += input_output.len();
- self.mac.input(input_output);
- }
-
- // If we were previously encrypting with `encrypt_in_place`, this method can be used to finish
- // encrypting and calculate the tag.
- pub(super) fn finish_and_get_tag(&mut self, out_tag: &mut [u8]) {
- debug_assert!(self.finished == false);
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.finished = true;
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
- self.mac.raw_result(out_tag);
- }
-
- pub fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
- assert!(input.len() == output.len());
- assert!(self.finished == false);
-
- self.finished = true;
-
- self.mac.input(input);
-
- self.data_len += input.len();
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
-
- let mut calc_tag = [0u8; 16];
- self.mac.raw_result(&mut calc_tag);
- if fixed_time_eq(&calc_tag, tag) {
- self.cipher.process(input, output);
- true
- } else {
- false
- }
- }
-
- pub fn check_decrypt_in_place(&mut self, input_output: &mut [u8], tag: &[u8]) -> Result<(), ()> {
- self.decrypt_in_place(input_output);
- if self.finish_and_check_tag(tag) { Ok(()) } else { Err(()) }
- }
-
- /// Decrypt in place, without checking the tag. Use `finish_and_check_tag` to check it
- /// later when decryption finishes.
- ///
- /// Should never be `pub` because the public API should always enforce tag checking.
- pub(super) fn decrypt_in_place(&mut self, input_output: &mut [u8]) {
- debug_assert!(self.finished == false);
- self.mac.input(input_output);
- self.data_len += input_output.len();
- self.cipher.process_in_place(input_output);
- }
-
- /// If we were previously decrypting with `just_decrypt_in_place`, this method must be used
- /// to check the tag. Returns whether or not the tag is valid.
- pub(super) fn finish_and_check_tag(&mut self, tag: &[u8]) -> bool {
- debug_assert!(self.finished == false);
- self.finished = true;
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
-
- let mut calc_tag = [0u8; 16];
- self.mac.raw_result(&mut calc_tag);
- if fixed_time_eq(&calc_tag, tag) {
- true
- } else {
- false
- }
- }
- }
-}
-#[cfg(not(fuzzing))]
-pub use self::real_chachapoly::ChaCha20Poly1305RFC;
-
-/// Enables simultaneously reading and decrypting a ChaCha20Poly1305RFC stream from a std::io::Read.
-struct ChaChaPolyReader<'a, R: Read> {
- pub chacha: &'a mut ChaCha20Poly1305RFC,
- pub read: R,
-}
-
-impl<'a, R: Read> Read for ChaChaPolyReader<'a, R> {
- // Decrypt bytes from Self::read into `dest`.
- // `ChaCha20Poly1305RFC::finish_and_check_tag` must be called to check the tag after all reads
- // complete.
- fn read(&mut self, dest: &mut [u8]) -> Result<usize, io::Error> {
- let res = self.read.read(dest)?;
- if res > 0 {
- self.chacha.decrypt_in_place(&mut dest[0..res]);
- }
- Ok(res)
- }
-}
-
-/// Enables simultaneously writing and encrypting a byte stream into a Writer.
-struct ChaChaPolyWriter<'a, W: Writer> {
- pub chacha: &'a mut ChaCha20Poly1305RFC,
- pub write: &'a mut W,
-}
-
-impl<'a, W: Writer> Writer for ChaChaPolyWriter<'a, W> {
- // Encrypt then write bytes from `src` into Self::write.
- // `ChaCha20Poly1305RFC::finish_and_get_tag` can be called to retrieve the tag after all writes
- // complete.
- fn write_all(&mut self, src: &[u8]) -> Result<(), io::Error> {
- let mut src_idx = 0;
- while src_idx < src.len() {
- let mut write_buffer = [0; 8192];
- let bytes_written = (&mut write_buffer[..]).write(&src[src_idx..]).expect("In-memory writes can't fail");
- self.chacha.encrypt_in_place(&mut write_buffer[..bytes_written]);
- self.write.write_all(&write_buffer[..bytes_written])?;
- src_idx += bytes_written;
- }
- Ok(())
- }
-}
-
-/// Enables the use of the serialization macros for objects that need to be simultaneously encrypted and
-/// serialized. This allows us to avoid an intermediate Vec allocation.
-pub(crate) struct ChaChaPolyWriteAdapter<'a, W: Writeable> {
- pub rho: [u8; 32],
- pub writeable: &'a W,
-}
-
-impl<'a, W: Writeable> ChaChaPolyWriteAdapter<'a, W> {
- #[allow(unused)] // This will be used for onion messages soon
- pub fn new(rho: [u8; 32], writeable: &'a W) -> ChaChaPolyWriteAdapter<'a, W> {
- Self { rho, writeable }
- }
-}
-
-impl<'a, T: Writeable> Writeable for ChaChaPolyWriteAdapter<'a, T> {
- // Simultaneously write and encrypt Self::writeable.
- fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
- let mut chacha = ChaCha20Poly1305RFC::new(&self.rho, &[0; 12], &[]);
- let mut chacha_stream = ChaChaPolyWriter { chacha: &mut chacha, write: w };
- self.writeable.write(&mut chacha_stream)?;
- let mut tag = [0 as u8; 16];
- chacha.finish_and_get_tag(&mut tag);
- tag.write(w)?;
-
- Ok(())
- }
-}
-
-/// Enables the use of the serialization macros for objects that need to be simultaneously decrypted and
-/// deserialized. This allows us to avoid an intermediate Vec allocation.
-pub(crate) struct ChaChaPolyReadAdapter<R: Readable> {
- pub readable: R,
-}
-
-impl<T: Readable> LengthReadableArgs<[u8; 32]> for ChaChaPolyReadAdapter<T> {
- // Simultaneously read and decrypt an object from a LengthRead, storing it in Self::readable.
- // LengthRead must be used instead of std::io::Read because we need the total length to separate
- // out the tag at the end.
- fn read<R: LengthRead>(mut r: &mut R, secret: [u8; 32]) -> Result<Self, DecodeError> {
- if r.total_bytes() < 16 { return Err(DecodeError::InvalidValue) }
-
- let mut chacha = ChaCha20Poly1305RFC::new(&secret, &[0; 12], &[]);
- let decrypted_len = r.total_bytes() - 16;
- let s = FixedLengthReader::new(&mut r, decrypted_len);
- let mut chacha_stream = ChaChaPolyReader { chacha: &mut chacha, read: s };
- let readable: T = Readable::read(&mut chacha_stream)?;
- chacha_stream.read.eat_remaining()?;
-
- let mut tag = [0 as u8; 16];
- r.read_exact(&mut tag)?;
- if !chacha.finish_and_check_tag(&tag) {
- return Err(DecodeError::InvalidValue)
- }
-
- Ok(Self { readable })
- }
-}
-
-#[cfg(fuzzing)]
-mod fuzzy_chachapoly {
- #[derive(Clone, Copy)]
- pub struct ChaCha20Poly1305RFC {
- tag: [u8; 16],
- finished: bool,
- }
- impl ChaCha20Poly1305RFC {
- pub fn new(key: &[u8], nonce: &[u8], _aad: &[u8]) -> ChaCha20Poly1305RFC {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 12);
-
- // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant
- assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0);
-
- let mut tag = [0; 16];
- tag.copy_from_slice(&key[0..16]);
-
- ChaCha20Poly1305RFC {
- tag,
- finished: false,
- }
- }
-
- pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
- assert!(input.len() == output.len());
- assert!(self.finished == false);
-
- output.copy_from_slice(&input);
- out_tag.copy_from_slice(&self.tag);
- self.finished = true;
- }
-
- pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
- self.encrypt_in_place(input_output);
- self.finish_and_get_tag(out_tag);
- }
-
- pub(super) fn encrypt_in_place(&mut self, _input_output: &mut [u8]) {
- assert!(self.finished == false);
- }
-
- pub(super) fn finish_and_get_tag(&mut self, out_tag: &mut [u8]) {
- assert!(self.finished == false);
- out_tag.copy_from_slice(&self.tag);
- self.finished = true;
- }
-
- pub fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
- assert!(input.len() == output.len());
- assert!(self.finished == false);
-
- if tag[..] != self.tag[..] { return false; }
- output.copy_from_slice(input);
- self.finished = true;
- true
- }
-
- pub fn check_decrypt_in_place(&mut self, input_output: &mut [u8], tag: &[u8]) -> Result<(), ()> {
- self.decrypt_in_place(input_output);
- if self.finish_and_check_tag(tag) { Ok(()) } else { Err(()) }
- }
-
- pub(super) fn decrypt_in_place(&mut self, _input: &mut [u8]) {
- assert!(self.finished == false);
- }
-
- pub(super) fn finish_and_check_tag(&mut self, tag: &[u8]) -> bool {
- if tag[..] != self.tag[..] { return false; }
- self.finished = true;
- true
- }
- }
-}
-#[cfg(fuzzing)]
-pub use self::fuzzy_chachapoly::ChaCha20Poly1305RFC;
-
-#[cfg(test)]
-mod tests {
- use crate::ln::msgs::DecodeError;
- use super::{ChaChaPolyReadAdapter, ChaChaPolyWriteAdapter};
- use crate::util::ser::{self, FixedLengthReader, LengthReadableArgs, Writeable};
-
- // Used for for testing various lengths of serialization.
- #[derive(Debug, PartialEq, Eq)]
- struct TestWriteable {
- field1: Vec<u8>,
- field2: Vec<u8>,
- field3: Vec<u8>,
- }
- impl_writeable_tlv_based!(TestWriteable, {
- (1, field1, required_vec),
- (2, field2, required_vec),
- (3, field3, required_vec),
- });
-
- #[test]
- fn test_chacha_stream_adapters() {
- // Check that ChaChaPolyReadAdapter and ChaChaPolyWriteAdapter correctly encode and decode an
- // encrypted object.
- macro_rules! check_object_read_write {
- ($obj: expr) => {
- // First, serialize the object, encrypted with ChaCha20Poly1305.
- let rho = [42; 32];
- let writeable_len = $obj.serialized_length() as u64 + 16;
- let write_adapter = ChaChaPolyWriteAdapter::new(rho, &$obj);
- let encrypted_writeable_bytes = write_adapter.encode();
- let encrypted_writeable = &encrypted_writeable_bytes[..];
-
- // Now deserialize the object back and make sure it matches the original.
- let mut rd = FixedLengthReader::new(encrypted_writeable, writeable_len);
- let read_adapter = <ChaChaPolyReadAdapter<TestWriteable>>::read(&mut rd, rho).unwrap();
- assert_eq!($obj, read_adapter.readable);
- };
- }
-
- // Try a big object that will require multiple write buffers.
- let big_writeable = TestWriteable {
- field1: vec![43],
- field2: vec![44; 4192],
- field3: vec![45; 4192 + 1],
- };
- check_object_read_write!(big_writeable);
-
- // Try a small object that fits into one write buffer.
- let small_writeable = TestWriteable {
- field1: vec![43],
- field2: vec![44],
- field3: vec![45],
- };
- check_object_read_write!(small_writeable);
- }
-
- fn do_chacha_stream_adapters_ser_macros() -> Result<(), DecodeError> {
- let writeable = TestWriteable {
- field1: vec![43],
- field2: vec![44; 4192],
- field3: vec![45; 4192 + 1],
- };
-
- // First, serialize the object into a TLV stream, encrypted with ChaCha20Poly1305.
- let rho = [42; 32];
- let write_adapter = ChaChaPolyWriteAdapter::new(rho, &writeable);
- let mut writer = ser::VecWriter(Vec::new());
- encode_tlv_stream!(&mut writer, {
- (1, write_adapter, required),
- });
-
- // Now deserialize the object back and make sure it matches the original.
- let mut read_adapter: Option<ChaChaPolyReadAdapter<TestWriteable>> = None;
- decode_tlv_stream!(&writer.0[..], {
- (1, read_adapter, (option: LengthReadableArgs, rho)),
- });
- assert_eq!(writeable, read_adapter.unwrap().readable);
-
- Ok(())
- }
-
- #[test]
- fn chacha_stream_adapters_ser_macros() {
- // Test that our stream adapters work as expected with the TLV macros.
- // This also serves to test the `option: $trait` variant of the `_decode_tlv` ser macro.
- do_chacha_stream_adapters_ser_macros().unwrap()
- }
-}
+++ /dev/null
-use bitcoin::hashes::{Hash, HashEngine};
-use bitcoin::hashes::hmac::{Hmac, HmacEngine};
-use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::secp256k1::{Message, Secp256k1, SecretKey, ecdsa::Signature, Signing};
-
-use crate::sign::EntropySource;
-
-use core::ops::Deref;
-
-macro_rules! hkdf_extract_expand {
- ($salt: expr, $ikm: expr) => {{
- let mut hmac = HmacEngine::<Sha256>::new($salt);
- hmac.input($ikm);
- let prk = Hmac::from_engine(hmac).to_byte_array();
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&[1; 1]);
- let t1 = Hmac::from_engine(hmac).to_byte_array();
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&t1);
- hmac.input(&[2; 1]);
- (t1, Hmac::from_engine(hmac).to_byte_array(), prk)
- }};
- ($salt: expr, $ikm: expr, 2) => {{
- let (k1, k2, _) = hkdf_extract_expand!($salt, $ikm);
- (k1, k2)
- }};
- ($salt: expr, $ikm: expr, 5) => {{
- let (k1, k2, prk) = hkdf_extract_expand!($salt, $ikm);
-
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&k2);
- hmac.input(&[3; 1]);
- let k3 = Hmac::from_engine(hmac).to_byte_array();
-
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&k3);
- hmac.input(&[4; 1]);
- let k4 = Hmac::from_engine(hmac).to_byte_array();
-
- let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
- hmac.input(&k4);
- hmac.input(&[5; 1]);
- let k5 = Hmac::from_engine(hmac).to_byte_array();
-
- (k1, k2, k3, k4, k5)
- }}
-}
-
-pub fn hkdf_extract_expand_twice(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
- hkdf_extract_expand!(salt, ikm, 2)
-}
-
-pub fn hkdf_extract_expand_5x(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32], [u8; 32], [u8; 32], [u8; 32]) {
- hkdf_extract_expand!(salt, ikm, 5)
-}
-
-#[inline]
-pub fn sign<C: Signing>(ctx: &Secp256k1<C>, msg: &Message, sk: &SecretKey) -> Signature {
- #[cfg(feature = "grind_signatures")]
- let sig = ctx.sign_ecdsa_low_r(msg, sk);
- #[cfg(not(feature = "grind_signatures"))]
- let sig = ctx.sign_ecdsa(msg, sk);
- sig
-}
-
-#[inline]
-#[allow(unused_variables)]
-pub fn sign_with_aux_rand<C: Signing, ES: Deref>(
- ctx: &Secp256k1<C>, msg: &Message, sk: &SecretKey, entropy_source: &ES
-) -> Signature where ES::Target: EntropySource {
- #[cfg(feature = "grind_signatures")]
- let sig = loop {
- let sig = ctx.sign_ecdsa_with_noncedata(msg, sk, &entropy_source.get_secure_random_bytes());
- if sig.serialize_compact()[0] < 0x80 {
- break sig;
- }
- };
- #[cfg(all(not(feature = "grind_signatures"), not(feature = "_test_vectors")))]
- let sig = ctx.sign_ecdsa_with_noncedata(msg, sk, &entropy_source.get_secure_random_bytes());
- #[cfg(all(not(feature = "grind_signatures"), feature = "_test_vectors"))]
- let sig = sign(ctx, msg, sk);
- sig
-}
pub(crate) mod atomic_counter;
pub(crate) mod byte_utils;
-pub(crate) mod chacha20;
-#[cfg(not(fuzzing))]
-pub(crate) mod poly1305;
-pub(crate) mod chacha20poly1305rfc;
pub(crate) mod transaction_utils;
pub(crate) mod scid_utils;
pub(crate) mod time;
#[macro_use]
pub(crate) mod macro_logger;
-/// Cryptography utilities.
-pub(crate) mod crypto;
-
// These have to come after macro_logger to build
pub mod logger;
pub mod config;
+++ /dev/null
-// 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.
-
-// This is a port of Andrew Moons poly1305-donna
-// https://github.com/floodyberry/poly1305-donna
-
-use core::cmp::min;
-use core::convert::TryInto;
-
-#[derive(Clone, Copy)]
-pub struct Poly1305 {
- r : [u32; 5],
- h : [u32; 5],
- pad : [u32; 4],
- leftover : usize,
- buffer : [u8; 16],
- finalized : bool,
-}
-
-impl Poly1305 {
- pub fn new(key: &[u8]) -> Poly1305 {
- assert!(key.len() == 32);
- let mut poly = Poly1305{ r: [0u32; 5], h: [0u32; 5], pad: [0u32; 4], leftover: 0, buffer: [0u8; 16], finalized: false };
-
- // r &= 0xffffffc0ffffffc0ffffffc0fffffff
- poly.r[0] = (u32::from_le_bytes(key[ 0.. 4].try_into().expect("len is 4")) ) & 0x3ffffff;
- poly.r[1] = (u32::from_le_bytes(key[ 3.. 7].try_into().expect("len is 4")) >> 2) & 0x3ffff03;
- poly.r[2] = (u32::from_le_bytes(key[ 6..10].try_into().expect("len is 4")) >> 4) & 0x3ffc0ff;
- poly.r[3] = (u32::from_le_bytes(key[ 9..13].try_into().expect("len is 4")) >> 6) & 0x3f03fff;
- poly.r[4] = (u32::from_le_bytes(key[12..16].try_into().expect("len is 4")) >> 8) & 0x00fffff;
-
- poly.pad[0] = u32::from_le_bytes(key[16..20].try_into().expect("len is 4"));
- poly.pad[1] = u32::from_le_bytes(key[20..24].try_into().expect("len is 4"));
- poly.pad[2] = u32::from_le_bytes(key[24..28].try_into().expect("len is 4"));
- poly.pad[3] = u32::from_le_bytes(key[28..32].try_into().expect("len is 4"));
-
- poly
- }
-
- fn block(&mut self, m: &[u8]) {
- let hibit : u32 = if self.finalized { 0 } else { 1 << 24 };
-
- let r0 = self.r[0];
- let r1 = self.r[1];
- let r2 = self.r[2];
- let r3 = self.r[3];
- let r4 = self.r[4];
-
- let s1 = r1 * 5;
- let s2 = r2 * 5;
- let s3 = r3 * 5;
- let s4 = r4 * 5;
-
- let mut h0 = self.h[0];
- let mut h1 = self.h[1];
- let mut h2 = self.h[2];
- let mut h3 = self.h[3];
- let mut h4 = self.h[4];
-
- // h += m
- h0 += (u32::from_le_bytes(m[ 0.. 4].try_into().expect("len is 4")) ) & 0x3ffffff;
- h1 += (u32::from_le_bytes(m[ 3.. 7].try_into().expect("len is 4")) >> 2) & 0x3ffffff;
- h2 += (u32::from_le_bytes(m[ 6..10].try_into().expect("len is 4")) >> 4) & 0x3ffffff;
- h3 += (u32::from_le_bytes(m[ 9..13].try_into().expect("len is 4")) >> 6) & 0x3ffffff;
- h4 += (u32::from_le_bytes(m[12..16].try_into().expect("len is 4")) >> 8) | hibit;
-
- // h *= r
- let d0 = (h0 as u64 * r0 as u64) + (h1 as u64 * s4 as u64) + (h2 as u64 * s3 as u64) + (h3 as u64 * s2 as u64) + (h4 as u64 * s1 as u64);
- let mut d1 = (h0 as u64 * r1 as u64) + (h1 as u64 * r0 as u64) + (h2 as u64 * s4 as u64) + (h3 as u64 * s3 as u64) + (h4 as u64 * s2 as u64);
- let mut d2 = (h0 as u64 * r2 as u64) + (h1 as u64 * r1 as u64) + (h2 as u64 * r0 as u64) + (h3 as u64 * s4 as u64) + (h4 as u64 * s3 as u64);
- let mut d3 = (h0 as u64 * r3 as u64) + (h1 as u64 * r2 as u64) + (h2 as u64 * r1 as u64) + (h3 as u64 * r0 as u64) + (h4 as u64 * s4 as u64);
- let mut d4 = (h0 as u64 * r4 as u64) + (h1 as u64 * r3 as u64) + (h2 as u64 * r2 as u64) + (h3 as u64 * r1 as u64) + (h4 as u64 * r0 as u64);
-
- // (partial) h %= p
- let mut c : u32;
- c = (d0 >> 26) as u32; h0 = d0 as u32 & 0x3ffffff;
- d1 += c as u64; c = (d1 >> 26) as u32; h1 = d1 as u32 & 0x3ffffff;
- d2 += c as u64; c = (d2 >> 26) as u32; h2 = d2 as u32 & 0x3ffffff;
- d3 += c as u64; c = (d3 >> 26) as u32; h3 = d3 as u32 & 0x3ffffff;
- d4 += c as u64; c = (d4 >> 26) as u32; h4 = d4 as u32 & 0x3ffffff;
- h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
- h1 += c;
-
- self.h[0] = h0;
- self.h[1] = h1;
- self.h[2] = h2;
- self.h[3] = h3;
- self.h[4] = h4;
- }
-
- pub fn finish(&mut self) {
- if self.leftover > 0 {
- self.buffer[self.leftover] = 1;
- for i in self.leftover+1..16 {
- self.buffer[i] = 0;
- }
- self.finalized = true;
- let tmp = self.buffer;
- self.block(&tmp);
- }
-
- // fully carry h
- let mut h0 = self.h[0];
- let mut h1 = self.h[1];
- let mut h2 = self.h[2];
- let mut h3 = self.h[3];
- let mut h4 = self.h[4];
-
- let mut c : u32;
- c = h1 >> 26; h1 = h1 & 0x3ffffff;
- h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
- h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
- h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
- h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
- h1 += c;
-
- // compute h + -p
- let mut g0 = h0.wrapping_add(5); c = g0 >> 26; g0 &= 0x3ffffff;
- let mut g1 = h1.wrapping_add(c); c = g1 >> 26; g1 &= 0x3ffffff;
- let mut g2 = h2.wrapping_add(c); c = g2 >> 26; g2 &= 0x3ffffff;
- let mut g3 = h3.wrapping_add(c); c = g3 >> 26; g3 &= 0x3ffffff;
- let mut g4 = h4.wrapping_add(c).wrapping_sub(1 << 26);
-
- // select h if h < p, or h + -p if h >= p
- let mut mask = (g4 >> (32 - 1)).wrapping_sub(1);
- g0 &= mask;
- g1 &= mask;
- g2 &= mask;
- g3 &= mask;
- g4 &= mask;
- mask = !mask;
- h0 = (h0 & mask) | g0;
- h1 = (h1 & mask) | g1;
- h2 = (h2 & mask) | g2;
- h3 = (h3 & mask) | g3;
- h4 = (h4 & mask) | g4;
-
- // h = h % (2^128)
- h0 = ((h0 ) | (h1 << 26)) & 0xffffffff;
- h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
- h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
- h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
-
- // h = mac = (h + pad) % (2^128)
- let mut f : u64;
- f = h0 as u64 + self.pad[0] as u64 ; h0 = f as u32;
- f = h1 as u64 + self.pad[1] as u64 + (f >> 32); h1 = f as u32;
- f = h2 as u64 + self.pad[2] as u64 + (f >> 32); h2 = f as u32;
- f = h3 as u64 + self.pad[3] as u64 + (f >> 32); h3 = f as u32;
-
- self.h[0] = h0;
- self.h[1] = h1;
- self.h[2] = h2;
- self.h[3] = h3;
- }
-
- pub fn input(&mut self, data: &[u8]) {
- assert!(!self.finalized);
- let mut m = data;
-
- if self.leftover > 0 {
- let want = min(16 - self.leftover, m.len());
- for i in 0..want {
- self.buffer[self.leftover+i] = m[i];
- }
- m = &m[want..];
- self.leftover += want;
-
- if self.leftover < 16 {
- return;
- }
-
- // self.block(self.buffer[..]);
- let tmp = self.buffer;
- self.block(&tmp);
-
- self.leftover = 0;
- }
-
- while m.len() >= 16 {
- self.block(&m[0..16]);
- m = &m[16..];
- }
-
- for i in 0..m.len() {
- self.buffer[i] = m[i];
- }
- self.leftover = m.len();
- }
-
- pub fn raw_result(&mut self, output: &mut [u8]) {
- assert!(output.len() >= 16);
- if !self.finalized{
- self.finish();
- }
- output[0..4].copy_from_slice(&self.h[0].to_le_bytes());
- output[4..8].copy_from_slice(&self.h[1].to_le_bytes());
- output[8..12].copy_from_slice(&self.h[2].to_le_bytes());
- output[12..16].copy_from_slice(&self.h[3].to_le_bytes());
- }
-}
-
-#[cfg(test)]
-mod test {
- use crate::prelude::*;
- use core::iter::repeat;
-
- use crate::util::poly1305::Poly1305;
-
- fn poly1305(key: &[u8], msg: &[u8], mac: &mut [u8]) {
- let mut poly = Poly1305::new(key);
- poly.input(msg);
- poly.raw_result(mac);
- }
-
- #[test]
- fn test_nacl_vector() {
- let key = [
- 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91,
- 0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25,
- 0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65,
- 0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80,
- ];
-
- let msg = [
- 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73,
- 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce,
- 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4,
- 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a,
- 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b,
- 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72,
- 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2,
- 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38,
- 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a,
- 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae,
- 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea,
- 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda,
- 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde,
- 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3,
- 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6,
- 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74,
- 0xe3,0x55,0xa5,
- ];
-
- let expected = [
- 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5,
- 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9,
- ];
-
- let mut mac = [0u8; 16];
- poly1305(&key, &msg, &mut mac);
- assert_eq!(&mac[..], &expected[..]);
-
- let mut poly = Poly1305::new(&key);
- poly.input(&msg[0..32]);
- poly.input(&msg[32..96]);
- poly.input(&msg[96..112]);
- poly.input(&msg[112..120]);
- poly.input(&msg[120..124]);
- poly.input(&msg[124..126]);
- poly.input(&msg[126..127]);
- poly.input(&msg[127..128]);
- poly.input(&msg[128..129]);
- poly.input(&msg[129..130]);
- poly.input(&msg[130..131]);
- poly.raw_result(&mut mac);
- assert_eq!(&mac[..], &expected[..]);
- }
-
- #[test]
- fn donna_self_test() {
- let wrap_key = [
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ];
-
- let wrap_msg = [
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- ];
-
- let wrap_mac = [
- 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ];
-
- let mut mac = [0u8; 16];
- poly1305(&wrap_key, &wrap_msg, &mut mac);
- assert_eq!(&mac[..], &wrap_mac[..]);
-
- let total_key = [
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff,
- 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- ];
-
- let total_mac = [
- 0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd,
- 0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62, 0x3d, 0x39,
- ];
-
- let mut tpoly = Poly1305::new(&total_key);
- for i in 0..256 {
- let key: Vec<u8> = repeat(i as u8).take(32).collect();
- let msg: Vec<u8> = repeat(i as u8).take(256).collect();
- let mut mac = [0u8; 16];
- poly1305(&key[..], &msg[0..i], &mut mac);
- tpoly.input(&mac);
- }
- tpoly.raw_result(&mut mac);
- assert_eq!(&mac[..], &total_mac[..]);
- }
-
- #[test]
- fn test_tls_vectors() {
- // from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
- let key = b"this is 32-byte key for Poly1305";
- let msg = [0u8; 32];
- let expected = [
- 0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6,
- 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07,
- ];
- let mut mac = [0u8; 16];
- poly1305(key, &msg, &mut mac);
- assert_eq!(&mac[..], &expected[..]);
-
- let msg = b"Hello world!";
- let expected= [
- 0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16,
- 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0,
- ];
- poly1305(key, msg, &mut mac);
- assert_eq!(&mac[..], &expected[..]);
- }
-}
use bitcoin::blockdata::constants::ChainHash;
use bitcoin::network::constants::Network;
use crate::sign::EntropySource;
- use crate::util::chacha20::ChaCha20;
+ use crate::crypto::chacha20::ChaCha20;
use crate::util::scid_utils;
use core::convert::TryInto;