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 __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 __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 __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 __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 __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 _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 _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 __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 __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 __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 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 __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 __add__(self, other): """ Performs an EC_POINT_add on two EC_POINTS. """ sum = backend._lib.EC_POINT_new(self.group) backend.openssl_assert(sum != backend._ffi.NULL) sum = backend._ffi.gc(sum, backend._lib.EC_POINT_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_add(self.group, sum, self.ec_point, other.ec_point, bn_ctx) backend.openssl_assert(res == 1) return Point(sum, self.curve_nid, self.group)
def __neg__(self) -> 'Point': """ Computes the additive inverse of a Point, by performing an EC_POINT_invert on itself. """ inv = backend._lib.EC_POINT_dup(self.ec_point, self.curve.ec_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.curve.ec_group, inv, bn_ctx) backend.openssl_assert(res == 1) return Point(inv, self.curve)
def __mod__(self, other): """ Performs a BN_nnmod on two BIGNUMS. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, None, None, None) rem = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_nnmod(rem, self.bignum, other.bignum, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(rem, self.curve_nid, self.group, self.order)
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)
def __sub__(self, other): """ Performs a BN_mod_sub on two BIGNUMS. """ diff = backend._lib.BN_new() backend.openssl_assert(diff != backend._ffi.NULL) diff = backend._ffi.gc(diff, backend._lib.BN_clear_free) 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 BigNum(diff, self.curve_nid, self.group, self.order)
def __add__(self, other): """ Performs a BN_mod_add on two BIGNUMs. """ sum = backend._lib.BN_new() backend.openssl_assert(sum != backend._ffi.NULL) sum = backend._ffi.gc(sum, backend._lib.BN_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_add(sum, self.bignum, other.bignum, self.order, bn_ctx) backend.openssl_assert(res == 1) return BigNum(sum, self.curve_nid, self.group, self.order)
def __sub__(self, other: Union[int, 'CurveBN']) -> 'CurveBN': """ Performs a BN_mod_sub on two BIGNUMS. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, self.curve) 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.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(diff, self.curve)
def __neg__(self) -> 'CurveBN': """ Computes the modular opposite (i.e., additive inverse) of a BIGNUM """ zero = backend._int_to_bn(0) zero = backend._ffi.gc(zero, backend._lib.BN_clear_free) the_opposite = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_sub(the_opposite, zero, self.bignum, self.curve.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(the_opposite, self.curve)
def __mod__(self, other: Union[int, 'CurveBN']) -> 'CurveBN': """ Performs a BN_nnmod on two BIGNUMS. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, self.curve) other = cast('CurveBN', other) # This is just for mypy rem = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_nnmod(rem, self.bignum, other.bignum, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(rem, self.curve)
def __mul__(self, other): """ Performs a BN_mod_mul between two BIGNUMS. """ if type(other) != BigNum: return NotImplemented product = backend._lib.BN_new() backend.openssl_assert(product != backend._ffi.NULL) product = backend._ffi.gc(product, backend._lib.BN_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod_mul(product, self.bignum, other.bignum, self.order, bn_ctx) backend.openssl_assert(res == 1) return BigNum(product, self.curve_nid, self.group, self.order)
def gen_rand(cls, curve: Optional[Curve] = None) -> 'Point': """ Returns a Point object with a cryptographically secure EC_POINT based on the provided curve. """ curve = curve if curve is not None else default_curve() rand_point = openssl._get_new_EC_POINT(curve) rand_bn = CurveBN.gen_rand(curve).bignum with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_mul(curve.ec_group, rand_point, backend._ffi.NULL, curve.generator, rand_bn, bn_ctx) backend.openssl_assert(res == 1) return cls(rand_point, curve)
def _tmp_bn_mont_ctx(modulus): """ Initializes and returns a BN_MONT_CTX for Montgomery ops. Requires a modulus to place in the Montgomery structure. """ bn_mont_ctx = backend._lib.BN_MONT_CTX_new() backend.openssl_assert(bn_mont_ctx != backend._ffi.NULL) # Don't set the garbage collector. Only free it when the context is done # or else you'll get a null pointer error. try: with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_MONT_CTX_set(bn_mont_ctx, modulus, bn_ctx) backend.openssl_assert(res == 1) yield bn_mont_ctx finally: backend._lib.BN_MONT_CTX_free(bn_mont_ctx)
def __pow__(self, other): """ Performs a BN_mod_exp on two BIGNUMS. WARNING: Only in constant time if BN_FLG_CONSTTIME is set on the BN. """ if type(other) == int: other = openssl._int_to_bn(other) other = CurveBN(other, None, None, None) power = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx, openssl._tmp_bn_mont_ctx(self.order) as bn_mont_ctx: res = backend._lib.BN_mod_exp_mont( power, self.bignum, other.bignum, self.order, bn_ctx, bn_mont_ctx ) backend.openssl_assert(res == 1) return CurveBN(power, self.curve_nid, self.group, self.order)
def to_affine(self): """ Returns a tuple of Python ints in the format of (x, y) that represents the point in the curve. """ affine_x = backend._lib.BN_new() backend.openssl_assert(affine_x != backend._ffi.NULL) affine_x = backend._ffi.gc(affine_x, backend._lib.BN_clear_free) affine_y = backend._lib.BN_new() backend.openssl_assert(affine_y != backend._ffi.NULL) affine_y = backend._ffi.gc(affine_y, backend._lib.BN_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_get_affine_coordinates_GFp( self.group, self.ec_point, affine_x, affine_y, bn_ctx) backend.openssl_assert(res == 1) return (backend._bn_to_int(affine_x), backend._bn_to_int(affine_y))
def __truediv__(self, other): """ Performs a BN_div on two BIGNUMs (modulo the order of the curve). WARNING: Only in constant time if BN_FLG_CONSTTIME is set on the BN. """ product = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: inv_other = backend._lib.BN_mod_inverse(backend._ffi.NULL, other.bignum, self.order, bn_ctx) backend.openssl_assert(inv_other != backend._ffi.NULL) res = backend._lib.BN_mod_mul(product, self.bignum, inv_other, self.order, bn_ctx) backend.openssl_assert(res == 1) return CurveBN(product, self.curve_nid, self.group, self.order)
def __mod__(self, other): """ Performs a BN_nnmod on two BIGNUMS. """ if type(other) == int: other = backend._int_to_bn(other) other = backend._ffi.gc(other, backend._lib.BN_clear_free) other = BigNum(other, None, None, None) rem = backend._lib.BN_new() backend.openssl_assert(rem != backend._ffi.NULL) rem = backend._ffi.gc(rem, backend._lib.BN_clear_free) with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_nnmod(rem, self.bignum, other.bignum, bn_ctx) backend.openssl_assert(res == 1) return BigNum(rem, self.curve_nid, self.group, self.order)
def hash(cls, *crypto_items, params=None): params = params if params is not None else default_params() curve_nid = backend._elliptic_curve_to_nid(params.curve) order = openssl._get_ec_order_by_curve_nid(curve_nid) group = openssl._get_ec_group_by_curve_nid(curve_nid) # TODO: Clean this in an upcoming cleanup of pyUmbral blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) for item in crypto_items: try: item_bytes = item.to_bytes() except AttributeError: if isinstance(item, bytes): item_bytes = item else: raise TypeError( "{} is not acceptable type, received {}".format( item, type(item))) blake2b.update(item_bytes) hash_digest = blake2b.finalize() hash_digest = int.from_bytes(hash_digest, byteorder='big', signed=False) hash_digest = openssl._int_to_bn(hash_digest) _1 = backend._lib.BN_value_one() order_minus_1 = openssl._get_new_BN() res = backend._lib.BN_sub(order_minus_1, order, _1) backend.openssl_assert(res == 1) bignum = openssl._get_new_BN() with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.BN_mod(bignum, hash_digest, order_minus_1, bn_ctx) backend.openssl_assert(res == 1) res = backend._lib.BN_add(bignum, bignum, _1) backend.openssl_assert(res == 1) return cls(bignum, curve_nid, group, order)