mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-21 05:41:33 +00:00
Make secio almost compile for asmjs/wasm (#519)
* Use the sha2 crate in the handshake * Return a Digest in algo_support instead of a ring ref * Switch to ed25519-dalek for keys * Make ring more or less optional * Switch to ed25519_dalek for the verification * Extract the key exchange to its own module * Remove the ring RNG from the handshake * Some warning fixes and forgot file * Move key exchange to own module * Remove usage of ring::digest * Remove ring from handshake entirely * Implement ECDH for WebCrypto * Remove the libp2p-secio feature * Fix ring being included * Address some concerns * Provde some panics in WebCrypto * Prove the Hmac panic * Prove more panics
This commit is contained in:
@ -20,9 +20,11 @@
|
||||
|
||||
use algo_support;
|
||||
use bytes::BytesMut;
|
||||
use codec::{full_codec, FullCodec};
|
||||
use codec::{full_codec, FullCodec, Hmac};
|
||||
use stream_cipher::{Cipher, ctr};
|
||||
use ed25519_dalek::{PublicKey as Ed25519PublicKey, Signature as Ed25519Signature};
|
||||
use error::SecioError;
|
||||
use exchange;
|
||||
use futures::future;
|
||||
use futures::sink::Sink;
|
||||
use futures::stream::Stream;
|
||||
@ -30,22 +32,23 @@ use futures::Future;
|
||||
use libp2p_core::PublicKey;
|
||||
use protobuf::parse_from_bytes as protobuf_parse_from_bytes;
|
||||
use protobuf::Message as ProtobufMessage;
|
||||
use ring::agreement::EphemeralPrivateKey;
|
||||
use ring::hmac::{SigningContext, SigningKey, VerificationKey};
|
||||
use ring::rand::SecureRandom;
|
||||
use ring::signature::verify as signature_verify;
|
||||
use ring::signature::{ED25519, RSASigningState, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA256};
|
||||
use ring::{agreement, digest, rand};
|
||||
use rand::{self, RngCore};
|
||||
#[cfg(all(feature = "ring", not(target_os = "emscripten")))]
|
||||
use ring::signature::{RSASigningState, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_SHA256, verify as ring_verify};
|
||||
#[cfg(all(feature = "ring", not(target_os = "emscripten")))]
|
||||
use ring::rand::SystemRandom;
|
||||
#[cfg(feature = "secp256k1")]
|
||||
use secp256k1;
|
||||
use sha2::{Digest as ShaDigestTrait, Sha256, Sha512};
|
||||
use std::cmp::{self, Ordering};
|
||||
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||
use std::mem;
|
||||
use structs_proto::{Exchange, Propose};
|
||||
use tokio_io::codec::length_delimited;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
#[cfg(all(feature = "ring", not(target_os = "emscripten")))]
|
||||
use untrusted::Input as UntrustedInput;
|
||||
use {SecioConfig, SecioKeyPairInner};
|
||||
use {KeyAgreement, SecioConfig, SecioKeyPairInner};
|
||||
|
||||
/// Performs a handshake on the given socket.
|
||||
///
|
||||
@ -71,7 +74,6 @@ where
|
||||
// Filled with this function's parameter.
|
||||
config: SecioConfig,
|
||||
|
||||
rng: rand::SystemRandom,
|
||||
// Locally-generated random number. The array size can be changed without any repercussion.
|
||||
local_nonce: [u8; 16],
|
||||
|
||||
@ -100,19 +102,18 @@ where
|
||||
hashes_ordering: Ordering,
|
||||
|
||||
// Crypto algorithms chosen for the communication.
|
||||
chosen_exchange: Option<&'static agreement::Algorithm>,
|
||||
chosen_exchange: Option<KeyAgreement>,
|
||||
// We only support AES for now, so store just a key size.
|
||||
chosen_cipher: Option<Cipher>,
|
||||
chosen_hash: Option<&'static digest::Algorithm>,
|
||||
chosen_hash: Option<algo_support::Digest>,
|
||||
|
||||
// Ephemeral key generated for the handshake and then thrown away.
|
||||
local_tmp_priv_key: Option<EphemeralPrivateKey>,
|
||||
local_tmp_priv_key: Option<exchange::AgreementPrivateKey>,
|
||||
local_tmp_pub_key: Vec<u8>,
|
||||
}
|
||||
|
||||
let context = HandshakeContext {
|
||||
config,
|
||||
rng: rand::SystemRandom::new(),
|
||||
local_nonce: Default::default(),
|
||||
local_public_key_in_protobuf_bytes: Vec::new(),
|
||||
local_proposition_bytes: Vec::new(),
|
||||
@ -137,7 +138,7 @@ where
|
||||
let future = future::ok::<_, SecioError>(context)
|
||||
// Generate our nonce.
|
||||
.and_then(|mut context| {
|
||||
context.rng.fill(&mut context.local_nonce)
|
||||
rand::thread_rng().try_fill_bytes(&mut context.local_nonce)
|
||||
.map_err(|_| SecioError::NonceGenerationFailed)?;
|
||||
trace!("starting handshake ; local nonce = {:?}", context.local_nonce);
|
||||
Ok(context)
|
||||
@ -175,7 +176,9 @@ where
|
||||
proposition.set_hashes(algo_support::DEFAULT_DIGESTS_PROPOSITION.into())
|
||||
}
|
||||
|
||||
let proposition_bytes = proposition.write_to_bytes().unwrap();
|
||||
let proposition_bytes = proposition.write_to_bytes()
|
||||
.expect("we fill all the elements of proposition, therefore writing can never \
|
||||
fail ; qed");
|
||||
context.local_proposition_bytes = proposition_bytes.clone();
|
||||
|
||||
trace!("sending proposition to remote");
|
||||
@ -231,17 +234,17 @@ where
|
||||
// based on which hash is larger.
|
||||
context.hashes_ordering = {
|
||||
let oh1 = {
|
||||
let mut ctx = digest::Context::new(&digest::SHA256);
|
||||
ctx.update(&context.remote_public_key_in_protobuf_bytes);
|
||||
ctx.update(&context.local_nonce);
|
||||
ctx.finish()
|
||||
let mut ctx = Sha256::new();
|
||||
ctx.input(&context.remote_public_key_in_protobuf_bytes);
|
||||
ctx.input(&context.local_nonce);
|
||||
ctx.result()
|
||||
};
|
||||
|
||||
let oh2 = {
|
||||
let mut ctx = digest::Context::new(&digest::SHA256);
|
||||
ctx.update(&context.local_public_key_in_protobuf_bytes);
|
||||
ctx.update(&context.remote_nonce);
|
||||
ctx.finish()
|
||||
let mut ctx = Sha256::new();
|
||||
ctx.input(&context.local_public_key_in_protobuf_bytes);
|
||||
ctx.input(&context.remote_nonce);
|
||||
ctx.result()
|
||||
};
|
||||
|
||||
oh1.as_ref().cmp(&oh2.as_ref())
|
||||
@ -298,31 +301,28 @@ where
|
||||
|
||||
// Generate an ephemeral key for the negotiation.
|
||||
.and_then(|(socket, context)| {
|
||||
match EphemeralPrivateKey::generate(context.chosen_exchange.as_ref().unwrap(), &context.rng) {
|
||||
Ok(tmp_priv_key) => Ok((socket, context, tmp_priv_key)),
|
||||
Err(_) => {
|
||||
debug!("failed to generate ECDH key");
|
||||
Err(SecioError::EphemeralKeyGenerationFailed)
|
||||
},
|
||||
}
|
||||
let exchange = context.chosen_exchange
|
||||
.expect("chosen_exchange is set to Some earlier then never touched again ; qed");
|
||||
exchange::generate_agreement(exchange)
|
||||
.map(move |(tmp_priv_key, tmp_pub_key)| (socket, context, tmp_priv_key, tmp_pub_key))
|
||||
})
|
||||
|
||||
// Send the ephemeral pub key to the remote in an `Exchange` struct. The `Exchange` also
|
||||
// contains a signature of the two propositions encoded with our static public key.
|
||||
.and_then(|(socket, mut context, tmp_priv)| {
|
||||
.and_then(|(socket, mut context, tmp_priv, tmp_pub_key)| {
|
||||
let exchange = {
|
||||
let mut local_tmp_pub_key: Vec<u8> = (0 .. tmp_priv.public_key_len()).map(|_| 0).collect();
|
||||
tmp_priv.compute_public_key(&mut local_tmp_pub_key).unwrap();
|
||||
context.local_tmp_priv_key = Some(tmp_priv);
|
||||
context.local_tmp_pub_key = tmp_pub_key.clone();
|
||||
|
||||
let mut data_to_sign = context.local_proposition_bytes.clone();
|
||||
data_to_sign.extend_from_slice(&context.remote_proposition_bytes);
|
||||
data_to_sign.extend_from_slice(&local_tmp_pub_key);
|
||||
data_to_sign.extend_from_slice(&tmp_pub_key);
|
||||
|
||||
let mut exchange = Exchange::new();
|
||||
exchange.set_epubkey(local_tmp_pub_key.clone());
|
||||
exchange.set_epubkey(tmp_pub_key);
|
||||
exchange.set_signature({
|
||||
match context.config.key.inner {
|
||||
#[cfg(all(feature = "ring", not(target_os = "emscripten")))]
|
||||
SecioKeyPairInner::Rsa { ref private, .. } => {
|
||||
let mut state = match RSASigningState::new(private.clone()) {
|
||||
Ok(s) => s,
|
||||
@ -332,9 +332,8 @@ where
|
||||
},
|
||||
};
|
||||
let mut signature = vec![0; private.public_modulus_len()];
|
||||
match state.sign(&RSA_PKCS1_SHA256, &context.rng, &data_to_sign,
|
||||
&mut signature)
|
||||
{
|
||||
let rng = SystemRandom::new();
|
||||
match state.sign(&RSA_PKCS1_SHA256, &rng, &data_to_sign, &mut signature) {
|
||||
Ok(_) => (),
|
||||
Err(_) => {
|
||||
debug!("failed to sign local exchange");
|
||||
@ -345,12 +344,12 @@ where
|
||||
signature
|
||||
},
|
||||
SecioKeyPairInner::Ed25519 { ref key_pair } => {
|
||||
let signature = key_pair.sign(&data_to_sign);
|
||||
signature.as_ref().to_owned()
|
||||
let signature = key_pair.sign::<Sha512>(&data_to_sign);
|
||||
signature.to_bytes().to_vec()
|
||||
},
|
||||
#[cfg(feature = "secp256k1")]
|
||||
SecioKeyPairInner::Secp256k1 { ref private } => {
|
||||
let data_to_sign = digest::digest(&digest::SHA256, &data_to_sign);
|
||||
let data_to_sign = Sha256::digest(&data_to_sign);
|
||||
let message = secp256k1::Message::from_slice(data_to_sign.as_ref())
|
||||
.expect("digest output length doesn't match secp256k1 input length");
|
||||
let secp256k1 = secp256k1::Secp256k1::with_caps(secp256k1::ContextFlag::SignOnly);
|
||||
@ -414,14 +413,15 @@ where
|
||||
data_to_verify.extend_from_slice(remote_exch.get_epubkey());
|
||||
|
||||
match context.remote_public_key {
|
||||
#[cfg(all(feature = "ring", not(target_os = "emscripten")))]
|
||||
Some(PublicKey::Rsa(ref remote_public_key)) => {
|
||||
// TODO: The ring library doesn't like some stuff in our DER public key,
|
||||
// therefore we scrap the first 24 bytes of the key. A proper fix would
|
||||
// be to write a DER parser, but that's not trivial.
|
||||
match signature_verify(&RSA_PKCS1_2048_8192_SHA256,
|
||||
UntrustedInput::from(&remote_public_key[24..]),
|
||||
UntrustedInput::from(&data_to_verify),
|
||||
UntrustedInput::from(remote_exch.get_signature()))
|
||||
match ring_verify(&RSA_PKCS1_2048_8192_SHA256,
|
||||
UntrustedInput::from(&remote_public_key[24..]),
|
||||
UntrustedInput::from(&data_to_verify),
|
||||
UntrustedInput::from(remote_exch.get_signature()))
|
||||
{
|
||||
Ok(()) => (),
|
||||
Err(_) => {
|
||||
@ -431,21 +431,25 @@ where
|
||||
}
|
||||
},
|
||||
Some(PublicKey::Ed25519(ref remote_public_key)) => {
|
||||
match signature_verify(&ED25519,
|
||||
UntrustedInput::from(remote_public_key),
|
||||
UntrustedInput::from(&data_to_verify),
|
||||
UntrustedInput::from(remote_exch.get_signature()))
|
||||
{
|
||||
Ok(()) => (),
|
||||
Err(_) => {
|
||||
debug!("failed to verify the remote's signature");
|
||||
return Err(SecioError::SignatureVerificationFailed)
|
||||
},
|
||||
let signature = Ed25519Signature::from_bytes(remote_exch.get_signature());
|
||||
let pubkey = Ed25519PublicKey::from_bytes(remote_public_key);
|
||||
|
||||
if let (Ok(signature), Ok(pubkey)) = (signature, pubkey) {
|
||||
match pubkey.verify::<Sha512>(&data_to_verify, &signature) {
|
||||
Ok(()) => (),
|
||||
Err(_) => {
|
||||
debug!("failed to verify the remote's signature");
|
||||
return Err(SecioError::SignatureVerificationFailed)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("the remote's signature or publickey are in the wrong format");
|
||||
return Err(SecioError::SignatureVerificationFailed)
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "secp256k1")]
|
||||
Some(PublicKey::Secp256k1(ref remote_public_key)) => {
|
||||
let data_to_verify = digest::digest(&digest::SHA256, &data_to_verify);
|
||||
let data_to_verify = Sha256::digest(&data_to_verify);
|
||||
let message = secp256k1::Message::from_slice(data_to_verify.as_ref())
|
||||
.expect("digest output length doesn't match secp256k1 input length");
|
||||
let secp256k1 = secp256k1::Secp256k1::with_caps(secp256k1::ContextFlag::VerifyOnly);
|
||||
@ -464,6 +468,11 @@ where
|
||||
return Err(SecioError::SignatureVerificationFailed)
|
||||
}
|
||||
},
|
||||
#[cfg(not(all(feature = "ring", not(target_os = "emscripten"))))]
|
||||
Some(PublicKey::Rsa(_)) => {
|
||||
debug!("support for RSA was disabled at compile-time");
|
||||
return Err(SecioError::SignatureVerificationFailed);
|
||||
},
|
||||
#[cfg(not(feature = "secp256k1"))]
|
||||
Some(PublicKey::Secp256k1(_)) => {
|
||||
debug!("support for secp256k1 was disabled at compile-time");
|
||||
@ -482,58 +491,57 @@ where
|
||||
.and_then(|(remote_exch, socket, mut context)| {
|
||||
let local_priv_key = context.local_tmp_priv_key.take()
|
||||
.expect("we filled this Option earlier, and extract it now");
|
||||
let codec = agreement::agree_ephemeral(local_priv_key,
|
||||
&context.chosen_exchange.unwrap(),
|
||||
UntrustedInput::from(remote_exch.get_epubkey()),
|
||||
SecioError::SecretGenerationFailed,
|
||||
|key_material| {
|
||||
let key = SigningKey::new(context.chosen_hash.unwrap(), key_material);
|
||||
let key_size = context.chosen_hash.as_ref()
|
||||
.expect("chosen_hash is set to Some earlier never modified again ; qed")
|
||||
.num_bytes();
|
||||
exchange::agree(context.chosen_exchange.unwrap(), local_priv_key, remote_exch.get_epubkey(), key_size)
|
||||
.map(move |key_material| (socket, context, key_material))
|
||||
})
|
||||
|
||||
let chosen_cipher = context.chosen_cipher.unwrap();
|
||||
let cipher_key_size = chosen_cipher.key_size();
|
||||
let iv_size = chosen_cipher.iv_size();
|
||||
// Generate a key from the local ephemeral private key and the remote ephemeral public key,
|
||||
// derive from it a ciper key, an iv, and a hmac key, and build the encoder/decoder.
|
||||
.and_then(|(socket, context, key_material)| {
|
||||
let chosen_cipher = context.chosen_cipher
|
||||
.expect("chosen_cipher is set to Some earlier never modified again ; qed");
|
||||
let cipher_key_size = chosen_cipher.key_size();
|
||||
let iv_size = chosen_cipher.iv_size();
|
||||
|
||||
let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)];
|
||||
stretch_key(&key, &mut longer_key);
|
||||
let chosen_hash = context.chosen_hash
|
||||
.expect("chosen_hash is set to Some earlier never modified again ; qed");
|
||||
let key = Hmac::from_key(chosen_hash, &key_material);
|
||||
let mut longer_key = vec![0u8; 2 * (iv_size + cipher_key_size + 20)];
|
||||
stretch_key(key, &mut longer_key);
|
||||
|
||||
let (local_infos, remote_infos) = {
|
||||
let (first_half, second_half) = longer_key.split_at(longer_key.len() / 2);
|
||||
match context.hashes_ordering {
|
||||
Ordering::Equal => {
|
||||
let msg = "equal digest of public key and nonce for local and remote";
|
||||
return Err(SecioError::InvalidProposition(msg))
|
||||
}
|
||||
Ordering::Less => (second_half, first_half),
|
||||
Ordering::Greater => (first_half, second_half),
|
||||
let (local_infos, remote_infos) = {
|
||||
let (first_half, second_half) = longer_key.split_at(longer_key.len() / 2);
|
||||
match context.hashes_ordering {
|
||||
Ordering::Equal => {
|
||||
let msg = "equal digest of public key and nonce for local and remote";
|
||||
return Err(SecioError::InvalidProposition(msg))
|
||||
}
|
||||
};
|
||||
Ordering::Less => (second_half, first_half),
|
||||
Ordering::Greater => (first_half, second_half),
|
||||
}
|
||||
};
|
||||
|
||||
let (encoding_cipher, encoding_hmac) = {
|
||||
let (iv, rest) = local_infos.split_at(iv_size);
|
||||
let (cipher_key, mac_key) = rest.split_at(cipher_key_size);
|
||||
let hmac = SigningKey::new(&context.chosen_hash.unwrap(), mac_key);
|
||||
let cipher = ctr(chosen_cipher, cipher_key, iv);
|
||||
(cipher, hmac)
|
||||
};
|
||||
let (encoding_cipher, encoding_hmac) = {
|
||||
let (iv, rest) = local_infos.split_at(iv_size);
|
||||
let (cipher_key, mac_key) = rest.split_at(cipher_key_size);
|
||||
let hmac = Hmac::from_key(chosen_hash.into(), mac_key);
|
||||
let cipher = ctr(chosen_cipher, cipher_key, iv);
|
||||
(cipher, hmac)
|
||||
};
|
||||
|
||||
let (decoding_cipher, decoding_hmac) = {
|
||||
let (iv, rest) = remote_infos.split_at(iv_size);
|
||||
let (cipher_key, mac_key) = rest.split_at(cipher_key_size);
|
||||
let hmac = VerificationKey::new(&context.chosen_hash.unwrap(), mac_key);
|
||||
let cipher = ctr(chosen_cipher, cipher_key, iv);
|
||||
(cipher, hmac)
|
||||
};
|
||||
let (decoding_cipher, decoding_hmac) = {
|
||||
let (iv, rest) = remote_infos.split_at(iv_size);
|
||||
let (cipher_key, mac_key) = rest.split_at(cipher_key_size);
|
||||
let hmac = Hmac::from_key(chosen_hash.into(), mac_key);
|
||||
let cipher = ctr(chosen_cipher, cipher_key, iv);
|
||||
(cipher, hmac)
|
||||
};
|
||||
|
||||
Ok(full_codec(socket, encoding_cipher, encoding_hmac, decoding_cipher, decoding_hmac))
|
||||
});
|
||||
|
||||
match codec {
|
||||
Ok(c) => Ok((c, context)),
|
||||
Err(err) => {
|
||||
debug!("failed to generate shared secret with remote");
|
||||
Err(err)
|
||||
},
|
||||
}
|
||||
let codec = full_codec(socket, encoding_cipher, encoding_hmac, decoding_cipher, decoding_hmac);
|
||||
Ok((codec, context))
|
||||
})
|
||||
|
||||
// We send back their nonce to check if the connection works.
|
||||
@ -570,21 +578,30 @@ where
|
||||
Box::new(future)
|
||||
}
|
||||
|
||||
// Custom algorithm translated from reference implementations. Needs to be the same algorithm
|
||||
// amongst all implementations.
|
||||
fn stretch_key(key: &SigningKey, result: &mut [u8]) {
|
||||
/// Custom algorithm translated from reference implementations. Needs to be the same algorithm
|
||||
/// amongst all implementations.
|
||||
fn stretch_key(hmac: Hmac, result: &mut [u8]) {
|
||||
match hmac {
|
||||
Hmac::Sha256(hmac) => stretch_key_inner(hmac, result),
|
||||
Hmac::Sha512(hmac) => stretch_key_inner(hmac, result),
|
||||
}
|
||||
}
|
||||
|
||||
fn stretch_key_inner<D: ::hmac::digest::Digest + Clone>(hmac: ::hmac::Hmac<D>, result: &mut [u8])
|
||||
where ::hmac::Hmac<D>: Clone {
|
||||
use ::hmac::Mac;
|
||||
const SEED: &[u8] = b"key expansion";
|
||||
|
||||
let mut init_ctxt = SigningContext::with_key(key);
|
||||
init_ctxt.update(SEED);
|
||||
let mut a = init_ctxt.sign();
|
||||
let mut init_ctxt = hmac.clone();
|
||||
init_ctxt.input(SEED);
|
||||
let mut a = init_ctxt.result().code();
|
||||
|
||||
let mut j = 0;
|
||||
while j < result.len() {
|
||||
let mut context = SigningContext::with_key(key);
|
||||
context.update(a.as_ref());
|
||||
context.update(SEED);
|
||||
let b = context.sign();
|
||||
let mut context = hmac.clone();
|
||||
context.input(a.as_ref());
|
||||
context.input(SEED);
|
||||
let b = context.result().code();
|
||||
|
||||
let todo = cmp::min(b.as_ref().len(), result.len() - j);
|
||||
|
||||
@ -592,9 +609,9 @@ fn stretch_key(key: &SigningKey, result: &mut [u8]) {
|
||||
|
||||
j += todo;
|
||||
|
||||
let mut context = SigningContext::with_key(key);
|
||||
context.update(a.as_ref());
|
||||
a = context.sign();
|
||||
let mut context = hmac.clone();
|
||||
context.input(a.as_ref());
|
||||
a = context.result().code();
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,13 +623,14 @@ mod tests {
|
||||
use self::tokio_tcp::TcpStream;
|
||||
use super::handshake;
|
||||
use super::stretch_key;
|
||||
use algo_support::Digest;
|
||||
use codec::Hmac;
|
||||
use futures::Future;
|
||||
use futures::Stream;
|
||||
use ring::digest::SHA256;
|
||||
use ring::hmac::SigningKey;
|
||||
use {SecioConfig, SecioKeyPair};
|
||||
|
||||
#[test]
|
||||
#[cfg(all(feature = "ring", not(target_os = "emscripten")))]
|
||||
fn handshake_with_self_succeeds_rsa() {
|
||||
let key1 = {
|
||||
let private = include_bytes!("../tests/test-rsa-private-key.pk8");
|
||||
@ -673,8 +691,8 @@ mod tests {
|
||||
fn stretch() {
|
||||
let mut output = [0u8; 32];
|
||||
|
||||
let key1 = SigningKey::new(&SHA256, &[]);
|
||||
stretch_key(&key1, &mut output);
|
||||
let key1 = Hmac::from_key(Digest::Sha256, &[]);
|
||||
stretch_key(key1, &mut output);
|
||||
assert_eq!(
|
||||
&output,
|
||||
&[
|
||||
@ -683,8 +701,8 @@ mod tests {
|
||||
]
|
||||
);
|
||||
|
||||
let key2 = SigningKey::new(
|
||||
&SHA256,
|
||||
let key2 = Hmac::from_key(
|
||||
Digest::Sha256,
|
||||
&[
|
||||
157, 166, 80, 144, 77, 193, 198, 6, 23, 220, 87, 220, 191, 72, 168, 197, 54, 33,
|
||||
219, 225, 84, 156, 165, 37, 149, 224, 244, 32, 170, 79, 125, 35, 171, 26, 178, 176,
|
||||
@ -692,7 +710,7 @@ mod tests {
|
||||
89, 145, 5, 162, 108, 230, 55, 54, 9, 17,
|
||||
],
|
||||
);
|
||||
stretch_key(&key2, &mut output);
|
||||
stretch_key(key2, &mut output);
|
||||
assert_eq!(
|
||||
&output,
|
||||
&[
|
||||
@ -701,8 +719,8 @@ mod tests {
|
||||
]
|
||||
);
|
||||
|
||||
let key3 = SigningKey::new(
|
||||
&SHA256,
|
||||
let key3 = Hmac::from_key(
|
||||
Digest::Sha256,
|
||||
&[
|
||||
98, 219, 94, 104, 97, 70, 139, 13, 185, 110, 56, 36, 66, 3, 80, 224, 32, 205, 102,
|
||||
170, 59, 32, 140, 245, 86, 102, 231, 68, 85, 249, 227, 243, 57, 53, 171, 36, 62,
|
||||
@ -710,7 +728,7 @@ mod tests {
|
||||
19, 48, 127, 127, 55, 82, 117, 154, 124, 108,
|
||||
],
|
||||
);
|
||||
stretch_key(&key3, &mut output);
|
||||
stretch_key(key3, &mut output);
|
||||
assert_eq!(
|
||||
&output,
|
||||
&[
|
||||
|
Reference in New Issue
Block a user