def _create_private_key(self, pubkey, subkey=True): """ Create a private (sub)key from public key and firmware key material """ fp = bytes(pubkey.fingerprint) if fp not in self._keys: return None key = self._keys[fp] pubkm = pubkey._key.keymaterial if key.algo == KeyAlgo.RSA2048 or key.algo == KeyAlgo.RSA4096: assert pubkey._key.pkalg in [PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.RSAEncrypt, PubKeyAlgorithm.RSASign] plen = len(key.priv) // 2 km = RSAPriv() km.n = pubkm.n km.e = pubkm.e km.p = MPI(MPIs.bytes_to_int(key.priv[:plen])) km.q = MPI(MPIs.bytes_to_int(key.priv[plen:])) km.d = MPI(rsa.rsa_crt_iqmp((km.p-1) * (km.q-1), km.e)) km.u = MPI(rsa.rsa_crt_iqmp(km.q, km.p)) elif key.algo == KeyAlgo.CURVE25519: km = ECDHPriv() km.oid = EllipticCurveOID.Curve25519 km.p = pubkm.p km.kdf = pubkm.kdf # GnuPG stores the secret value in the wrong order # https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html km.s = MPI(MPIs.bytes_to_int(key.priv, 'little')) elif key.algo == KeyAlgo.ED25519: # GNUK stores "SHA-512(secret)" # PGP private key stores "secret" logging.warning("Cannot extract Ed25519 key: GNUK format incompatible with PGP format\n" " sha512(secret) = {}".format(hexlify(key.priv).decode('utf-8'))) return None elif key.algo in [KeyAlgo.SECP256K1, KeyAlgo.NISTP256R1]: # Secp256k1 can be used with both ECDH and ECDSA if isinstance(pubkm, ECDSAPub): km = ECDSAPriv() elif isinstance(pubkm, ECDHPub): km = ECDHPriv() km.kdf = pubkm.kdf else: raise Exception("Curve {} cannot be used with algorithm {}".format( str(key.algo), pubkm.__class__.__name__)) if key.algo == KeyAlgo.SECP256K1: km.oid = EllipticCurveOID.SECP256K1 elif key.algo == KeyAlgo.NISTP256R1: km.oid = EllipticCurveOID.NIST_P256 else: raise Exception("Should not happen") km.p = pubkm.p km.s = MPI(MPIs.bytes_to_int(key.priv)) else: # https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-06 raise Exception("Key algo {} not implemented yet".format(str(key.algo))) km._compute_chksum() privkey = PrivSubKeyV4() if subkey else PrivKeyV4() privkey.pkalg = pubkey._key.pkalg privkey.keymaterial = km privkey.created = pubkey._key.created privkey.update_hlen() key = PGPKey() key._key = privkey key._signatures = pubkey._signatures return key
def strip_signatures(key: PGPKey) -> None: # pylint: disable=protected-access key._signatures = SorteDeque()