1 // This file is Copyright its original authors, visible in version control
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
10 //! Utilities for signing offer messages and verifying metadata.
12 use bitcoin::hashes::{Hash, HashEngine};
13 use bitcoin::hashes::cmp::fixed_time_eq;
14 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
15 use bitcoin::hashes::sha256::Hash as Sha256;
16 use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey, self};
18 use crate::ln::channelmanager::PaymentId;
19 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
20 use crate::offers::merkle::TlvRecord;
21 use crate::util::ser::Writeable;
23 use crate::prelude::*;
25 // Use a different HMAC input for each derivation. Otherwise, an attacker could:
26 // - take an Offer that has metadata consisting of a nonce and HMAC
27 // - strip off the HMAC and replace the signing_pubkey where the privkey is the HMAC,
28 // - generate and sign an invoice using the new signing_pubkey, and
29 // - claim they paid it since they would know the preimage of the invoice's payment_hash
30 const DERIVED_METADATA_HMAC_INPUT: &[u8; 16] = &[1; 16];
31 const DERIVED_METADATA_AND_KEYS_HMAC_INPUT: &[u8; 16] = &[2; 16];
33 // Additional HMAC inputs to distinguish use cases, either Offer or Refund/InvoiceRequest, where
34 // metadata for the latter contain an encrypted PaymentId.
35 const WITHOUT_ENCRYPTED_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[3; 16];
36 const WITH_ENCRYPTED_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[4; 16];
38 /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be
41 pub(super) enum Metadata {
42 /// Metadata as parsed, supplied by the user, or derived from the message contents.
45 /// Metadata to be derived from message contents and given material.
46 Derived(MetadataMaterial),
48 /// Metadata and signing pubkey to be derived from message contents and given material.
49 DerivedSigningPubkey(MetadataMaterial),
53 pub fn as_bytes(&self) -> Option<&Vec<u8>> {
55 Metadata::Bytes(bytes) => Some(bytes),
56 Metadata::Derived(_) => None,
57 Metadata::DerivedSigningPubkey(_) => None,
61 pub fn has_derivation_material(&self) -> bool {
63 Metadata::Bytes(_) => false,
64 Metadata::Derived(_) => true,
65 Metadata::DerivedSigningPubkey(_) => true,
69 pub fn derives_payer_keys(&self) -> bool {
71 // Infer whether Metadata::derived_from was called on Metadata::DerivedSigningPubkey to
72 // produce Metadata::Bytes. This is merely to determine which fields should be included
73 // when verifying a message. It doesn't necessarily indicate that keys were in fact
74 // derived, as wouldn't be the case if a Metadata::Bytes with length PaymentId::LENGTH +
75 // Nonce::LENGTH had been set explicitly.
76 Metadata::Bytes(bytes) => bytes.len() == PaymentId::LENGTH + Nonce::LENGTH,
77 Metadata::Derived(_) => false,
78 Metadata::DerivedSigningPubkey(_) => true,
82 pub fn derives_recipient_keys(&self) -> bool {
84 // Infer whether Metadata::derived_from was called on Metadata::DerivedSigningPubkey to
85 // produce Metadata::Bytes. This is merely to determine which fields should be included
86 // when verifying a message. It doesn't necessarily indicate that keys were in fact
87 // derived, as wouldn't be the case if a Metadata::Bytes with length Nonce::LENGTH had
88 // been set explicitly.
89 Metadata::Bytes(bytes) => bytes.len() == Nonce::LENGTH,
90 Metadata::Derived(_) => false,
91 Metadata::DerivedSigningPubkey(_) => true,
95 pub fn without_keys(self) -> Self {
97 Metadata::Bytes(_) => self,
98 Metadata::Derived(_) => self,
99 Metadata::DerivedSigningPubkey(material) => Metadata::Derived(material),
103 pub fn derive_from<W: Writeable, T: secp256k1::Signing>(
104 self, tlv_stream: W, secp_ctx: Option<&Secp256k1<T>>
105 ) -> (Self, Option<Keypair>) {
107 Metadata::Bytes(_) => (self, None),
108 Metadata::Derived(mut metadata_material) => {
109 tlv_stream.write(&mut metadata_material.hmac).unwrap();
110 (Metadata::Bytes(metadata_material.derive_metadata()), None)
112 Metadata::DerivedSigningPubkey(mut metadata_material) => {
113 tlv_stream.write(&mut metadata_material.hmac).unwrap();
114 let secp_ctx = secp_ctx.unwrap();
115 let (metadata, keys) = metadata_material.derive_metadata_and_keys(secp_ctx);
116 (Metadata::Bytes(metadata), Some(keys))
122 impl Default for Metadata {
123 fn default() -> Self {
124 Metadata::Bytes(vec![])
128 impl fmt::Debug for Metadata {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 Metadata::Bytes(bytes) => bytes.fmt(f),
132 Metadata::Derived(_) => f.write_str("Derived"),
133 Metadata::DerivedSigningPubkey(_) => f.write_str("DerivedSigningPubkey"),
139 impl PartialEq for Metadata {
140 fn eq(&self, other: &Self) -> bool {
142 Metadata::Bytes(bytes) => if let Metadata::Bytes(other_bytes) = other {
147 Metadata::Derived(_) => false,
148 Metadata::DerivedSigningPubkey(_) => false,
153 /// Material used to create metadata for a message.
155 pub(super) struct MetadataMaterial {
157 hmac: HmacEngine<Sha256>,
158 // Some for payer metadata and None for offer metadata
159 encrypted_payment_id: Option<[u8; PaymentId::LENGTH]>,
162 impl MetadataMaterial {
164 nonce: Nonce, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
165 payment_id: Option<PaymentId>
167 // Encrypt payment_id
168 let encrypted_payment_id = payment_id.map(|payment_id| {
169 expanded_key.crypt_for_offer(payment_id.0, nonce)
174 hmac: expanded_key.hmac_for_offer(nonce, iv_bytes),
175 encrypted_payment_id,
179 fn derive_metadata(mut self) -> Vec<u8> {
180 self.hmac.input(DERIVED_METADATA_HMAC_INPUT);
181 self.maybe_include_encrypted_payment_id();
183 let mut bytes = self.encrypted_payment_id.map(|id| id.to_vec()).unwrap_or(vec![]);
184 bytes.extend_from_slice(self.nonce.as_slice());
185 bytes.extend_from_slice(Hmac::from_engine(self.hmac).as_byte_array());
189 fn derive_metadata_and_keys<T: secp256k1::Signing>(
190 mut self, secp_ctx: &Secp256k1<T>
191 ) -> (Vec<u8>, Keypair) {
192 self.hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
193 self.maybe_include_encrypted_payment_id();
195 let mut bytes = self.encrypted_payment_id.map(|id| id.to_vec()).unwrap_or(vec![]);
196 bytes.extend_from_slice(self.nonce.as_slice());
198 let hmac = Hmac::from_engine(self.hmac);
199 let privkey = SecretKey::from_slice(hmac.as_byte_array()).unwrap();
200 let keys = Keypair::from_secret_key(secp_ctx, &privkey);
205 fn maybe_include_encrypted_payment_id(&mut self) {
206 match self.encrypted_payment_id {
207 None => self.hmac.input(WITHOUT_ENCRYPTED_PAYMENT_ID_HMAC_INPUT),
208 Some(encrypted_payment_id) => {
209 self.hmac.input(WITH_ENCRYPTED_PAYMENT_ID_HMAC_INPUT);
210 self.hmac.input(&encrypted_payment_id)
216 pub(super) fn derive_keys(nonce: Nonce, expanded_key: &ExpandedKey) -> Keypair {
217 const IV_BYTES: &[u8; IV_LEN] = b"LDK Invoice ~~~~";
218 let secp_ctx = Secp256k1::new();
219 let hmac = Hmac::from_engine(expanded_key.hmac_for_offer(nonce, IV_BYTES));
220 let privkey = SecretKey::from_slice(hmac.as_byte_array()).unwrap();
221 Keypair::from_secret_key(&secp_ctx, &privkey)
224 /// Verifies data given in a TLV stream was used to produce the given metadata, consisting of:
225 /// - a 256-bit [`PaymentId`],
226 /// - a 128-bit [`Nonce`], and possibly
227 /// - a [`Sha256`] hash of the nonce and the TLV records using the [`ExpandedKey`].
229 /// If the latter is not included in the metadata, the TLV stream is used to check if the given
230 /// `signing_pubkey` can be derived from it.
232 /// Returns the [`PaymentId`] that should be used for sending the payment.
233 pub(super) fn verify_payer_metadata<'a, T: secp256k1::Signing>(
234 metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
235 signing_pubkey: PublicKey, tlv_stream: impl core::iter::Iterator<Item = TlvRecord<'a>>,
236 secp_ctx: &Secp256k1<T>
237 ) -> Result<PaymentId, ()> {
238 if metadata.len() < PaymentId::LENGTH {
242 let mut encrypted_payment_id = [0u8; PaymentId::LENGTH];
243 encrypted_payment_id.copy_from_slice(&metadata[..PaymentId::LENGTH]);
245 let mut hmac = hmac_for_message(
246 &metadata[PaymentId::LENGTH..], expanded_key, iv_bytes, tlv_stream
248 hmac.input(WITH_ENCRYPTED_PAYMENT_ID_HMAC_INPUT);
249 hmac.input(&encrypted_payment_id);
252 &metadata[PaymentId::LENGTH..], Hmac::from_engine(hmac), signing_pubkey, secp_ctx
255 let nonce = Nonce::try_from(&metadata[PaymentId::LENGTH..][..Nonce::LENGTH]).unwrap();
256 let payment_id = expanded_key.crypt_for_offer(encrypted_payment_id, nonce);
258 Ok(PaymentId(payment_id))
261 /// Verifies data given in a TLV stream was used to produce the given metadata, consisting of:
262 /// - a 128-bit [`Nonce`] and possibly
263 /// - a [`Sha256`] hash of the nonce and the TLV records using the [`ExpandedKey`].
265 /// If the latter is not included in the metadata, the TLV stream is used to check if the given
266 /// `signing_pubkey` can be derived from it.
268 /// Returns the [`Keypair`] for signing the invoice, if it can be derived from the metadata.
269 pub(super) fn verify_recipient_metadata<'a, T: secp256k1::Signing>(
270 metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
271 signing_pubkey: PublicKey, tlv_stream: impl core::iter::Iterator<Item = TlvRecord<'a>>,
272 secp_ctx: &Secp256k1<T>
273 ) -> Result<Option<Keypair>, ()> {
274 let mut hmac = hmac_for_message(metadata, expanded_key, iv_bytes, tlv_stream)?;
275 hmac.input(WITHOUT_ENCRYPTED_PAYMENT_ID_HMAC_INPUT);
277 verify_metadata(metadata, Hmac::from_engine(hmac), signing_pubkey, secp_ctx)
280 fn verify_metadata<T: secp256k1::Signing>(
281 metadata: &[u8], hmac: Hmac<Sha256>, signing_pubkey: PublicKey, secp_ctx: &Secp256k1<T>
282 ) -> Result<Option<Keypair>, ()> {
283 if metadata.len() == Nonce::LENGTH {
284 let derived_keys = Keypair::from_secret_key(
285 secp_ctx, &SecretKey::from_slice(hmac.as_byte_array()).unwrap()
287 if fixed_time_eq(&signing_pubkey.serialize(), &derived_keys.public_key().serialize()) {
288 Ok(Some(derived_keys))
292 } else if metadata[Nonce::LENGTH..].len() == Sha256::LEN {
293 if fixed_time_eq(&metadata[Nonce::LENGTH..], &hmac.to_byte_array()) {
303 fn hmac_for_message<'a>(
304 metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
305 tlv_stream: impl core::iter::Iterator<Item = TlvRecord<'a>>
306 ) -> Result<HmacEngine<Sha256>, ()> {
307 if metadata.len() < Nonce::LENGTH {
311 let nonce = match Nonce::try_from(&metadata[..Nonce::LENGTH]) {
313 Err(_) => return Err(()),
315 let mut hmac = expanded_key.hmac_for_offer(nonce, iv_bytes);
317 for record in tlv_stream {
318 hmac.input(record.record_bytes);
321 if metadata.len() == Nonce::LENGTH {
322 hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
324 hmac.input(DERIVED_METADATA_HMAC_INPUT);