def msg_authenticate_sign(challenge: bytes, app_id: bytes, privkey: bytes) -> bytes: flags = bytes([_AUTH_FLAG_TUP]) # get next counter ctr = storage.next_u2f_counter() ctrbuf = ustruct.pack(">L", ctr) # hash input data together with counter dig = hashlib.sha256() dig.update(app_id) # uint8_t appId[32]; dig.update(flags) # uint8_t flags; dig.update(ctrbuf) # uint8_t ctr[4]; dig.update(challenge) # uint8_t chal[32]; dig = dig.digest() # sign the digest and convert to der sig = nist256p1.sign(privkey, dig, False) sig = der.encode_seq((sig[1:33], sig[33:])) # pack to a response buf, resp = make_struct(resp_cmd_authenticate(len(sig))) resp.flags = flags[0] resp.ctr = ctr utils.memcpy(resp.sig, 0, sig, 0, len(sig)) resp.status = _SW_NO_ERROR return buf
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_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 sign_challenge( seckey: bytes, challenge_hidden: bytes, challenge_visual: str, sigtype: Union[str, coininfo.CoinInfo], curve: str, ) -> bytes: from trezor.crypto.hashlib import sha256 if curve == "secp256k1": from trezor.crypto.curve import secp256k1 elif curve == "nist256p1": from trezor.crypto.curve import nist256p1 elif curve == "ed25519": from trezor.crypto.curve import ed25519 from apps.common.signverify import message_digest if sigtype == "gpg": data = challenge_hidden elif sigtype == "signify": if curve != "ed25519": raise wire.DataError("Unsupported curve") data = challenge_hidden elif sigtype == "ssh": if curve != "ed25519": data = sha256(challenge_hidden).digest() else: data = challenge_hidden elif isinstance(sigtype, coininfo.CoinInfo): # sigtype is coin challenge = ( sha256(challenge_hidden).digest() + sha256(challenge_visual.encode()).digest() ) data = message_digest(sigtype, challenge) else: raise wire.DataError("Unsupported sigtype") if curve == "secp256k1": signature = secp256k1.sign(seckey, data) elif curve == "nist256p1": signature = nist256p1.sign(seckey, data) elif curve == "ed25519": signature = ed25519.sign(seckey, data) else: raise wire.DataError("Unknown curve") if curve == "ed25519": signature = b"\x00" + signature elif sigtype == "gpg" or sigtype == "ssh": signature = b"\x00" + signature[1:] return signature
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 sign_challenge(seckey: bytes, challenge_hidden: bytes, challenge_visual: str, sigtype, curve: str) -> bytes: from trezor.crypto.hashlib import sha256 if curve == 'secp256k1': from trezor.crypto.curve import secp256k1 elif curve == 'nist256p1': from trezor.crypto.curve import nist256p1 elif curve == 'ed25519': from trezor.crypto.curve import ed25519 from ..common.signverify import message_digest if sigtype == 'gpg': data = challenge_hidden elif sigtype == 'ssh': if curve != 'ed25519': data = sha256(challenge_hidden).digest() else: data = challenge_hidden else: # sigtype is coin challenge = sha256(challenge_hidden).digest() + sha256(challenge_visual).digest() data = message_digest(sigtype, challenge) if curve == 'secp256k1': signature = secp256k1.sign(seckey, data) elif curve == 'nist256p1': signature = nist256p1.sign(seckey, data) elif curve == 'ed25519': signature = ed25519.sign(seckey, data) else: raise ValueError('Unknown curve') if curve == 'ed25519': signature = b'\x00' + signature elif sigtype == 'gpg' or sigtype == 'ssh': signature = b'\x00' + signature[1:] return signature
def sign_challenge(seckey: bytes, challenge_hidden: bytes, challenge_visual: str, sigtype, curve: str) -> bytes: from trezor.crypto.hashlib import sha256 if curve == "secp256k1": from trezor.crypto.curve import secp256k1 elif curve == "nist256p1": from trezor.crypto.curve import nist256p1 elif curve == "ed25519": from trezor.crypto.curve import ed25519 from apps.common.signverify import message_digest if sigtype == "gpg": data = challenge_hidden elif sigtype == "ssh": if curve != "ed25519": data = sha256(challenge_hidden).digest() else: data = challenge_hidden else: # sigtype is coin challenge = (sha256(challenge_hidden).digest() + sha256(challenge_visual).digest()) data = message_digest(sigtype, challenge) if curve == "secp256k1": signature = secp256k1.sign(seckey, data) elif curve == "nist256p1": signature = nist256p1.sign(seckey, data) elif curve == "ed25519": signature = ed25519.sign(seckey, data) else: raise ValueError("Unknown curve") if curve == "ed25519": signature = b"\x00" + signature elif sigtype == "gpg" or sigtype == "ssh": signature = b"\x00" + signature[1:] return signature
def _u2f_sign(self, data: Iterable[bytes]) -> bytes: dig = hashlib.sha256() for segment in data: dig.update(segment) sig = nist256p1.sign(self._private_key(), dig.digest(), False) return der.encode_seq((sig[1:33], sig[33:]))