From 10e6f46569beb2b0d6f28609fd616eea79446f4f Mon Sep 17 00:00:00 2001 From: Matt David Date: Mon, 22 Feb 2016 12:04:54 -0800 Subject: [PATCH] - Make message public key sharing mandatory for messages that are encrypted and where both keys are known. For EncryptedInvoiceRequest, only the sender_public_key is required - Add nonce to EncryptedPaymentRequest, EncryptedPayment and EncryptedPaymentACK - Update ECDH instruction to allow for the current message instead of an InvoiceRequest to contain the nonce - Updated paymentrequest.proto with BIP definition changes --- bip-invoicerequest-extension.mediawiki | 84 ++++++++++++++++++-------- bip-ir/paymentrequest.proto | 49 +++++++++------ 2 files changed, 92 insertions(+), 41 deletions(-) diff --git a/bip-invoicerequest-extension.mediawiki b/bip-invoicerequest-extension.mediawiki index 1ca2ffd..c9f1c2e 100644 --- a/bip-invoicerequest-extension.mediawiki +++ b/bip-invoicerequest-extension.mediawiki @@ -145,13 +145,15 @@ message EncryptedInvoiceRequest { |- | sender_public_key || Sender's EC public key |- -| receiver_public_key || Receiver's EC public key, can be omitted if this message is sent directly to the recipient, or is sent to a Store & Forward server that already understands who the recipient should be (if specified by URI endpoint, for example) +| receiver_public_key || Receiver's EC public key |- | nonce || The nonce in use for the CBC encryption |- -| identifier || A unique key to identify this entire exchange on the server. By default, invoice_request_hash SHOULD be used. +| identifier || A unique key to identify this entire exchange on the server. invoice_request_hash SHOULD be used by default. |} +receiver_public_key MAY be omitted if this message is sent directly to the Receiver. receiver_public_key MAY also be omitted if the EncryptedInvoiceRequest is being sent to a Store & Forward server which already understands who the Receiver is. An example of this is a Store & Forward server URL that uniquely identifies the Receiver (and their public key). + ===EncryptedPaymentRequest=== The EncryptedPaymentRequest message is an encapsulating message that allows the transmission of an encrypted, serialized PaymentRequest. @@ -160,12 +162,12 @@ The EncryptedPaymentRequest message is an encapsulating message that allows the message EncryptedPaymentRequest { required bytes encrypted_payment_request = 1; required bytes payment_request_hash = 2; - optional bytes receiver_public_key = 3; - optional bytes sender_public_key = 4; - optional uint64 nonce = 5; + required bytes receiver_public_key = 3; + required bytes sender_public_key = 4; + required uint64 nonce = 5; optional bool requires_payment_message = 6; optional bytes signature = 7; - optional bytes identifier = 6; + optional bytes identifier = 8; } {| class="wikitable" @@ -175,17 +177,17 @@ message EncryptedPaymentRequest { |- | payment_request_hash || SHA256 Hash of non-encrypted, serialized PaymentRequest. MUST be used for verification to prevent oracle attacks. |- -| receiver_public_key || Receiver's EC public key, only necessary if not already shared or known (for example, if this message is not in response to an InvoiceRequest) +| receiver_public_key || Receiver's EC public key |- -| sender_public_key || Sender's EC public key, can be omitted if this message is sent directly to the recipient, or is sent to a Store & Forward server that already understands who the recipient should be (if specified by URI endpoint, for example) +| sender_public_key || Sender's EC public key |- -| nonce || The nonce in use for the CBC encryption, only necessary if not already shared (for example, if this message is not in response to an InvoiceRequest) +| nonce || The nonce in use for the CBC encryption |- | requires_payment_message || Internal PaymentRequest requires follow-up Payment message |- -| signature || A signature of this message using Receiver's EC key, serialized with a value of "" for signature. Only necessary if required by the server to authenticate a reply to an InvoiceRequest. +| signature || A signature of this message using Receiver's EC key, serialized with a value of "" for signature. REQUIRED if server requires InvoiceRequest reply authentication. |- -| identifier || If the PaymentRequest is in response to an InvoiceRequest, use the identifier specified with the InvoiceRequest, if any. Otherwise, use payment_request_hash or other unique value. +| identifier || MUST use the identifier specified with the InvoiceRequest if the PaymentRequest is in response to an InvoiceRequest. Otherwise, use payment_request_hash or other unique value. |} ===EncryptedPayment=== @@ -194,10 +196,13 @@ The EncryptedPayment message allows a BIP70 Payment message to be transmitted th
 message EncryptedPayment {
-        required bytes encrypted_payment = 1;
-        required bytes payment_hash = 2;
-        required bytes signature = 3;
-        optional bytes identifier = 4;
+        required bytes  encrypted_payment = 1;
+        required bytes  payment_hash = 2;
+        required bytes  receiver_public_key = 3;
+        required bytes  sender_public_key = 4;
+        required uint64 nonce = 5;
+        required bytes  signature = 6;
+        optional bytes  identifier = 7;
 }
 
{| class="wikitable" @@ -207,6 +212,12 @@ message EncryptedPayment { |- | payment_hash || SHA256 Hash of original non-encrypted, serialized Payment message. MUST be used for verification to prevent oracle attacks. |- +| receiver_public_key || Receiver's EC public key +|- +| sender_public_key || Sender's EC public key +|- +| nonce || The nonce in use for the CBC encryption +|- | signature || A signature of this message using Sender's EC key, serialized with a value of "" for signature. |- | identifier || Use the identifier specified with the EncryptedPaymentRequest, if any. @@ -218,10 +229,13 @@ An encrypted version of the BIP70 PaymentAck.
 message EncryptedPaymentACK {
-        required bytes encrypted_payment_ack = 1;
-        required bytes payment_ack_hash = 2;
-        required bytes signature = 3;
-        optional bytes identifier = 4;
+        required bytes  encrypted_payment_ack = 1;
+        required bytes  payment_ack_hash = 2;
+        required bytes  receiver_public_key = 3;
+        required bytes  sender_public_key = 4;
+        required uint64 nonce = 5;
+        required bytes  signature = 6;
+        optional bytes  identifier = 7;
 }
 
{| class="wikitable" @@ -231,6 +245,12 @@ message EncryptedPaymentACK { |- | payment_ack_hash || SHA256 Hash of original non-encrypted, serialized Payment message. MUST be used for verification to prevent oracle attacks. |- +| receiver_public_key || Receiver's EC public key +|- +| sender_public_key || Sender's EC public key +|- +| nonce || The nonce in use for the CBC encryption +|- | signature || A signature of this message using Receiver's EC key, serialized with a value of "" for signature. |- | identifier || Use the identifier specified with the EncryptedPayment, if any. @@ -301,10 +321,12 @@ SHOULD be done through standard HTTP Status Code messaging ([https://tools.ietf. For the following we assume the Sender already knows the Receiver's public key, and the exchange starts with an EncryptedInvoiceRequest. +Where used, **nonce** MUST be set to a non-repeating number. The current epoch time in microseconds SHOULD be used, unless the creating device doesn't have access to a RTC (in the case of a smart card, for example). The service receiving the message containing the **nonce** MAY use whatever method to make sure that the **nonce** is never repeated. + ===InvoiceRequest Message Creation=== * Create an InvoiceRequest message * sender_public_key MUST be set to the public key of an EC keypair -* nonce MUST be set to a non-repeating number. The current epoch time in microseconds SHOULD be used, unless the creating device doesn't have access to a RTC (in the case of a smart card, for example) +* nonce MUST be set according to the requirement above. * Amount is optional. If the amount is not specified by the InvoiceRequest, the Receiver MAY specify the amount in the returned PaymentRequest. If an amount is specified by the InvoiceRequest and a PaymentRequest cannot be generated for that amount, the InvoiceRequest SHOULD be rejected with HTTP status code 406. * Memo is optional. This MAY be set to a human readable description of the InvoiceRequest * Set notification_url to URL that the Receiver will submit completed EncryptedPaymentRequest to @@ -318,10 +340,12 @@ For the following we assume the Sender already knows the Receiver's public key, ===EncryptedInvoiceRequest Message Creation=== * Create an EncryptedInvoiceRequest * Retrieve endpoint public key to use in ECDH Point Generation as specified in Initial Public Key Retrieval for InvoiceRequest Encryption (see below) -* sender_public_key MUST be set to the public key of an EC keypair +* sender_public_key MUST be set to the public key of the Sender's EC keypair +* receiver_public_key MAY be set to the public key of the Receiver's EC keypair * invoice_request_hash MUST be set to the SHA256 hash of the serialized InvoiceRequest (without encryption) * Encrypt the serialized InvoiceRequest using AES-256-CBC setup as described in ECDH Point Generation and AES-256 (CBC Mode) Setup (see below) * encrypted_invoice_Request MUST be set to the encrypted values of the InvoiceRequest +* nonce MUST be set to the nonce used in the AES-256-CBC encryption operation * Set identifier to invoice_request_hash ===InvoiceRequest Validation=== @@ -336,9 +360,14 @@ For the following we assume the Sender already knows the Receiver's public key, * Create EncryptedPaymentRequest message * Set encrypted_payment_request to be the encrypted value of the PaymentRequest * Set payment_request_hash to generated SHA256 hash of the serialized PaymentRequest (without encryption) +* sender_public_key MUST be set to the public key of the Sender's EC keypair +* receiver_public_key MUST be set to the public key of the Receiver's EC keypair +* nonce MUST be set to the nonce used in the AES-256-CBC encryption operation +* requires_payment_message MAY be set to true if the PaymentRequest requires a Payment message * Set identifier to the value received in EncryptedInvoiceRequest * Set signature to "" * Sign the serialized EncryptedPayment message with the Receiver's EC public key +* Set signature to the result of the signature operation above ===EncryptedPaymentRequest Validation and Decryption=== * Decrypt the serialized PaymentRequest using AES-256-CBC setup as described in ECDH Point Generation and AES-256 (CBC Mode) Setup (see below) @@ -349,7 +378,7 @@ For the following we assume the Sender already knows the Receiver's public key, * Generate the '''secret point''' using [https://en.wikipedia.org/wiki/Elliptic_curve_Diffie–Hellman ECDH] using the local entity's private key and the remote entity's public key as inputs. * Initialize [http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf HMAC_DRBG] ** Use '''secret point's''' X value for Entropy -** Use the given InvoiceRequest's nonce field for Nonce +** Use the given message's nonce field for Nonce * Initialize AES-256 in CBC Mode ** Use HMAC_DRBG.GENERATE(32) as the Encryption Key (256 bits) ** Use HMAC_DRBG.GENERATE(16) as the Initialization Vector (IV) (128 bits) @@ -366,8 +395,11 @@ Initial public key retrieval for InvoiceRequest encryption can be done in a numb * Encrypt the serialized Payment using AES-256-CBC using secret key calculated in the EncryptedPaymentRequest Message Creation and PaymentRequest Encryption step (see above) * Create EncryptedPayment message * Set encrypted_payment to be the encrypted value of the Payment -* Set identifier to the value received in EncryptedPaymentRequest * Set payment_hash to generated SHA256 hash of the serialized Payment (without encryption) +* sender_public_key MUST be set to the public key of the Sender's EC keypair +* receiver_public_key MUST be set to the public key of the Receiver's EC keypair +* nonce MUST be set to the nonce used in the AES-256-CBC encryption operation +* Set identifier to the value received in EncryptedPaymentRequest * Set signature to "" * Sign the serialized EncryptedPayment message with the Sender's EC public key * Set signature to the result of the signature operation above @@ -377,6 +409,10 @@ Initial public key retrieval for InvoiceRequest encryption can be done in a numb * Create EncryptedPaymentACK message * Set encrypted_payment_ack to be the encrypted value of the PaymentACK * Set payment_ack_hash to generated SHA256 hash of the serialized PaymentACK (without encryption) +* sender_public_key MUST be set to the public key of the Sender's EC keypair +* receiver_public_key MUST be set to the public key of the Receiver's EC keypair +* nonce MUST be set to the nonce used in the AES-256-CBC encryption operation +* Set identifier to the value received in EncryptedPaymentRequest * Set signature to "" * Sign the serialized EncryptedPaymentACK message with the Receiver's EC public key * Set signature to the result of the signature operation above @@ -432,4 +468,4 @@ In this case, the Sender submits the transaction to the bitcoin network. * [https://en.wikipedia.org/wiki/Elliptic_curve_Diffie–Hellman ECDH] * [http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf HMAC_DRBG] * [https://tools.ietf.org/html/rfc6979 RFC6979] -* [https://en.bitcoin.it/wiki/Address_reuse Address Reuse] +* [https://en.bitcoin.it/wiki/Address_reuse Address Reuse] \ No newline at end of file diff --git a/bip-ir/paymentrequest.proto b/bip-ir/paymentrequest.proto index 5fcd65f..8c99f24 100644 --- a/bip-ir/paymentrequest.proto +++ b/bip-ir/paymentrequest.proto @@ -46,11 +46,6 @@ message PaymentACK { } // BIP-IR Extensions -message EncryptedInvoiceRequest { - required bytes encrypted_invoice_request = 1; // AES-256-CBC Encrypted InvoiceRequest as defined in InvoiceRequest Spec - required bytes sender_public_key = 2; // Sender's EC Public Key - required bytes invoice_request_hash = 3; // SHA256 Hash of Non-Encrypted, Serialized InvoiceRequest (used for authentication) -} message InvoiceRequest { required bytes sender_public_key = 1; // Sender's EC Public Key @@ -63,22 +58,42 @@ message InvoiceRequest { optional bytes signature = 8; // PKI-dependent signature } +message EncryptedInvoiceRequest { + required bytes encrypted_invoice_request = 1; // AES-256-CBC Encrypted InvoiceRequest as defined in InvoiceRequest Spec + required bytes invoice_request_hash = 2; // SHA256 Hash of Non-Encrypted, Serialized InvoiceRequest (used for authentication) + required bytes sender_public_key = 3; // Sender's EC Public Key + optional bytes receiver_public_key = 4; // Receiver's EC Public Key + required uint64 nonce = 5; // Microseconds since epoch + optional bytes identifier = 6; // Unique key to identify this entire exchange on the server. invoice_request_hash SHOULD be used by default +} + message EncryptedPaymentRequest { - required bytes encrypted_payment_request = 1; // AES-256-CBC Encrypted PaymentRequest as defined in InvoiceRequest Spec - required bytes receiver_public_key = 2; // Receiver's EC Public Key - required bytes ephemeral_public_key = 3; // Public Key of ECDH-derived keypair - required bytes payment_request_hash = 4; // SHA256 Hash of Non-Encrypted, Serialized PaymentRequest (used for authentication) - required bool requires_payment_message = 5 [default = false]; // Requires Payment/PaymentACK message exchange + required bytes encrypted_payment_request = 1; // AES-256-CBC Encrypted PaymentRequest as defined in InvoiceRequest Spec + required bytes payment_request_hash = 2; // SHA256 Hash of Non-Encrypted, Serialized PaymentRequest (used for authentication) + required bytes receiver_public_key = 3; // Receiver's EC Public Key + required bytes sender_public_key = 4; // Sender's EC Public Key + required uint64 nonce = 5; // Microseconds since epoch + optional bool requires_payment_message = 6 [default = false]; // Requires Payment/PaymentACK message exchange + optional bytes signature = 7; // Signature of this message using Receiver's EC key + optional bytes identifier = 8; // MUST use the identifier specified with the InvoiceRequest if the PaymentRequest is in response to an InvoiceRequest. Otherwise, use payment_request_hash or other unique value. } message EncryptedPayment { - required bytes encrypted_payment = 1; // AES-256-CBC Encrypted Payment as defined in InvoiceRequest Spec - required bytes payment_request_hash = 2; // SHA256 Hash of Non-Encrypted, Serialized PaymentRequest returned in the transaction's EncryptedPaymentRequest message - required bytes signature = 3; // Signature over EncryptedPayment with original Sender's EC Private Key + required bytes encrypted_payment = 1; // AES-256-CBC Encrypted BIP70 Payment as defined in InvoiceRequest Spec + required bytes payment_hash = 2; // SHA256 Hash of Non-Encrypted, Serialized BIP70 Payment + required bytes receiver_public_key = 3; // Receiver's EC Public Key + required bytes sender_public_key = 4; // Sender's EC Public Key + required uint64 nonce = 5; // Microseconds since epoch + required bytes signature = 6; // Signature over EncryptedPayment with Sender's EC Key + optional bytes identifier = 7; // Use the identifier specified with the EncryptedPaymentRequest, if any. } message EncryptedPaymentACK { - required bytes encrypted_payment_ack = 1; // AES-256-CBC Encrypted Payment as defined in InvoiceRequest Spec - required bytes payment_request_hash = 2; // SHA256 Hash of Non-Encrypted, Serialized PaymentRequest returned in the transaction's EncryptedPaymentRequest message - required bytes signature = 3; // Signature over EncryptedPaymentACK with the Receiver's EC Private key. -} \ No newline at end of file + required bytes encrypted_payment_ack = 1; // AES-256-CBC Encrypted BIP70 PaymentACK as defined in InvoiceRequest Spec + required bytes payment_ack_hash = 2; // SHA256 Hash of Non-Encrypted, Serialized BIP70 PaymentACK + required bytes receiver_public_key = 3; // Receiver's EC Public Key + required bytes sender_public_key = 4; // Sender's EC Public Key + required uint64 nonce = 5; // Microseconds since epoch + required bytes signature = 6; // Signature over EncryptedPaymentACK with Receiver's EC Key + optional bytes identifier = 7; // Use the identifier specified with the EncryptedPaymentRequest, if any. +}