Skip to content

Commit 7cd43ae

Browse files
f Use unique keys for deriving inbound payment secrets
1 parent fb8b349 commit 7cd43ae

File tree

1 file changed

+36
-9
lines changed

1 file changed

+36
-9
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,8 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
643643
our_network_key: SecretKey,
644644
our_network_pubkey: PublicKey,
645645

646+
inbound_payment_key: SecretKey,
647+
646648
/// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
647649
/// value increases strictly since we don't assume access to a time source.
648650
last_node_announcement_serial: AtomicUsize,
@@ -1343,6 +1345,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
13431345
our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()),
13441346
secp_ctx,
13451347

1348+
inbound_payment_key: keys_manager.get_inbound_payment_secret(),
1349+
13461350
last_node_announcement_serial: AtomicUsize::new(0),
13471351
highest_seen_timestamp: AtomicUsize::new(0),
13481352

@@ -2594,7 +2598,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25942598
// `create_inbound_payment_for_hash` for details on our checks.
25952599
fn verify_inbound_payment_data(&self, payment_hash: PaymentHash, payment_data: msgs::FinalOnionHopData) -> Result<Option<PaymentPreimage>, ()> {
25962600
let (iv_bytes, encrypted_metadata_bytes) = payment_data.payment_secret.0.split_at(16);
2597-
let mut chacha = ChaCha20::new(&self.our_network_key[..], &iv_bytes[..12]);
2601+
let mut chacha = ChaCha20::new(&self.inbound_payment_key[..], &iv_bytes[..12]);
25982602
let mut chacha_bytes = [0; 16];
25992603
chacha.process_in_place(&mut chacha_bytes);
26002604

@@ -2610,9 +2614,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26102614
}
26112615

26122616
let is_user_payment_hash = metadata_bytes[0] & 1 << 7 != 0;
2617+
let (user_pmt_hash_key, ldk_pmt_hash_key) = hkdf_extract_expand(&vec![0], &self.inbound_payment_key[..]);
26132618
let mut payment_preimage = None;
26142619
if is_user_payment_hash {
2615-
let mut hmac = HmacEngine::<Sha256>::new(&self.our_network_key[..]);
2620+
let mut hmac = HmacEngine::<Sha256>::new(&user_pmt_hash_key);
26162621
hmac.input(&metadata_bytes[..]);
26172622
hmac.input(&payment_hash.0[..]);
26182623
if iv_bytes != Hmac::from_engine(hmac).into_inner().split_at_mut(16).0 {
@@ -2634,7 +2639,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26342639
log_trace!(self.logger, "Failing HTLC with payment_hash {} due to total_msat {} being less than the minimum amount of {} msat", log_bytes!(payment_hash.0), payment_data.total_msat, min_amt_msat);
26352640
return Err(())
26362641
}
2637-
let mut hmac = HmacEngine::<Sha256>::new(&self.our_network_key[..]);
2642+
let mut hmac = HmacEngine::<Sha256>::new(&ldk_pmt_hash_key);
26382643
hmac.input(&iv_bytes);
26392644
hmac.input(&metadata_bytes);
26402645
let decoded_payment_preimage = Hmac::from_engine(hmac).into_inner();
@@ -4616,7 +4621,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
46164621
// METADATA = payment amount (8 bytes) || expiry (8 bytes)
46174622
// IV = 16 random bytes
46184623
// payment_preimage = HMAC(ldk_pmt_hash_key, IV || METADATA)
4619-
// payment_secret = IV || CHACHA(self.inbound_payments_key, IV) xor METADATA
4624+
// payment_secret = IV || CHACHA(self.inbound_payment_key, IV) xor METADATA
46204625
//
46214626
// Then on payment receipt, we verify in `verify_inbound_payment_data` that the payment preimage
46224627
// and payment secret match what was constructed in `create_inbound_payment`.
@@ -4641,7 +4646,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
46414646
let rand_bytes = self.keys_manager.get_secure_random_bytes();
46424647
let iv_bytes = &rand_bytes[..16];
46434648

4644-
let mut hmac = HmacEngine::<Sha256>::new(&self.our_network_key[..]);
4649+
let (_, ldk_pmt_hash_key) = hkdf_extract_expand(&vec![0], &self.inbound_payment_key[..]);
4650+
let mut hmac = HmacEngine::<Sha256>::new(&ldk_pmt_hash_key);
46454651
hmac.input(iv_bytes);
46464652
hmac.input(&metadata_bytes);
46474653
let payment_preimage_bytes = Hmac::from_engine(hmac).into_inner();
@@ -4651,7 +4657,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
46514657
let (iv_slice, encrypted_metadata_slice) = payment_secret_bytes.split_at_mut(16);
46524658
iv_slice.copy_from_slice(iv_bytes);
46534659

4654-
let mut chacha = ChaCha20::new(&self.our_network_key[..], &iv_bytes[..12]);
4660+
let mut chacha = ChaCha20::new(&self.inbound_payment_key[..], &iv_bytes[..12]);
46554661
let mut chacha_bytes = [0; 16];
46564662
chacha.process_in_place(&mut chacha_bytes);
46574663

@@ -4702,7 +4708,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
47024708
//
47034709
// METADATA = top bit set for user-generated payment hash || payment amount (8 bytes) || expiry (8 bytes)
47044710
// IV = HMAC(user_pmt_hash_key, METADATA || payment_hash)[0..16]
4705-
// payment_secret = IV || CHACHA(self.inbound_payments_key, IV) xor METADATA
4711+
// payment_secret = IV || CHACHA(self.inbound_payment_key, IV) xor METADATA
47064712
//
47074713
// Then on payment receipt, we verify in `verify_inbound_payment_data` that the payment preimage
47084714
// and payment secret match what was constructed in `create_inbound_payment`.
@@ -4729,7 +4735,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
47294735
expiry_slice.copy_from_slice(&expiry_bytes);
47304736
}
47314737

