-
Notifications
You must be signed in to change notification settings - Fork 219
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: hide sensitive data on tari repo (see issue #4846) #4967
fix: hide sensitive data on tari repo (see issue #4846) #4967
Conversation
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.
LGTM
I'm guessing there is still a leak at the clap
level. Doesn't look like they support marking sensitive args.
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.
utACK
1c5df3e
|
||
use super::{CoreTransactionAEADKey, AEAD_KEY_LEN}; |
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.
Might consider renaming to something that describes the intent more clearly, like ValueEncryptionKey
. But that's just a nit.
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.
Done in PR 4994.
const AEAD_KEY_LENGTH: usize = 32; // The length in bytes of a ChaCha20-Poly1305 AEAD key | ||
fn kdf_aead(shared_secret: &PrivateKey, commitment: &Commitment) -> CoreTransactionAEADKey { | ||
let output = DomainSeparatedHasher::<Blake256, TransactionKdfDomain>::new_with_label("encrypted_value") | ||
.chain(shared_secret.as_bytes()) | ||
.chain(commitment.as_bytes()) | ||
.finalize(); | ||
|
||
*Key::from_slice(&output.as_ref()[..AEAD_KEY_LENGTH]) | ||
let default_array = SafeArray::<u8, AEAD_KEY_LEN>::default(); | ||
let mut aead_key = CoreTransactionAEADKey::from(default_array); | ||
aead_key.reveal_mut().copy_from_slice(&output.as_ref()[..AEAD_KEY_LEN]); | ||
|
||
aead_key | ||
} |
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 can simplify this by using finalize_into
on the hasher to populate aead_key
in place. Otherwise output
sticks around in memory.
use digest::FixedOutput;
let mut aead_key = CoreTransactionAEADKey::from(SafeArray::default());
DomainSeparatedHasher::<Blake256, TransactionKdfDomain>::new_with_label("encrypted_value")
.chain(shared_secret.as_bytes())
.chain(commitment.as_bytes())
.finalize_into(GenericArray::from_mut_slice(aead_key.reveal_mut()));
aead_key
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.
Done in PR 4994.
value_bytes.clone_from_slice(&decrypted_bytes[..8]); | ||
Ok(u64::from_le_bytes(value_bytes).into()) | ||
} | ||
} | ||
|
||
// Generate a ChaCha20-Poly1305 key from an ECDH shared secret and commitment using Blake2b | ||
fn kdf_aead(shared_secret: &PrivateKey, commitment: &Commitment) -> Key { | ||
const AEAD_KEY_LENGTH: usize = 32; // The length in bytes of a ChaCha20-Poly1305 AEAD key | ||
fn kdf_aead(shared_secret: &PrivateKey, commitment: &Commitment) -> CoreTransactionAEADKey { | ||
let output = DomainSeparatedHasher::<Blake256, TransactionKdfDomain>::new_with_label("encrypted_value") |
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.
May wish to rename the label to be consistent with the reverse-domain notation used elsewhere.
@@ -1550,7 +1551,8 @@ pub unsafe extern "C" fn encrypted_value_as_bytes( | |||
#[no_mangle] | |||
pub unsafe extern "C" fn encrypted_value_destroy(encrypted_value: *mut TariEncryptedValue) { | |||
if !encrypted_value.is_null() { | |||
Box::from_raw(encrypted_value); | |||
// zeroize the data content of encrypted_value, as to prevent memory leaks |
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 this functionality even necessary since the encrypted value is already included on chain?
fn noise_kdf(shared_key: &CommsDHKE) -> CommsNoiseKey { | ||
let hasher = DomainSeparatedHasher::<Blake256, CommsCoreHashDomain>::new_with_label("noise.dh"); | ||
Digest::finalize(hasher.chain(shared_key.as_bytes())).into() | ||
let mut comms_noise_kdf = CommsNoiseKey::from([0u8; NOISE_KEY_LEN]); | ||
comms_noise_kdf | ||
.reveal_mut() | ||
.copy_from_slice(hasher.chain(shared_key.as_bytes()).finalize().as_ref()); | ||
comms_noise_kdf | ||
} |
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 can simplify this and avoid an in-memory copy of the KDF output using finalize_into
.
use digest::FixedOutput;
use digest::generic_array::GenericArray;
use tari_utilities::safe_array::SafeArray;
let mut comms_noise_key = CommsNoiseKey::from(SafeArray::default());
DomainSeparatedHasher::<Blake256, CommsCoreHashDomain>::new_with_label("noise.dh")
.chain(shared_key.as_bytes())
.finalize_into(GenericArray::from_mut_slice(comms_noise_key.reveal_mut()));
comms_noise_key
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.
Done in PR 4994.
|
||
pub(crate) const NOISE_KEY_LEN: usize = 32; | ||
|
||
hidden_type!(CommsNoiseKey, [u8; NOISE_KEY_LEN]); |
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.
Recommend redefining this as a SafeArray
.
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 made a comment regarding the use of SafeArray
, in this PR. I think his point was accurate, given the use of this CommsNoiseKey
.
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.
Done in PR 4994 but certainly open to discussion.
Description --- Updates the use of `CoreTransactionAEADKey` and `CommsNoiseKey` to be populated in place. Switches `CommsNoiseKey` to use a `SafeArray` under the hood. Extends the work of [PR 4967](#4967). Motivation and Context --- Earlier work updates the use of keys for value encryption and Noise. Value encryption keys use a `SafeArray` type in a `Hidden` wrapper, and Noise keys use a `Hidden` array. However, in both cases, a copy of the hash output used to populate the keys is left in memory. This work mitigates the problem. Because the hashing API now supports in-place output finalization via `finalize_into` and `finalize_into_reset`, we can populate keys directly by mutable reference. It also renames `CoreTransactionAEADKey` to `EncryptedValueKey` for clarity, and switches `CommsNoiseKey` to be a `SafeArray` under the hood. There is [discussion](#4967 (comment)) on whether `CommsNoiseKey` needs to be a `SafeArray`; while the reasoning makes sense, I still think it's good practice to take advantage of the benefits of `SafeArray` for array-like key types unless there's a compelling performance reason otherwise. Discussion on this is welcome! How Has This Been Tested? --- Existing tests pass.
Description
The goal of this PR is to zeroize sensitive data content across the Tari repo. We pay special attention to kdf key data and other occurrences of sensitive data. For more details, we refer to issue #4846. Moreover, this PR is a companion to #4953 and #4925
Motivation and Context
Tackle issue #4846.
How Has This Been Tested?