/** * Extract a PgpPrivate key from the SecretKey's encrypted contents. * * @param decryptorFactory factory to use to generate a decryptor for the passed in secretKey. * @return PgpPrivateKey the unencrypted private key. * @throws PgpException on failure. */ public PgpPrivateKey ExtractPrivateKey( IPbeSecretKeyDecryptorProvider decryptorProvider) { if (IsPrivateKeyEmpty) { return(null); } PublicKeyPacket pubPk = secret.PublicKeyPacket; try { byte[] data = extractKeyData(decryptorProvider); BcpgInputStream input = BcpgInputStream.Wrap(new MemoryInputStream(data)); switch (pubPk.Algorithm) { case PublicKeyAlgorithmTag.RsaEncrypt: case PublicKeyAlgorithmTag.RsaGeneral: case PublicKeyAlgorithmTag.RsaSign: RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(input); return(new PgpPrivateKey(this.KeyId, pubPk, rsaPriv)); case PublicKeyAlgorithmTag.Dsa: DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(input); return(new PgpPrivateKey(this.KeyId, pubPk, dsaPriv)); case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(input); return(new PgpPrivateKey(this.KeyId, pubPk, elPriv)); case PublicKeyAlgorithmTag.ECDH: case PublicKeyAlgorithmTag.ECDsa: ECSecretBcpgKey ecPriv = new ECSecretBcpgKey(input); return(new PgpPrivateKey(this.KeyId, pubPk, ecPriv)); default: throw new PgpException("unknown public key algorithm encountered"); } } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception constructing key", e); } }
/** * Return a copy of the passed in secret key, encrypted using a new * password and the passed in algorithm. * * @param key the PgpSecretKey to be copied. * @param oldKeyDecryptor the current decryptor based on the current password for key. * @param newKeyEncryptor a new encryptor based on a new password for encrypting the secret key material. */ public static PgpSecretKey CopyWithNewPassword( PgpSecretKey key, IPbeSecretKeyDecryptorProvider oldKeyDecryptor, IPbeSecretKeyEncryptor newKeyEncryptor) { if (key.IsPrivateKeyEmpty) { throw new PgpException("no private key in this SecretKey - public key present only."); } byte[] rawKeyData = key.extractKeyData(oldKeyDecryptor); int s2kUsage = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; byte[] keyData = null; SymmetricKeyAlgorithmTag newEncAlgorithm = SymmetricKeyAlgorithmTag.Null; if (newKeyEncryptor == null || newKeyEncryptor.AlgorithmDetails.Algorithm == SymmetricKeyAlgorithmTag.Null) { s2kUsage = SecretKeyPacket.UsageNone; if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite checksum { keyData = new byte[rawKeyData.Length - 18]; Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); byte[] check = checksum(null, keyData, keyData.Length - 2); keyData[keyData.Length - 2] = check[0]; keyData[keyData.Length - 1] = check[1]; } else { keyData = rawKeyData; } } else { if (s2kUsage == SecretKeyPacket.UsageNone) { s2kUsage = SecretKeyPacket.UsageChecksum; } if (key.secret.PublicKeyPacket.Version < 4) { // Version 2 or 3 - RSA Keys only keyData = new byte[rawKeyData.Length]; if (newKeyEncryptor.ChecksumCalculatorFactory.AlgorithmDetails.Algorithm != HashAlgorithmTag.MD5) { throw new PgpException("MD5 Digest Calculator required for version 3 key encryptor."); } // // process 4 numbers // int pos = 0; for (int i = 0; i != 4; i++) { int encLen = (((rawKeyData[pos] << 8) | (rawKeyData[pos + 1] & 0xff)) + 7) / 8; keyData[pos] = rawKeyData[pos]; keyData[pos + 1] = rawKeyData[pos + 1]; byte[] tmp; if (i == 0) { tmp = newKeyEncryptor.Wrap(Arrays.CopyOfRange(rawKeyData, pos + 2, pos + 2 + encLen)).Collect(); iv = newKeyEncryptor.AlgorithmDetails.GetIV(); } else { byte[] tmpIv = new byte[iv.Length]; Array.Copy(keyData, pos - iv.Length, tmpIv, 0, tmpIv.Length); newKeyEncryptor = newKeyEncryptor.WithIV(tmpIv); tmp = newKeyEncryptor.Wrap(Arrays.CopyOfRange(rawKeyData, pos + 2, pos + 2 + encLen)).Collect(); } Array.Copy(tmp, 0, keyData, pos + 2, tmp.Length); pos += 2 + encLen; } // // copy in checksum. // keyData[pos] = rawKeyData[pos]; keyData[pos + 1] = rawKeyData[pos + 1]; s2k = newKeyEncryptor.AlgorithmDetails.S2k; newEncAlgorithm = newKeyEncryptor.AlgorithmDetails.Algorithm; } else { keyData = newKeyEncryptor.Wrap(rawKeyData).Collect(); iv = newKeyEncryptor.AlgorithmDetails.GetIV(); s2k = newKeyEncryptor.AlgorithmDetails.S2k; newEncAlgorithm = newKeyEncryptor.AlgorithmDetails.Algorithm; } } SecretKeyPacket secret; if (key.secret is SecretSubkeyPacket) { secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return(new PgpSecretKey(secret, key.pub)); }
private byte[] extractKeyData( IPbeSecretKeyDecryptorProvider decryptorFactory) { byte[] encData = secret.GetSecretKeyData(); byte[] data; if (secret.EncAlgorithm != SymmetricKeyAlgorithmTag.Null) { try { if (secret.PublicKeyPacket.Version == 4) { IKeyUnwrapper <PgpPbeKeyEncryptionParameters> unwrapper = decryptorFactory.CreateKeyUnwrapper(new PgpPbeKeyEncryptionParameters(secret.EncAlgorithm, secret.S2k, secret.GetIV())); data = unwrapper.Unwrap(encData, 0, encData.Length).Collect(); bool useSHA1 = secret.S2kUsage == SecretKeyPacket.UsageSha1; byte[] check = checksum(useSHA1 ? decryptorFactory.CreateDigestFactory(new PgpDigestTypeIdentifier(HashAlgorithmTag.Sha1)) : null, data, (useSHA1) ? data.Length - 20 : data.Length - 2); for (int i = 0; i != check.Length; i++) { if (check[i] != data[data.Length - check.Length + i]) { throw new PgpException("checksum mismatch at " + i + " of " + check.Length); } } } else // version 2 or 3, Rsa only. { IKeyUnwrapper <PgpPbeKeyEncryptionParameters> unwrapper = decryptorFactory.CreateKeyUnwrapper(new PgpPbeKeyEncryptionParameters(secret.EncAlgorithm, secret.S2k, secret.GetIV())); data = new byte[encData.Length]; byte[] iv = new byte[secret.GetIV().Length]; Array.Copy(secret.GetIV(), 0, iv, 0, iv.Length); // // read in the four numbers // int pos = 0; for (int i = 0; i != 4; i++) { int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; byte[] tmp = unwrapper.Unwrap(encData, pos + 2, encLen).Collect(); Array.Copy(tmp, 0, data, pos + 2, tmp.Length); pos += 2 + encLen; if (i != 3) { Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length); } } // // verify and copy checksum // data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); int calcCs = 0; for (int j = 0; j < data.Length - 2; j++) { calcCs += data[j] & 0xff; } calcCs &= 0xffff; if (calcCs != cs) { throw new PgpException("checksum mismatch: passphrase wrong, expected " + cs.ToString("X") + " found " + calcCs.ToString("X")); } } } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception decrypting key", e); } } else { data = encData; } return(data); }