def generate_key( algorithm: CoseAlgorithms, key_ops: KeyOps, curve_type: CoseEllipticCurves = CoseEllipticCurves.X25519 ) -> 'OKP': """ Generate a random OKP COSE key object. :param algorithm: Specify the CoseAlgorithm to use. :param key_ops: Specify the key operation (KeyOps). :param curve_type: Specify curve, must be X25519 or X448. """ if curve_type == CoseEllipticCurves.X25519: private_key = X25519PrivateKey.generate() elif curve_type == CoseEllipticCurves.X448: private_key = X448PrivateKey.generate() else: raise CoseIllegalCurve( f"curve must be of type {CoseEllipticCurves.X25519} or {CoseEllipticCurves.X448}" ) encoding = Encoding(serialization.Encoding.Raw) private_format = PrivateFormat(serialization.PrivateFormat.Raw) public_format = PublicFormat(serialization.PublicFormat.Raw) encryption = serialization.NoEncryption() return OKP(alg=CoseAlgorithms(algorithm), key_ops=KeyOps(key_ops), crv=CoseEllipticCurves(curve_type), x=private_key.public_key().public_bytes( encoding, public_format), d=private_key.private_bytes(encoding, private_format, encryption))
def crv(self, crv: Union[Type['CoseCurve'], int, str]): supported_curves = {X25519, X448, Ed25519, Ed448} if not self._supported_by_key_type(crv, supported_curves): raise CoseIllegalCurve( f"Invalid COSE curve {crv} for key type {OKPKey.__name__}") else: self.store[OKPKpCurve] = CoseCurve.from_id(crv)
def verify(self, to_be_verified: bytes, signature: bytes, alg: Optional[CoseAlgorithms] = None, curve: Optional[CoseEllipticCurves] = None) -> bool: """ Verifies the digital signature over 'to_be_verified'. The parameter 'alg' and 'curve' parameters are optional in case they are already provided by the key object self. :param to_be_verified: Data that was signed. :param signature: Signature to verify. :param alg: An optional algorithm parameter. :param curve: An optional curve :return: True when the signature is valid and False if the signature is invalid. """ self._check_key_conf(algorithm=alg, key_operation=KeyOps.VERIFY, curve=curve) if self.crv == CoseEllipticCurves.ED25519: vk = Ed25519PublicKey.from_public_bytes(self.x) elif self._crv == CoseEllipticCurves.ED448: vk = Ed448PublicKey.from_public_bytes(self.x) else: raise CoseIllegalCurve( f"Illegal curve for OKP singing: {self.crv}") try: vk.verify(signature, to_be_verified) return True except InvalidSignature: return False
def sign(self, to_be_signed: bytes, alg: Optional[CoseAlgorithms] = None, curve: CoseEllipticCurves = None) -> bytes: """ Computes a digital signature over 'to_be_signed'. The parameter 'alg' and 'curve' parameters are optional in case they are already provided by the key object self. :param to_be_signed: Data over which the signature is calculated. :param alg: An optional algorithm parameter. :param curve: An optional curve parameter. :return: the signature over the COSE object. """ self._check_key_conf(algorithm=alg, key_operation=KeyOps.SIGN, curve=curve) if self.crv == CoseEllipticCurves.ED25519: sk = Ed25519PrivateKey.from_private_bytes(self.d) elif self._crv == CoseEllipticCurves.ED448: sk = Ed448PrivateKey.from_private_bytes(self.d) else: raise CoseIllegalCurve( f"Illegal curve for OKP singing: {self.crv}") return sk.sign(to_be_signed)
def shared_secret(private_key: 'CK', public_key: 'CK') -> bytes: """ Compute the shared secret. """ if public_key.crv == X25519: d = X25519PrivateKey.from_private_bytes(private_key.d) x = X25519PublicKey.from_public_bytes(public_key.x) secret = d.exchange(x) elif public_key.crv == X448: d = X448PrivateKey.from_private_bytes(private_key.d) x = X448PublicKey.from_public_bytes(public_key.x) secret = d.exchange(x) elif public_key.crv == P256: d = ec.derive_private_key(int(hexlify(private_key.d), 16), SECP256R1(), default_backend()) x = ec.EllipticCurvePublicNumbers(int(hexlify(public_key.x), 16), int(hexlify(public_key.y), 16), SECP256R1()) x = x.public_key() secret = d.exchange(ec.ECDH(), x) else: raise CoseIllegalCurve(f"{public_key.crv} is unsupported") return secret
def _ecdh(cls, curve: 'CoseCurve', private_key: 'EC2', public_key: 'EC2') -> bytes: if curve == curves.P256(): curve_instance = SECP256R1() elif curve == curves.P384(): curve_instance = SECP384R1() elif curve == curves.P521(): curve_instance = SECP521R1() else: raise CoseIllegalCurve() d_value = int(hexlify(private_key.d), 16) x_value = int(hexlify(public_key.x), 16) y_value = int(hexlify(public_key.y), 16) d = ec.derive_private_key(d_value, curve_instance, default_backend()) p = ec.EllipticCurvePublicNumbers(x_value, y_value, curve_instance) p = p.public_key(default_backend()) shared_key = d.exchange(ECDH(), p) return shared_key
def generate_key(crv: Union[Type['CoseCurve'], str, int], optional_params: dict = None) -> 'OKPKey': """ Generate a random OKPKey COSE key object. :param crv: Specify an elliptic curve. :param optional_params: Optional key attributes for the :class:`~cose.keys.okp.OKPKey` object, e.g., \ :class:`~cose.keys.keyparam.KpAlg` or :class:`~cose.keys.keyparam.KpKid`. :returns: A COSE `OKPKey` key. """ if type(crv) == str or type(crv) == int: crv = CoseCurve.from_id(crv) if crv == X25519: private_key = X25519PrivateKey.generate() elif crv == Ed25519: private_key = Ed25519PrivateKey.generate() elif crv == Ed448: private_key = Ed448PrivateKey.generate() elif crv == X448: private_key = X448PrivateKey.generate() else: raise CoseIllegalCurve( f"Curve must be of type {X25519}, {X448}, {Ed25519}, or {Ed448}" ) encoding = Encoding(serialization.Encoding.Raw) private_format = PrivateFormat(serialization.PrivateFormat.Raw) public_format = PublicFormat(serialization.PublicFormat.Raw) encryption = serialization.NoEncryption() return OKPKey(crv=crv, x=private_key.public_key().public_bytes( encoding, public_format), d=private_key.private_bytes(encoding, private_format, encryption), optional_params=optional_params)
def shared_secret(private_key: Key, public_key: Key) -> bytes: """ Compute the shared secret. """ if public_key.crv == CoseEllipticCurves.X25519: d = X25519PrivateKey.from_private_bytes(private_key.d) x = X25519PublicKey.from_public_bytes(public_key.x) elif public_key.crv == CoseEllipticCurves.X448: d = X448PrivateKey.from_private_bytes(private_key.d) x = X448PublicKey.from_public_bytes(public_key.x) elif public_key.crv == CoseEllipticCurves.P_256: d = ec.derive_private_key(int(hexlify(private_key.d), 16), config_cose(public_key.crv).curve[1](), default_backend()) x = ec.EllipticCurvePublicNumbers( int(hexlify(public_key.x), 16), int(hexlify(public_key.y), 16), config_cose(public_key.crv).curve[1]()) else: raise CoseIllegalCurve(f"{public_key.crv} is unsupported") secret = d.exchange(x) return secret
def generate_key(crv: Union[Type['CoseCurve'], str, int], optional_params: dict = None) -> 'EC2Key': """ Generate a random EC2Key COSE key object. :param crv: Specify an :class:`~cose.attributes.algorithms.CoseEllipticCurves`. :param optional_params: Optional key attributes for the :class:`~cose.keys.ec2.EC2Key` object, e.g., \ :class:`~cose.keys.keyparam.KpAlg` or :class:`~cose.keys.keyparam.KpKid`. :return: An COSE `EC2Key` key. """ if type(crv) == str or type(crv) == int: crv = CoseCurve.from_id(crv) if crv == P256: curve_obj = SECP256R1() elif crv == P384: curve_obj = SECP384R1() elif crv == P521: curve_obj = SECP521R1() else: raise CoseIllegalCurve(f'Illegal COSE curve: {crv}') private_key = ec.generate_private_key(curve_obj, backend=default_backend()) d_value = private_key.private_numbers().private_value x_coor = private_key.public_key().public_numbers().x y_coor = private_key.public_key().public_numbers().y return EC2Key(crv=crv, d=d_value.to_bytes((d_value.bit_length() + 7) // 8, byteorder="big"), x=x_coor.to_bytes((x_coor.bit_length() + 7) // 8, byteorder="big"), y=y_coor.to_bytes((y_coor.bit_length() + 7) // 8, byteorder="big"), optional_params=optional_params)
def crv(self, crv: Union[Type['CoseCurve'], int, str]): supported_curves = {P256, P384, P521, SECP256K1} if not self._supported_by_key_type(crv, supported_curves): raise CoseIllegalCurve("Invalid COSE curve attribute") else: self.store[EC2KpCurve] = CoseCurve.from_id(crv)