Skip to content
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(dht)!: fixes MAC related key vuln for propagated cleartext msgs #3907

Merged
merged 2 commits into from
May 24, 2022

Conversation

sdbondi
Copy link
Member

@sdbondi sdbondi commented Mar 10, 2022

Description

  • changes challenge in signed messages to e = H(P||R||H(m))
  • remove minor from DHT versioning

Motivation and Context

This only affects signed cleartext messages that are propagated through adversarial nodes.
Encrypted propagated messages are unaffected because only the recipient can decrypt the MAC and so cannot forge a signature.

Nonce malleability

e = H(P||m)
<R, s> for P

Attacker chooses 
R' = s.G - eP
s' any scalar
and transmits <R', s'> for P

Verifier:
s'.G ?= R' + eP
      ?= s'.G - eP + eP
      ?= s'.G  (true for any s')

Related key

sig = <R, s> for P
e = H(R||m)

Attacker:
sig' = <R, s'> for P'
s' = s + a.H(R||m)
P' = P + a.G

Verifier:
s'.G ?= R + eP'
       ?= R + e(k + a).G

All signed cleartext and encrypted DHT messages are incompatible with current network:
Namely,

  • Peer discovery
  • Wallet Propagated/SAF messages

How Has This Been Tested?

New unit tests that verify OriginMac is secure against these vulnerabilities

Tested base node manually, and normal cleartext block and tx propagation messages continue to work

Tested wallet, direct send transactions are still compatible

@sdbondi sdbondi force-pushed the dht-origin-mac branch 2 times, most recently from 97add0f to f773132 Compare March 10, 2022 07:59
@sdbondi sdbondi force-pushed the dht-origin-mac branch 2 times, most recently from 792d5ec to 0a2b9d7 Compare March 29, 2022 12:48
@sdbondi sdbondi force-pushed the dht-origin-mac branch 3 times, most recently from 049cdff to 55008eb Compare April 12, 2022 13:31
Comment on lines 74 to 84
pub fn from_key<K: ByteArray>(key: &K) -> Self {
let bytes = key.as_bytes();
let mut buf = [0u8; NodeId::byte_size()];
VarBlake2b::new(NodeId::byte_size())
Blake2bVar::new(NodeId::byte_size())
.expect("NodeId::byte_size() is invalid")
.chain(bytes)
.finalize_variable(|hash| {
// Safety: output size and buf size are equal
buf.copy_from_slice(hash)
});
// Safety: output size and buf size are equal
.finalize_variable(&mut buf).unwrap();
NodeId(buf)
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hash invocation should use domain separation to avoid unexpected collisions elsewhere. This is supported directly using Blake2 personalization.

mac_challenge.update(&protocol_version.to_bytes());
mac_challenge.update(destination.as_inner_bytes());
mac_challenge.update(&protocol_version.as_bytes());
mac_challenge.update(destination.to_inner_bytes());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this guaranteed to have a fixed-length byte representation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this has a fixed-length representation, and types are differentiated using a flag.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible, if desired, to use variable-length representations. In this case, the length (as a fixed-length representation!) should be prepended after the (fixed-length) flag.

Copy link
Member Author

@sdbondi sdbondi May 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, each variant of NodeDestination has a single byte representation prepended to the encoding. Gotcha, both the NodeId and CommsPublicKey have fixed-length representations so I don't think we'll have a need for variable-length encodings here.

let signer_public_key = CommsPublicKey::from_secret_key(&signer_secret_key);
let challenge = construct_origin_mac_hash(&signer_public_key, &nonce_pk, message);
let signature = Signature::sign(signer_secret_key, nonce_s, &challenge)
.expect("challenge is [u8;32] but SchnorrSignature::sign failed");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this is basically infallible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's 100% infallible with a 32-byte challenge and Ristretto - we should probably make an infallible version of sign that takes a [u8;32]

@aviator-app aviator-app bot merged commit 1e96d45 into tari-project:development May 24, 2022
@sdbondi sdbondi deleted the dht-origin-mac branch May 24, 2022 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants