mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
lnonion: implement error packet construction
This commit is contained in:
parent
1503227bbf
commit
5538b9bb8a
2 changed files with 44 additions and 7 deletions
|
@ -33,7 +33,7 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
|
||||||
from . import ecc
|
from . import ecc
|
||||||
from .crypto import sha256
|
from .crypto import sha256, hmac_oneshot
|
||||||
from .util import bh2u, profiler, xor_bytes, bfh
|
from .util import bh2u, profiler, xor_bytes, bfh
|
||||||
from .lnutil import get_ecdh
|
from .lnutil import get_ecdh
|
||||||
from .lnrouter import RouteEdge
|
from .lnrouter import RouteEdge
|
||||||
|
@ -139,7 +139,7 @@ class OnionPacket:
|
||||||
def get_bolt04_onion_key(key_type: bytes, secret: bytes) -> bytes:
|
def get_bolt04_onion_key(key_type: bytes, secret: bytes) -> bytes:
|
||||||
if key_type not in (b'rho', b'mu', b'um', b'ammag'):
|
if key_type not in (b'rho', b'mu', b'um', b'ammag'):
|
||||||
raise Exception('invalid key_type {}'.format(key_type))
|
raise Exception('invalid key_type {}'.format(key_type))
|
||||||
key = hmac.new(key_type, msg=secret, digestmod=hashlib.sha256).digest()
|
key = hmac_oneshot(key_type, msg=secret, digest=hashlib.sha256)
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ def new_onion_packet(payment_path_pubkeys: Sequence[bytes], session_key: bytes,
|
||||||
if i == num_hops - 1 and len(filler) != 0:
|
if i == num_hops - 1 and len(filler) != 0:
|
||||||
mix_header = mix_header[:-len(filler)] + filler
|
mix_header = mix_header[:-len(filler)] + filler
|
||||||
packet = mix_header + associated_data
|
packet = mix_header + associated_data
|
||||||
next_hmac = hmac.new(mu_key, msg=packet, digestmod=hashlib.sha256).digest()
|
next_hmac = hmac_oneshot(mu_key, msg=packet, digest=hashlib.sha256)
|
||||||
|
|
||||||
return OnionPacket(
|
return OnionPacket(
|
||||||
public_key=ecc.ECPrivkey(session_key).get_public_key_bytes(),
|
public_key=ecc.ECPrivkey(session_key).get_public_key_bytes(),
|
||||||
|
@ -241,8 +241,8 @@ def process_onion_packet(onion_packet: OnionPacket, associated_data: bytes,
|
||||||
|
|
||||||
# check message integrity
|
# check message integrity
|
||||||
mu_key = get_bolt04_onion_key(b'mu', shared_secret)
|
mu_key = get_bolt04_onion_key(b'mu', shared_secret)
|
||||||
calculated_mac = hmac.new(mu_key, msg=onion_packet.hops_data+associated_data,
|
calculated_mac = hmac_oneshot(mu_key, msg=onion_packet.hops_data+associated_data,
|
||||||
digestmod=hashlib.sha256).digest()
|
digest=hashlib.sha256)
|
||||||
if onion_packet.hmac != calculated_mac:
|
if onion_packet.hmac != calculated_mac:
|
||||||
raise InvalidOnionMac()
|
raise InvalidOnionMac()
|
||||||
|
|
||||||
|
@ -285,6 +285,35 @@ class OnionRoutingFailureMessage:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return repr((self.code, self.data))
|
return repr((self.code, self.data))
|
||||||
|
|
||||||
|
def to_bytes(self) -> bytes:
|
||||||
|
ret = self.code.to_bytes(2, byteorder="big")
|
||||||
|
ret += self.data
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def construct_onion_error(reason: OnionRoutingFailureMessage,
|
||||||
|
onion_packet: OnionPacket,
|
||||||
|
our_onion_private_key: bytes) -> bytes:
|
||||||
|
# create payload
|
||||||
|
failure_msg = reason.to_bytes()
|
||||||
|
failure_len = len(failure_msg)
|
||||||
|
pad_len = 256 - failure_len
|
||||||
|
assert pad_len >= 0
|
||||||
|
error_packet = failure_len.to_bytes(2, byteorder="big")
|
||||||
|
error_packet += failure_msg
|
||||||
|
error_packet += pad_len.to_bytes(2, byteorder="big")
|
||||||
|
error_packet += bytes(pad_len)
|
||||||
|
# add hmac
|
||||||
|
shared_secret = get_ecdh(our_onion_private_key, onion_packet.public_key)
|
||||||
|
um_key = get_bolt04_onion_key(b'um', shared_secret)
|
||||||
|
hmac_ = hmac_oneshot(um_key, msg=error_packet, digest=hashlib.sha256)
|
||||||
|
error_packet = hmac_ + error_packet
|
||||||
|
# obfuscate
|
||||||
|
ammag_key = get_bolt04_onion_key(b'ammag', shared_secret)
|
||||||
|
stream_bytes = generate_cipher_stream(ammag_key, len(error_packet))
|
||||||
|
error_packet = xor_bytes(error_packet, stream_bytes)
|
||||||
|
return error_packet
|
||||||
|
|
||||||
|
|
||||||
def _decode_onion_error(error_packet: bytes, payment_path_pubkeys: Sequence[bytes],
|
def _decode_onion_error(error_packet: bytes, payment_path_pubkeys: Sequence[bytes],
|
||||||
session_key: bytes) -> (bytes, int):
|
session_key: bytes) -> (bytes, int):
|
||||||
|
@ -296,7 +325,7 @@ def _decode_onion_error(error_packet: bytes, payment_path_pubkeys: Sequence[byte
|
||||||
um_key = get_bolt04_onion_key(b'um', hop_shared_secrets[i])
|
um_key = get_bolt04_onion_key(b'um', hop_shared_secrets[i])
|
||||||
stream_bytes = generate_cipher_stream(ammag_key, len(error_packet))
|
stream_bytes = generate_cipher_stream(ammag_key, len(error_packet))
|
||||||
error_packet = xor_bytes(error_packet, stream_bytes)
|
error_packet = xor_bytes(error_packet, stream_bytes)
|
||||||
hmac_computed = hmac.new(um_key, msg=error_packet[32:], digestmod=hashlib.sha256).digest()
|
hmac_computed = hmac_oneshot(um_key, msg=error_packet[32:], digest=hashlib.sha256)
|
||||||
hmac_found = error_packet[:32]
|
hmac_found = error_packet[:32]
|
||||||
if hmac_computed == hmac_found:
|
if hmac_computed == hmac_found:
|
||||||
return error_packet, i
|
return error_packet, i
|
||||||
|
@ -317,6 +346,7 @@ def get_failure_msg_from_onion_error(decrypted_error_packet: bytes) -> OnionRout
|
||||||
failure_msg = decrypted_error_packet[34:34+failure_len]
|
failure_msg = decrypted_error_packet[34:34+failure_len]
|
||||||
# create failure message object
|
# create failure message object
|
||||||
failure_code = int.from_bytes(failure_msg[:2], byteorder='big')
|
failure_code = int.from_bytes(failure_msg[:2], byteorder='big')
|
||||||
|
failure_code = OnionFailureCode(failure_code)
|
||||||
failure_data = failure_msg[2:]
|
failure_data = failure_msg[2:]
|
||||||
return OnionRoutingFailureMessage(failure_code, failure_data)
|
return OnionRoutingFailureMessage(failure_code, failure_data)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ import asyncio
|
||||||
|
|
||||||
from electrum.util import bh2u, bfh
|
from electrum.util import bh2u, bfh
|
||||||
from electrum.lnonion import (OnionHopsDataSingle, new_onion_packet, OnionPerHop,
|
from electrum.lnonion import (OnionHopsDataSingle, new_onion_packet, OnionPerHop,
|
||||||
process_onion_packet, _decode_onion_error)
|
process_onion_packet, _decode_onion_error, decode_onion_error,
|
||||||
|
OnionFailureCode)
|
||||||
from electrum import bitcoin, lnrouter
|
from electrum import bitcoin, lnrouter
|
||||||
from electrum.simple_config import SimpleConfig
|
from electrum.simple_config import SimpleConfig
|
||||||
|
|
||||||
|
@ -182,7 +183,13 @@ class Test_LNRouter(TestCaseForTestnet):
|
||||||
]
|
]
|
||||||
session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
|
session_key = bfh('4141414141414141414141414141414141414141414141414141414141414141')
|
||||||
error_packet_for_node_0 = bfh('9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d')
|
error_packet_for_node_0 = bfh('9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d')
|
||||||
|
|
||||||
decoded_error, index_of_sender = _decode_onion_error(error_packet_for_node_0, payment_path_pubkeys, session_key)
|
decoded_error, index_of_sender = _decode_onion_error(error_packet_for_node_0, payment_path_pubkeys, session_key)
|
||||||
self.assertEqual(bfh('4c2fc8bc08510334b6833ad9c3e79cd1b52ae59dfe5c2a4b23ead50f09f7ee0b0002200200fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
|
self.assertEqual(bfh('4c2fc8bc08510334b6833ad9c3e79cd1b52ae59dfe5c2a4b23ead50f09f7ee0b0002200200fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'),
|
||||||
decoded_error)
|
decoded_error)
|
||||||
self.assertEqual(4, index_of_sender)
|
self.assertEqual(4, index_of_sender)
|
||||||
|
|
||||||
|
failure_msg, index_of_sender = decode_onion_error(error_packet_for_node_0, payment_path_pubkeys, session_key)
|
||||||
|
self.assertEqual(4, index_of_sender)
|
||||||
|
self.assertEqual(OnionFailureCode.TEMPORARY_NODE_FAILURE, failure_msg.code)
|
||||||
|
self.assertEqual(b'', failure_msg.data)
|
||||||
|
|
Loading…
Add table
Reference in a new issue