Merge pull request #270 from TheBlueMatt/2018-12-drop-rust-crypto

Drop rust-crypto for bitcoin_hashes
This commit is contained in:
Matt Corallo 2018-12-19 20:35:46 -05:00 committed by GitHub
commit 50ed320503
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1113 additions and 403 deletions

View file

@ -9,12 +9,11 @@ A Bitcoin Lightning library in Rust.
Does most of the hard work, without implying a specific runtime, requiring clients implement basic network logic, chain interactions and disk storage.
Still missing tons of error-handling. See GitHub issues for suggested projects if you want to contribute. Don't have to bother telling you not to use this for anything serious, because you'd have to build a client around it to even try.
"""
build = "build.rs"
[features]
# Supports tracking channels with a non-bitcoin chain hashes. Currently enables all kinds of fun DoS attacks.
non_bitcoin_chain_hash_routing = []
fuzztarget = ["secp256k1/fuzztarget", "bitcoin/fuzztarget"]
fuzztarget = ["secp256k1/fuzztarget", "bitcoin/fuzztarget", "bitcoin_hashes/fuzztarget"]
# Unlog messages superior at targeted level.
max_level_off = []
max_level_error = []
@ -24,13 +23,10 @@ max_level_debug = []
[dependencies]
bitcoin = "0.15"
rust-crypto = "0.2"
bitcoin_hashes = { git = "https://github.com/TheBlueMatt/bitcoin_hashes", branch = "rust-lightning-dep" }
rand = "0.4"
secp256k1 = "0.11"
[build-dependencies]
cc = "1.0"
[dev-dependencies.bitcoin]
version = "0.15"
features = ["bitcoinconsensus"]

View file

@ -1,10 +0,0 @@
extern crate cc;
fn main() {
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm")))]
{
let mut cfg = cc::Build::new();
cfg.file("src/util/rust_crypto_nonstd_arch.c");
cfg.compile("lib_rust_crypto_nonstd_arch.a");
}
}

View file

@ -6,7 +6,6 @@ publish = false
# Because the function is unused it gets dropped before we link lightning, so
# we have to duplicate build.rs here. Note that this is only required for
# fuzztarget mode.
build = "../build.rs"
[package.metadata]
cargo-fuzz = true
@ -19,9 +18,9 @@ honggfuzz_fuzz = ["honggfuzz"]
afl = { version = "0.4", optional = true }
lightning = { path = "..", features = ["fuzztarget"] }
bitcoin = { version = "0.15", features = ["fuzztarget"] }
bitcoin_hashes = { git = "https://github.com/TheBlueMatt/bitcoin_hashes", branch = "rust-lightning-dep", features=["fuzztarget"] }
hex = "0.3"
honggfuzz = { version = "0.5", optional = true }
rust-crypto = "0.2"
secp256k1 = { version = "0.11", features=["fuzztarget"] }
[build-dependencies]

File diff suppressed because one or more lines are too long

View file

@ -6,17 +6,16 @@ use bitcoin::blockdata::transaction::{OutPoint, TxOut};
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
use bitcoin::network::constants::Network;
use bitcoin::util::hash::Hash160;
use bitcoin::util::bip32::{ExtendedPrivKey, ExtendedPubKey, ChildNumber};
use bitcoin_hashes::{Hash, HashEngine};
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::hash160::Hash as Hash160;
use secp256k1::key::{SecretKey, PublicKey};
use secp256k1::Secp256k1;
use secp256k1;
use crypto::hkdf::{hkdf_extract,hkdf_expand};
use crypto::digest::Digest;
use util::sha2::Sha256;
use util::logger::Logger;
use util::rng;
use util::byte_utils;
@ -109,43 +108,6 @@ impl_writeable!(ChannelKeys, 0, {
commitment_seed
});
impl ChannelKeys {
/// Generate a set of lightning keys needed to operate a channel by HKDF-expanding a given
/// random 32-byte seed
pub fn new_from_seed(seed: &[u8; 32]) -> ChannelKeys {
let mut prk = [0; 32];
hkdf_extract(Sha256::new(), b"rust-lightning key gen salt", seed, &mut prk);
let secp_ctx = Secp256k1::without_caps();
let mut okm = [0; 32];
hkdf_expand(Sha256::new(), &prk, b"rust-lightning funding key info", &mut okm);
let funding_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
hkdf_expand(Sha256::new(), &prk, b"rust-lightning revocation base key info", &mut okm);
let revocation_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
hkdf_expand(Sha256::new(), &prk, b"rust-lightning payment base key info", &mut okm);
let payment_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
hkdf_expand(Sha256::new(), &prk, b"rust-lightning delayed payment base key info", &mut okm);
let delayed_payment_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
hkdf_expand(Sha256::new(), &prk, b"rust-lightning htlc base key info", &mut okm);
let htlc_base_key = SecretKey::from_slice(&secp_ctx, &okm).expect("Sha256 is broken");
hkdf_expand(Sha256::new(), &prk, b"rust-lightning local commitment seed info", &mut okm);
ChannelKeys {
funding_key: funding_key,
revocation_base_key: revocation_base_key,
payment_base_key: payment_base_key,
delayed_payment_base_key: delayed_payment_base_key,
htlc_base_key: htlc_base_key,
commitment_seed: okm
}
}
}
/// Simple KeysInterface implementor that takes a 32-byte seed for use as a BIP 32 extended key
/// and derives keys from that.
///
@ -176,9 +138,9 @@ impl KeysManager {
let node_secret = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(0)).expect("Your RNG is busted").secret_key;
let destination_script = match master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(1)) {
Ok(destination_key) => {
let pubkey_hash160 = Hash160::from_data(&ExtendedPubKey::from_private(&secp_ctx, &destination_key).public_key.serialize()[..]);
let pubkey_hash160 = Hash160::hash(&ExtendedPubKey::from_private(&secp_ctx, &destination_key).public_key.serialize()[..]);
Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0)
.push_slice(pubkey_hash160.as_bytes())
.push_slice(&pubkey_hash160.into_inner())
.into_script()
},
Err(_) => panic!("Your RNG is busted"),
@ -225,7 +187,7 @@ impl KeysInterface for KeysManager {
// entropy, everything else just ensures uniqueness. We generally don't expect
// all clients to have non-broken RNGs here, so we also include the current
// time as a fallback to get uniqueness.
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
let mut seed = [0u8; 32];
rng::fill_bytes(&mut seed[..]);
@ -239,13 +201,41 @@ impl KeysInterface for KeysManager {
let child_privkey = self.channel_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32)).expect("Your RNG is busted");
sha.input(&child_privkey.secret_key[..]);
sha.result(&mut seed);
ChannelKeys::new_from_seed(&seed)
seed = Sha256::from_engine(sha).into_inner();
let commitment_seed = {
let mut sha = Sha256::engine();
sha.input(&seed);
sha.input(&b"commitment seed"[..]);
Sha256::from_engine(sha).into_inner()
};
macro_rules! key_step {
($info: expr, $prev_key: expr) => {{
let mut sha = Sha256::engine();
sha.input(&seed);
sha.input(&$prev_key[..]);
sha.input(&$info[..]);
SecretKey::from_slice(&self.secp_ctx, &Sha256::from_engine(sha).into_inner()).expect("SHA-256 is busted")
}}
}
let funding_key = key_step!(b"funding key", commitment_seed);
let revocation_base_key = key_step!(b"revocation base key", funding_key);
let payment_base_key = key_step!(b"payment base key", revocation_base_key);
let delayed_payment_base_key = key_step!(b"delayed payment base key", payment_base_key);
let htlc_base_key = key_step!(b"HTLC base key", delayed_payment_base_key);
ChannelKeys {
funding_key,
revocation_base_key,
payment_base_key,
delayed_payment_base_key,
htlc_base_key,
commitment_seed,
}
}
fn get_session_key(&self) -> SecretKey {
let mut sha = Sha256::new();
let mut res = [0u8; 32];
let mut sha = Sha256::engine();
let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
sha.input(&byte_utils::be32_to_array(now.subsec_nanos()));
@ -254,7 +244,6 @@ impl KeysInterface for KeysManager {
let child_ix = self.session_child_index.fetch_add(1, Ordering::AcqRel);
let child_privkey = self.session_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32)).expect("Your RNG is busted");
sha.input(&child_privkey.secret_key[..]);
sha.result(&mut res);
SecretKey::from_slice(&self.secp_ctx, &res).expect("Your RNG is busted")
SecretKey::from_slice(&self.secp_ctx, &Sha256::from_engine(sha).into_inner()).expect("Your RNG is busted")
}
}

View file

@ -12,7 +12,7 @@
#![cfg_attr(not(feature = "fuzztarget"), deny(missing_docs))]
extern crate bitcoin;
extern crate crypto;
extern crate bitcoin_hashes;
extern crate rand;
extern crate secp256k1;
#[cfg(test)] extern crate hex;

View file

@ -1,7 +1,12 @@
use bitcoin::blockdata::script::{Script,Builder};
use bitcoin::blockdata::opcodes;
use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction};
use bitcoin::util::hash::{Hash160,Sha256dHash};
use bitcoin::util::hash::{Sha256dHash};
use bitcoin_hashes::{Hash, HashEngine};
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::ripemd160::Hash as Ripemd160;
use bitcoin_hashes::hash160::Hash as Hash160;
use ln::channelmanager::PaymentHash;
@ -9,11 +14,6 @@ use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::Secp256k1;
use secp256k1;
use crypto::digest::Digest;
use crypto::ripemd160::Ripemd160;
use util::sha2::Sha256;
pub const HTLC_SUCCESS_TX_WEIGHT: u64 = 703;
pub const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663;
@ -26,20 +26,17 @@ pub fn build_commitment_secret(commitment_seed: [u8; 32], idx: u64) -> [u8; 32]
let bitpos = 47 - i;
if idx & (1 << bitpos) == (1 << bitpos) {
res[bitpos / 8] ^= 1 << (bitpos & 7);
let mut sha = Sha256::new();
sha.input(&res);
sha.result(&mut res);
res = Sha256::hash(&res).into_inner();
}
}
res
}
pub fn derive_private_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_secret: &SecretKey) -> Result<SecretKey, secp256k1::Error> {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
sha.input(&PublicKey::from_secret_key(&secp_ctx, &base_secret).serialize());
let mut res = [0; 32];
sha.result(&mut res);
let res = Sha256::from_engine(sha).into_inner();
let mut key = base_secret.clone();
key.add_assign(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &res)?)?;
@ -47,11 +44,10 @@ pub fn derive_private_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_co
}
pub fn derive_public_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
sha.input(&base_point.serialize());
let mut res = [0; 32];
sha.result(&mut res);
let res = Sha256::from_engine(sha).into_inner();
let hashkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&secp_ctx, &res)?);
base_point.combine(&secp_ctx, &hashkey)
@ -63,22 +59,18 @@ pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1
let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret);
let rev_append_commit_hash_key = {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&revocation_base_point.serialize());
sha.input(&per_commitment_point.serialize());
let mut res = [0; 32];
sha.result(&mut res);
SecretKey::from_slice(&secp_ctx, &res)?
SecretKey::from_slice(&secp_ctx, &Sha256::from_engine(sha).into_inner())?
};
let commit_append_rev_hash_key = {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
sha.input(&revocation_base_point.serialize());
let mut res = [0; 32];
sha.result(&mut res);
SecretKey::from_slice(&secp_ctx, &res)?
SecretKey::from_slice(&secp_ctx, &Sha256::from_engine(sha).into_inner())?
};
let mut part_a = revocation_base_secret.clone();
@ -91,22 +83,18 @@ pub fn derive_private_revocation_key<T: secp256k1::Signing>(secp_ctx: &Secp256k1
pub fn derive_public_revocation_key<T: secp256k1::Verification>(secp_ctx: &Secp256k1<T>, per_commitment_point: &PublicKey, revocation_base_point: &PublicKey) -> Result<PublicKey, secp256k1::Error> {
let rev_append_commit_hash_key = {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&revocation_base_point.serialize());
sha.input(&per_commitment_point.serialize());
let mut res = [0; 32];
sha.result(&mut res);
SecretKey::from_slice(&secp_ctx, &res)?
SecretKey::from_slice(&secp_ctx, &Sha256::from_engine(sha).into_inner())?
};
let commit_append_rev_hash_key = {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&per_commitment_point.serialize());
sha.input(&revocation_base_point.serialize());
let mut res = [0; 32];
sha.result(&mut res);
SecretKey::from_slice(&secp_ctx, &res)?
SecretKey::from_slice(&secp_ctx, &Sha256::from_engine(sha).into_inner())?
};
let mut part_a = revocation_base_point.clone();
@ -164,17 +152,11 @@ pub struct HTLCOutputInCommitment {
#[inline]
pub fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script {
let payment_hash160 = {
let mut ripemd = Ripemd160::new();
ripemd.input(&htlc.payment_hash.0[..]);
let mut res = [0; 20];
ripemd.result(&mut res);
res
};
let payment_hash160 = Ripemd160::hash(&htlc.payment_hash.0[..]).into_inner();
if htlc.offered {
Builder::new().push_opcode(opcodes::All::OP_DUP)
.push_opcode(opcodes::All::OP_HASH160)
.push_slice(&Hash160::from_data(&revocation_key.serialize())[..])
.push_slice(&Hash160::hash(&revocation_key.serialize())[..])
.push_opcode(opcodes::All::OP_EQUAL)
.push_opcode(opcodes::All::OP_IF)
.push_opcode(opcodes::All::OP_CHECKSIG)
@ -202,7 +184,7 @@ pub fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a
} else {
Builder::new().push_opcode(opcodes::All::OP_DUP)
.push_opcode(opcodes::All::OP_HASH160)
.push_slice(&Hash160::from_data(&revocation_key.serialize())[..])
.push_slice(&Hash160::hash(&revocation_key.serialize())[..])
.push_opcode(opcodes::All::OP_EQUAL)
.push_opcode(opcodes::All::OP_IF)
.push_opcode(opcodes::All::OP_CHECKSIG)

View file

@ -2,16 +2,18 @@ use bitcoin::blockdata::block::BlockHeader;
use bitcoin::blockdata::script::{Script,Builder};
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
use bitcoin::blockdata::opcodes;
use bitcoin::util::hash::{BitcoinHash, Sha256dHash, Hash160};
use bitcoin::util::hash::{BitcoinHash, Sha256dHash};
use bitcoin::util::bip143;
use bitcoin::consensus::encode::{self, Encodable, Decodable};
use bitcoin_hashes::{Hash, HashEngine};
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::hash160::Hash as Hash160;
use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1;
use crypto::digest::Digest;
use ln::msgs;
use ln::msgs::DecodeError;
use ln::channelmonitor::ChannelMonitor;
@ -23,7 +25,6 @@ use chain::transaction::OutPoint;
use chain::keysinterface::{ChannelKeys, KeysInterface};
use util::{transaction_utils,rng};
use util::ser::{Readable, ReadableArgs, Writeable, Writer, WriterWriteAdaptor};
use util::sha2::Sha256;
use util::logger::Logger;
use util::errors::APIError;
use util::config::{UserConfig,ChannelConfig};
@ -722,7 +723,7 @@ impl Channel {
// Utilities to build transactions:
fn get_commitment_transaction_number_obscure_factor(&self) -> u64 {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
let our_payment_basepoint = PublicKey::from_secret_key(&self.secp_ctx, &self.local_keys.payment_base_key);
if self.channel_outbound {
@ -732,8 +733,7 @@ impl Channel {
sha.input(&self.their_payment_basepoint.unwrap().serialize());
sha.input(&our_payment_basepoint.serialize());
}
let mut res = [0; 32];
sha.result(&mut res);
let res = Sha256::from_engine(sha).into_inner();
((res[26] as u64) << 5*8) |
((res[27] as u64) << 4*8) |
@ -907,7 +907,7 @@ impl Channel {
if value_to_b >= (dust_limit_satoshis as i64) {
txouts.push((TxOut {
script_pubkey: Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0)
.push_slice(&Hash160::from_data(&keys.b_payment_key.serialize())[..])
.push_slice(&Hash160::hash(&keys.b_payment_key.serialize())[..])
.into_script(),
value: value_to_b as u64
}, None));
@ -940,7 +940,7 @@ impl Channel {
#[inline]
fn get_closing_scriptpubkey(&self) -> Script {
let our_channel_close_key_hash = Hash160::from_data(&self.shutdown_pubkey.serialize());
let our_channel_close_key_hash = Hash160::hash(&self.shutdown_pubkey.serialize());
Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script()
}
@ -1151,10 +1151,7 @@ impl Channel {
}
assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0);
let mut sha = Sha256::new();
sha.input(&payment_preimage_arg.0[..]);
let mut payment_hash_calc = PaymentHash([0; 32]);
sha.result(&mut payment_hash_calc.0[..]);
let payment_hash_calc = PaymentHash(Sha256::hash(&payment_preimage_arg.0[..]).into_inner());
// ChannelManager may generate duplicate claims/fails due to HTLC update events from
// on-chain ChannelsMonitors during block rescan. Ideally we'd figure out a way to drop
@ -1650,11 +1647,7 @@ impl Channel {
return Err(ChannelError::Close("Peer sent update_fulfill_htlc when we needed a channel_reestablish"));
}
let mut sha = Sha256::new();
sha.input(&msg.payment_preimage.0[..]);
let mut payment_hash = PaymentHash([0; 32]);
sha.result(&mut payment_hash.0[..]);
let payment_hash = PaymentHash(Sha256::hash(&msg.payment_preimage.0[..]).into_inner());
self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None).map(|source| source.clone())
}
@ -3927,8 +3920,8 @@ mod tests {
use util::logger::Logger;
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1::key::{SecretKey,PublicKey};
use crypto::sha2::Sha256;
use crypto::digest::Digest;
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::Hash;
use std::sync::Arc;
struct TestFeeEstimator {
@ -4054,12 +4047,7 @@ mod tests {
let mut preimage: Option<PaymentPreimage> = None;
if !htlc.offered {
for i in 0..5 {
let mut sha = Sha256::new();
sha.input(&[i; 32]);
let mut out = PaymentHash([0; 32]);
sha.result(&mut out.0[..]);
let out = PaymentHash(Sha256::hash(&[i; 32]).into_inner());
if out == htlc.payment_hash {
preimage = Some(PaymentPreimage([i; 32]));
}
@ -4091,9 +4079,7 @@ mod tests {
payment_hash: PaymentHash([0; 32]),
state: InboundHTLCState::Committed,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap());
sha.result(&mut out.payment_hash.0[..]);
out.payment_hash.0 = Sha256::hash(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap()).into_inner();
out
});
chan.pending_inbound_htlcs.push({
@ -4104,9 +4090,7 @@ mod tests {
payment_hash: PaymentHash([0; 32]),
state: InboundHTLCState::Committed,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap());
sha.result(&mut out.payment_hash.0[..]);
out.payment_hash.0 = Sha256::hash(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()).into_inner();
out
});
chan.pending_outbound_htlcs.push({
@ -4119,9 +4103,7 @@ mod tests {
source: HTLCSource::dummy(),
fail_reason: None,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap());
sha.result(&mut out.payment_hash.0[..]);
out.payment_hash.0 = Sha256::hash(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).into_inner();
out
});
chan.pending_outbound_htlcs.push({
@ -4134,9 +4116,7 @@ mod tests {
source: HTLCSource::dummy(),
fail_reason: None,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap());
sha.result(&mut out.payment_hash.0[..]);
out.payment_hash.0 = Sha256::hash(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).into_inner();
out
});
chan.pending_inbound_htlcs.push({
@ -4147,9 +4127,7 @@ mod tests {
payment_hash: PaymentHash([0; 32]),
state: InboundHTLCState::Committed,
};
let mut sha = Sha256::new();
sha.input(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap());
sha.result(&mut out.payment_hash.0[..]);
out.payment_hash.0 = Sha256::hash(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap()).into_inner();
out
});

View file

@ -14,6 +14,11 @@ use bitcoin::blockdata::constants::genesis_block;
use bitcoin::network::constants::Network;
use bitcoin::util::hash::{BitcoinHash, Sha256dHash};
use bitcoin_hashes::{Hash, HashEngine};
use bitcoin_hashes::hmac::{Hmac, HmacEngine};
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::cmp::fixed_time_eq;
use secp256k1::key::{SecretKey,PublicKey};
use secp256k1::{Secp256k1,Message};
use secp256k1::ecdh::SharedSecret;
@ -29,19 +34,12 @@ use ln::msgs::{ChannelMessageHandler, DecodeError, HandleError};
use chain::keysinterface::KeysInterface;
use util::config::UserConfig;
use util::{byte_utils, events, internal_traits, rng};
use util::sha2::Sha256;
use util::ser::{Readable, ReadableArgs, Writeable, Writer};
use util::chacha20poly1305rfc::ChaCha20;
use util::chacha20::ChaCha20;
use util::logger::Logger;
use util::errors::APIError;
use util::errors;
use crypto;
use crypto::mac::{Mac,MacResult};
use crypto::hmac::Hmac;
use crypto::digest::Digest;
use crypto::symmetriccipher::SynchronousStreamCipher;
use std::{cmp, ptr, mem};
use std::collections::{HashMap, hash_map, HashSet};
use std::io::Cursor;
@ -722,39 +720,31 @@ impl ChannelManager {
fn gen_rho_mu_from_shared_secret(shared_secret: &[u8]) -> ([u8; 32], [u8; 32]) {
assert_eq!(shared_secret.len(), 32);
({
let mut hmac = Hmac::new(Sha256::new(), &[0x72, 0x68, 0x6f]); // rho
let mut hmac = HmacEngine::<Sha256>::new(&[0x72, 0x68, 0x6f]); // rho
hmac.input(&shared_secret[..]);
let mut res = [0; 32];
hmac.raw_result(&mut res);
res
Hmac::from_engine(hmac).into_inner()
},
{
let mut hmac = Hmac::new(Sha256::new(), &[0x6d, 0x75]); // mu
let mut hmac = HmacEngine::<Sha256>::new(&[0x6d, 0x75]); // mu
hmac.input(&shared_secret[..]);
let mut res = [0; 32];
hmac.raw_result(&mut res);
res
Hmac::from_engine(hmac).into_inner()
})
}
#[inline]
fn gen_um_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
assert_eq!(shared_secret.len(), 32);
let mut hmac = Hmac::new(Sha256::new(), &[0x75, 0x6d]); // um
let mut hmac = HmacEngine::<Sha256>::new(&[0x75, 0x6d]); // um
hmac.input(&shared_secret[..]);
let mut res = [0; 32];
hmac.raw_result(&mut res);
res
Hmac::from_engine(hmac).into_inner()
}
#[inline]
fn gen_ammag_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
assert_eq!(shared_secret.len(), 32);
let mut hmac = Hmac::new(Sha256::new(), &[0x61, 0x6d, 0x6d, 0x61, 0x67]); // ammag
let mut hmac = HmacEngine::<Sha256>::new(&[0x61, 0x6d, 0x6d, 0x61, 0x67]); // ammag
hmac.input(&shared_secret[..]);
let mut res = [0; 32];
hmac.raw_result(&mut res);
res
Hmac::from_engine(hmac).into_inner()
}
// can only fail if an intermediary hop has an invalid public key or session_priv is invalid
@ -766,11 +756,10 @@ impl ChannelManager {
for hop in route.hops.iter() {
let shared_secret = SharedSecret::new(secp_ctx, &hop.pubkey, &blinded_priv);
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&blinded_pub.serialize()[..]);
sha.input(&shared_secret[..]);
let mut blinding_factor = [0u8; 32];
sha.result(&mut blinding_factor);
let blinding_factor = Sha256::from_engine(sha).into_inner();
let ephemeral_pubkey = blinded_pub;
@ -896,10 +885,10 @@ impl ChannelManager {
packet_data[20*65 - filler.len()..20*65].copy_from_slice(&filler[..]);
}
let mut hmac = Hmac::new(Sha256::new(), &keys.mu);
let mut hmac = HmacEngine::<Sha256>::new(&keys.mu);
hmac.input(&packet_data);
hmac.input(&associated_data.0[..]);
hmac.raw_result(&mut hmac_res);
hmac_res = Hmac::from_engine(hmac).into_inner();
}
msgs::OnionPacket{
@ -948,9 +937,9 @@ impl ChannelManager {
pad: pad,
};
let mut hmac = Hmac::new(Sha256::new(), &um);
let mut hmac = HmacEngine::<Sha256>::new(&um);
hmac.input(&packet.encode()[32..]);
hmac.raw_result(&mut packet.hmac);
packet.hmac = Hmac::from_engine(hmac).into_inner();
packet
}
@ -966,14 +955,10 @@ impl ChannelManager {
($msg: expr, $err_code: expr) => {
{
log_info!(self, "Failed to accept/forward incoming HTLC: {}", $msg);
let mut sha256_of_onion = [0; 32];
let mut sha = Sha256::new();
sha.input(&msg.onion_routing_packet.hop_data);
sha.result(&mut sha256_of_onion);
return (PendingHTLCStatus::Fail(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
channel_id: msg.channel_id,
htlc_id: msg.htlc_id,
sha256_of_onion,
sha256_of_onion: Sha256::hash(&msg.onion_routing_packet.hop_data).into_inner(),
failure_code: $err_code,
})), self.channel_state.lock().unwrap());
}
@ -1001,10 +986,11 @@ impl ChannelManager {
return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
}
let mut hmac = Hmac::new(Sha256::new(), &mu);
let mut hmac = HmacEngine::<Sha256>::new(&mu);
hmac.input(&msg.onion_routing_packet.hop_data);
hmac.input(&msg.payment_hash.0[..]);
if hmac.result() != MacResult::new(&msg.onion_routing_packet.hmac) {
if !fixed_time_eq(&Hmac::from_engine(hmac).into_inner(), &msg.onion_routing_packet.hmac) {
return_malformed_err!("HMAC Check failed", 0x8000 | 0x4000 | 5);
}
@ -1077,12 +1063,10 @@ impl ChannelManager {
let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap();
let blinding_factor = {
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&new_pubkey.serialize()[..]);
sha.input(&shared_secret);
let mut res = [0u8; 32];
sha.result(&mut res);
SecretKey::from_slice(&self.secp_ctx, &res).expect("SHA-256 is broken?")
SecretKey::from_slice(&self.secp_ctx, &Sha256::from_engine(sha).into_inner()).expect("SHA-256 is broken?")
};
let public_key = if let Err(e) = new_pubkey.mul_assign(&self.secp_ctx, &blinding_factor) {
@ -1652,10 +1636,7 @@ impl ChannelManager {
///
/// May panic if called except in response to a PaymentReceived event.
pub fn claim_funds(&self, payment_preimage: PaymentPreimage) -> bool {
let mut sha = Sha256::new();
sha.input(&payment_preimage.0[..]);
let mut payment_hash = PaymentHash([0; 32]);
sha.result(&mut payment_hash.0[..]);
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
let _ = self.total_consistency_lock.read().unwrap();
@ -2156,12 +2137,10 @@ impl ChannelManager {
if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&packet_decrypted)) {
let um = ChannelManager::gen_um_from_shared_secret(&shared_secret[..]);
let mut hmac = Hmac::new(Sha256::new(), &um);
let mut hmac = HmacEngine::<Sha256>::new(&um);
hmac.input(&err_packet.encode()[32..]);
let mut calc_tag = [0u8; 32];
hmac.raw_result(&mut calc_tag);
if crypto::util::fixed_time_eq(&calc_tag, &err_packet.hmac) {
if fixed_time_eq(&Hmac::from_engine(hmac).into_inner(), &err_packet.hmac) {
if let Some(error_code_slice) = err_packet.failuremsg.get(0..2) {
const PERM: u16 = 0x4000;
const NODE: u16 = 0x2000;
@ -3382,14 +3361,14 @@ mod tests {
use bitcoin::blockdata::constants::genesis_block;
use bitcoin::network::constants::Network;
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::Hash;
use hex;
use secp256k1::{Secp256k1, Message};
use secp256k1::key::{PublicKey,SecretKey};
use crypto::sha2::Sha256;
use crypto::digest::Digest;
use rand::{thread_rng,Rng};
use std::cell::RefCell;
@ -4030,10 +4009,7 @@ mod tests {
{
let payment_preimage = PaymentPreimage([*$node.network_payment_count.borrow(); 32]);
*$node.network_payment_count.borrow_mut() += 1;
let mut payment_hash = PaymentHash([0; 32]);
let mut sha = Sha256::new();
sha.input(&payment_preimage.0[..]);
sha.result(&mut payment_hash.0[..]);
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
(payment_preimage, payment_hash)
}
}

View file

@ -17,10 +17,12 @@ use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
use bitcoin::consensus::encode::{self, Decodable, Encodable};
use bitcoin::util::hash::{Hash160, BitcoinHash,Sha256dHash};
use bitcoin::util::hash::{BitcoinHash,Sha256dHash};
use bitcoin::util::bip143;
use crypto::digest::Digest;
use bitcoin_hashes::Hash;
use bitcoin_hashes::sha256::Hash as Sha256;
use bitcoin_hashes::hash160::Hash as Hash160;
use secp256k1::{Secp256k1,Message,Signature};
use secp256k1::key::{SecretKey,PublicKey};
@ -36,7 +38,6 @@ use chain::transaction::OutPoint;
use chain::keysinterface::SpendableOutputDescriptor;
use util::logger::Logger;
use util::ser::{ReadableArgs, Readable, Writer, Writeable, WriterWriteAdaptor, U48};
use util::sha2::Sha256;
use util::{byte_utils, events};
use std::collections::{HashMap, hash_map};
@ -487,9 +488,7 @@ impl ChannelMonitor {
let bitpos = bits - 1 - i;
if idx & (1 << bitpos) == (1 << bitpos) {
res[(bitpos / 8) as usize] ^= 1 << (bitpos & 7);
let mut sha = Sha256::new();
sha.input(&res);
sha.result(&mut res);
res = Sha256::hash(&res).into_inner();
}
}
res
@ -569,6 +568,8 @@ impl ChannelMonitor {
}
let new_txid = unsigned_commitment_tx.txid();
log_trace!(self, "Tracking new remote commitment transaction with txid {} at commitment number {} with {} HTLC outputs", new_txid, commitment_number, htlc_outputs.len());
log_trace!(self, "New potential remote commitment transaction: {}", encode::serialize_hex(unsigned_commitment_tx));
if let Storage::Local { ref mut current_remote_commitment_txid, ref mut prev_remote_commitment_txid, .. } = self.key_storage {
*prev_remote_commitment_txid = current_remote_commitment_txid.take();
*current_remote_commitment_txid = Some(new_txid);
@ -1079,7 +1080,7 @@ impl ChannelMonitor {
let local_payment_p2wpkh = if let Some(payment_key) = local_payment_key {
// Note that the Network here is ignored as we immediately drop the address for the
// script_pubkey version.
let payment_hash160 = Hash160::from_data(&PublicKey::from_secret_key(&self.secp_ctx, &payment_key).serialize());
let payment_hash160 = Hash160::hash(&PublicKey::from_secret_key(&self.secp_ctx, &payment_key).serialize());
Some(Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script())
} else { None };
@ -1247,6 +1248,8 @@ impl ChannelMonitor {
watch_outputs.append(&mut tx.output.clone());
self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect()));
log_trace!(self, "Got broadcast of non-revoked remote commitment transaction {}", commitment_txid);
if let Some(revocation_points) = self.their_cur_revocation_points {
let revocation_point_option =
if revocation_points.0 == commitment_number { Some(&revocation_points.1) }
@ -1621,7 +1624,7 @@ impl ChannelMonitor {
if tx.input[0].sequence == 0xFFFFFFFF && !tx.input[0].witness.is_empty() && tx.input[0].witness.last().unwrap().len() == 71 {
match self.key_storage {
Storage::Local { ref shutdown_pubkey, .. } => {
let our_channel_close_key_hash = Hash160::from_data(&shutdown_pubkey.serialize());
let our_channel_close_key_hash = Hash160::hash(&shutdown_pubkey.serialize());
let shutdown_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script();
for (idx, output) in tx.output.iter().enumerate() {
if shutdown_script == output.script_pubkey {
@ -2098,13 +2101,9 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
let payment_preimages_len: u64 = Readable::read(reader)?;
let mut payment_preimages = HashMap::with_capacity(cmp::min(payment_preimages_len as usize, MAX_ALLOC_SIZE / 32));
let mut sha = Sha256::new();
for _ in 0..payment_preimages_len {
let preimage: PaymentPreimage = Readable::read(reader)?;
sha.reset();
sha.input(&preimage.0[..]);
let mut hash = PaymentHash([0; 32]);
sha.result(&mut hash.0[..]);
let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner());
if let Some(_) = payment_preimages.insert(hash, preimage) {
return Err(DecodeError::InvalidValue);
}
@ -2148,12 +2147,12 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelM
mod tests {
use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::transaction::Transaction;
use crypto::digest::Digest;
use bitcoin_hashes::Hash;
use bitcoin_hashes::sha256::Hash as Sha256;
use hex;
use ln::channelmanager::{PaymentPreimage, PaymentHash};
use ln::channelmonitor::ChannelMonitor;
use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys};
use util::sha2::Sha256;
use util::test_utils::TestLogger;
use secp256k1::key::{SecretKey,PublicKey};
use secp256k1::{Secp256k1, Signature};
@ -2544,10 +2543,7 @@ mod tests {
for _ in 0..20 {
let mut preimage = PaymentPreimage([0; 32]);
rng.fill_bytes(&mut preimage.0[..]);
let mut sha = Sha256::new();
sha.input(&preimage.0[..]);
let mut hash = PaymentHash([0; 32]);
sha.result(&mut hash.0[..]);
let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner());
preimages.push((preimage, hash));
}
}

View file

@ -1,19 +1,16 @@
use ln::msgs::HandleError;
use ln::msgs;
use bitcoin_hashes::{Hash, HashEngine, Hmac, HmacEngine};
use bitcoin_hashes::sha256::Hash as Sha256;
use secp256k1::Secp256k1;
use secp256k1::key::{PublicKey,SecretKey};
use secp256k1::ecdh::SharedSecret;
use secp256k1;
use crypto::digest::Digest;
use crypto::hkdf::{hkdf_extract,hkdf_expand};
use crypto::aead::{AeadEncryptor, AeadDecryptor};
use util::chacha20poly1305rfc::ChaCha20Poly1305RFC;
use util::{byte_utils,rng};
use util::sha2::Sha256;
// Sha256("Noise_XK_secp256k1_ChaChaPoly_SHA256")
const NOISE_CK: [u8; 32] = [0x26, 0x40, 0xf5, 0x2e, 0xeb, 0xcd, 0x9e, 0x88, 0x29, 0x58, 0x95, 0x1c, 0x79, 0x42, 0x50, 0xee, 0xdb, 0x28, 0x00, 0x2c, 0x05, 0xd7, 0xdc, 0x2e, 0xa0, 0xf1, 0x95, 0x40, 0x60, 0x42, 0xca, 0xf1];
@ -80,11 +77,10 @@ impl PeerChannelEncryptor {
let secp_ctx = Secp256k1::signing_only();
let sec_key = SecretKey::from_slice(&secp_ctx, &key).unwrap(); //TODO: nicer rng-is-bad error message
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&NOISE_H);
sha.input(&their_node_id.serialize()[..]);
let mut h = [0; 32];
sha.result(&mut h);
let h = Sha256::from_engine(sha).into_inner();
PeerChannelEncryptor {
their_node_id: Some(their_node_id),
@ -105,12 +101,11 @@ impl PeerChannelEncryptor {
pub fn new_inbound(our_node_secret: &SecretKey) -> PeerChannelEncryptor {
let secp_ctx = Secp256k1::signing_only();
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&NOISE_H);
let our_node_id = PublicKey::from_secret_key(&secp_ctx, our_node_secret);
sha.input(&our_node_id.serialize()[..]);
let mut h = [0; 32];
sha.result(&mut h);
let h = Sha256::from_engine(sha).into_inner();
PeerChannelEncryptor {
their_node_id: None,
@ -153,28 +148,34 @@ impl PeerChannelEncryptor {
Ok(())
}
fn hkdf_extract_expand(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
let mut hmac = HmacEngine::<Sha256>::new(salt);
hmac.input(ikm);
let prk = Hmac::from_engine(hmac).into_inner();
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
hmac.input(&[1; 1]);
let t1 = Hmac::from_engine(hmac).into_inner();
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
hmac.input(&t1);
hmac.input(&[2; 1]);
(t1, Hmac::from_engine(hmac).into_inner())
}
#[inline]
fn hkdf(state: &mut BidirectionalNoiseState, ss: SharedSecret) -> [u8; 32] {
let mut hkdf = [0; 64];
{
let mut prk = [0; 32];
hkdf_extract(Sha256::new(), &state.ck, &ss[..], &mut prk);
hkdf_expand(Sha256::new(), &prk, &[0;0], &mut hkdf);
}
state.ck.copy_from_slice(&hkdf[0..32]);
let mut res = [0; 32];
res.copy_from_slice(&hkdf[32..]);
res
let (t1, t2) = Self::hkdf_extract_expand(&state.ck, &ss[..]);
state.ck = t1;
t2
}
#[inline]
fn outbound_noise_act<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, state: &mut BidirectionalNoiseState, our_key: &SecretKey, their_key: &PublicKey) -> ([u8; 50], [u8; 32]) {
let our_pub = PublicKey::from_secret_key(secp_ctx, &our_key);
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&state.h);
sha.input(&our_pub.serialize()[..]);
sha.result(&mut state.h);
state.h = Sha256::from_engine(sha).into_inner();
let ss = SharedSecret::new(secp_ctx, &their_key, &our_key);
let temp_k = PeerChannelEncryptor::hkdf(state, ss);
@ -183,10 +184,10 @@ impl PeerChannelEncryptor {
res[1..34].copy_from_slice(&our_pub.serialize()[..]);
PeerChannelEncryptor::encrypt_with_ad(&mut res[34..], 0, &temp_k, &state.h, &[0; 0]);
sha.reset();
let mut sha = Sha256::engine();
sha.input(&state.h);
sha.input(&res[34..]);
sha.result(&mut state.h);
state.h = Sha256::from_engine(sha).into_inner();
(res, temp_k)
}
@ -204,10 +205,10 @@ impl PeerChannelEncryptor {
Ok(key) => key,
};
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&state.h);
sha.input(&their_pub.serialize()[..]);
sha.result(&mut state.h);
state.h = Sha256::from_engine(sha).into_inner();
let ss = SharedSecret::new(secp_ctx, &their_pub, &our_key);
let temp_k = PeerChannelEncryptor::hkdf(state, ss);
@ -215,10 +216,10 @@ impl PeerChannelEncryptor {
let mut dec = [0; 0];
PeerChannelEncryptor::decrypt_with_ad(&mut dec, 0, &temp_k, &state.h, &act[34..])?;
sha.reset();
let mut sha = Sha256::engine();
sha.input(&state.h);
sha.input(&act[34..]);
sha.result(&mut state.h);
state.h = Sha256::from_engine(sha).into_inner();
Ok((their_pub, temp_k))
}
@ -282,7 +283,7 @@ impl PeerChannelEncryptor {
pub fn process_act_two(&mut self, act_two: &[u8], our_node_secret: &SecretKey) -> Result<([u8; 66], PublicKey), HandleError> {
assert_eq!(act_two.len(), 50);
let mut final_hkdf = [0; 64];
let final_hkdf;
let ck;
let res: [u8; 66] = match self.noise_state {
NoiseState::InProgress { ref state, ref directional_state, ref mut bidirectional_state } =>
@ -299,19 +300,16 @@ impl PeerChannelEncryptor {
PeerChannelEncryptor::encrypt_with_ad(&mut res[1..50], 1, &temp_k2, &bidirectional_state.h, &our_node_id.serialize()[..]);
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&bidirectional_state.h);
sha.input(&res[1..50]);
sha.result(&mut bidirectional_state.h);
bidirectional_state.h = Sha256::from_engine(sha).into_inner();
let ss = SharedSecret::new(&self.secp_ctx, &re, our_node_secret);
let temp_k = PeerChannelEncryptor::hkdf(bidirectional_state, ss);
PeerChannelEncryptor::encrypt_with_ad(&mut res[50..], 0, &temp_k, &bidirectional_state.h, &[0; 0]);
let mut prk = [0; 32];
hkdf_extract(Sha256::new(), &bidirectional_state.ck, &[0; 0], &mut prk);
hkdf_expand(Sha256::new(), &prk, &[0;0], &mut final_hkdf);
final_hkdf = Self::hkdf_extract_expand(&bidirectional_state.ck, &[0; 0]);
ck = bidirectional_state.ck.clone();
res
},
@ -320,11 +318,7 @@ impl PeerChannelEncryptor {
_ => panic!("Cannot get act one after noise handshake completes"),
};
let mut sk = [0; 32];
let mut rk = [0; 32];
sk.copy_from_slice(&final_hkdf[0..32]);
rk.copy_from_slice(&final_hkdf[32..]);
let (sk, rk) = final_hkdf;
self.noise_state = NoiseState::Finished {
sk: sk,
sn: 0,
@ -340,7 +334,7 @@ impl PeerChannelEncryptor {
pub fn process_act_three(&mut self, act_three: &[u8]) -> Result<PublicKey, HandleError> {
assert_eq!(act_three.len(), 66);
let mut final_hkdf = [0; 64];
let final_hkdf;
let ck;
match self.noise_state {
NoiseState::InProgress { ref state, ref directional_state, ref mut bidirectional_state } =>
@ -360,19 +354,16 @@ impl PeerChannelEncryptor {
Err(_) => return Err(HandleError{err: "Bad node_id from peer", action: Some(msgs::ErrorAction::DisconnectPeer{ msg: None })}),
});
let mut sha = Sha256::new();
let mut sha = Sha256::engine();
sha.input(&bidirectional_state.h);
sha.input(&act_three[1..50]);
sha.result(&mut bidirectional_state.h);
bidirectional_state.h = Sha256::from_engine(sha).into_inner();
let ss = SharedSecret::new(&self.secp_ctx, &self.their_node_id.unwrap(), &re.unwrap());
let temp_k = PeerChannelEncryptor::hkdf(bidirectional_state, ss);
PeerChannelEncryptor::decrypt_with_ad(&mut [0; 0], 0, &temp_k, &bidirectional_state.h, &act_three[50..])?;
let mut prk = [0; 32];
hkdf_extract(Sha256::new(), &bidirectional_state.ck, &[0; 0], &mut prk);
hkdf_expand(Sha256::new(), &prk, &[0;0], &mut final_hkdf);
final_hkdf = Self::hkdf_extract_expand(&bidirectional_state.ck, &[0; 0]);
ck = bidirectional_state.ck.clone();
},
_ => panic!("Wrong direction for act"),
@ -380,11 +371,7 @@ impl PeerChannelEncryptor {
_ => panic!("Cannot get act one after noise handshake completes"),
}
let mut rk = [0; 32];
let mut sk = [0; 32];
rk.copy_from_slice(&final_hkdf[0..32]);
sk.copy_from_slice(&final_hkdf[32..]);
let (rk, sk) = final_hkdf;
self.noise_state = NoiseState::Finished {
sk: sk,
sn: 0,
@ -410,13 +397,9 @@ impl PeerChannelEncryptor {
match self.noise_state {
NoiseState::Finished { ref mut sk, ref mut sn, ref mut sck, rk: _, rn: _, rck: _ } => {
if *sn >= 1000 {
let mut prk = [0; 32];
hkdf_extract(Sha256::new(), sck, sk, &mut prk);
let mut hkdf = [0; 64];
hkdf_expand(Sha256::new(), &prk, &[0;0], &mut hkdf);
sck[..].copy_from_slice(&hkdf[0..32]);
sk[..].copy_from_slice(&hkdf[32..]);
let (new_sck, new_sk) = Self::hkdf_extract_expand(sck, sk);
*sck = new_sck;
*sk = new_sk;
*sn = 0;
}
@ -440,13 +423,9 @@ impl PeerChannelEncryptor {
match self.noise_state {
NoiseState::Finished { sk: _, sn: _, sck: _, ref mut rk, ref mut rn, ref mut rck } => {
if *rn >= 1000 {
let mut prk = [0; 32];
hkdf_extract(Sha256::new(), rck, rk, &mut prk);
let mut hkdf = [0; 64];
hkdf_expand(Sha256::new(), &prk, &[0;0], &mut hkdf);
rck[..].copy_from_slice(&hkdf[0..32]);
rk[..].copy_from_slice(&hkdf[32..]);
let (new_rck, new_rk) = Self::hkdf_extract_expand(rck, rk);
*rck = new_rck;
*rk = new_rk;
*rn = 0;
}

View file

@ -11,6 +11,13 @@ pub fn slice_to_be32(v: &[u8]) -> u32 {
((v[3] as u32) << 8*0)
}
#[inline]
pub fn slice_to_le32(v: &[u8]) -> u32 {
((v[0] as u32) << 8*0) |
((v[1] as u32) << 8*1) |
((v[2] as u32) << 8*2) |
((v[3] as u32) << 8*3)
}
#[inline]
pub fn slice_to_be48(v: &[u8]) -> u64 {
((v[0] as u64) << 8*5) |
((v[1] as u64) << 8*4) |
@ -48,6 +55,15 @@ pub fn be32_to_array(u: u32) -> [u8; 4] {
v
}
#[inline]
pub fn le32_to_array(u: u32) -> [u8; 4] {
let mut v = [0; 4];
v[0] = ((u >> 8*0) & 0xff) as u8;
v[1] = ((u >> 8*1) & 0xff) as u8;
v[2] = ((u >> 8*2) & 0xff) as u8;
v[3] = ((u >> 8*3) & 0xff) as u8;
v
}
#[inline]
pub fn be48_to_array(u: u64) -> [u8; 6] {
assert!(u & 0xffff_0000_0000_0000 == 0);
let mut v = [0; 6];

550
src/util/chacha20.rs Normal file
View file

@ -0,0 +1,550 @@
// 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.
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[cfg(not(feature = "fuzztarget"))]
mod real_chacha {
use std::cmp;
use util::byte_utils::{slice_to_le32, le32_to_array};
#[derive(Clone, Copy, PartialEq, Eq)]
#[allow(non_camel_case_types)]
struct u32x4(pub u32, pub u32, pub u32, pub u32);
impl ::std::ops::Add for u32x4 {
type Output = u32x4;
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 ::std::ops::Sub for u32x4 {
type Output = u32x4;
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 ::std::ops::BitXor for u32x4 {
type Output = u32x4;
fn bitxor(self, rhs: u32x4) -> u32x4 {
u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
}
}
impl ::std::ops::Shr<u32x4> for u32x4 {
type Output = u32x4;
fn shr(self, rhs: u32x4) -> u32x4 {
u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3)
}
}
impl ::std::ops::Shl<u32x4> for u32x4 {
type Output = u32x4;
fn shl(self, rhs: u32x4) -> u32x4 {
u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3)
}
}
#[derive(Clone,Copy)]
struct ChaChaState {
a: u32x4,
b: u32x4,
c: u32x4,
d: u32x4
}
#[derive(Copy)]
pub struct ChaCha20 {
state : ChaChaState,
output : [u8; 64],
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(&le32_to_array(lens[i]));
}
}}
}
macro_rules! round{
($state: expr) => {{
$state.a = $state.a + $state.b;
rotate!($state.d, $state.a, S16);
$state.c = $state.c + $state.d;
rotate!($state.b, $state.c, S12);
$state.a = $state.a + $state.b;
rotate!($state.d, $state.a, S8);
$state.c = $state.c + $state.d;
rotate!($state.b, $state.c, S7);
}}
}
macro_rules! rotate {
($a: expr, $b: expr, $c:expr) => {{
let v = $a ^ $b;
let r = S32 - $c;
let right = v >> r;
$a = (v << $c) ^ right
}}
}
const S32:u32x4 = u32x4(32, 32, 32, 32);
const S16:u32x4 = u32x4(16, 16, 16, 16);
const S12:u32x4 = u32x4(12, 12, 12, 12);
const S8:u32x4 = u32x4(8, 8, 8, 8);
const S7:u32x4 = u32x4(7, 7, 7, 7);
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; 64], offset: 64 }
}
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(
slice_to_le32(&constant[0..4]),
slice_to_le32(&constant[4..8]),
slice_to_le32(&constant[8..12]),
slice_to_le32(&constant[12..16])
),
b: u32x4(
slice_to_le32(&key[0..4]),
slice_to_le32(&key[4..8]),
slice_to_le32(&key[8..12]),
slice_to_le32(&key[12..16])
),
c: if key.len() == 16 {
u32x4(
slice_to_le32(&key[0..4]),
slice_to_le32(&key[4..8]),
slice_to_le32(&key[8..12]),
slice_to_le32(&key[12..16])
)
} else {
u32x4(
slice_to_le32(&key[16..20]),
slice_to_le32(&key[20..24]),
slice_to_le32(&key[24..28]),
slice_to_le32(&key[28..32])
)
},
d: if nonce.len() == 16 {
u32x4(
slice_to_le32(&nonce[0..4]),
slice_to_le32(&nonce[4..8]),
slice_to_le32(&nonce[8..12]),
slice_to_le32(&nonce[12..16])
)
} else if nonce.len() == 12 {
u32x4(
0,
slice_to_le32(&nonce[0..4]),
slice_to_le32(&nonce[4..8]),
slice_to_le32(&nonce[8..12])
)
} else {
u32x4(
0,
0,
slice_to_le32(&nonce[0..4]),
slice_to_le32(&nonce[4..8])
)
}
}
}
// put the the next 64 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;
}
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 == 64 {
self.update();
}
// Process the min(available keystream, remaining input length).
let count = cmp::min(64 - 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;
}
}
}
}
#[cfg(not(feature = "fuzztarget"))]
pub use self::real_chacha::ChaCha20;
#[cfg(feature = "fuzztarget")]
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 process(&mut self, input: &[u8], output: &mut [u8]) {
output.copy_from_slice(input);
}
}
}
#[cfg(feature = "fuzztarget")]
pub use self::fuzzy_chacha::ChaCha20;
#[cfg(test)]
mod test {
use std::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);
}
}
}

View file

@ -12,19 +12,15 @@
#[cfg(not(feature = "fuzztarget"))]
mod real_chachapoly {
use crypto::aead::{AeadEncryptor,AeadDecryptor};
use crypto::symmetriccipher::SynchronousStreamCipher;
use crypto::poly1305::Poly1305;
use crypto::mac::Mac;
use crypto::util::fixed_time_eq;
pub use crypto::chacha20::ChaCha20;
use util::chacha20::ChaCha20;
use util::poly1305::Poly1305;
use bitcoin_hashes::cmp::fixed_time_eq;
use util::byte_utils;
#[derive(Clone, Copy)]
pub struct ChaCha20Poly1305RFC {
cipher : ChaCha20,
cipher: ChaCha20,
mac: Poly1305,
finished: bool,
data_len: usize,
@ -62,10 +58,8 @@ mod real_chachapoly {
aad_len: aad.len() as u64,
}
}
}
impl AeadEncryptor for ChaCha20Poly1305RFC {
fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
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);
@ -77,10 +71,8 @@ mod real_chachapoly {
self.mac.input(&byte_utils::le64_to_array(self.data_len as u64));
self.mac.raw_result(out_tag);
}
}
impl AeadDecryptor for ChaCha20Poly1305RFC {
fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
pub fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
assert!(input.len() == output.len());
assert!(self.finished == false);
@ -105,13 +97,10 @@ mod real_chachapoly {
}
}
#[cfg(not(feature = "fuzztarget"))]
pub use self::real_chachapoly::{ChaCha20Poly1305RFC, ChaCha20};
pub use self::real_chachapoly::ChaCha20Poly1305RFC;
#[cfg(feature = "fuzztarget")]
mod fuzzy_chachapoly {
use crypto::aead::{AeadEncryptor,AeadDecryptor};
use crypto::symmetriccipher::SynchronousStreamCipher;
#[derive(Clone, Copy)]
pub struct ChaCha20Poly1305RFC {
tag: [u8; 16],
@ -133,10 +122,8 @@ mod fuzzy_chachapoly {
finished: false,
}
}
}
impl AeadEncryptor for ChaCha20Poly1305RFC {
fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
assert!(input.len() == output.len());
assert!(self.finished == false);
@ -144,10 +131,8 @@ mod fuzzy_chachapoly {
out_tag.copy_from_slice(&self.tag);
self.finished = true;
}
}
impl AeadDecryptor for ChaCha20Poly1305RFC {
fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
pub fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
assert!(input.len() == output.len());
assert!(self.finished == false);
@ -157,22 +142,6 @@ mod fuzzy_chachapoly {
true
}
}
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 {}
}
}
impl SynchronousStreamCipher for ChaCha20 {
fn process(&mut self, input: &[u8], output: &mut [u8]) {
output.copy_from_slice(input);
}
}
}
#[cfg(feature = "fuzztarget")]
pub use self::fuzzy_chachapoly::{ChaCha20Poly1305RFC, ChaCha20};
pub use self::fuzzy_chachapoly::ChaCha20Poly1305RFC;

View file

@ -5,6 +5,8 @@ pub mod errors;
pub mod ser;
pub(crate) mod byte_utils;
pub(crate) mod chacha20;
pub(crate) mod poly1305;
pub(crate) mod chacha20poly1305rfc;
pub(crate) mod internal_traits;
pub(crate) mod rng;
@ -19,11 +21,6 @@ pub(crate) mod macro_logger;
pub mod logger;
pub mod config;
#[cfg(feature = "fuzztarget")]
pub mod sha2;
#[cfg(not(feature = "fuzztarget"))]
pub(crate) mod sha2;
#[cfg(feature = "fuzztarget")]
pub use self::rng::{reset_rng_state, fill_bytes};

340
src/util/poly1305.rs Normal file
View file

@ -0,0 +1,340 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This is a port of Andrew Moons poly1305-donna
// https://github.com/floodyberry/poly1305-donna
use std::cmp::min;
use util::byte_utils::{slice_to_le32, le32_to_array};
#[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] = (slice_to_le32(&key[0..4]) ) & 0x3ffffff;
poly.r[1] = (slice_to_le32(&key[3..7]) >> 2) & 0x3ffff03;
poly.r[2] = (slice_to_le32(&key[6..10]) >> 4) & 0x3ffc0ff;
poly.r[3] = (slice_to_le32(&key[9..13]) >> 6) & 0x3f03fff;
poly.r[4] = (slice_to_le32(&key[12..16]) >> 8) & 0x00fffff;
poly.pad[0] = slice_to_le32(&key[16..20]);
poly.pad[1] = slice_to_le32(&key[20..24]);
poly.pad[2] = slice_to_le32(&key[24..28]);
poly.pad[3] = slice_to_le32(&key[28..32]);
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 += (slice_to_le32(&m[0..4]) ) & 0x3ffffff;
h1 += (slice_to_le32(&m[3..7]) >> 2) & 0x3ffffff;
h2 += (slice_to_le32(&m[6..10]) >> 4) & 0x3ffffff;
h3 += (slice_to_le32(&m[9..13]) >> 6) & 0x3ffffff;
h4 += (slice_to_le32(&m[12..16]) >> 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(&le32_to_array(self.h[0]));
output[4..8].copy_from_slice(&le32_to_array(self.h[1]));
output[8..12].copy_from_slice(&le32_to_array(self.h[2]));
output[12..16].copy_from_slice(&le32_to_array(self.h[3]));
}
}
#[cfg(test)]
mod test {
use std::iter::repeat;
use 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[..]);
}
}

View file

@ -1,13 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
uint32_t rust_crypto_util_fixed_time_eq_asm(uint8_t* lhsp, uint8_t* rhsp, size_t count) {
if (count == 0) {
return 1;
}
uint8_t result = 0;
for (size_t i = 0; i < count; i++) {
result |= (lhsp[i] ^ rhsp[i]);
}
return result;
}

View file

@ -1,35 +0,0 @@
#[cfg(not(feature = "fuzztarget"))]
pub use crypto::sha2::Sha256;
#[cfg(feature = "fuzztarget")]
mod fuzzy_sha {
use crypto::digest::Digest;
pub struct Sha256 {
state: u8,
}
impl Sha256 {
pub fn new() -> Sha256 {
Sha256 {
state: 0,
}
}
}
impl Digest for Sha256 {
fn result(&mut self, data: &mut [u8]) {
data[0] = self.state;
for i in 1..32 {
data[i] = 0;
}
}
fn input(&mut self, data: &[u8]) { for i in data { self.state ^= i; } }
fn reset(&mut self) { self.state = 0; }
fn output_bits(&self) -> usize { 256 }
fn block_size(&self) -> usize { 64 }
}
}
#[cfg(feature = "fuzztarget")]
pub use self::fuzzy_sha::Sha256;