def make(cls): private = ec.generate_private_key(ec.SECP256K1(), default_backend()) public_bytes = private.public_key().public_bytes( Encoding.X962, PublicFormat.UncompressedPoint) private_num = private.private_numbers().private_value private_bytes = pad32(int_to_big(private_num)) return cls(private_bytes, public_bytes[1:])
def recover(hashes: bytes, sig_vrs): r, s, v = sig_vrs v = v + 33 # todo range exception x = r a = (x * x * x + CURVE.A * x + CURVE.B) % CURVE.P b = pow(a, (CURVE.P + 1) // 4, CURVE.P) y = b if (b - (v % 2)) % 2 == 0 else CURVE.P - b e = int_from_big(hashes) mg = ec_mul((CURVE.Gx, CURVE.Gy, 1), (CURVE.N - e) % CURVE.N) xy = ec_mul((x, y, 1), s) _xy = ec_add(mg, xy) Q = ec_mul(_xy, ec_inv(r, CURVE.N)) p, q = from_jacob(Q) return b''.join((pad32(int_to_big(p)), pad32(int_to_big(q))))
def _encode(data): if isinstance(data, Serializer): payload = b''.join(_encode(field) for field in data) offset_type = 216 # obj elif isinstance(data, bytes): payload = pad32(data) offset_type = 27 # data prefix = encode_prefix(len(data), offset_type) return prefix + payload
async def accept_handshake(reader: asyncio.StreamReader, writer: asyncio.StreamWriter, keys, cipher: bytes): exchange_random, ephem_pubkey, pubkey = _accept_decode_secret(keys, cipher) address, port, *_ = writer.get_extra_info('peername') endpoint = EndPoint.make(pubkey, address, port) # responder [keys, endpoint, token, (bool) got eip8] random = os.urandom(16) random_secret = sha3_256(random).digest() sequence = pad32(int_to_big32(1)) ephemeral_keys = ecies.generate_random() payload = encode_payload(sequence, ephemeral_keys.public_bytes, random_secret) cipher = ecies.encrypt(payload, pubkey) return endpoint
async def _handshake_shared_secret(reader: asyncio.StreamReader, writer: asyncio.StreamWriter, endpoint: EndPoint, keys, token): ephemeral_keys = ecies.generate_random() shared_secret = ecies.make_shared_secret(keys.private_bytes, endpoint.pubkey) random = os.urandom(16) random_secret = sha3_256(random).digest() sequence = pad32(int_to_big32(0)) exchange_secret = sha3_256(shared_secret + random_secret + sequence).digest() sig = ephemeral_keys.sign(exchange_secret) encode_sig = encode_signature(sig) # --- temporary version = pad16(int_to_big16(1)) handshake_suffix = pad16(int_to_big16(0)) # --------------------------------------------- # payload = encode_payload(sequence, encode_sig, keys.public_bytes, random_secret, version, handshake_suffix) cipher = ecies.encrypt(ephemeral_keys.public_bytes, payload) if writer.is_closing(): raise ConnectionError( 'during open_connection handling, connection closed') writer.write(cipher) await writer.drain() token.cancellable_wait(reader.read(169), timeout=5) if reader.at_eof(): raise ConnectionError('disconnected')
def handshake_flows(): # $ exchange keys $ # # peer private, public my_keys = ecies.generate_random() # ephemeral private, public my_ephem_keys = ecies.generate_random() # stranger key keys = ecies.generate_random() # *-- connect --* # # my private key, stranger public key = shared secret shared_secret = ecies.make_shared_secret(my_keys.private_bytes, keys.public_bytes) random = os.urandom(16) nonce = sha3_256(random).digest() seq = pad32(int_to_big(0)) secret = sha3_256(shared_secret + nonce + seq).digest() s = my_ephem_keys.sign(secret) encode_sig = encode_signature(s) # 65, 65, 32, 4, 4 # signature, public, nonce, version, suffix (170): handshake messages encode_payload = b''.join((seq, encode_sig, my_keys.public_bytes, nonce, pad16(int_to_big(1)), pad16(int_to_big(0)))) cipher = ecies.encrypt(keys.public_bytes, encode_payload) # -------------------------------------------------------------------------------# # *-- accept --* # plain = ecies.decrypt(keys.private_bytes, cipher) if plain != encode_payload: raise ValueError('plain != payload') if len(plain) != 169: raise ValueError('payload size error', len(plain)) # decode payload seqe = plain[:4] plain = plain[4:] accept_sig = plain[:65] accept_public = plain[65:129] accept_nonce = plain[129:161] ve, suff = plain[-4:-2], plain[-2:] if ve != b'\x00\x01': raise ValueError if suff != b'\x00\x00': raise ValueError # stranger private key, my public key = shared secret stranger_shared_secret = ecies.make_shared_secret(keys.private_bytes, accept_public) accept_secret = sha3_256(stranger_shared_secret + accept_nonce + seqe).digest() if accept_secret != secret: raise ValueError decode_sig = decode_signature(accept_sig) if s != decode_sig: raise ValueError accept_ephem_key = recover(accept_secret, decode_sig) handshake_sset = (accept_ephem_key, accept_nonce, accept_public) print('verifies:', verifies(accept_secret, decode_sig[:2], accept_ephem_key))
def encode_signature(sig_vrs): r, s, v = sig_vrs r_bytes = pad32(int_to_big(r)) s_bytes = pad32(int_to_big(s)) v_bytes = int_to_big(v) return b''.join((r_bytes, s_bytes, v_bytes))
def encode_payload(body, mackey, shared, pubkey): body_size = pad32(int_to_big(len(body))) checksum = sha3_256_mac(mackey, body + body_size + shared) payload = [b'\x04' + pubkey, checksum, body, body_size] return b''.join(payload)