-
Notifications
You must be signed in to change notification settings - Fork 220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: address points in issue #4138 and companions #4336
fix: address points in issue #4138 and companions #4336
Conversation
comms/dht/src/crypt.rs
Outdated
const DOMAIN_SEPARATION_CHALLENGE_LABEL: &str = "com.tari.comms.dht.crypt.challenge"; | ||
const DOMAIN_SEPARATION_KEY_MESSAGE_LABEL: &str = "com.tari.comms.dht.crypt.challenge"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Domain separators must be unique.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely, changed !
comms/dht/src/crypt.rs
Outdated
|
||
/// Generates a Diffie-Hellman secret `kx.G` as a `chacha20::Key` given secret scalar `k` and public key `P = x.G`. | ||
pub fn generate_ecdh_secret<PK>(secret_key: &PK::K, public_key: &PK) -> CipherKey | ||
pub fn generate_ecdh_secret<PK>(secret_key: &PK::K, public_key: &PK) -> [u8; 32] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This encoded output size is specific to the elliptic curve group used, and does not hold generically.
where PK: PublicKey + DiffieHellmanSharedSecret<PK = PK> { | ||
// TODO: PK will still leave the secret in released memory. Implementing Zerioze on RistrettoPublicKey is not | ||
// currently possible because (Compressed)RistrettoPoint does not implement it. | ||
let k = PK::shared_secret(secret_key, public_key); | ||
CipherKey(*Key::from_slice(k.as_bytes())) | ||
let mut output = [0u8; 32]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This encoded size is specific to the elliptic curve group used, and is not generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be useful to define a generic DiffieHellmanSharedSecret
type that holds the result of an ECDH exchange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jorgeantonio21 Would like to have the well-defined DH return type, perhaps for a follow-up PR?
.finalize() | ||
.into_vec(); | ||
|
||
// Domain separation uses Challenge = Blake256, thus its output has 32-byte length |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to check and enforce this at compile time, in case later changes subtly break this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of a specific ECDH shared secret type would mean this function enforces this input type.
.finalize() | ||
.into_vec(); | ||
|
||
// Domain separation uses Challenge = Blake256, thus its output has 32-byte length |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to check and enforce this at compile time, in case later changes subtly break this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of a specific ECDH shared secret type would mean this function enforces this input type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to check and enforce this at compile time, in case later changes subtly break this?
I believe so. Noting that this will not really break sublty and will panic in Key::from_slice
if not 32-bytes. There are many tests that would signal this breakage, so we can decide if the following is worthwhile.
digest::Output<D>
returned from finalize
implements Into<[u8;32]>
for 32-byte outputs - this could be used to generate a compile error if the DomainSeparatedHash<D>
type exposed the inner output type e.g into_inner(self) -> Output<D>
let domain_separated_hash =
DomainSeparatedHasher::<Blake256, GenericHashDomain>::new(DOMAIN_SEPARATION_KEY_SIGNATURE_LABEL)
.chain(data)
.finalize();
// Will not compile if Into<[u8;32]> is not implemented.
let output_array : [u8;32] = domain_separated_hash.into_inner().into();
This requires adding the into_inner
function or reimplementing (something like) From<[u8;D::OutputSize::to_usize()]>
on DomainSeparatedHash
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sdbondi How generic can that be made? It may be the case that other domain-separated hash function applications require output of a different length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AaronFeickert That is handled by the generic_array
crate. Here, we are enforcing in this function (or else compile fails) that the hash output is correctly convertible to a 32-byte array representation.
Adding trait bounds are not necessary here as we use concrete types, but the trait bounds would be where digest::Output<D>: Into<[u8;32]>
This became possible with this change (tari-project/tari-crypto#119) since we can now use digest::Output<D>
let domain_separated_hash = DomainSeparatedHasher::<Blake256, GenericHashDomain>::new(DOMAIN_SEPARATION_KEY_SIGNATURE_LABEL) .chain(data) .finalize();
// Will not compile if Into<[u8;32]> is not implemented.
let output_array : [u8;32] = domain_separated_hash.into();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as the tari_crypto domain hasher code currently stands, you'd need to disambiguate between the functions on the hasher type and the impl Digest
functions with the same name.
e.g.
let hasher = comms_dht_hash_domain_key_signature().chain(data);
let domain_separated_hash =<DomainSeparatedHasher<CommsChallenge, DHTCommsHashDomain> as Digest>::finalize(hasher);
let hash: [u8; 32] = domain_separated_hash.into();
Since we know that we're using Blake256 and breakage will be caught in tests - I think we can leave this as is
comms/dht/src/crypt.rs
Outdated
/// Produces authenticated encryption of the signature using the ChaCha20-Poly1305 stream cipher, | ||
/// refer to https://docs.rs/chacha20poly1305/latest/chacha20poly1305/# for more details. | ||
/// Attention: as pointed in https://github.com/tari-project/tari/issues/4138, it is possible | ||
/// to use a fixed length Nonce, with homogeneous zero data, as this does not incur any security |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a fixed-length nonce, but a fixed nonce.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely ! Thank you !
.map_err(|_| DhtOutboundError::CipherError(String::from("Authenticated encryption failed"))) | ||
.unwrap(); | ||
|
||
assert_eq!(encrypted.len(), n + 16); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could remove the magic number by getting the tag size programmatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack
Tested with memorynet
Description
--- Fix issues #4138, #4333 and #4170.
Motivation and Context
--- Add domain separation and cipher authentication for out bound messaging
How Has This Been Tested?
--- Unit tests.