Skip to content

Commit af69fae

Browse files
authored
Merge pull request #674 from TheBlueMatt/2020-08-keyif-rand-names
Simplify + clarify random-bytes-fetching from KeysInterface
2 parents 501974d + 6497465 commit af69fae

File tree

7 files changed

+37
-71
lines changed

7 files changed

+37
-71
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ impl channelmonitor::ManyChannelMonitor for TestChannelMonitor {
142142

143143
struct KeyProvider {
144144
node_id: u8,
145-
session_id: atomic::AtomicU8,
146-
channel_id: atomic::AtomicU8,
145+
rand_bytes_id: atomic::AtomicU8,
147146
}
148147
impl KeysInterface for KeyProvider {
149148
type ChanKeySigner = EnforcingChannelKeys;
@@ -179,14 +178,8 @@ impl KeysInterface for KeyProvider {
179178
))
180179
}
181180

182-
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
183-
let id = self.session_id.fetch_add(1, atomic::Ordering::Relaxed);
184-
(SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, id, 10, self.node_id]).unwrap(),
185-
[0; 32])
186-
}
187-
188-
fn get_channel_id(&self) -> [u8; 32] {
189-
let id = self.channel_id.fetch_add(1, atomic::Ordering::Relaxed);
181+
fn get_secure_random_bytes(&self) -> [u8; 32] {
182+
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
190183
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, id, 11, self.node_id]
191184
}
192185
}
@@ -202,7 +195,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
202195
let watch = Arc::new(ChainWatchInterfaceUtil::new(Network::Bitcoin));
203196
let monitor = Arc::new(TestChannelMonitor::new(watch.clone(), broadcast.clone(), logger.clone(), fee_est.clone()));
204197

205-
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, session_id: atomic::AtomicU8::new(0), channel_id: atomic::AtomicU8::new(0) });
198+
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0) });
206199
let mut config = UserConfig::default();
207200
config.channel_options.fee_proportional_millionths = 0;
208201
config.channel_options.announced_channel = true;
@@ -218,7 +211,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
218211
let watch = Arc::new(ChainWatchInterfaceUtil::new(Network::Bitcoin));
219212
let monitor = Arc::new(TestChannelMonitor::new(watch.clone(), broadcast.clone(), logger.clone(), fee_est.clone()));
220213

221-
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, session_id: atomic::AtomicU8::new(0), channel_id: atomic::AtomicU8::new(0) });
214+
let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0) });
222215
let mut config = UserConfig::default();
223216
config.channel_options.fee_proportional_millionths = 0;
224217
config.channel_options.announced_channel = true;

fuzz/src/full_stack.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,7 @@ impl KeysInterface for KeyProvider {
295295
})
296296
}
297297

298-
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
299-
let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8;
300-
(SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, ctr]).unwrap(),
301-
[0; 32])
302-
}
303-
304-
fn get_channel_id(&self) -> [u8; 32] {
298+
fn get_secure_random_bytes(&self) -> [u8; 32] {
305299
let ctr = self.counter.fetch_add(1, Ordering::Relaxed);
306300
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
307301
(ctr >> 8*7) as u8, (ctr >> 8*6) as u8, (ctr >> 8*5) as u8, (ctr >> 8*4) as u8, (ctr >> 8*3) as u8, (ctr >> 8*2) as u8, (ctr >> 8*1) as u8, 14, (ctr >> 8*0) as u8]

lightning/src/chain/keysinterface.rs

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,10 @@ pub trait KeysInterface: Send + Sync {
341341
/// Get a new set of ChannelKeys for per-channel secrets. These MUST be unique even if you
342342
/// restarted with some stale data!
343343
fn get_channel_keys(&self, inbound: bool, channel_value_satoshis: u64) -> Self::ChanKeySigner;
344-
/// Get a secret and PRNG seed for constructing an onion packet
345-
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]);
346-
/// Get a unique temporary channel id. Channels will be referred to by this until the funding
347-
/// transaction is created, at which point they will use the outpoint in the funding
348-
/// transaction.
349-
fn get_channel_id(&self) -> [u8; 32];
344+
/// Gets a unique, cryptographically-secure, random 32 byte value. This is used for encrypting
345+
/// onion packets and for temporary channel IDs. There is no requirement that these be
346+
/// persisted anywhere, though they must be unique across restarts.
347+
fn get_secure_random_bytes(&self) -> [u8; 32];
350348
}
351349

