Refactor the onionkey stuff to be more like @maqp's revised version (thanks)

This commit is contained in:
Miguel Jacq 2018-09-13 12:21:38 +10:00
parent f9e614eba1
commit 8955ce0699
No known key found for this signature in database
GPG key ID: EEA4341C6D97A0B6

View file

@ -37,39 +37,40 @@ from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import rsa
b = 256 def stem_compatible_base64_blob_from_private_key(private_key_seed: bytes) -> str:
"""
Provides a base64-encoded private key for v3-style Onions.
"""
b = 256
def bit(h, i): def bit(h: bytes, i: int) -> int:
return (h[i // 8] >> (i % 8)) & 1 return (h[i // 8] >> (i % 8)) & 1
def encode_int(y: int) -> bytes:
bits = [(y >> i) & 1 for i in range(b)]
return b''.join([bytes([(sum([bits[i * 8 + j] << j for j in range(8)]))]) for i in range(b // 8)])
def expand_private_key(sk: bytes) -> bytes:
h = hashlib.sha512(sk).digest()
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
k = b''.join([bytes([h[i]]) for i in range(b // 8, b // 4)])
assert len(k) == 32
return encode_int(a) + k
expanded_private_key = expand_private_key(private_key_seed)
return base64.b64encode(expanded_private_key).decode()
def encodeint(y): def onion_url_from_private_key(private_key_seed: bytes) -> str:
bits = [(y >> i) & 1 for i in range(b)]
return b''.join([bytes([(sum([bits[i * 8 + j] << j for j in range(8)]))]) for i in range(b // 8)])
def H(m):
return hashlib.sha512(m).digest()
def expandSK(sk):
h = H(sk)
a = 2 ** (b - 2) + sum(2 ** i * bit(h, i) for i in range(3, b - 2))
k = b''.join([bytes([h[i]]) for i in range(b // 8, b // 4)])
assert len(k) == 32
return encodeint(a) + k
def onion_url_from_private_key(private_key):
""" """
Derives the public key (.onion hostname) from a v3-style Derives the public key (.onion hostname) from a v3-style
Onion private key. Onion private key.
""" """
private_key = nacl.signing.SigningKey(seed=private_key) signing_key = nacl.signing.SigningKey(seed=private_key_seed)
pubkey = bytes(private_key.verify_key) public_key = bytes(signing_key.verify_key)
version = b'\x03' version = b'\x03'
checksum = hashlib.sha3_256(b".onion checksum" + pubkey + version).digest()[:2] checksum = hashlib.sha3_256(b".onion checksum" + public_key + version).digest()[:2]
onion_address = "http://{}.onion".format(base64.b32encode(pubkey + checksum + version).decode().lower()) onion_address = "http://{}.onion".format(base64.b32encode(public_key + checksum + version).decode().lower())
return onion_address return onion_address
@ -78,10 +79,10 @@ def generate_v3_private_key():
Generates a private and public key for use with v3 style Onions. Generates a private and public key for use with v3 style Onions.
Returns both the private key as well as the public key (.onion hostname) Returns both the private key as well as the public key (.onion hostname)
""" """
secretKey = os.urandom(32) private_key_seed = os.urandom(32)
expandedSecretKey = expandSK(secretKey) private_key = stem_compatible_base64_blob_from_private_key(private_key_seed)
private_key = base64.b64encode(expandedSecretKey).decode() return (private_key, onion_url_from_private_key(private_key_seed))
return (private_key, onion_url_from_private_key(secretKey))
def generate_v2_private_key(): def generate_v2_private_key():
""" """
@ -109,6 +110,7 @@ def generate_v2_private_key():
return (serialized_key, onion_url) return (serialized_key, onion_url)
def is_v2_key(key): def is_v2_key(key):
""" """
Helper function for determining if a key is RSA1024 (v2) or not. Helper function for determining if a key is RSA1024 (v2) or not.