using System; using System.Collections; using System.IO; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Bcpg.OpenPgp; public class PgpSecretKey { private readonly SecretKeyPacket secret; private readonly PgpPublicKey pub; public bool IsSigningKey { get { switch (pub.Algorithm) { case PublicKeyAlgorithmTag.RsaGeneral: case PublicKeyAlgorithmTag.RsaSign: case PublicKeyAlgorithmTag.Dsa: case PublicKeyAlgorithmTag.ECDsa: case PublicKeyAlgorithmTag.ElGamalGeneral: return true; default: return false; } } } public bool IsMasterKey => pub.IsMasterKey; public bool IsPrivateKeyEmpty { get { byte[] secretKeyData = secret.GetSecretKeyData(); if (secretKeyData != null) { return secretKeyData.Length < 1; } return true; } } public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm => secret.EncAlgorithm; public long KeyId => pub.KeyId; public int S2kUsage => secret.S2kUsage; public S2k S2k => secret.S2k; public PgpPublicKey PublicKey => pub; public IEnumerable UserIds => pub.GetUserIds(); public IEnumerable UserAttributes => pub.GetUserAttributes(); internal PgpSecretKey(SecretKeyPacket secret, PgpPublicKey pub) { this.secret = secret; this.pub = pub; } internal PgpSecretKey(PgpPrivateKey privKey, PgpPublicKey pubKey, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, bool useSha1, SecureRandom rand, bool isMasterKey) { pub = pubKey; BcpgObject bcpgObject; switch (pubKey.Algorithm) { case PublicKeyAlgorithmTag.RsaGeneral: case PublicKeyAlgorithmTag.RsaEncrypt: case PublicKeyAlgorithmTag.RsaSign: { RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = (RsaPrivateCrtKeyParameters)privKey.Key; bcpgObject = new RsaSecretBcpgKey(rsaPrivateCrtKeyParameters.Exponent, rsaPrivateCrtKeyParameters.P, rsaPrivateCrtKeyParameters.Q); break; } case PublicKeyAlgorithmTag.Dsa: { DsaPrivateKeyParameters dsaPrivateKeyParameters = (DsaPrivateKeyParameters)privKey.Key; bcpgObject = new DsaSecretBcpgKey(dsaPrivateKeyParameters.X); break; } case PublicKeyAlgorithmTag.EC: case PublicKeyAlgorithmTag.ECDsa: { ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)privKey.Key; bcpgObject = new ECSecretBcpgKey(eCPrivateKeyParameters.D); break; } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: { ElGamalPrivateKeyParameters elGamalPrivateKeyParameters = (ElGamalPrivateKeyParameters)privKey.Key; bcpgObject = new ElGamalSecretBcpgKey(elGamalPrivateKeyParameters.X); break; } default: throw new PgpException("unknown key class"); } try { MemoryStream memoryStream = new MemoryStream(); BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream); bcpgOutputStream.WriteObject(bcpgObject); byte[] array = memoryStream.ToArray(); byte[] b = Checksum(useSha1, array, array.Length); array = Arrays.Concatenate(array, b); if (encAlgorithm == SymmetricKeyAlgorithmTag.Null) { if (isMasterKey) { secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, array); } else { secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, array); } return; } S2k s2k; byte[] iv; byte[] secKeyData = ((pub.Version < 4) ? EncryptKeyDataV3(array, encAlgorithm, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv) : EncryptKeyDataV4(array, encAlgorithm, HashAlgorithmTag.Sha1, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv)); int s2kUsage = (useSha1 ? 254 : 255); if (isMasterKey) { secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, secKeyData); } else { secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, secKeyData); } } catch (PgpException ex) { throw ex; } catch (Exception exception) { throw new PgpException("Exception encrypting key", exception); } } [Obsolete("Use the constructor taking an explicit 'useSha1' parameter instead")] public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand) { } public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand) { } public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), clearPassPhrase: true, useSha1, hashedPackets, unhashedPackets, rand) { } public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand) { } internal PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, isMasterKey: true) { } public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand) { } public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), clearPassPhrase: true, useSha1, hashedPackets, unhashedPackets, rand) { } public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand) { } internal PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm), encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, isMasterKey: true) { } private static PgpPublicKey CertifiedPublicKey(int certificationLevel, PgpKeyPair keyPair, string id, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets) { PgpSignatureGenerator pgpSignatureGenerator; try { pgpSignatureGenerator = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1); } catch (Exception ex) { throw new PgpException("Creating signature generator: " + ex.Message, ex); } pgpSignatureGenerator.InitSign(certificationLevel, keyPair.PrivateKey); pgpSignatureGenerator.SetHashedSubpackets(hashedPackets); pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets); try { PgpSignature certification = pgpSignatureGenerator.GenerateCertification(id, keyPair.PublicKey); return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification); } catch (Exception ex2) { throw new PgpException("Exception doing certification: " + ex2.Message, ex2); } } private static PgpPublicKey CertifiedPublicKey(int certificationLevel, PgpKeyPair keyPair, string id, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, HashAlgorithmTag hashAlgorithm) { PgpSignatureGenerator pgpSignatureGenerator; try { pgpSignatureGenerator = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, hashAlgorithm); } catch (Exception ex) { throw new PgpException("Creating signature generator: " + ex.Message, ex); } pgpSignatureGenerator.InitSign(certificationLevel, keyPair.PrivateKey); pgpSignatureGenerator.SetHashedSubpackets(hashedPackets); pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets); try { PgpSignature certification = pgpSignatureGenerator.GenerateCertification(id, keyPair.PublicKey); return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification); } catch (Exception ex2) { throw new PgpException("Exception doing certification: " + ex2.Message, ex2); } } public PgpSecretKey(int certificationLevel, PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, AsymmetricKeyParameter privKey, DateTime time, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand) { } public PgpSecretKey(int certificationLevel, PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, AsymmetricKeyParameter privKey, DateTime time, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand) : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand) { } private byte[] ExtractKeyData(byte[] rawPassPhrase, bool clearPassPhrase) { SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm; byte[] secretKeyData = secret.GetSecretKeyData(); if (encAlgorithm == SymmetricKeyAlgorithmTag.Null) { return secretKeyData; } try { KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, rawPassPhrase, clearPassPhrase); byte[] iV = secret.GetIV(); byte[] array; if (secret.PublicKeyPacket.Version >= 4) { array = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iV, secretKeyData, 0, secretKeyData.Length); bool flag = secret.S2kUsage == 254; byte[] array2 = Checksum(flag, array, flag ? (array.Length - 20) : (array.Length - 2)); for (int i = 0; i != array2.Length; i++) { if (array2[i] != array[array.Length - array2.Length + i]) { throw new PgpException("Checksum mismatch at " + i + " of " + array2.Length); } } } else { array = new byte[secretKeyData.Length]; iV = Arrays.Clone(iV); int num = 0; for (int j = 0; j != 4; j++) { int num2 = (((secretKeyData[num] << 8) | (secretKeyData[num + 1] & 0xFF)) + 7) / 8; array[num] = secretKeyData[num]; array[num + 1] = secretKeyData[num + 1]; num += 2; byte[] sourceArray = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iV, secretKeyData, num, num2); Array.Copy(sourceArray, 0, array, num, num2); num += num2; if (j != 3) { Array.Copy(secretKeyData, num - iV.Length, iV, 0, iV.Length); } } array[num] = secretKeyData[num]; array[num + 1] = secretKeyData[num + 1]; int num3 = ((secretKeyData[num] << 8) & 0xFF00) | (secretKeyData[num + 1] & 0xFF); int num4 = 0; for (int k = 0; k < num; k++) { num4 += array[k] & 0xFF; } num4 &= 0xFFFF; if (num4 != num3) { throw new PgpException("Checksum mismatch: passphrase wrong, expected " + num3.ToString("X") + " found " + num4.ToString("X")); } } return array; } catch (PgpException ex) { throw ex; } catch (Exception exception) { throw new PgpException("Exception decrypting key", exception); } } private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding, KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen) { IBufferedCipher cipher; try { string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); cipher = CipherUtilities.GetCipher(symmetricCipherName + modeAndPadding); } catch (Exception exception) { throw new PgpException("Exception creating cipher", exception); } cipher.Init(forEncryption: false, new ParametersWithIV(key, iv)); return cipher.DoFinal(keyData, keyOff, keyLen); } public PgpPrivateKey ExtractPrivateKey(char[] passPhrase) { return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true); } public PgpPrivateKey ExtractPrivateKeyUtf8(char[] passPhrase) { return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true); } public PgpPrivateKey ExtractPrivateKeyRaw(byte[] rawPassPhrase) { return DoExtractPrivateKey(rawPassPhrase, clearPassPhrase: false); } internal PgpPrivateKey DoExtractPrivateKey(byte[] rawPassPhrase, bool clearPassPhrase) { if (IsPrivateKeyEmpty) { return null; } PublicKeyPacket publicKeyPacket = secret.PublicKeyPacket; try { byte[] buffer = ExtractKeyData(rawPassPhrase, clearPassPhrase); BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(buffer, writable: false)); AsymmetricKeyParameter privateKey; switch (publicKeyPacket.Algorithm) { case PublicKeyAlgorithmTag.RsaGeneral: case PublicKeyAlgorithmTag.RsaEncrypt: case PublicKeyAlgorithmTag.RsaSign: { RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)publicKeyPacket.Key; RsaSecretBcpgKey rsaSecretBcpgKey = new RsaSecretBcpgKey(bcpgIn); RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = new RsaPrivateCrtKeyParameters(rsaSecretBcpgKey.Modulus, rsaPublicBcpgKey.PublicExponent, rsaSecretBcpgKey.PrivateExponent, rsaSecretBcpgKey.PrimeP, rsaSecretBcpgKey.PrimeQ, rsaSecretBcpgKey.PrimeExponentP, rsaSecretBcpgKey.PrimeExponentQ, rsaSecretBcpgKey.CrtCoefficient); privateKey = rsaPrivateCrtKeyParameters; break; } case PublicKeyAlgorithmTag.Dsa: { DsaPublicBcpgKey dsaPublicBcpgKey = (DsaPublicBcpgKey)publicKeyPacket.Key; DsaSecretBcpgKey dsaSecretBcpgKey = new DsaSecretBcpgKey(bcpgIn); DsaParameters parameters2 = new DsaParameters(dsaPublicBcpgKey.P, dsaPublicBcpgKey.Q, dsaPublicBcpgKey.G); privateKey = new DsaPrivateKeyParameters(dsaSecretBcpgKey.X, parameters2); break; } case PublicKeyAlgorithmTag.EC: privateKey = GetECKey("ECDH", bcpgIn); break; case PublicKeyAlgorithmTag.ECDsa: privateKey = GetECKey("ECDSA", bcpgIn); break; case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: { ElGamalPublicBcpgKey elGamalPublicBcpgKey = (ElGamalPublicBcpgKey)publicKeyPacket.Key; ElGamalSecretBcpgKey elGamalSecretBcpgKey = new ElGamalSecretBcpgKey(bcpgIn); ElGamalParameters parameters = new ElGamalParameters(elGamalPublicBcpgKey.P, elGamalPublicBcpgKey.G); privateKey = new ElGamalPrivateKeyParameters(elGamalSecretBcpgKey.X, parameters); break; } default: throw new PgpException("unknown public key algorithm encountered"); } return new PgpPrivateKey(KeyId, publicKeyPacket, privateKey); } catch (PgpException ex) { throw ex; } catch (Exception exception) { throw new PgpException("Exception constructing key", exception); } } private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn) { ECPublicBcpgKey eCPublicBcpgKey = (ECPublicBcpgKey)secret.PublicKeyPacket.Key; ECSecretBcpgKey eCSecretBcpgKey = new ECSecretBcpgKey(bcpgIn); return new ECPrivateKeyParameters(algorithm, eCSecretBcpgKey.X, eCPublicBcpgKey.CurveOid); } private static byte[] Checksum(bool useSha1, byte[] bytes, int length) { if (useSha1) { try { IDigest digest = DigestUtilities.GetDigest("SHA1"); digest.BlockUpdate(bytes, 0, length); return DigestUtilities.DoFinal(digest); } catch (Exception exception) { throw new PgpException("Can't find SHA-1", exception); } } int num = 0; for (int i = 0; i != length; i++) { num += bytes[i]; } return new byte[2] { (byte)(num >> 8), (byte)num }; } public byte[] GetEncoded() { MemoryStream memoryStream = new MemoryStream(); Encode(memoryStream); return memoryStream.ToArray(); } public void Encode(Stream outStr) { BcpgOutputStream bcpgOutputStream = BcpgOutputStream.Wrap(outStr); bcpgOutputStream.WritePacket(secret); if (pub.trustPk != null) { bcpgOutputStream.WritePacket(pub.trustPk); } if (pub.subSigs == null) { foreach (PgpSignature keySig in pub.keySigs) { keySig.Encode(bcpgOutputStream); } for (int i = 0; i != pub.ids.Count; i++) { object obj = pub.ids[i]; if (obj is string) { string id = (string)obj; bcpgOutputStream.WritePacket(new UserIdPacket(id)); } else { PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector = (PgpUserAttributeSubpacketVector)obj; bcpgOutputStream.WritePacket(new UserAttributePacket(pgpUserAttributeSubpacketVector.ToSubpacketArray())); } if (pub.idTrusts[i] != null) { bcpgOutputStream.WritePacket((ContainedPacket)pub.idTrusts[i]); } foreach (PgpSignature item in (IList)pub.idSigs[i]) { item.Encode(bcpgOutputStream); } } return; } foreach (PgpSignature subSig in pub.subSigs) { subSig.Encode(bcpgOutputStream); } } public static PgpSecretKey CopyWithNewPassword(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, utf8: false), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: false), clearPassPhrase: true, newEncAlgorithm, rand); } public static PgpSecretKey CopyWithNewPasswordUtf8(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, utf8: true), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: true), clearPassPhrase: true, newEncAlgorithm, rand); } public static PgpSecretKey CopyWithNewPasswordRaw(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, clearPassPhrase: false, newEncAlgorithm, rand); } internal static PgpSecretKey DoCopyWithNewPassword(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, bool clearPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { if (key.IsPrivateKeyEmpty) { throw new PgpException("no private key in this SecretKey - public key present only."); } byte[] array = key.ExtractKeyData(rawOldPassPhrase, clearPassPhrase); int num = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; PublicKeyPacket publicKeyPacket = key.secret.PublicKeyPacket; byte[] array2; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { num = 0; if (key.secret.S2kUsage == 254) { array2 = new byte[array.Length - 18]; Array.Copy(array, 0, array2, 0, array2.Length - 2); byte[] array3 = Checksum(useSha1: false, array2, array2.Length - 2); array2[^2] = array3[0]; array2[^1] = array3[1]; } else { array2 = array; } } else { if (num == 0) { num = 255; } try { array2 = ((publicKeyPacket.Version < 4) ? EncryptKeyDataV3(array, newEncAlgorithm, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv) : EncryptKeyDataV4(array, newEncAlgorithm, HashAlgorithmTag.Sha1, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv)); } catch (PgpException ex) { throw ex; } catch (Exception exception) { throw new PgpException("Exception encrypting key", exception); } } SecretKeyPacket secretKeyPacket = ((!(key.secret is SecretSubkeyPacket)) ? new SecretKeyPacket(publicKeyPacket, newEncAlgorithm, num, s2k, iv, array2) : new SecretSubkeyPacket(publicKeyPacket, newEncAlgorithm, num, s2k, iv, array2)); return new PgpSecretKey(secretKeyPacket, key.pub); } public static PgpSecretKey ReplacePublicKey(PgpSecretKey secretKey, PgpPublicKey publicKey) { if (publicKey.KeyId != secretKey.KeyId) { throw new ArgumentException("KeyId's do not match"); } return new PgpSecretKey(secretKey.secret, publicKey); } private static byte[] EncryptKeyDataV3(byte[] rawKeyData, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, SecureRandom random, out S2k s2k, out byte[] iv) { s2k = null; iv = null; KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase); byte[] array = new byte[rawKeyData.Length]; int num = 0; for (int i = 0; i != 4; i++) { int num2 = (((rawKeyData[num] << 8) | (rawKeyData[num + 1] & 0xFF)) + 7) / 8; array[num] = rawKeyData[num]; array[num + 1] = rawKeyData[num + 1]; byte[] array2; if (i == 0) { array2 = EncryptData(encAlgorithm, key, rawKeyData, num + 2, num2, random, ref iv); } else { byte[] iv2 = Arrays.CopyOfRange(array, num - iv.Length, num); array2 = EncryptData(encAlgorithm, key, rawKeyData, num + 2, num2, random, ref iv2); } Array.Copy(array2, 0, array, num + 2, array2.Length); num += 2 + num2; } array[num] = rawKeyData[num]; array[num + 1] = rawKeyData[num + 1]; return array; } private static byte[] EncryptKeyDataV4(byte[] rawKeyData, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool clearPassPhrase, SecureRandom random, out S2k s2k, out byte[] iv) { s2k = PgpUtilities.GenerateS2k(hashAlgorithm, 96, random); KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase); iv = null; return EncryptData(encAlgorithm, key, rawKeyData, 0, rawKeyData.Length, random, ref iv); } private static byte[] EncryptData(SymmetricKeyAlgorithmTag encAlgorithm, KeyParameter key, byte[] data, int dataOff, int dataLen, SecureRandom random, ref byte[] iv) { IBufferedCipher cipher; try { string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm); cipher = CipherUtilities.GetCipher(symmetricCipherName + "/CFB/NoPadding"); } catch (Exception exception) { throw new PgpException("Exception creating cipher", exception); } if (iv == null) { iv = PgpUtilities.GenerateIV(cipher.GetBlockSize(), random); } cipher.Init(forEncryption: true, new ParametersWithRandom(new ParametersWithIV(key, iv), random)); return cipher.DoFinal(data, dataOff, dataLen); } public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true, pubKey); } public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true, pubKey); } public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase, PgpPublicKey pubKey) { return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, clearPassPhrase: false, pubKey); } internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey) { SXprUtilities.SkipOpenParenthesis(inputStream); string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text.Equals("protected-private-key")) { SXprUtilities.SkipOpenParenthesis(inputStream); string text2 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text2.Equals("ecc")) { SXprUtilities.SkipOpenParenthesis(inputStream); SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); string curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); SXprUtilities.SkipCloseParenthesis(inputStream); SXprUtilities.SkipOpenParenthesis(inputStream); text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text.Equals("q")) { SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); SXprUtilities.SkipCloseParenthesis(inputStream); byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName); return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), pubKey); } throw new PgpException("no q value found"); } throw new PgpException("no curve details found"); } throw new PgpException("unknown key type found"); } public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true); } public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true); } public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase) { return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, clearPassPhrase: false); } internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase) { SXprUtilities.SkipOpenParenthesis(inputStream); string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text.Equals("protected-private-key")) { SXprUtilities.SkipOpenParenthesis(inputStream); string text2 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text2.Equals("ecc")) { SXprUtilities.SkipOpenParenthesis(inputStream); SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); string text3 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (Platform.StartsWith(text3, "NIST ")) { text3 = text3.Substring("NIST ".Length); } SXprUtilities.SkipCloseParenthesis(inputStream); SXprUtilities.SkipOpenParenthesis(inputStream); text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text.Equals("q")) { byte[] bytes = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); PublicKeyPacket publicKeyPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow, new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(text3), new BigInteger(1, bytes))); SXprUtilities.SkipCloseParenthesis(inputStream); byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, text3); return new PgpSecretKey(new SecretKeyPacket(publicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(publicKeyPacket)); } throw new PgpException("no q value found"); } throw new PgpException("no curve details found"); } throw new PgpException("unknown key type found"); } private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName) { SXprUtilities.SkipOpenParenthesis(inputStream); string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (text.Equals("protected")) { SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); SXprUtilities.SkipOpenParenthesis(inputStream); S2k s2k = SXprUtilities.ParseS2k(inputStream); byte[] iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); SXprUtilities.SkipCloseParenthesis(inputStream); byte[] array = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, rawPassPhrase, clearPassPhrase); byte[] buffer = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, array, 0, array.Length); Stream stream = new MemoryStream(buffer, writable: false); SXprUtilities.SkipOpenParenthesis(stream); SXprUtilities.SkipOpenParenthesis(stream); SXprUtilities.SkipOpenParenthesis(stream); SXprUtilities.ReadString(stream, stream.ReadByte()); return SXprUtilities.ReadBytes(stream, stream.ReadByte()); } throw new PgpException("protected block not found"); } }