Obfuscate SharedSecret when printing

Currently printing the `SharedSecret` using `Display` or `Debug` prints
the real secret, this is sub-optimal. We have a solution for other
secrets in the project where printing is obfuscated and we provide a
`display_secret` method for explicitly printing.

Mirror the logic for other secrets and obfuscate the `SharedSecret` when printing.
This commit is contained in:
Tobin Harding 2022-02-18 12:10:02 +00:00
parent e4be664d97
commit cf6badf96a
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 53 additions and 3 deletions

View File

@ -21,6 +21,10 @@ use core::borrow::Borrow;
use key::{SecretKey, PublicKey}; use key::{SecretKey, PublicKey};
use ffi::{self, CPtr}; use ffi::{self, CPtr};
use secp256k1_sys::types::{c_int, c_uchar, c_void}; use secp256k1_sys::types::{c_int, c_uchar, c_void};
use constants;
// The logic for displaying shared secrets relies on this (see `secret.rs`).
const SHARED_SECRET_SIZE: usize = constants::SECRET_KEY_SIZE;
/// Enables two parties to create a shared secret without revealing their own secrets. /// Enables two parties to create a shared secret without revealing their own secrets.
/// ///
@ -39,14 +43,15 @@ use secp256k1_sys::types::{c_int, c_uchar, c_void};
/// assert_eq!(sec1, sec2); /// assert_eq!(sec1, sec2);
/// # } /// # }
// ``` // ```
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SharedSecret([u8; 32]); pub struct SharedSecret([u8; SHARED_SECRET_SIZE]);
impl_display_secret!(SharedSecret);
impl SharedSecret { impl SharedSecret {
/// Creates a new shared secret from a pubkey and secret key. /// Creates a new shared secret from a pubkey and secret key.
#[inline] #[inline]
pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret { pub fn new(point: &PublicKey, scalar: &SecretKey) -> SharedSecret {
let mut buf = [0u8; 32]; let mut buf = [0u8; SHARED_SECRET_SIZE];
let res = unsafe { let res = unsafe {
ffi::secp256k1_ecdh( ffi::secp256k1_ecdh(
ffi::secp256k1_context_no_precomp, ffi::secp256k1_context_no_precomp,
@ -60,6 +65,12 @@ impl SharedSecret {
debug_assert_eq!(res, 1); debug_assert_eq!(res, 1);
SharedSecret(buf) SharedSecret(buf)
} }
/// Returns the shared secret as a byte value.
#[inline]
pub fn secret_bytes(&self) -> [u8; SHARED_SECRET_SIZE] {
self.0
}
} }
impl Borrow<[u8]> for SharedSecret { impl Borrow<[u8]> for SharedSecret {

View File

@ -16,6 +16,7 @@
use ::core::fmt; use ::core::fmt;
use ::{SecretKey, KeyPair, to_hex}; use ::{SecretKey, KeyPair, to_hex};
use ecdh::SharedSecret;
use constants::SECRET_KEY_SIZE; use constants::SECRET_KEY_SIZE;
macro_rules! impl_display_secret { macro_rules! impl_display_secret {
@ -177,3 +178,41 @@ impl KeyPair {
DisplaySecret { secret: self.secret_bytes() } DisplaySecret { secret: self.secret_bytes() }
} }
} }
impl SharedSecret {
/// Formats the explicit byte value of the shared secret kept inside the type as a
/// little-endian hexadecimal string using the provided formatter.
///
/// This is the only method that outputs the actual shared secret value, and, thus,
/// should be used with extreme caution.
///
/// # Examples
///
/// ```
/// # #[cfg(not(fuzzing))]
/// # #[cfg(feature = "std")] {
/// # use std::str::FromStr;
/// # use secp256k1::{SecretKey, PublicKey};
/// use secp256k1::ecdh::SharedSecret;
///
/// # let pk = PublicKey::from_slice(&[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]).expect("hard coded slice should parse correctly");
/// # let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
///
/// let secret = SharedSecret::new(&pk, &sk);
/// // Here we explicitly display the secret value:
/// assert_eq!(
/// format!("{}", secret.display_secret()),
/// "cf05ae7da039ddce6d56dd57d3000c6dd91c6f1695eae47e05389f11e2467043"
/// );
/// // Also, we can explicitly display with `Debug`:
/// assert_eq!(
/// format!("{:?}", secret.display_secret()),
/// format!("DisplaySecret(\"{}\")", secret.display_secret())
/// );
/// # }
/// ```
#[inline]
pub fn display_secret(&self) -> DisplaySecret {
DisplaySecret { secret: self.secret_bytes() }
}
}