def test_publickey(self): for sk, pk in self.vectors: sk = hex(sk)[2:] if len(sk) < 64: sk = '0' * (64 - len(sk)) + sk pk = pk.lower() pk65 = hexlify(nist256p1.publickey(unhexlify(sk), False)).decode( 'ascii') # uncompressed self.assertEqual(str(pk65), '04' + pk) pk33 = hexlify(nist256p1.publickey(unhexlify(sk))).decode('ascii') if pk[-1] in '02468ace': self.assertEqual(pk33, '02' + pk[:64]) else: self.assertEqual(pk33, '03' + pk[:64])
def test_sign_verify_random(self): for _ in range(100): sk = nist256p1.generate_secret() pk = nist256p1.publickey(sk) dig = random.bytes(32) sig = nist256p1.sign(sk, dig) self.assertTrue(nist256p1.verify(pk, sig, dig)) self.assertTrue(nist256p1.verify(pk, sig[1:], dig))
def test_verify_recover(self): for compressed in [False, True]: for _ in range(100): sk = nist256p1.generate_secret() pk = nist256p1.publickey(sk, compressed) dig = random.bytes(32) sig = nist256p1.sign(sk, dig, compressed) pk2 = nist256p1.verify_recover(sig, dig) self.assertEqual(pk, pk2)
def test_fido2_credential_decode(self): mnemonic_secret = b"all all all all all all all all all all all all" mnemonic.get_secret = lambda: mnemonic_secret storage.is_initialized = lambda: True cred_id = ( b"f1d0020013e65c865634ad8abddf7a66df56ae7d8c3afd356f76426801508b2e" b"579bcb3496fe6396a6002e3cd6d80f6359dfa9961e24c544bfc2f26acec1b8d8" b"78ba56727e1f6a7b5176c607552aea63a5abe5d826d69fab3063edfa0201d9a5" b"1013d69eddb2eff37acdd5963f" ) rp_id = "example.com" rp_id_hash = sha256(rp_id).digest() user_id = ( b"3082019330820138a0030201023082019330820138a003020102308201933082" ) user_name = "*****@*****.**" creation_time = 2 public_key = ( b"0451f0d4c307bc737c90ac605c6279f7d01e451798aa7b74df550fdb43a7760c" b"7c02b5107fef42094d00f52a9b1e90afb90e1b9decbf15a6f13d4f882de857e2" b"f4" ) cred_random = ( b"36a9b5d71c13ed54594474b54073af1fb03ea91cd056588909dae43ae2f35dbf" ) # Load credential. cred = Fido2Credential.from_cred_id(unhexlify(cred_id), rp_id_hash) self.assertIsNotNone(cred) # Check credential data. self.assertEqual(hexlify(cred.id), cred_id) self.assertEqual(cred.rp_id, rp_id) self.assertEqual(cred.rp_id_hash, rp_id_hash) self.assertEqual(hexlify(cred.user_id), user_id) self.assertEqual(cred.user_name, user_name) self.assertEqual(cred.creation_time, creation_time) self.assertTrue(cred.hmac_secret) self.assertIsNone(cred.rp_name) self.assertIsNone(cred.user_display_name) # Check credential keys. self.assertEqual(hexlify(cred.hmac_secret_key()), cred_random) cred_public_key = nist256p1.publickey(cred.private_key(), False) self.assertEqual(hexlify(cred_public_key), public_key)
def msg_register_sign(challenge: bytes, app_id: bytes) -> bytes: from apps.common import seed # derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' keypath = [0x80000000 | random.uniform(0xf0000000) for _ in range(0, 8)] nodepath = [_U2F_KEY_PATH] + keypath # prepare signing key from random path, compute decompressed public key node = seed.get_root_without_passphrase('nist256p1') node.derive_path(nodepath) pubkey = nist256p1.publickey(node.private_key(), False) # first half of keyhandle is keypath keybuf = ustruct.pack('>8L', *keypath) # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) keybase.update(keybuf) keybase = keybase.digest() # hash the request data together with keyhandle and pubkey dig = hashlib.sha256() dig.update(b'\x00') # uint8_t reserved; dig.update(app_id) # uint8_t appId[32]; dig.update(challenge) # uint8_t chal[32]; dig.update(keybuf) # uint8_t keyHandle[64]; dig.update(keybase) dig.update(pubkey) # uint8_t pubKey[65]; dig = dig.digest() # sign the digest and convert to der sig = nist256p1.sign(_U2F_ATT_PRIV_KEY, dig, False) sig = der.encode_seq((sig[1:33], sig[33:])) # pack to a response buf, resp = make_struct( resp_cmd_register( len(keybuf) + len(keybase), len(_U2F_ATT_CERT), len(sig))) resp.registerId = _U2F_REGISTER_ID utils.memcpy(resp.pubKey, 0, pubkey, 0, len(pubkey)) resp.keyHandleLen = len(keybuf) + len(keybase) utils.memcpy(resp.keyHandle, 0, keybuf, 0, len(keybuf)) utils.memcpy(resp.keyHandle, len(keybuf), keybase, 0, len(keybase)) utils.memcpy(resp.cert, 0, _U2F_ATT_CERT, 0, len(_U2F_ATT_CERT)) utils.memcpy(resp.sig, 0, sig, 0, len(sig)) resp.status = _SW_NO_ERROR return buf
def test_sign_verify_min_max(self): sk = nist256p1.generate_secret() pk = nist256p1.publickey(sk) dig = bytes([1] + [0] * 31) sig = nist256p1.sign(sk, dig) self.assertTrue(nist256p1.verify(pk, sig, dig)) self.assertTrue(nist256p1.verify(pk, sig[1:], dig)) dig = bytes([0] * 31 + [1]) sig = nist256p1.sign(sk, dig) self.assertTrue(nist256p1.verify(pk, sig, dig)) self.assertTrue(nist256p1.verify(pk, sig[1:], dig)) dig = bytes([0xFF] * 32) sig = nist256p1.sign(sk, dig) self.assertTrue(nist256p1.verify(pk, sig, dig)) self.assertTrue(nist256p1.verify(pk, sig[1:], dig))
def public_key(self) -> bytes: if self.curve == common.COSE_CURVE_P256: pubkey = nist256p1.publickey(self._private_key(), False) return cbor.encode({ common.COSE_KEY_ALG: self.algorithm, common.COSE_KEY_KTY: common.COSE_KEYTYPE_EC2, common.COSE_KEY_CRV: self.curve, common.COSE_KEY_X: pubkey[1:33], common.COSE_KEY_Y: pubkey[33:], }) elif self.curve == common.COSE_CURVE_ED25519: pubkey = ed25519.publickey(self._private_key()) return cbor.encode({ common.COSE_KEY_ALG: self.algorithm, common.COSE_KEY_KTY: common.COSE_KEYTYPE_OKP, common.COSE_KEY_CRV: self.curve, common.COSE_KEY_X: pubkey, }) raise TypeError
def public_key(self) -> bytes: return nist256p1.publickey(self._private_key(), False)