def point_add(curve: Curve, point1, point2): op_sum = _point_new(curve.ec_group) with tmp_bn_ctx() as bn_ctx: res = BACKEND_LIB.EC_POINT_add(curve.ec_group, op_sum, point1, point2, bn_ctx) backend.openssl_assert(res == 1) return op_sum
def gen_rand(cls, curve: ec.EllipticCurve = None): """ Returns a BigNum object with a cryptographically secure BigNum based on the given curve. """ curve = curve if curve is not None else default_curve() curve_nid = backend._elliptic_curve_to_nid(curve) group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid) backend.openssl_assert(group != backend._ffi.NULL) order = backend._lib.BN_new() backend.openssl_assert(order != backend._ffi.NULL) order = backend._ffi.gc(order, backend._lib.BN_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_GROUP_get_order(group, order, bn_ctx) backend.openssl_assert(res == 1) new_rand_bn = backend._lib.BN_new() backend.openssl_assert(new_rand_bn != backend._ffi.NULL) new_rand_bn = backend._ffi.gc(new_rand_bn, backend._lib.BN_clear_free) rand_res = backend._lib.BN_rand_range(new_rand_bn, order) backend.openssl_assert(rand_res == 1) return cls(new_rand_bn, curve_nid, group, order)
def point_mul_bn(curve: Curve, point, bn): prod = _point_new(curve.ec_group) with tmp_bn_ctx() as bn_ctx: res = BACKEND_LIB.EC_POINT_mul(curve.ec_group, prod, BACKEND_FFI.NULL, point, bn, bn_ctx) backend.openssl_assert(res == 1) return prod
def BN_MOD_INVERSE(priv_a) -> _EllipticCurvePrivateKey: """ Performs an OpenSSL BN_mod_inverse on an EllipticCurvePrivateKey and returns the result in an EllipticCurvePrivateKey. """ group = backend._lib.EC_KEY_get0_group(priv_a._ec_key) backend.openssl_assert(group != backend._ffi.NULL) prv_a = backend._lib.EC_KEY_get0_private_key(priv_a._ec_key) backend.openssl_assert(prv_a != backend._ffi.NULL) order = backend._lib.BN_new() backend.openssl_assert(order != backend._ffi.NULL) order = backend._ffi.gc(order, backend._lib.BN_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_GROUP_get_order(group, order, bn_ctx) backend.openssl_assert(res == 1) inv = backend._lib.BN_mod_inverse(backend._ffi.NULL, prv_a, order, bn_ctx) backend.openssl_assert(inv != backend._ffi.NULL) inv = backend._ffi.gc(inv, backend._lib.BN_free) return _bignum_to_private_key(backend, group, inv)
def point_eq(curve: Curve, point1, point2): with tmp_bn_ctx() as bn_ctx: is_equal = BACKEND_LIB.EC_POINT_cmp(curve.ec_group, point1, point2, bn_ctx) backend.openssl_assert(is_equal != -1) # 1 is not-equal, 0 is equal, -1 is error return is_equal == 0
def _get_ec_group_by_curve_nid(nid: int): """ Returns the group of a given curve via its OpenSSL nid. This must be freed after each use otherwise it leaks memory. """ group = BACKEND_LIB.EC_GROUP_new_by_curve_name(nid) backend.openssl_assert(group != BACKEND_FFI.NULL) return group
def _get_ec_group_by_curve_nid(curve_nid: int): """ Returns the group of a given curve via its OpenSSL nid. """ group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid) backend.openssl_assert(group != backend._ffi.NULL) return group
def _get_ec_order_by_group(ec_group): """ Returns the order of a given curve via its OpenSSL EC_GROUP. """ ec_order = _get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_GROUP_get_order(ec_group, ec_order, bn_ctx) backend.openssl_assert(res == 1) return ec_order
def _get_ec_generator_by_group(ec_group): """ Returns the generator point of a given curve via its OpenSSL EC_GROUP. """ generator = backend._lib.EC_GROUP_get0_generator(ec_group) backend.openssl_assert(generator != backend._ffi.NULL) generator = backend._ffi.gc(generator, backend._lib.EC_POINT_clear_free) return generator
def point_neg(curve: Curve, point): inv = BACKEND_LIB.EC_POINT_dup(point, curve.ec_group) backend.openssl_assert(inv != BACKEND_FFI.NULL) inv = BACKEND_FFI.gc(inv, BACKEND_LIB.EC_POINT_clear_free) with tmp_bn_ctx() as bn_ctx: res = BACKEND_LIB.EC_POINT_invert(curve.ec_group, inv, bn_ctx) backend.openssl_assert(res == 1) return inv
def _point_new(ec_group): """ Returns a new and initialized OpenSSL EC_POINT given the group of a curve. If __curve_nid is provided, it retrieves the group from the curve provided. """ new_point = BACKEND_LIB.EC_POINT_new(ec_group) backend.openssl_assert(new_point != BACKEND_FFI.NULL) new_point = BACKEND_FFI.gc(new_point, BACKEND_LIB.EC_POINT_clear_free) return new_point
def _get_ec_generator_by_curve_nid(curve_nid: int): """ Returns the generator point of a given curve via its OpenSSL nid. """ ec_group = _get_ec_group_by_curve_nid(curve_nid) generator = backend._lib.EC_GROUP_get0_generator(ec_group) backend.openssl_assert(generator != backend._ffi.NULL) return generator
def __add__(self, other): """ Performs an EC_POINT_add on two EC_POINTS. """ op_sum = openssl._get_new_EC_POINT(ec_group=self.group) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_add(self.group, op_sum, self.ec_point, other.ec_point, bn_ctx) backend.openssl_assert(res == 1) return Point(op_sum, self.curve_nid, self.group)
def _bytes_to_bn(bytes_seq: bytes, set_consttime_flag=True): """ Converts the given byte sequence to an OpenSSL BIGNUM. If set_consttime_flag is set to True, OpenSSL will use constant time operations when using this BIGNUM. """ bn = _get_new_BN(set_consttime_flag) backend._lib.BN_bin2bn(bytes_seq, len(bytes_seq), bn) backend.openssl_assert(bn != backend._ffi.NULL) return bn
def _get_new_EC_POINT(curve: 'Curve'): """ Returns a new and initialized OpenSSL EC_POINT given the group of a curve. If __curve_nid is provided, it retrieves the group from the curve provided. """ new_point = backend._lib.EC_POINT_new(curve.ec_group) backend.openssl_assert(new_point != backend._ffi.NULL) new_point = backend._ffi.gc(new_point, backend._lib.EC_POINT_clear_free) return new_point
def __sub__(self, other): """ Performs a BN_mod_sub on two BIGNUMS. """ diff = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_sub(diff, self.bignum, other.bignum, self.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(diff, self.curve_nid, self.group, self.order)
def __invert__(self): """ Performs a BN_mod_inverse. """ with backend._tmp_bn_ctx() as bn_ctx: inv = backend._lib.BN_mod_inverse(backend._ffi.NULL, self.bignum, self.order, bn_ctx) backend.openssl_assert(inv != backend._ffi.NULL) inv = backend._ffi.gc(inv, backend._lib.BN_clear_free) return BigNum(inv, self.curve_nid, self.group, self.order)
def _bn_new(): """ Returns a new and initialized OpenSSL BIGNUM. """ new_bn = BACKEND_LIB.BN_new() backend.openssl_assert(new_bn != BACKEND_FFI.NULL) new_bn = BACKEND_FFI.gc(new_bn, BACKEND_LIB.BN_clear_free) # Always use constant time operations. BACKEND_LIB.BN_set_flags(new_bn, BACKEND_LIB.BN_FLG_CONSTTIME) return new_bn
def __eq__(self, other): """ Compares two EC_POINTS for equality. """ with backend._tmp_bn_ctx() as bn_ctx: is_equal = backend._lib.EC_POINT_cmp(self.group, self.ec_point, other.ec_point, bn_ctx) backend.openssl_assert(is_equal != -1) # 1 is not-equal, 0 is equal, -1 is error return not bool(is_equal)
def __add__(self, other) -> 'CurveBN': """ Performs a BN_mod_add on two BIGNUMs. """ op_sum = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_add(op_sum, self.bignum, other.bignum, self.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(op_sum, self.curve)
def _get_EC_POINT_via_affine(affine_x, affine_y, curve: 'Curve'): """ Returns an EC_POINT given the group of a curve and the affine coordinates provided. """ new_point = _get_new_EC_POINT(curve) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_set_affine_coordinates_GFp( curve.ec_group, new_point, affine_x, affine_y, bn_ctx) backend.openssl_assert(res == 1) return new_point
def __mul__(self, other): """ Performs an EC_POINT_mul on an EC_POINT and a BIGNUM. """ prod = openssl._get_new_EC_POINT(ec_group=self.group) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_mul( self.group, prod, backend._ffi.NULL, self.ec_point, other.bignum, bn_ctx ) backend.openssl_assert(res == 1) return Point(prod, self.curve_nid, self.group)
def _get_affine_coords_via_EC_POINT(ec_point, curve: 'Curve'): """ Returns the affine coordinates of a given point on the provided ec_group. """ affine_x = _get_new_BN() affine_y = _get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_get_affine_coordinates_GFp( curve.ec_group, ec_point, affine_x, affine_y, bn_ctx) backend.openssl_assert(res == 1) return (affine_x, affine_y)
def __invert__(self): """ Performs an EC_POINT_invert on itself. """ inv = backend._lib.EC_POINT_dup(self.ec_point, self.group) backend.openssl_assert(inv != backend._ffi.NULL) inv = backend._ffi.gc(inv, backend._lib.EC_POINT_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_invert(self.group, inv, bn_ctx) backend.openssl_assert(res == 1) return Point(inv, self.curve_nid, self.group)
def from_bytes(cls, data: bytes, curve: Optional[Curve] = None) -> 'Point': """ Returns a Point object from the given byte data on the curve provided. """ curve = curve if curve is not None else default_curve() point = openssl._get_new_EC_POINT(curve) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_oct2point(curve.ec_group, point, data, len(data), bn_ctx) backend.openssl_assert(res == 1) return cls(point, curve)
def point_to_bytes_compressed(curve: Curve, point): point_conversion_form = BACKEND_LIB.POINT_CONVERSION_COMPRESSED size = curve.field_element_size + 1 # compressed point size bin_ptr = BACKEND_FFI.new("unsigned char[]", size) with tmp_bn_ctx() as bn_ctx: bin_len = BACKEND_LIB.EC_POINT_point2oct(curve.ec_group, point, point_conversion_form, bin_ptr, size, bn_ctx) backend.openssl_assert(bin_len != 0) return bytes(BACKEND_FFI.buffer(bin_ptr, bin_len)[:])
def __mul__(self, other) -> 'Point': """ Performs an EC_POINT_mul on an EC_POINT and a BIGNUM. """ # TODO: Check that both points use the same curve. prod = openssl._get_new_EC_POINT(self.curve) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_mul(self.curve.ec_group, prod, backend._ffi.NULL, self.ec_point, other.bignum, bn_ctx) backend.openssl_assert(res == 1) return Point(prod, self.curve)
def __mul__(self, other) -> 'CurveBN': """ Performs a BN_mod_mul between two BIGNUMS. """ if type(other) != CurveBN: return NotImplemented product = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_mul(product, self.bignum, other.bignum, self.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(product, self.curve)
def _get_new_BN(set_consttime_flag=True): """ Returns a new and initialized OpenSSL BIGNUM. The set_consttime_flag is set to True by default. When this instance of a CurveBN object has BN_FLG_CONSTTIME set, OpenSSL will use constant time operations whenever this CurveBN is passed. """ new_bn = backend._lib.BN_new() backend.openssl_assert(new_bn != backend._ffi.NULL) new_bn = backend._ffi.gc(new_bn, backend._lib.BN_clear_free) if set_consttime_flag: backend._lib.BN_set_flags(new_bn, backend._lib.BN_FLG_CONSTTIME) return new_bn
def __invert__(self) -> 'CurveBN': """ Performs a BN_mod_inverse. WARNING: Only in constant time if BN_FLG_CONSTTIME is set on the BN. """ with backend._tmp_bn_ctx() as bn_ctx: inv = backend._lib.BN_mod_inverse(backend._ffi.NULL, self.bignum, self.curve.order, bn_ctx) backend.openssl_assert(inv != backend._ffi.NULL) inv = backend._ffi.gc(inv, backend._lib.BN_clear_free) return CurveBN(inv, self.curve)