From 8849efe0deeb28ede680b83f0a7f9a6543627bd5 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 23 Jul 2024 13:36:39 -0500 Subject: [PATCH] Delay adding iv_bytes to MetadataMaterial::hmac In an upcoming commit, the iv_bytes used in MetadataMaterial will vary depending on when whether a blinded path is included in the corresponding message. Delay adding into MetadataMaterial::hmac as otherwise the HmacEngine would need to be re-initialized using an ExpandedKey, which won't be readily available. --- lightning/src/ln/inbound_payment.rs | 9 ++--- lightning/src/offers/invoice_request.rs | 7 ++-- lightning/src/offers/offer.rs | 5 +-- lightning/src/offers/refund.rs | 5 +-- lightning/src/offers/signer.rs | 45 +++++++++++++++---------- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index 2d807d550..0ae260a50 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -81,13 +81,8 @@ impl ExpandedKey { /// Returns an [`HmacEngine`] used to construct [`Offer::metadata`]. /// /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata - pub(crate) fn hmac_for_offer( - &self, nonce: Nonce, iv_bytes: &[u8; IV_LEN] - ) -> HmacEngine { - let mut hmac = HmacEngine::::new(&self.offers_base_key); - hmac.input(iv_bytes); - hmac.input(&nonce.0); - hmac + pub(crate) fn hmac_for_offer(&self) -> HmacEngine { + HmacEngine::::new(&self.offers_base_key) } /// Encrypts or decrypts the given `bytes`. Used for data included in an offer message's diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index 4b3404702..de9c9c2db 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -174,7 +174,7 @@ macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident, payment_id: PaymentId, ) -> Self { let payment_id = Some(payment_id); - let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id); + let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id); let metadata = Metadata::Derived(derivation_material); Self { offer, @@ -203,7 +203,7 @@ macro_rules! invoice_request_derived_payer_id_builder_methods { ( secp_ctx: &'b Secp256k1<$secp_context>, payment_id: PaymentId ) -> Self { let payment_id = Some(payment_id); - let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id); + let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id); let metadata = Metadata::DerivedSigningPubkey(derivation_material); Self { offer, @@ -346,7 +346,8 @@ macro_rules! invoice_request_builder_methods { ( tlv_stream.2.payer_id = $self.payer_id.as_ref(); } - let (derived_metadata, derived_keys) = metadata.derive_from(tlv_stream, $self.secp_ctx); + let (derived_metadata, derived_keys) = + metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx); metadata = derived_metadata; keys = derived_keys; if let Some(keys) = keys { diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 29220125f..deacacd15 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -258,7 +258,7 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => { node_id: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce, secp_ctx: &'a Secp256k1<$secp_context> ) -> Self { - let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, None); + let derivation_material = MetadataMaterial::new(nonce, expanded_key, None); let metadata = Metadata::DerivedSigningPubkey(derivation_material); Self { offer: OfferContents { @@ -405,7 +405,8 @@ macro_rules! offer_builder_methods { ( // Either replace the signing pubkey with the derived pubkey or include the metadata // for verification. In the former case, the blinded paths must include // `OffersContext::InvoiceRequest` instead. - let (derived_metadata, keys) = metadata.derive_from(tlv_stream, $self.secp_ctx); + let (derived_metadata, keys) = + metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx); match keys { Some(keys) => $self.offer.signing_pubkey = Some(keys.public_key()), None => $self.offer.metadata = Some(derived_metadata), diff --git a/lightning/src/offers/refund.rs b/lightning/src/offers/refund.rs index 8547cfe99..76605c77f 100644 --- a/lightning/src/offers/refund.rs +++ b/lightning/src/offers/refund.rs @@ -210,7 +210,7 @@ macro_rules! refund_builder_methods { ( } let payment_id = Some(payment_id); - let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id); + let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id); let metadata = Metadata::DerivedSigningPubkey(derivation_material); Ok(Self { refund: RefundContents { @@ -316,7 +316,8 @@ macro_rules! refund_builder_methods { ( tlv_stream.2.payer_id = None; } - let (derived_metadata, keys) = metadata.derive_from(tlv_stream, $self.secp_ctx); + let (derived_metadata, keys) = + metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx); metadata = derived_metadata; if let Some(keys) = keys { $self.refund.payer_id = keys.public_key(); diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index 2e12a1705..c15b94d49 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -140,20 +140,19 @@ impl Metadata { } pub fn derive_from( - self, tlv_stream: W, secp_ctx: Option<&Secp256k1> + self, iv_bytes: &[u8; IV_LEN], tlv_stream: W, secp_ctx: Option<&Secp256k1> ) -> (Self, Option) { match self { Metadata::Bytes(_) => (self, None), Metadata::RecipientData(_) => { debug_assert!(false); (self, None) }, Metadata::PayerData(_) => { debug_assert!(false); (self, None) }, - Metadata::Derived(mut metadata_material) => { - tlv_stream.write(&mut metadata_material.hmac).unwrap(); - (Metadata::Bytes(metadata_material.derive_metadata()), None) + Metadata::Derived(metadata_material) => { + (Metadata::Bytes(metadata_material.derive_metadata(iv_bytes, tlv_stream)), None) }, - Metadata::DerivedSigningPubkey(mut metadata_material) => { - tlv_stream.write(&mut metadata_material.hmac).unwrap(); + Metadata::DerivedSigningPubkey(metadata_material) => { let secp_ctx = secp_ctx.unwrap(); - let (metadata, keys) = metadata_material.derive_metadata_and_keys(secp_ctx); + let (metadata, keys) = + metadata_material.derive_metadata_and_keys(iv_bytes, tlv_stream, secp_ctx); (Metadata::Bytes(metadata), Some(keys)) }, } @@ -217,10 +216,7 @@ pub(super) struct MetadataMaterial { } impl MetadataMaterial { - pub fn new( - nonce: Nonce, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN], - payment_id: Option - ) -> Self { + pub fn new(nonce: Nonce, expanded_key: &ExpandedKey, payment_id: Option) -> Self { // Encrypt payment_id let encrypted_payment_id = payment_id.map(|payment_id| { expanded_key.crypt_for_offer(payment_id.0, nonce) @@ -228,12 +224,16 @@ impl MetadataMaterial { Self { nonce, - hmac: expanded_key.hmac_for_offer(nonce, iv_bytes), + hmac: expanded_key.hmac_for_offer(), encrypted_payment_id, } } - fn derive_metadata(mut self) -> Vec { + fn derive_metadata(mut self, iv_bytes: &[u8; IV_LEN], tlv_stream: W) -> Vec { + self.hmac.input(iv_bytes); + self.hmac.input(&self.nonce.0); + tlv_stream.write(&mut self.hmac).unwrap(); + self.hmac.input(DERIVED_METADATA_HMAC_INPUT); self.maybe_include_encrypted_payment_id(); @@ -243,9 +243,13 @@ impl MetadataMaterial { bytes } - fn derive_metadata_and_keys( - mut self, secp_ctx: &Secp256k1 + fn derive_metadata_and_keys( + mut self, iv_bytes: &[u8; IV_LEN], tlv_stream: W, secp_ctx: &Secp256k1 ) -> (Vec, Keypair) { + self.hmac.input(iv_bytes); + self.hmac.input(&self.nonce.0); + tlv_stream.write(&mut self.hmac).unwrap(); + self.hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT); self.maybe_include_encrypted_payment_id(); @@ -271,9 +275,12 @@ impl MetadataMaterial { pub(super) fn derive_keys(nonce: Nonce, expanded_key: &ExpandedKey) -> Keypair { const IV_BYTES: &[u8; IV_LEN] = b"LDK Invoice ~~~~"; + let mut hmac = expanded_key.hmac_for_offer(); + hmac.input(IV_BYTES); + hmac.input(&nonce.0); + let secp_ctx = Secp256k1::new(); - let hmac = Hmac::from_engine(expanded_key.hmac_for_offer(nonce, IV_BYTES)); - let privkey = SecretKey::from_slice(hmac.as_byte_array()).unwrap(); + let privkey = SecretKey::from_slice(Hmac::from_engine(hmac).as_byte_array()).unwrap(); Keypair::from_secret_key(&secp_ctx, &privkey) } @@ -368,7 +375,9 @@ fn hmac_for_message<'a>( Ok(nonce) => nonce, Err(_) => return Err(()), }; - let mut hmac = expanded_key.hmac_for_offer(nonce, iv_bytes); + let mut hmac = expanded_key.hmac_for_offer(); + hmac.input(iv_bytes); + hmac.input(&nonce.0); for record in tlv_stream { hmac.input(record.record_bytes); -- 2.39.5