352350
#[derive(Clone)]
@@ -666,10 +664,8 @@ pub struct KeysManager {
666664
shutdown_pubkey: PublicKey,
667665
channel_master_key: ExtendedPrivKey,
668666
channel_child_index: AtomicUsize,
669-
session_master_key: ExtendedPrivKey,
670-
session_child_index: AtomicUsize,
671-
channel_id_master_key: ExtendedPrivKey,
672-
channel_id_child_index: AtomicUsize,
667+
rand_bytes_master_key: ExtendedPrivKey,
668+
rand_bytes_child_index: AtomicUsize,
673669

674670
seed: [u8; 32],
675671
starting_time_secs: u64,
@@ -678,7 +674,7 @@ pub struct KeysManager {
678674

679675
impl KeysManager {
680676
/// Constructs a KeysManager from a 32-byte seed. If the seed is in some way biased (eg your
681-
/// RNG is busted) this may panic (but more importantly, you will possibly lose funds).
677+
/// CSRNG is busted) this may panic (but more importantly, you will possibly lose funds).
682678
/// starting_time isn't strictly required to actually be a time, but it must absolutely,
683679
/// without a doubt, be unique to this instance. ie if you start multiple times with the same
684680
/// seed, starting_time must be unique to each run. Thus, the easiest way to achieve this is to
@@ -715,8 +711,7 @@ impl KeysManager {
715711
Err(_) => panic!("Your RNG is busted"),
716712
};
717713
let channel_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(3).unwrap()).expect("Your RNG is busted");
718-
let session_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted");
719-
let channel_id_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(5).unwrap()).expect("Your RNG is busted");
714+
let rand_bytes_master_key = master_key.ckd_priv(&secp_ctx, ChildNumber::from_hardened_idx(4).unwrap()).expect("Your RNG is busted");
720715

721716
KeysManager {
722717
secp_ctx,
@@ -725,10 +720,8 @@ impl KeysManager {
725720
shutdown_pubkey,
726721
channel_master_key,
727722
channel_child_index: AtomicUsize::new(0),
728-
session_master_key,
729-
session_child_index: AtomicUsize::new(0),
730-
channel_id_master_key,
731-
channel_id_child_index: AtomicUsize::new(0),
723+
rand_bytes_master_key,
724+
rand_bytes_child_index: AtomicUsize::new(0),
732725

733726
seed: *seed,
734727
starting_time_secs,
@@ -821,29 +814,14 @@ impl KeysInterface for KeysManager {
821814
self.derive_channel_keys(channel_value_satoshis, ix_and_nanos, self.starting_time_secs)
822815
}
823816

824-
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
817+
fn get_secure_random_bytes(&self) -> [u8; 32] {
825818
let mut sha = self.derive_unique_start();
826819

827-
let child_ix = self.session_child_index.fetch_add(1, Ordering::AcqRel);
828-
let child_privkey = self.session_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted");
829-
sha.input(&child_privkey.private_key.key[..]);
830-
831-
let mut rng_seed = sha.clone();
832-
// Not exactly the most ideal construction, but the second value will get fed into
833-
// ChaCha so it is another step harder to break.
834-
rng_seed.input(b"RNG Seed Salt");
835-
sha.input(b"Session Key Salt");
836-
(SecretKey::from_slice(&Sha256::from_engine(sha).into_inner()).expect("Your RNG is busted"),
837-
Sha256::from_engine(rng_seed).into_inner())
838-
}
839-
840-
fn get_channel_id(&self) -> [u8; 32] {
841-
let mut sha = self.derive_unique_start();
842-
843-
let child_ix = self.channel_id_child_index.fetch_add(1, Ordering::AcqRel);
844-
let child_privkey = self.channel_id_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted");
820+
let child_ix = self.rand_bytes_child_index.fetch_add(1, Ordering::AcqRel);
821+
let child_privkey = self.rand_bytes_master_key.ckd_priv(&self.secp_ctx, ChildNumber::from_hardened_idx(child_ix as u32).expect("key space exhausted")).expect("Your RNG is busted");
845822
sha.input(&child_privkey.private_key.key[..]);
846823

824+
sha.input(b"Unique Secure Random Bytes Salt");
847825
Sha256::from_engine(sha).into_inner()
848826
}
849827
}

lightning/src/ln/channel.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
488488
user_id: user_id,
489489
config: config.channel_options.clone(),
490490

491-
channel_id: keys_provider.get_channel_id(),
491+
channel_id: keys_provider.get_secure_random_bytes(),
492492
channel_state: ChannelState::OurInitSent as u32,
493493
channel_outbound: true,
494494
secp_ctx: Secp256k1::new(),
@@ -4520,8 +4520,7 @@ mod tests {
45204520
fn get_channel_keys(&self, _inbound: bool, _channel_value_satoshis: u64) -> InMemoryChannelKeys {
45214521
self.chan_keys.clone()
45224522
}
4523-
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) { panic!(); }
4524-
fn get_channel_id(&self) -> [u8; 32] { [0; 32] }
4523+
fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }
45254524
}
45264525