4732-
let mut hmac = HmacEngine::<Sha256>::new(&self.our_network_key[..]);
4738+
let (user_pmt_hash_key, _) = hkdf_extract_expand(&vec![0], &self.inbound_payment_key[..]);
4739+
let mut hmac = HmacEngine::<Sha256>::new(&user_pmt_hash_key);
47334740
hmac.input(&metadata_bytes);
47344741
hmac.input(&payment_hash.0);
47354742
let hmac_bytes = Hmac::from_engine(hmac).into_inner();
@@ -4740,7 +4747,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
47404747
let (iv_slice, encrypted_metadata_slice) = payment_secret_bytes.split_at_mut(16);
47414748
iv_slice.copy_from_slice(iv_bytes);
47424749

4743-
let mut chacha = ChaCha20::new(&self.our_network_key[..], &iv_bytes[..12]);
4750+
let mut chacha = ChaCha20::new(&self.inbound_payment_key[..], &iv_bytes[..12]);
47444751
let mut chacha_bytes = [0; 16];
47454752
chacha.process_in_place(&mut chacha_bytes);
47464753

@@ -5820,6 +5827,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
58205827
}
58215828
write_tlv_fields!(writer, {
58225829
(1, pending_outbound_payments_no_retry, required),
5830+
(2, self.inbound_payment_key, required),
58235831
(3, pending_outbound_payments, required),
58245832
});
58255833

@@ -6115,10 +6123,15 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
61156123
// pending_outbound_payments_no_retry is for compatibility with 0.0.101 clients.
61166124
let mut pending_outbound_payments_no_retry: Option<HashMap<PaymentId, HashSet<[u8; 32]>>> = None;
61176125
let mut pending_outbound_payments = None;
6126+
let mut inbound_payment_key = None;
61186127
read_tlv_fields!(reader, {
61196128
(1, pending_outbound_payments_no_retry, option),
6129+
(2, inbound_payment_key, option),
61206130
(3, pending_outbound_payments, option),
61216131
});
6132+
if inbound_payment_key.is_none() {
6133+
inbound_payment_key = Some(args.keys_manager.get_inbound_payment_secret());
6134+
}
61226135
if pending_outbound_payments.is_none() && pending_outbound_payments_no_retry.is_none() {
61236136
pending_outbound_payments = Some(pending_outbound_payments_compat);
61246137
} else if pending_outbound_payments.is_none() {
@@ -6196,6 +6209,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
61966209
claimable_htlcs,
61976210
pending_msg_events: Vec::new(),
61986211
}),
6212+
inbound_payment_key: inbound_payment_key.unwrap(),
61996213
pending_inbound_payments: Mutex::new(pending_inbound_payments),
62006214
pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()),
62016215

@@ -6229,6 +6243,19 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
62296243
}
62306244
}
62316245

6246+
fn hkdf_extract_expand(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) {
6247+
let mut hmac = HmacEngine::<Sha256>::new(salt);
6248+
hmac.input(ikm);
6249+
let prk = Hmac::from_engine(hmac).into_inner();
6250+
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
6251+
hmac.input(&[1; 1]);
6252+
let t1 = Hmac::from_engine(hmac).into_inner();
6253+
let mut hmac = HmacEngine::<Sha256>::new(&prk[..]);
6254+
hmac.input(&t1);
6255+
hmac.input(&[2; 1]);
6256+
(t1, Hmac::from_engine(hmac).into_inner())
6257+
}
6258+
62326259
#[cfg(test)]
62336260
mod tests {
62346261
use bitcoin::hashes::Hash;

0 commit comments

Comments
 (0)