def __init__(self, credential_id, app_id): if not hasattr(serialization.Encoding, "X962"): raise unittest.SkipTest("Requires Cryptography >= 2.5") assert isinstance(credential_id, six.binary_type) assert isinstance(app_id, six.binary_type) # Note: do not use in production, no garantees is provided this is # cryptographically safe to use. priv_key_params = ConcatKDFHash( algorithm=hashes.SHA256(), length=32, otherinfo=credential_id + app_id, backend=default_backend(), ).derive(self._priv_key_bytes) self.app_id = app_id self.priv_key = ec.derive_private_key(bytes2int(priv_key_params), ec.SECP256R1(), default_backend()) self.pub_key = self.priv_key.public_key() self.public_key_bytes = self.pub_key.public_bytes( serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint) self.credential_id = self.key_handle = credential_id
def __init__(self, auth_data): # aaguid: probably zeroes, maybe not in FIDO2? 16 bytes self.aaguid = bytes2int(auth_data.credential_data.aaguid) # credential_id: too large to store as a BigInteger, so converted to string and stored in a Text field # we do lookups on this (see cls.get_by()) self.credential_id = str(bytes2int(auth_data.credential_data.credential_id)) # public_key: AttestedCredentalData, like a dict but: # * has numerical keys that get converted to strings # * bytes cannot be serialised into JSON, so turn them into ints self.public_key = dict({ **auth_data.credential_data.public_key, -2: bytes2int(auth_data.credential_data.public_key.get(-2)), -3: bytes2int(auth_data.credential_data.public_key.get(-3)), })
def get_by(cls, credential_id_bytes): return User.query.filter(cls.credential_id == str( bytes2int(credential_id_bytes))).one_or_none()