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
This commit is contained in:
Jonathan Zernik 2020-07-03 21:51:47 -07:00 committed by GitHub
parent 6fd4940a0a
commit 74817948cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 75 additions and 47 deletions

View file

@ -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

View file

@ -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

View file

@ -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)
);

View file

@ -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.")

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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):