def _nosecrete_private_key(pubkey): """ Create the parent certify key without the private parts """ km = OpaquePrivKey() km.parse(pubkey.keymaterial.__bytearray__()) # S2K GNU extension: private key without secrete parts km.s2k.parse(bytearray(b'\xff\x00\x65\x00GNU\x01')) # wrap key material in PrivKeyV4 containing info about algo, creation timestamp, ... privkey = PrivKeyV4() privkey.pkalg = pubkey.pkalg privkey.keymaterial = km privkey.created = pubkey.created privkey.update_hlen() # wrap private key in a PGPKey object key = PGPKey() key._key = privkey return key
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
rsa_priv = RSAPriv() rsa_priv.e = MPI(int(gpg['e'], 16)) rsa_priv.n = MPI(int(gpg['n'], 16)) rsa_priv.d = MPI(int(gpg['d'], 16)) rsa_priv.p = MPI(int(gpg['p'], 16)) rsa_priv.q = MPI(int(gpg['q'], 16)) rsa_priv.u = MPI(int(gpg['u'], 16)) rsa_priv._compute_chksum() restored_priv_key = PrivKeyV4() restored_priv_key.pkalg = PubKeyAlgorithm.RSAEncryptOrSign restored_priv_key.keymaterial = rsa_priv restored_priv_key.update_hlen() pgp_key = PGPKey() pgp_key._key = restored_priv_key public_key, _ = PGPKey.from_blob(gpg['public']) # fingerprint contains cration date so we need explicit copy this one pgp_key._key.created = public_key._key.created pgp_key.add_uid(public_key.userids[0], usage={ KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage }, hashes=[ HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224 ],