X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Fsigner.rs;h=8d5f98e6f6b050993474bbedbcc9a0f25c409980;hb=9d5adfcd1003df37edf2fae42284ae6772a42237;hp=a8ea941e3be834e3504af6c23643db5219e11e33;hpb=3880e69237d7f6a33db1912176de5a745ea99b41;p=rust-lightning diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index a8ea941e..8d5f98e6 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -162,6 +162,14 @@ impl MetadataMaterial { } } +pub(super) fn derive_keys(nonce: Nonce, expanded_key: &ExpandedKey) -> KeyPair { + const IV_BYTES: &[u8; IV_LEN] = b"LDK Invoice ~~~~"; + 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_inner()).unwrap(); + KeyPair::from_secret_key(&secp_ctx, &privkey) +} + /// Verifies data given in a TLV stream was used to produce the given metadata, consisting of: /// - a 128-bit [`Nonce`] and possibly /// - a [`Sha256`] hash of the nonce and the TLV records using the [`ExpandedKey`]. @@ -169,17 +177,43 @@ impl MetadataMaterial { /// If the latter is not included in the metadata, the TLV stream is used to check if the given /// `signing_pubkey` can be derived from it. pub(super) fn verify_metadata<'a, T: secp256k1::Signing>( - metadata: &Vec, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN], + metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN], signing_pubkey: PublicKey, tlv_stream: impl core::iter::Iterator>, secp_ctx: &Secp256k1 -) -> bool { +) -> Result, ()> { + let hmac = hmac_for_message(metadata, expanded_key, iv_bytes, tlv_stream)?; + + if metadata.len() == Nonce::LENGTH { + let derived_keys = KeyPair::from_secret_key( + secp_ctx, &SecretKey::from_slice(hmac.as_inner()).unwrap() + ); + if fixed_time_eq(&signing_pubkey.serialize(), &derived_keys.public_key().serialize()) { + Ok(Some(derived_keys)) + } else { + Err(()) + } + } else if metadata[Nonce::LENGTH..].len() == Sha256::LEN { + if fixed_time_eq(&metadata[Nonce::LENGTH..], &hmac.into_inner()) { + Ok(None) + } else { + Err(()) + } + } else { + Err(()) + } +} + +fn hmac_for_message<'a>( + metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN], + tlv_stream: impl core::iter::Iterator> +) -> Result, ()> { if metadata.len() < Nonce::LENGTH { - return false; + return Err(()); } let nonce = match Nonce::try_from(&metadata[..Nonce::LENGTH]) { Ok(nonce) => nonce, - Err(_) => return false, + Err(_) => return Err(()), }; let mut hmac = expanded_key.hmac_for_offer(nonce, iv_bytes); @@ -189,13 +223,9 @@ pub(super) fn verify_metadata<'a, T: secp256k1::Signing>( if metadata.len() == Nonce::LENGTH { hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT); - let hmac = Hmac::from_engine(hmac); - let derived_pubkey = SecretKey::from_slice(hmac.as_inner()).unwrap().public_key(&secp_ctx); - fixed_time_eq(&signing_pubkey.serialize(), &derived_pubkey.serialize()) - } else if metadata[Nonce::LENGTH..].len() == Sha256::LEN { - hmac.input(DERIVED_METADATA_HMAC_INPUT); - fixed_time_eq(&metadata[Nonce::LENGTH..], &Hmac::from_engine(hmac).into_inner()) } else { - false + hmac.input(DERIVED_METADATA_HMAC_INPUT); } + + Ok(Hmac::from_engine(hmac)) }