Update hmac and blake3 (#673)
* Update hmac and blake3 * Remain paranoid for `0.*` crates * Most paranoid versions :) * Updated aes and using published version of blake3 Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>
This commit is contained in:
Generated
+203
-267
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ pub enum ReplyKeyStorageError {
|
||||
/// Permanent storage for keys in all sent [`ReplySURB`]
|
||||
///
|
||||
/// Each sent out [`ReplySURB`] has a new key associated with it that is going to be used for
|
||||
/// payload encryption. In order to decrypt whatever reply we receive, we need to know which
|
||||
/// payload encryption. In order to -decrypt whatever reply we receive, we need to know which
|
||||
/// key to use for that purpose. We do it based on received `H(t)` which has to be included
|
||||
/// with each reply.
|
||||
/// Moreover, there is no restriction when the [`ReplySURB`] might get used so we need to
|
||||
|
||||
@@ -7,15 +7,14 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
aes-ctr = "0.6.0"
|
||||
bs58 = "0.4"
|
||||
blake3 = "0.3"
|
||||
#blake3 = { version = "0.3", features = ["traits-preview"]}
|
||||
digest = "0.9"
|
||||
aes = { version = "0.7.4", features = ["ctr"] }
|
||||
bs58 = "0.4.0"
|
||||
blake3 = { version = "1.0.0", features = ["traits-preview"] }
|
||||
digest = "0.9.0"
|
||||
generic-array = "0.14"
|
||||
hkdf = "0.10"
|
||||
hmac = "0.8"
|
||||
cipher = "0.2"
|
||||
hkdf = "0.11.0"
|
||||
hmac = "0.11.0"
|
||||
cipher = "0.3.0"
|
||||
x25519-dalek = "1.1"
|
||||
ed25519-dalek = "1.0"
|
||||
log = "0.4"
|
||||
|
||||
@@ -18,7 +18,7 @@ where
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
{
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_varkey(key).expect("HMAC should be able to take key of any size!");
|
||||
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
|
||||
hmac.update(data);
|
||||
hmac.finalize()
|
||||
}
|
||||
@@ -31,7 +31,7 @@ where
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
{
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_varkey(key).expect("HMAC should be able to take key of any size!");
|
||||
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
|
||||
hmac.update(data);
|
||||
// note, under the hood ct_eq is called
|
||||
hmac.verify(tag).is_ok()
|
||||
|
||||
@@ -13,7 +13,7 @@ pub use generic_array;
|
||||
|
||||
// with the below my idea was to try to introduce having a single place of importing all hashing, encryption,
|
||||
// etc. algorithms and import them elsewhere as needed via common/crypto
|
||||
pub use aes_ctr;
|
||||
pub use aes;
|
||||
pub use blake3;
|
||||
|
||||
// TODO: this function uses all three modules: asymmetric crypto, symmetric crypto and derives key...,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::asymmetric::encryption;
|
||||
use crate::hkdf;
|
||||
use cipher::stream::{Key, NewStreamCipher, SyncStreamCipher};
|
||||
use cipher::{CipherKey, NewCipher, StreamCipher};
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::{typenum::Unsigned, ArrayLength};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
@@ -13,9 +13,9 @@ use rand::{CryptoRng, RngCore};
|
||||
pub fn new_ephemeral_shared_key<C, D, R>(
|
||||
rng: &mut R,
|
||||
remote_key: &encryption::PublicKey,
|
||||
) -> (encryption::KeyPair, Key<C>)
|
||||
) -> (encryption::KeyPair, CipherKey<C>)
|
||||
where
|
||||
C: SyncStreamCipher + NewStreamCipher,
|
||||
C: StreamCipher + NewCipher,
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
@@ -31,7 +31,7 @@ where
|
||||
.expect("somehow too long okm was provided");
|
||||
|
||||
let derived_shared_key =
|
||||
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
|
||||
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
|
||||
|
||||
(ephemeral_keypair, derived_shared_key)
|
||||
}
|
||||
@@ -40,9 +40,9 @@ where
|
||||
pub fn recompute_shared_key<C, D>(
|
||||
remote_key: &encryption::PublicKey,
|
||||
local_key: &encryption::PrivateKey,
|
||||
) -> Key<C>
|
||||
) -> CipherKey<C>
|
||||
where
|
||||
C: SyncStreamCipher + NewStreamCipher,
|
||||
C: StreamCipher + NewCipher,
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
@@ -53,5 +53,5 @@ where
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::KeySize::to_usize())
|
||||
.expect("somehow too long okm was provided");
|
||||
|
||||
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
|
||||
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cipher::stream::{Nonce, StreamCipher, SyncStreamCipher};
|
||||
use cipher::{Nonce, StreamCipher};
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
// re-export this for ease of use
|
||||
pub use cipher::stream::{Key, NewStreamCipher};
|
||||
pub use cipher::{CipherKey, NewCipher};
|
||||
|
||||
// SECURITY:
|
||||
// TODO: note that this is not the most secure approach here
|
||||
// we are not using nonces properly but instead "kinda" thinking of them as IVs.
|
||||
// Nonce require, as the name suggest, being only seen once. Ever.
|
||||
@@ -20,9 +21,9 @@ pub use cipher::stream::{Key, NewStreamCipher};
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub type IV<C> = Nonce<C>;
|
||||
|
||||
pub fn generate_key<C, R>(rng: &mut R) -> Key<C>
|
||||
pub fn generate_key<C, R>(rng: &mut R) -> CipherKey<C>
|
||||
where
|
||||
C: NewStreamCipher,
|
||||
C: NewCipher,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut key = GenericArray::default();
|
||||
@@ -32,7 +33,7 @@ where
|
||||
|
||||
pub fn random_iv<C, R>(rng: &mut R) -> IV<C>
|
||||
where
|
||||
C: NewStreamCipher,
|
||||
C: NewCipher,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut iv = GenericArray::default();
|
||||
@@ -42,14 +43,14 @@ where
|
||||
|
||||
pub fn zero_iv<C>() -> IV<C>
|
||||
where
|
||||
C: NewStreamCipher,
|
||||
C: NewCipher,
|
||||
{
|
||||
GenericArray::default()
|
||||
}
|
||||
|
||||
pub fn iv_from_slice<C>(b: &[u8]) -> &IV<C>
|
||||
where
|
||||
C: NewStreamCipher,
|
||||
C: NewCipher,
|
||||
{
|
||||
if b.len() != C::NonceSize::to_usize() {
|
||||
// `from_slice` would have caused a panic about this issue anyway.
|
||||
@@ -66,38 +67,42 @@ where
|
||||
// TODO: there's really no way to use more parts of the keystream if it was required at some point.
|
||||
// However, do we really expect to ever need it?
|
||||
|
||||
pub fn encrypt<C>(key: &Key<C>, iv: &IV<C>, data: &[u8]) -> Vec<u8>
|
||||
#[inline]
|
||||
pub fn encrypt<C>(key: &CipherKey<C>, iv: &IV<C>, data: &[u8]) -> Vec<u8>
|
||||
where
|
||||
C: SyncStreamCipher + NewStreamCipher,
|
||||
C: StreamCipher + NewCipher,
|
||||
{
|
||||
let mut ciphertext = data.to_vec();
|
||||
encrypt_in_place::<C>(key, iv, &mut ciphertext);
|
||||
ciphertext
|
||||
}
|
||||
|
||||
pub fn encrypt_in_place<C>(key: &Key<C>, iv: &IV<C>, data: &mut [u8])
|
||||
#[inline]
|
||||
pub fn encrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
|
||||
where
|
||||
C: SyncStreamCipher + NewStreamCipher,
|
||||
C: StreamCipher + NewCipher,
|
||||
{
|
||||
let mut cipher = C::new(key, iv);
|
||||
cipher.encrypt(data)
|
||||
cipher.apply_keystream(data)
|
||||
}
|
||||
|
||||
pub fn decrypt<C>(key: &Key<C>, iv: &IV<C>, ciphertext: &[u8]) -> Vec<u8>
|
||||
#[inline]
|
||||
pub fn decrypt<C>(key: &CipherKey<C>, iv: &IV<C>, ciphertext: &[u8]) -> Vec<u8>
|
||||
where
|
||||
C: SyncStreamCipher + NewStreamCipher,
|
||||
C: StreamCipher + NewCipher,
|
||||
{
|
||||
let mut data = ciphertext.to_vec();
|
||||
decrypt_in_place::<C>(key, iv, &mut data);
|
||||
data
|
||||
}
|
||||
|
||||
pub fn decrypt_in_place<C>(key: &Key<C>, iv: &IV<C>, data: &mut [u8])
|
||||
#[inline]
|
||||
pub fn decrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
|
||||
where
|
||||
C: SyncStreamCipher + NewStreamCipher,
|
||||
C: StreamCipher + NewCipher,
|
||||
{
|
||||
let mut cipher = C::new(key, iv);
|
||||
cipher.decrypt(data)
|
||||
cipher.apply_keystream(data)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -108,7 +113,7 @@ mod tests {
|
||||
#[cfg(test)]
|
||||
mod aes_ctr128 {
|
||||
use super::*;
|
||||
use aes_ctr::Aes128Ctr;
|
||||
use aes::Aes128Ctr;
|
||||
|
||||
#[test]
|
||||
fn zero_iv_is_actually_zero() {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::AckKey;
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, NewStreamCipher};
|
||||
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, NewCipher};
|
||||
use nymsphinx_params::{
|
||||
packet_sizes::PacketSize, AckEncryptionAlgorithm, SerializedFragmentIdentifier, FRAG_ID_LEN,
|
||||
};
|
||||
@@ -33,7 +33,7 @@ pub fn recover_identifier(
|
||||
return None;
|
||||
}
|
||||
|
||||
let iv_size = <AckEncryptionAlgorithm as NewStreamCipher>::NonceSize::to_usize();
|
||||
let iv_size = <AckEncryptionAlgorithm as NewCipher>::NonceSize::to_usize();
|
||||
let iv = iv_from_slice::<AckEncryptionAlgorithm>(&iv_id_ciphertext[..iv_size]);
|
||||
|
||||
let id = stream_cipher::decrypt::<AckEncryptionAlgorithm>(
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::{typenum::Unsigned, GenericArray};
|
||||
use crypto::symmetric::stream_cipher::{generate_key, Key, NewStreamCipher};
|
||||
use crypto::symmetric::stream_cipher::{generate_key, CipherKey, NewCipher};
|
||||
use nymsphinx_params::AckEncryptionAlgorithm;
|
||||
use pemstore::traits::PemStorableKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
pub struct AckKey(Key<AckEncryptionAlgorithm>);
|
||||
pub struct AckKey(CipherKey<AckEncryptionAlgorithm>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AckKeyConversionError {
|
||||
@@ -33,7 +33,7 @@ impl AckKey {
|
||||
}
|
||||
|
||||
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, AckKeyConversionError> {
|
||||
if bytes.len() != <AckEncryptionAlgorithm as NewStreamCipher>::KeySize::to_usize() {
|
||||
if bytes.len() != <AckEncryptionAlgorithm as NewCipher>::KeySize::to_usize() {
|
||||
return Err(AckKeyConversionError::BytesOfInvalidLengthError);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ impl AckKey {
|
||||
self.0.as_ref()
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &Key<AckEncryptionAlgorithm> {
|
||||
pub fn inner(&self) -> &CipherKey<AckEncryptionAlgorithm> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ pub use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::{
|
||||
crypto_hash,
|
||||
generic_array::GenericArray,
|
||||
symmetric::stream_cipher::{generate_key, Key, NewStreamCipher},
|
||||
symmetric::stream_cipher::{generate_key, CipherKey, NewCipher},
|
||||
Digest,
|
||||
};
|
||||
use nymsphinx_params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
||||
@@ -15,10 +15,10 @@ use std::fmt::{self, Display, Formatter};
|
||||
pub type EncryptionKeyDigest =
|
||||
GenericArray<u8, <ReplySurbKeyDigestAlgorithm as Digest>::OutputSize>;
|
||||
|
||||
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as NewStreamCipher>::KeySize;
|
||||
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as NewCipher>::KeySize;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SurbEncryptionKey(Key<ReplySurbEncryptionAlgorithm>);
|
||||
pub struct SurbEncryptionKey(CipherKey<ReplySurbEncryptionAlgorithm>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SurbEncryptionKeyError {
|
||||
@@ -64,7 +64,7 @@ impl SurbEncryptionKey {
|
||||
self.0.as_ref()
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &Key<ReplySurbEncryptionAlgorithm> {
|
||||
pub fn inner(&self) -> &CipherKey<ReplySurbEncryptionAlgorithm> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::aes_ctr::Aes128Ctr;
|
||||
use crypto::aes::Aes128Ctr;
|
||||
use crypto::blake3;
|
||||
|
||||
// Re-export for ease of use
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::{typenum::Unsigned, GenericArray};
|
||||
use crypto::symmetric::stream_cipher::{random_iv, NewStreamCipher, IV as CryptoIV};
|
||||
use crypto::symmetric::stream_cipher::{random_iv, NewCipher, IV as CryptoIV};
|
||||
use nymsphinx::params::GatewayEncryptionAlgorithm;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
type NonceSize = <GatewayEncryptionAlgorithm as NewStreamCipher>::NonceSize;
|
||||
type NonceSize = <GatewayEncryptionAlgorithm as NewCipher>::NonceSize;
|
||||
|
||||
// I think 'IV' looks better than 'Iv', feel free to change that.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
|
||||
@@ -7,7 +7,7 @@ use crypto::generic_array::{
|
||||
GenericArray,
|
||||
};
|
||||
use crypto::hmac::{compute_keyed_hmac, recompute_keyed_hmac_and_verify_tag};
|
||||
use crypto::symmetric::stream_cipher::{self, Key, NewStreamCipher, IV};
|
||||
use crypto::symmetric::stream_cipher::{self, CipherKey, NewCipher, IV};
|
||||
use nymsphinx::params::{GatewayEncryptionAlgorithm, GatewayIntegrityHmacAlgorithm};
|
||||
use pemstore::traits::PemStorableKey;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
@@ -17,14 +17,14 @@ pub type SharedKeySize = Sum<EncryptionKeySize, MacKeySize>;
|
||||
|
||||
// we're using 16 byte long key in sphinx, so let's use the same one here
|
||||
type MacKeySize = U16;
|
||||
type EncryptionKeySize = <GatewayEncryptionAlgorithm as NewStreamCipher>::KeySize;
|
||||
type EncryptionKeySize = <GatewayEncryptionAlgorithm as NewCipher>::KeySize;
|
||||
|
||||
/// Shared key used when computing MAC for messages exchanged between client and its gateway.
|
||||
pub type MacKey = GenericArray<u8, MacKeySize>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SharedKeys {
|
||||
encryption_key: Key<GatewayEncryptionAlgorithm>,
|
||||
encryption_key: CipherKey<GatewayEncryptionAlgorithm>,
|
||||
mac_key: MacKey,
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ impl SharedKeys {
|
||||
Ok(message_bytes_mut.to_vec())
|
||||
}
|
||||
|
||||
pub fn encryption_key(&self) -> &Key<GatewayEncryptionAlgorithm> {
|
||||
pub fn encryption_key(&self) -> &CipherKey<GatewayEncryptionAlgorithm> {
|
||||
&self.encryption_key
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user