from cryptography.exceptions import InvalidTag from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 from cryptography.hazmat.primitives.kdf.hkdf import HKDF from .primitives import Secret, PrivateKey, PublicKey from hashlib import sha256 from typing import Tuple import coincurve import os import socket import socks import struct import threading __all__ = [ 'PrivateKey', 'PublicKey', 'Secret', 'LightningConnection', 'LightningServerSocket', 'connect' ] def hkdf(ikm, salt=b"", info=b""): hkdf = HKDF( algorithm=hashes.SHA256(), length=64, salt=salt, info=info, backend=default_backend()) return hkdf.derive(ikm) def hkdf_two_keys(ikm, salt): t = hkdf(ikm, salt) return t[:32], t[32:] def ecdh(k, rk): k = coincurve.PrivateKey(secret=k.rawkey) rk = coincurve.PublicKey(data=rk.serializeCompressed()) a = k.ecdh(rk.public_key) return Secret(a) def encryptWithAD(k, n, ad, plaintext): chacha = ChaCha20Poly1305(k) return chacha.encrypt(n, plaintext, ad) def decryptWithAD(k, n, ad, ciphertext): chacha = ChaCha20Poly1305(k) return chacha.decrypt(n, ciphertext, ad) class Sha256Mixer(object): def __init__(self, base): self.hash = sha256(base).digest() def update(self, data): h = sha256(self.hash) h.update(data) self.hash = h.digest() return self.hash def digest(self): return self.hash def __str__(self): return "Sha256Mixer[0x{}]".format(self.hash.hex()) class LightningConnection(object): def __init__(self, connection, remote_pubkey, local_privkey, is_initiator): self.connection = connection self.chaining_key = None self.handshake_hash = None self.local_privkey = local_privkey self.local_pubkey = self.local_privkey.public_key() self.remote_pubkey = remote_pubkey self.is_initiator = is_initiator self.init_handshake() self.rn, self.sn = 0, 0 self.send_lock, self.recv_lock = threading.Lock(), threading.Lock() @classmethod def nonce(cls, n): """Transforms a numeric nonce into a byte formatted one Nonce n encoded as 32 zero bits, followed by a little-endian 64-bit value. Note: this follows the Noise Protocol convention, rather than our normal endian. """ return b'\x00' * 4 + struct.pack("