def _accept_decode_secret(keys, cipher): payload = ecies.decrypt(keys.private_bytes, cipher) raw_seq = payload[:4] raw_ver, raw_suf = payload[-4:-2], payload[-2:] # expected exception: not bytes, decode version = int_from_big(raw_ver) suffix = int_from_big(raw_suf) sequence = int_from_big(raw_seq) has_accept = all((version == 1, suffix == 0, sequence == 0)) if not has_accept: raise ValueError('during accept handling, unexpected payload') random, pubkey, sig = decode_payload(payload[4:]) shared_secret = ecies.make_shared_secret(keys.private_bytes, pubkey) exchange_secret = sha3_256(shared_secret + random + sequence).digest() decode_sig = decode_signature(sig) accept_ephemeral_key = recover(exchange_secret, decode_sig) # ---- # return random, accept_ephemeral_key, pubkey
def sign(hashes: bytes, privkey: bytes): # X9.62 hashes_numbers = int_from_big(hashes) privkey_numbers = int_from_big(privkey) k = generate_k(hashes, privkey) r, y = mul(CURVE.G, k) s = ec_inv(k, CURVE.N) * (hashes_numbers + r * privkey_numbers) % CURVE.N v = 33 + ((y % 2) ^ (0 if s * 2 < CURVE.N else 1)) s = s if s * 2 < CURVE.N else CURVE.N - s return [r, s, v - 33]
def decode_payload(data): pubkey_len = 65 enter_shared = data[:pubkey_len] size = -1 * (int_from_big(data[-4:]) + 4) checksum = data[pubkey_len:size] body = data[size:] return enter_shared, checksum, body
def decode_signature(sig_vrs): sig = sig_vrs[:32], sig_vrs[32:64], sig_vrs[-1:] decode_sig = [ int_from_big(point) for point in sig ] return decode_sig
def verifies(hashes: bytes, sig_rs, pubkey): r, s = sig_rs public_p = int_from_big(pubkey[:32]), int_from_big(pubkey[32:64]) w = ec_inv(s, CURVE.N) e = int_from_big(hashes) p, q = e * w % CURVE.N, r * w % CURVE.N a = mul(CURVE.G, p) b = mul(public_p, q) v = ec_add(to_jacob(a), to_jacob(b)) x, _ = from_jacob(v) is_verified_r = r == x == r % CURVE.N is_verified_s = s == s % CURVE.N if is_verified_r and is_verified_s: return True else: return False
def generate_k(hashes, privkey, hash_func=hashlib.sha3_256): # RFC6979::section#3.2: https://tools.ietf.org/html/rfc6979 v = b'\x01' * 32 k = b'\x00' * 32 k = hmac.new(k, v + b'\x00' + privkey + hashes, hash_func).digest() v = hmac.new(k, v, hash_func).digest() k = hmac.new(k, v + b'\x01' + privkey + hashes, hash_func).digest() v = hmac.new(k, v, hash_func).digest() v = hmac.new(k, v, hash_func).digest() k = int_from_big(v) return k
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 __init__(self, private_bytes, public_bytes): self._private_bytes = private_bytes self._private_numbers = int_from_big(self.private_bytes) self.public_bytes = public_bytes self.public_numbers = int_from_big(self.public_bytes)
def datagram_port(self): return int_from_big(self._datagram_port)
def stream_port(self): return int_from_big(self._stream_port)
def deserialize(self, data): return int_from_big(data)