From 74817948cc9841bb0ddaf3353542edb8a6ed5760 Mon Sep 17 00:00:00 2001 From: Jonathan Zernik Date: Fri, 3 Jul 2020 21:51:47 -0700 Subject: [PATCH] Use new squeak protocol (#64) * Use new squeak protocol with encryption/decryption key instead of data key hash. * Use from_bytes method for encrypted decryption key * Undo changes to use temporary local install of squeaklib --- docker/sqkserver/Dockerfile | 8 +++--- docker/test/Dockerfile | 8 +++--- init.sql | 5 ++-- itests/test.py | 17 ++++++++--- squeakserver/common/rpc/squeak_server.proto | 19 +++++++------ squeakserver/server/buy_offer.py | 5 ++-- squeakserver/server/postgres_db.py | 24 ++++++++-------- squeakserver/server/squeak_server_handler.py | 28 ++++++++++++------- squeakserver/server/squeak_server_servicer.py | 4 +-- squeakserver/server/util.py | 4 +++ 10 files changed, 75 insertions(+), 47 deletions(-) diff --git a/docker/sqkserver/Dockerfile b/docker/sqkserver/Dockerfile index bb3613fb..0b17a91d 100644 --- a/docker/sqkserver/Dockerfile +++ b/docker/sqkserver/Dockerfile @@ -7,15 +7,15 @@ RUN apt-get update && apt-get install -y \ curl \ git +# Download the rpc files. +RUN git clone https://github.com/googleapis/googleapis.git +RUN curl -o rpc.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/rpc.proto + COPY requirements.txt / RUN pip3 install --upgrade pip RUN pip3 install -r requirements.txt -# Download the rpc files. -RUN git clone https://github.com/googleapis/googleapis.git -RUN curl -o rpc.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/rpc.proto - # Copy the source code. COPY . /app diff --git a/docker/test/Dockerfile b/docker/test/Dockerfile index 33c8da61..07dc86ef 100644 --- a/docker/test/Dockerfile +++ b/docker/test/Dockerfile @@ -6,15 +6,15 @@ RUN apt-get update && apt-get install -y \ curl \ git +# Download the rpc files. +RUN git clone https://github.com/googleapis/googleapis.git +RUN curl -o rpc.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/rpc.proto + COPY requirements-itest.txt / RUN pip3 install --upgrade pip RUN pip3 install -r requirements-itest.txt -RUN git clone https://github.com/googleapis/googleapis.git - -RUN curl -o rpc.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/rpc.proto - Run mkdir /app COPY ./squeakserver/common/rpc/squeak_server.proto /app RUN cp -r googleapis /app diff --git a/init.sql b/init.sql index 326391ee..ac3517d1 100644 --- a/init.sql +++ b/init.sql @@ -7,14 +7,15 @@ CREATE TABLE IF NOT EXISTS squeak ( hashBlock CHAR(64) NOT NULL, nBlockHeight INTEGER NOT NULL, scriptPubKey VARCHAR(100) NOT NULL, - hashDataKey CHAR(64) NOT NULL, + encryptionKey CHAR(324) NOT NULL, + encDatakey CHAR(256) NOT NULL, vchIv CHAR(32) NOT NULL, nTime INTEGER NOT NULL, nNonce BIGINT NOT NULL, encContent CHAR(2272) NOT NULL, scriptSig VARCHAR(400) NOT NULL, address VARCHAR(50) NOT NULL, - vchDataKey CHAR(64), + vchDecryptionKey VARCHAR(8000), content CHAR(1120) ); diff --git a/itests/test.py b/itests/test.py index 3a9bc969..6c7dd747 100644 --- a/itests/test.py +++ b/itests/test.py @@ -10,6 +10,7 @@ from squeak.core import CSqueak from squeak.core import CheckSqueak from squeak.core import HASH_LENGTH from squeak.core import MakeSqueakFromStr +from squeak.core.encryption import CEncryptedDecryptionKey from squeak.core.signing import CSigningKey from squeak.core.signing import CSqueakAddress @@ -196,10 +197,18 @@ def run(): preimage = payment.payment_preimage print("preimage: " + str(preimage)) - # Clear the data key from the squeak and verify with the payment preimage - new_data_key = bxor(buy_response.offer.nonce, preimage) - print("new data key: " + str(new_data_key)) - get_response_squeak.SetDataKey(new_data_key) + # Verify with the payment preimage and decryption key ciphertext + decryption_key_cipher_bytes = buy_response.offer.key_cipher + iv = buy_response.offer.iv + encrypted_decryption_key = CEncryptedDecryptionKey.from_bytes(decryption_key_cipher_bytes) + + # Decrypt the decryption key + decryption_key = encrypted_decryption_key.get_decryption_key(preimage, iv) + serialized_decryption_key = decryption_key.serialize() + + print("new decryption key: " + str(decryption_key)) + print("new decryption key: " + str(serialized_decryption_key)) + get_response_squeak.SetDecryptionKey(serialized_decryption_key) CheckSqueak(get_response_squeak) assert get_response_squeak.GetDecryptedContentStr() == 'hello from itest!' print("Finished checking squeak.") diff --git a/squeakserver/common/rpc/squeak_server.proto b/squeakserver/common/rpc/squeak_server.proto index 457fdfaa..bd4266a1 100644 --- a/squeakserver/common/rpc/squeak_server.proto +++ b/squeakserver/common/rpc/squeak_server.proto @@ -82,24 +82,27 @@ message SqueakBuyOffer { /// The squeak hash. bytes squeak_hash = 1; - /// The decryption nonce - bytes nonce = 2; + /// The decrypted decryption key + bytes key_cipher = 3; + + /// The decryption iv + bytes iv = 4; /// The amount - int64 amount = 3; + int64 amount = 5; /// The invoice preimage hash. - bytes preimage_hash = 4; + bytes preimage_hash = 6; /// The invoice - string payment_request = 5; + string payment_request = 7; /// The seller node pubkey - string pubkey = 6; + string pubkey = 8; /// The host of the seller lightning node - string host = 7; + string host = 9; /// The port of the seller lightning node - int32 port = 8; + int32 port = 10; } diff --git a/squeakserver/server/buy_offer.py b/squeakserver/server/buy_offer.py index dd89ed1b..45645a93 100644 --- a/squeakserver/server/buy_offer.py +++ b/squeakserver/server/buy_offer.py @@ -2,9 +2,10 @@ class BuyOffer(): - def __init__(self, squeak_hash, nonce, amount, preimage_hash, payment_request, pubkey, host, port): + def __init__(self, squeak_hash, key_cipher, iv, amount, preimage_hash, payment_request, pubkey, host, port): self.squeak_hash = squeak_hash - self.nonce = nonce + self.key_cipher = key_cipher + self.iv = iv self.amount = amount self.preimage_hash = preimage_hash self.payment_request = payment_request diff --git a/squeakserver/server/postgres_db.py b/squeakserver/server/postgres_db.py index db13eb5e..1c74124d 100644 --- a/squeakserver/server/postgres_db.py +++ b/squeakserver/server/postgres_db.py @@ -51,8 +51,8 @@ class PostgresDb(): def insert_squeak(self, squeak): """ Insert a new squeak. """ sql = """ - INSERT INTO squeak(hash, nVersion, hashEncContent, hashReplySqk, hashBlock, nBlockHeight, scriptPubKey, hashDataKey, vchIv, nTime, nNonce, encContent, scriptSig, address, vchDataKey, content) - VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + INSERT INTO squeak(hash, nVersion, hashEncContent, hashReplySqk, hashBlock, nBlockHeight, scriptPubKey, encryptionKey, encDatakey, vchIv, nTime, nNonce, encContent, scriptSig, address, vchDecryptionKey, content) + VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING hash;""" with self.get_cursor() as curs: @@ -65,14 +65,15 @@ class PostgresDb(): squeak.hashBlock.hex(), squeak.nBlockHeight, bytes(squeak.scriptPubKey).hex(), - squeak.hashDataKey.hex(), + squeak.vchEncryptionKey.hex(), + squeak.vchEncDatakey.hex(), squeak.vchIv.hex(), squeak.nTime, squeak.nNonce, bytes(squeak.encContent.vchEncContent).hex(), bytes(squeak.scriptSig).hex(), str(squeak.GetAddress()), - squeak.vchDataKey.hex(), + squeak.vchDecryptionKey.hex(), squeak.GetDecryptedContentStr(), )) # get the generated hash back @@ -97,13 +98,14 @@ class PostgresDb(): hashBlock=bytes.fromhex(row[5]), nBlockHeight=row[6], scriptPubKey=CScript(bytes.fromhex(row[7])), - hashDataKey=bytes.fromhex(row[8]), - vchIv=bytes.fromhex((row[9])), - nTime=row[10], - nNonce=row[11], - encContent=CSqueakEncContent(bytes.fromhex((row[12]))), - scriptSig=CScript(bytes.fromhex((row[13]))), - vchDataKey=bytes.fromhex((row[15])), + vchEncryptionKey=bytes.fromhex(row[8]), + vchEncDatakey=bytes.fromhex(row[9]), + vchIv=bytes.fromhex((row[10])), + nTime=row[11], + nNonce=row[12], + encContent=CSqueakEncContent(bytes.fromhex((row[13]))), + scriptSig=CScript(bytes.fromhex((row[14]))), + vchDecryptionKey=bytes.fromhex((row[16])), ) return squeak diff --git a/squeakserver/server/squeak_server_handler.py b/squeakserver/server/squeak_server_handler.py index 279b27d4..c4dfdc7c 100644 --- a/squeakserver/server/squeak_server_handler.py +++ b/squeakserver/server/squeak_server_handler.py @@ -1,6 +1,8 @@ import logging import threading +from squeak.core.encryption import generate_initialization_vector +from squeak.core.encryption import CEncryptedDecryptionKey from squeak.core.signing import CSigningKey from squeak.core.signing import CSqueakAddress @@ -8,7 +10,7 @@ from squeakserver.server.buy_offer import BuyOffer from squeakserver.common.lnd_lightning_client import LNDLightningClient from squeakserver.server.lightning_address import LightningAddressHostPort from squeakserver.server.postgres_db import PostgresDb -from squeakserver.server.util import generate_offer_nonce +from squeakserver.server.util import generate_offer_preimage from squeakserver.server.util import bxor from squeakserver.server.util import get_hash @@ -41,8 +43,8 @@ class SqueakServerHandler(object): def handle_get_squeak(self, squeak_hash): logger.info("Handle get squeak by hash: {}".format(squeak_hash.hex())) squeak = self.postgres_db.get_squeak(squeak_hash) - # Remove the data key before sending response. - squeak.ClearDataKey() + # Remove the decryption key before sending response. + squeak.ClearDecryptionKey() return squeak def handle_lookup_squeaks(self, addresses, min_block, max_block): @@ -55,12 +57,17 @@ class SqueakServerHandler(object): logger.info("Handle buy squeak by hash: {}".format(squeak_hash.hex())) # Get the squeak from the database squeak = self.postgres_db.get_squeak(squeak_hash) - # Get the datakey from the squeak - data_key = squeak.GetDataKey() - # Generate a new random offer nonce - nonce = generate_offer_nonce() - # Get the invoice preimage from the nonce and the squeak data key - preimage = bxor(nonce, data_key) + + # Get the decryption key from the squeak + decryption_key = squeak.GetDecryptionKey() + + # Generate a new random preimage + preimage = generate_offer_preimage() + + # Encrypt the decryption key + iv = generate_initialization_vector() + encrypted_decryption_key = CEncryptedDecryptionKey.from_decryption_key(decryption_key, preimage, iv) + # Get the offer price amount = self.price # Create the lightning invoice @@ -73,7 +80,8 @@ class SqueakServerHandler(object): # Return the buy offer return BuyOffer( squeak_hash, - nonce, + encrypted_decryption_key, + iv, amount, preimage_hash, invoice_payment_request, diff --git a/squeakserver/server/squeak_server_servicer.py b/squeakserver/server/squeak_server_servicer.py index b30ea672..8b13decb 100644 --- a/squeakserver/server/squeak_server_servicer.py +++ b/squeakserver/server/squeak_server_servicer.py @@ -87,7 +87,6 @@ class SqueakServerServicer(squeak_server_pb2_grpc.SqueakServerServicer): offer_squeak_hash = buy_response.squeak_hash amount = buy_response.amount - nonce = buy_response.nonce if offer_squeak_hash != squeak_hash: context.set_code(grpc.StatusCode.INVALID_ARGUMENT) @@ -98,7 +97,8 @@ class SqueakServerServicer(squeak_server_pb2_grpc.SqueakServerServicer): return squeak_server_pb2.BuySqueakReply( offer=squeak_server_pb2.SqueakBuyOffer( squeak_hash=offer_squeak_hash, - nonce=nonce, + key_cipher=buy_response.key_cipher.cipher_bytes, + iv=buy_response.iv, amount=amount, preimage_hash=buy_response.preimage_hash, payment_request=buy_response.payment_request, diff --git a/squeakserver/server/util.py b/squeakserver/server/util.py index d971fe21..1ec67daf 100644 --- a/squeakserver/server/util.py +++ b/squeakserver/server/util.py @@ -12,6 +12,10 @@ def generate_offer_nonce(): return os.urandom(DATA_KEY_LENGTH) +def generate_offer_preimage(): + return os.urandom(DATA_KEY_LENGTH) + + def bxor(b1, b2): # use xor for bytes result = bytearray() for b1, b2 in zip(b1, b2):