def __init__(self, crv: Union[Type['CoseCurve'], str, int], x: bytes = b'', d: bytes = b'', optional_params: Optional[dict] = None, allow_unknown_key_attrs: bool = True): """ Create an COSE OKP key. :param crv: An OKP elliptic curve. :param x: Public value of the OKP key. :param d: Private value of the OKP key. :param optional_params: A dictionary with optional key parameters. :param allow_unknown_key_attrs: Allow unknown key attributes (not registered at the IANA registry) """ transformed_dict = {KpKty: KtyOKP} if optional_params is None: optional_params = {} for _key_attribute, _value in optional_params.items(): try: # translate the key_attribute kp = OKPKeyParam.from_id(_key_attribute, allow_unknown_key_attrs) # parse the value of the key attribute if possible if hasattr(kp, 'value_parser') and hasattr( kp.value_parser, '__call__'): _value = kp.value_parser(_value) # store in new dict transformed_dict[kp] = _value except ValueError: transformed_dict[_key_attribute] = _value # final check if key type is correct if transformed_dict.get(KpKty) != KtyOKP: raise CoseIllegalKeyType( f"Illegal key type in OKP COSE Key: {transformed_dict.get(KpKty)}" ) super(OKPKey, self).__init__(transformed_dict) if len(x) == 0 and len(d) == 0: raise CoseInvalidKey( "Either the public values or the private value must be specified" ) if crv is not None: self.crv = crv else: raise CoseInvalidKey("COSE curve cannot be None") if x != b'': self.x = x if d != b'': self.d = d
def __init__(self, crv: Union[Type['CoseCurve'], str, int], x: bytes = b'', y: bytes = b'', d: bytes = b'', optional_params: Optional[dict] = None, allow_unknown_key_attrs: bool = True): transformed_dict = {} if len(x) == 0 and len(y) == 0 and len(d) == 0: raise CoseInvalidKey( "Either the public values or the private value must be specified" ) if (len(x) == 0 and len(y) != 0) or (len(x) != 0 and len(y) == 0): raise CoseInvalidKey("Missing public coordinate X/Y") new_dict = dict({KpKty: KtyEC2, EC2KpCurve: crv}) if len(x) != 0 and len(y) != 0: new_dict.update({EC2KpX: x, EC2KpY: y}) if len(d) != 0: new_dict.update({EC2KpD: d}) if optional_params is not None: new_dict.update(optional_params) for _key_attribute, _value in new_dict.items(): try: # translate the key_attribute kp = EC2KeyParam.from_id(_key_attribute, allow_unknown_key_attrs) # parse the value of the key attribute if possible if hasattr(kp, 'value_parser') and hasattr( kp.value_parser, '__call__'): _value = kp.value_parser(_value) # store in new dict transformed_dict[kp] = _value except ValueError: transformed_dict[_key_attribute] = _value # final check if key type is correct if transformed_dict.get(KpKty) != KtyEC2: raise CoseIllegalKeyType( f"Illegal key type in EC2 COSE Key: {transformed_dict.get(KpKty)}" ) super(EC2Key, self).__init__(transformed_dict)
def k(self, k: bytes): if type(k) is not bytes: raise ValueError("SymKpK parameter must be of type 'bytes'") if len(k) not in [16, 24, 32]: raise CoseInvalidKey( "Key length should be either 16, 24, or 32 bytes") self.store[SymKpK] = k
def k(self) -> bytes: """ Returns the mandatory :class:`~cose.keys.keyparam.SymKpK` attribute of the COSE Symmetric Key object. """ if SymKpK in self.store: return self.store[SymKpK] else: raise CoseInvalidKey( "Symmetric COSE key must have the SymKpK attribute")
def __delitem__(self, key): if self._key_transform(key) != KpKty and self._key_transform( key) != SymKpK: super().__delitem__(key) else: raise CoseInvalidKey( f"Deleting {key} attribute would lead to an invalide COSE Symmetric Key" )
def key(self, key: Optional['CK']): if not isinstance(key, SymmetricKey) and \ not isinstance(key, EC2Key) and \ not isinstance(key, OKPKey) and \ not isinstance(key, RSAKey) and \ key is not None: raise CoseInvalidKey(f"Unknown key type: {type(key)}") else: self._key = key
def crv(self) -> Optional[Type['CoseCurve']]: """ Returns the mandatory :class:`~cose.keys.keyparam.OKPKpCurve` attribute of the COSE OKP Key object. """ if OKPKpCurve in self.store: return self.store[OKPKpCurve] else: raise CoseInvalidKey( "OKP COSE key must have the OKP KpCurve attribute")
def __delitem__(self, key: Union['KeyParam', str, int]): if self._key_transform(key) != KpKty and self._key_transform( key) != OKPKpCurve: if self._key_transform(key) == OKPKpD and OKPKpX not in self.store: pass if self._key_transform(key) == OKPKpX and OKPKpD not in self.store: pass else: return super(OKPKey, self).__delitem__(key) raise CoseInvalidKey( f"Deleting {key} attribute would lead to an invalid COSE OKP Key")
def from_dict(cls, cose_key: dict) -> 'EC2Key': """ Returns an initialized COSE Key object of type EC2Key. :param cose_key: Dict containing COSE Key parameters and there values. :return: an initialized EC2Key key """ if EC2KpX in cose_key: x = cose_key[EC2KpX] elif EC2KpX.identifier in cose_key: x = cose_key[EC2KpX.identifier] elif EC2KpX.fullname in cose_key: x = cose_key[EC2KpX.fullname] else: x = b'' if EC2KpY in cose_key: y = cose_key[EC2KpY] elif EC2KpY.identifier in cose_key: y = cose_key[EC2KpY.identifier] elif EC2KpY.fullname in cose_key: y = cose_key[EC2KpY.fullname] else: y = b'' if EC2KpD in cose_key: d = cose_key[EC2KpD] elif EC2KpD.identifier in cose_key: d = cose_key[EC2KpD.identifier] elif EC2KpD.fullname in cose_key: d = cose_key[EC2KpD.fullname] else: d = b'' if EC2KpCurve in cose_key: curve = cose_key[EC2KpCurve] elif EC2KpCurve.identifier in cose_key: curve = cose_key[EC2KpCurve.identifier] elif EC2KpCurve.fullname in cose_key: curve = cose_key[EC2KpCurve.fullname] else: raise CoseInvalidKey( "COSE EC2 Key must have an EC2KpCurve attribute") return cls(crv=curve, x=x, y=y, d=d, optional_params=cose_key, allow_unknown_key_attrs=True)
def __delitem__(self, key): if self._key_transform(key) != KpKty and self._key_transform( key) != EC2KpCurve: if self._key_transform(key) == EC2KpD and ( EC2KpY not in self.store or EC2KpX not in self.store): pass elif self._key_transform( key) == EC2KpX and EC2KpD not in self.store: pass elif (self._key_transform(key) == EC2KpX or self._key_transform(key) == EC2KpY) and EC2KpD in self.store: super(EC2Key, self).__delitem__(EC2KpX) super(EC2Key, self).__delitem__(EC2KpY) return else: return super(EC2Key, self).__delitem__(key) raise CoseInvalidKey( f"Deleting {key} attribute would lead to an invalid COSE EC2 Key")
def from_dict(cls, cose_key: dict) -> 'SymmetricKey': """ Returns an initialized COSE Key object of type SymmetricKey. :param cose_key: Dict containing COSE Key parameters and their values. :return: an initialized COSE SymmetricKey object """ if SymKpK in cose_key: key_bytes = cose_key[SymKpK] elif SymKpK.identifier in cose_key: key_bytes = cose_key[SymKpK.identifier] elif SymKpK.fullname in cose_key: key_bytes = cose_key[SymKpK.fullname] else: raise CoseInvalidKey( "COSE Symmetric Key must have an SymKpK attribute") return cls(k=key_bytes, optional_params=cose_key, allow_unknown_key_attrs=True)
def __init__(self, k: bytes, optional_params: Optional[dict] = None, allow_unknown_key_attrs: bool = True): transformed_dict = {} if len(k) not in [16, 24, 32]: raise CoseInvalidKey( "Key length should be either 16, 24, or 32 bytes") new_dict = dict({KpKty: KtySymmetric, SymKpK: k}) if optional_params is not None: new_dict.update(optional_params) for _key_attribute, _value in new_dict.items(): try: # translate the key_attribute kp = SymmetricKeyParam.from_id(_key_attribute, allow_unknown_key_attrs) # parse the value of the key attribute if possible if hasattr(kp, 'value_parser') and hasattr( kp.value_parser, '__call__'): _value = kp.value_parser(_value) # store in new dict transformed_dict[kp] = _value except ValueError: transformed_dict[_key_attribute] = _value # final check if key type is correct if transformed_dict.get(KpKty) != KtySymmetric: raise CoseIllegalKeyType( f"Illegal key type in Symmetric COSE Key: {transformed_dict.get(KpKty)}" ) super(SymmetricKey, self).__init__(transformed_dict)
def __init__(self, k: bytes, optional_params: Optional[dict] = None, allow_unknown_key_attrs: bool = True): transformed_dict = {KpKty: KtySymmetric} if optional_params is None: optional_params = {} for _key_attribute, _value in optional_params.items(): try: # translate the key_attribute kp = SymmetricKeyParam.from_id(_key_attribute, allow_unknown_key_attrs) # parse the value of the key attribute if possible if hasattr(kp, 'value_parser') and hasattr( kp.value_parser, '__call__'): _value = kp.value_parser(_value) # store in new dict transformed_dict[kp] = _value except ValueError: transformed_dict[_key_attribute] = _value # final check if key type is correct if transformed_dict.get(KpKty) != KtySymmetric: raise CoseIllegalKeyType( f"Illegal key type in Symmetric COSE Key: {transformed_dict.get(KpKty)}" ) super(SymmetricKey, self).__init__(transformed_dict) if k != b'': self.k = k else: raise CoseInvalidKey("SymKpK parameter cannot be None")
def __init__(self, crv: Union[Type['CoseCurve'], str, int], x: bytes = b'', y: bytes = b'', d: bytes = b'', optional_params: Optional[dict] = None, allow_unknown_key_attrs: bool = True): """Initialize a COSE key from its components Not passing a `y` component is accepted; in this case, one (of the two) valid `y` will be found for the `x`. This is good enough for everything that only operates on the `x` of any derived outputs (in "compact" mode), as per RFC 6090 Section 4.2. """ transformed_dict = {KpKty: KtyEC2} if optional_params is None: optional_params = {} for _key_attribute, _value in optional_params.items(): try: # transform the key_attribute kp = EC2KeyParam.from_id(_key_attribute, allow_unknown_key_attrs) # parse the value of the key attribute if possible if hasattr(kp, 'value_parser') and hasattr( kp.value_parser, '__call__'): _value = kp.value_parser(_value) # store in new dict transformed_dict[kp] = _value except ValueError: transformed_dict[_key_attribute] = _value # final check if key type is correct if transformed_dict.get(KpKty) != KtyEC2: raise CoseIllegalKeyType( f"Illegal key type in EC2 COSE Key: {transformed_dict.get(KpKty)}" ) super(EC2Key, self).__init__(transformed_dict) if crv is not None: self.crv = crv else: raise CoseInvalidKey("COSE curve cannot be None") if not x and not y and not d: raise CoseInvalidKey( "Either the public values or the private value must be specified" ) if not d and not x: raise CoseInvalidKey("Missing public coordinate X") if d: public_nums = ec.derive_private_key( int.from_bytes(d, byteorder="big"), curve=self.crv.curve_obj()).public_key().public_numbers() if x: assert x == public_nums.x.to_bytes(self.crv.size, 'big') else: x = public_nums.x.to_bytes(self.crv.size, 'big') if y: assert y == public_nums.y.to_bytes(self.crv.size, 'big') else: y = public_nums.y.to_bytes(self.crv.size, 'big') if x and not y: # try to derive y from x key = ec.EllipticCurvePublicKey.from_encoded_point( self.crv.curve_obj(), # don't care which of the two possible Y values we get b'\x03' + x # or [::-1]? ) # Just to check the endianness of the conversions -- if we get the # right X back out, then the X and Y are consistent, and anyway the # crypto backend will check whether the point is on the curve assert x == key.public_numbers().x.to_bytes(self.crv.size, 'big') y = key.public_numbers().y.to_bytes(self.crv.size, 'big') if x != b'': self.x = x if y != b'': self.y = y if d != b'': self.d = d
def __init__(self, n: bytes = b'', e: bytes = b'', d: bytes = b'', p: bytes = b'', q: bytes = b'', dp: bytes = b'', dq: bytes = b'', qinv: bytes = b'', other: Optional[List[dict]] = None, r_i: bytes = b'', d_i: bytes = b'', t_i: bytes = b'', optional_params: Optional[dict] = None, allow_unknown_key_attrs: bool = True): transformed_dict = {KpKty: KtyRSA} if other is None: other = [] if optional_params is None: optional_params = {} # public key, n and e must be defined if len(n) != 0 and len(e) != 0 and all( map(lambda x: len(x) == 0, [d, p, q, dp, dq, qinv, other, r_i, d_i, t_i])): is_valid_key = True # private keys with two primes, except other, r_i, t_i and d_i, all other parameters need to be defined elif all(map(lambda x: len(x) == 0, [other, r_i, t_i, d_i])) and \ all(map(lambda x: len(x) != 0, [n, e, d, p, q, dp, dq, qinv])): is_valid_key = True # private keys with more than two primes, everything needs to be defined elif all( map(lambda x: len(x) != 0, [n, e, d, p, q, dp, dq, qinv, other, r_i, d_i, t_i])): is_valid_key = True # TODO: verify contents of other else: is_valid_key = False if not is_valid_key: raise CoseInvalidKey( "Invalid RSA key: not a public key, private key with two primes or private key " "with more than two primes") for _key_attribute, _value in optional_params.items(): try: # transform the key_attribute kp = RSAKeyParam.from_id(_key_attribute, allow_unknown_key_attrs) # parse the value of the key attribute if possible if hasattr(kp, 'value_parser') and hasattr( kp.value_parser, '__call__'): _value = kp.value_parser(_value) # store in new dict transformed_dict[kp] = _value except ValueError: transformed_dict[_key_attribute] = _value # final check if key type is correct if transformed_dict.get(KpKty) != KtyRSA: raise CoseIllegalKeyType( f"Illegal key type in RSA COSE Key: {transformed_dict.get(KpKty)}" ) super(RSAKey, self).__init__(transformed_dict) self.e = e self.n = n if d != b'': self.d = d if p != b'': self.p = p if q != b'': self.q = q if dp != b'': self.dp = dp if dq != b'': self.dq = dq if qinv != b'': self.qinv = qinv if other: self.other = other if r_i != b'': self.r_i = r_i if d_i != b'': self.d_i = d_i if t_i != b'': self.t_i = t_i