Skip to content

Commit 6788d4b

Browse files
committed
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. Includes improvements to rustdoc for the examples of all three secret printing types.
1 parent 5af56ec commit 6788d4b

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

src/ecdh.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ use secp256k1_sys::types::{c_int, c_uchar, c_void};
3939
/// assert_eq!(sec1, sec2);
4040
/// # }
4141
// ```
42-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
42+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4343
pub struct SharedSecret([u8; 32]);
44+
impl_display_secret!(SharedSecret);
4445

4546
impl SharedSecret {
4647
/// Creates a new shared secret from a pubkey and secret key.
@@ -62,6 +63,13 @@ impl SharedSecret {
6263
debug_assert_eq!(res, 1);
6364
SharedSecret(buf)
6465
}
66+
67+
/// Serializes the secret key as byte value.
68+
// We just use this for interoperability with the display secret infrastructure (see `secret.rs`).
69+
#[inline]
70+
pub(crate) fn serialize_secret(&self) -> [u8; 32] {
71+
self.0
72+
}
6573
}
6674

6775
impl Borrow<[u8]> for SharedSecret {

src/secret.rs

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
1717
use ::core::fmt;
1818
use ::{SecretKey, KeyPair, to_hex};
19+
use ecdh::SharedSecret;
1920
use constants::SECRET_KEY_SIZE;
2021

2122
macro_rules! impl_display_secret {
@@ -113,28 +114,26 @@ impl SecretKey {
113114
/// little-endian hexadecimal string using the provided formatter.
114115
///
115116
/// This is the only method that outputs the actual secret key value, and, thus,
116-
/// should be used with extreme precaution.
117+
/// should be used with extreme caution.
117118
///
118-
/// # Example
119+
/// # Examples
119120
///
120121
/// ```
121122
/// # #[cfg(all(feature = "std", not(feature = "bitcoin_hashes")))] {
122-
/// use secp256k1::ONE_KEY;
123-
/// let key = ONE_KEY;
124-
/// // Normal display hides value
125-
/// assert_eq!(
126-
/// "SecretKey(#2518682f7819fb2d)",
127-
/// format!("{:?}", key)
128-
/// );
123+
/// let key = secp256k1::ONE_KEY;
124+
///
125+
/// // Normal display hides value.
126+
/// assert_eq!("SecretKey(#2518682f7819fb2d)", format!("{:?}", key));
127+
///
129128
/// // Here we explicitly display the secret value:
130129
/// assert_eq!(
131130
/// "0000000000000000000000000000000000000000000000000000000000000001",
132131
/// format!("{}", key.display_secret())
133132
/// );
133+
/// // Also, we can explicitly display with `Debug`:
134134
/// assert_eq!(
135-
/// "DisplaySecret(\"0000000000000000000000000000000000000000000000000000000000000001\")",
136-
/// format!("{:?}", key.display_secret())
137-
/// );
135+
/// format!("{:?}", key.display_secret()),
136+
/// format!("DisplaySecret(\"{}\")", key.display_secret()));
138137
/// # }
139138
/// ```
140139
#[inline]
@@ -172,6 +171,7 @@ impl KeyPair {
172171
/// "0000000000000000000000000000000000000000000000000000000000000001",
173172
/// format!("{}", key.display_secret())
174173
/// );
174+
/// // Also, we can explicitly display with `Debug`:
175175
/// assert_eq!(
176176
/// "DisplaySecret(\"0000000000000000000000000000000000000000000000000000000000000001\")",
177177
/// format!("{:?}", key.display_secret())
@@ -183,3 +183,42 @@ impl KeyPair {
183183
DisplaySecret { secret: self.serialize_secret() }
184184
}
185185
}
186+
187+
impl SharedSecret {
188+
/// Formats the explicit byte value of the shared secret kept inside the type as a
189+
/// little-endian hexadecimal string using the provided formatter.
190+
///
191+
/// This is the only method that outputs the actual shared secret value, and, thus,
192+
/// should be used with extreme caution.
193+
///
194+
/// # Examples
195+
///
196+
/// ```
197+
/// # #[cfg(all(feature = "std", not(feature = "bitcoin_hashes")))] {
198+
/// # use std::str::FromStr;
199+
/// # use secp256k1::{SecretKey, PublicKey};
200+
/// use secp256k1::ecdh::SharedSecret;
201+
///
202+
/// # 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");
203+
/// # let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
204+
///
205+
/// let secret = SharedSecret::new(&pk, &sk);
206+
/// // Normal display hides the value.
207+
/// assert_eq!(format!("{:?}", secret), "SharedSecret(#2f7b793c9a1de4bf)");
208+
///
209+
/// // Here we explicitly display the secret value:
210+
/// assert_eq!(
211+
/// format!("{}", secret.display_secret()),
212+
/// "cf05ae7da039ddce6d56dd57d3000c6dd91c6f1695eae47e05389f11e2467043"
213+
/// );
214+
/// // Also, we can explicitly display with `Debug`:
215+
/// assert_eq!(
216+
/// format!("{:?}", secret.display_secret()),
217+
/// format!("DisplaySecret(\"{}\")", secret.display_secret()));
218+
/// # }
219+
/// ```
220+
#[inline]
221+
pub fn display_secret(&self) -> DisplaySecret {
222+
DisplaySecret { secret: self.serialize_secret() }
223+
}
224+
}

0 commit comments

Comments
 (0)