45274526
fn public_from_secret_hex(secp_ctx: &Secp256k1<All>, hex: &str) -> PublicKey {

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,8 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
12431243
// Only public for testing, this should otherwise never be called direcly
12441244
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32) -> Result<(), APIError> {
12451245
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
1246-
let (session_priv, prng_seed) = self.keys_manager.get_onion_rand();
1246+
let prng_seed = self.keys_manager.get_secure_random_bytes();
1247+
let session_priv = SecretKey::from_slice(&self.keys_manager.get_secure_random_bytes()[..]).expect("RNG is busted");
12471248

12481249
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
12491250
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;

lightning/src/ln/functional_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6143,7 +6143,7 @@ fn test_onion_failure() {
61436143
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
61446144
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
61456145
for node in nodes.iter() {
6146-
*node.keys_manager.override_session_priv.lock().unwrap() = Some(SecretKey::from_slice(&[3; 32]).unwrap());
6146+
*node.keys_manager.override_session_priv.lock().unwrap() = Some([3; 32]);
61476147
}
61486148
let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()), create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known())];
61496149
let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]);

lightning/src/util/test_utils.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ impl Logger for TestLogger {
350350

351351
pub struct TestKeysInterface {
352352
backing: keysinterface::KeysManager,
353-
pub override_session_priv: Mutex<Option<SecretKey>>,
353+
pub override_session_priv: Mutex<Option<[u8; 32]>>,
354354
pub override_channel_id_priv: Mutex<Option<[u8; 32]>>,
355355
}
356356

@@ -364,18 +364,19 @@ impl keysinterface::KeysInterface for TestKeysInterface {
364364
EnforcingChannelKeys::new(self.backing.get_channel_keys(inbound, channel_value_satoshis))
365365
}
366366

367-
fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) {
368-
match *self.override_session_priv.lock().unwrap() {
369-
Some(key) => (key.clone(), [0; 32]),
370-
None => self.backing.get_onion_rand()
367+
fn get_secure_random_bytes(&self) -> [u8; 32] {
368+
let override_channel_id = self.override_channel_id_priv.lock().unwrap();
369+
let override_session_key = self.override_session_priv.lock().unwrap();
370+
if override_channel_id.is_some() && override_session_key.is_some() {
371+
panic!("We don't know which override key to use!");
371372
}
372-
}
373-
374-
fn get_channel_id(&self) -> [u8; 32] {
375-
match *self.override_channel_id_priv.lock().unwrap() {
376-
Some(key) => key.clone(),
377-
None => self.backing.get_channel_id()
373+
if let Some(key) = &*override_channel_id {
374+
return *key;
375+
}
376+
if let Some(key) = &*override_session_key {
377+
return *key;
378378
}
379+
self.backing.get_secure_random_bytes()
379380
}
380381
}
381382

0 commit comments

Comments
 (0)