<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />

PgpSecretKey

public class PgpSecretKey : PgpObject
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cryptlib; using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Gnu; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Math.EC.Rfc8032; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; using System.Collections.Generic; using System.IO; namespace Org.BouncyCastle.Bcpg.OpenPgp { public class PgpSecretKey : PgpObject { 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: case PublicKeyAlgorithmTag.EdDsa: 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<string> UserIds => pub.GetUserIds(); public IEnumerable<PgpUserAttributeSubpacketVector> 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; PublicKeyAlgorithmTag algorithm = pubKey.Algorithm; BcpgObject bcpgObject; if ((uint)(algorithm - 1) > 2) { switch (algorithm) { case PublicKeyAlgorithmTag.Dsa: bcpgObject = new DsaSecretBcpgKey(((DsaPrivateKeyParameters)privKey.Key).X); break; case PublicKeyAlgorithmTag.ECDH: { ECPrivateKeyParameters eCPrivateKeyParameters = privKey.Key as ECPrivateKeyParameters; if (eCPrivateKeyParameters != null) bcpgObject = new ECSecretBcpgKey(eCPrivateKeyParameters.D); else { X25519PrivateKeyParameters x25519PrivateKeyParameters = (X25519PrivateKeyParameters)privKey.Key; bcpgObject = new ECSecretBcpgKey(new BigInteger(1, x25519PrivateKeyParameters.DataSpan, false)); } break; } case PublicKeyAlgorithmTag.ECDsa: bcpgObject = new ECSecretBcpgKey(((ECPrivateKeyParameters)privKey.Key).D); break; case PublicKeyAlgorithmTag.EdDsa: { Ed25519PrivateKeyParameters ed25519PrivateKeyParameters = privKey.Key as Ed25519PrivateKeyParameters; if (ed25519PrivateKeyParameters != null) bcpgObject = new EdSecretBcpgKey(new BigInteger(1, ed25519PrivateKeyParameters.DataSpan)); else { Ed448PrivateKeyParameters ed448PrivateKeyParameters = privKey.Key as Ed448PrivateKeyParameters; if (ed448PrivateKeyParameters == null) throw new PgpException("unknown EdDSA key class"); bcpgObject = new EdSecretBcpgKey(new BigInteger(1, ed448PrivateKeyParameters.DataSpan)); } break; } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: bcpgObject = new ElGamalSecretBcpgKey(((ElGamalPrivateKeyParameters)privKey.Key).X); break; default: throw new PgpException("unknown key class"); } } else { RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = (RsaPrivateCrtKeyParameters)privKey.Key; bcpgObject = new RsaSecretBcpgKey(rsaPrivateCrtKeyParameters.Exponent, rsaPrivateCrtKeyParameters.P, rsaPrivateCrtKeyParameters.Q); } try { MemoryStream memoryStream = new MemoryStream(); new BcpgOutputStream(memoryStream).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); } else { 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) { throw; } catch (Exception innerException) { throw new PgpException("Exception encrypting key", innerException); } } 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, 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), 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, 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, 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, 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), 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, 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, 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, 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) { } public byte[] GetFingerprint() { return pub.GetFingerprint(); } private byte[] ExtractKeyData(byte[] rawPassPhrase, bool clearPassPhrase) { SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm; byte[] secretKeyData = secret.GetSecretKeyData(); if (encAlgorithm != 0) 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.ToString() + " of " + array2.Length.ToString()); } } else { array = new byte[secretKeyData.Length]; iV = Arrays.Clone(iV); int num = 0; for (int j = 0; j != 4; j++) { int num2 = ((((secretKeyData[num] & 255) << 8) | (secretKeyData[num + 1] & 255)) + 7) / 8; array[num] = secretKeyData[num]; array[num + 1] = secretKeyData[num + 1]; num += 2; if (num2 > secretKeyData.Length - num) throw new PgpException("out of range encLen found in encData"); Array.Copy(RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iV, secretKeyData, num, num2), 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) & 65280) | (secretKeyData[num + 1] & 255); int num4 = 0; for (int k = 0; k < num; k++) { num4 += (array[k] & 255); } num4 &= 65535; if (num4 != num3) throw new PgpException("Checksum mismatch: passphrase wrong, expected " + num3.ToString("X") + " found " + num4.ToString("X")); } return array; } catch (PgpException) { throw; } catch (Exception innerException) { throw new PgpException("Exception decrypting key", innerException); } return secretKeyData; } private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding, KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen) { IBufferedCipher cipher; try { cipher = CipherUtilities.GetCipher(PgpUtilities.GetSymmetricCipherName(encAlgorithm) + modeAndPadding); } catch (Exception innerException) { throw new PgpException("Exception creating cipher", innerException); } cipher.Init(false, new ParametersWithIV(key, iv)); return cipher.DoFinal(keyData, keyOff, keyLen); } public PgpPrivateKey ExtractPrivateKey(char[] passPhrase) { return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, false), true); } public PgpPrivateKey ExtractPrivateKeyUtf8(char[] passPhrase) { return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, true), true); } public PgpPrivateKey ExtractPrivateKeyRaw(byte[] rawPassPhrase) { return DoExtractPrivateKey(rawPassPhrase, false); } internal PgpPrivateKey DoExtractPrivateKey(byte[] rawPassPhrase, bool clearPassPhrase) { if (!IsPrivateKeyEmpty) { PublicKeyPacket publicKeyPacket = secret.PublicKeyPacket; try { BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(ExtractKeyData(rawPassPhrase, clearPassPhrase), false)); PublicKeyAlgorithmTag algorithm = publicKeyPacket.Algorithm; AsymmetricKeyParameter privateKey; if ((uint)(algorithm - 1) > 2) { switch (algorithm) { case PublicKeyAlgorithmTag.Dsa: { DsaPublicBcpgKey dsaPublicBcpgKey = (DsaPublicBcpgKey)publicKeyPacket.Key; DsaSecretBcpgKey dsaSecretBcpgKey = new DsaSecretBcpgKey(bcpgIn); privateKey = new DsaPrivateKeyParameters(parameters: new DsaParameters(dsaPublicBcpgKey.P, dsaPublicBcpgKey.Q, dsaPublicBcpgKey.G), x: dsaSecretBcpgKey.X); break; } case PublicKeyAlgorithmTag.ECDH: { ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)publicKeyPacket.Key; ECSecretBcpgKey eCSecretBcpgKey2 = new ECSecretBcpgKey(bcpgIn); DerObjectIdentifier curveOid2 = eCDHPublicBcpgKey.CurveOid; privateKey = ((EdECObjectIdentifiers.id_X25519.Equals(curveOid2) || CryptlibObjectIdentifiers.curvey25519.Equals(curveOid2)) ? PrivateKeyFactory.CreateKey(new PrivateKeyInfo(new AlgorithmIdentifier(curveOid2), new DerOctetString(Arrays.ReverseInPlace(BigIntegers.AsUnsignedByteArray(eCSecretBcpgKey2.X))))) : ((!EdECObjectIdentifiers.id_X448.Equals(curveOid2)) ? new ECPrivateKeyParameters("ECDH", eCSecretBcpgKey2.X, eCDHPublicBcpgKey.CurveOid) : PrivateKeyFactory.CreateKey(new PrivateKeyInfo(new AlgorithmIdentifier(curveOid2), new DerOctetString(Arrays.ReverseInPlace(BigIntegers.AsUnsignedByteArray(eCSecretBcpgKey2.X))))))); break; } case PublicKeyAlgorithmTag.ECDsa: { ECPublicBcpgKey eCPublicBcpgKey = (ECPublicBcpgKey)publicKeyPacket.Key; ECSecretBcpgKey eCSecretBcpgKey = new ECSecretBcpgKey(bcpgIn); privateKey = new ECPrivateKeyParameters("ECDSA", eCSecretBcpgKey.X, eCPublicBcpgKey.CurveOid); break; } case PublicKeyAlgorithmTag.EdDsa: { EdDsaPublicBcpgKey obj = (EdDsaPublicBcpgKey)publicKeyPacket.Key; EdSecretBcpgKey edSecretBcpgKey = new EdSecretBcpgKey(bcpgIn); DerObjectIdentifier curveOid = obj.CurveOid; if (EdECObjectIdentifiers.id_Ed25519.Equals(curveOid) || GnuObjectIdentifiers.Ed25519.Equals(curveOid)) privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo(new AlgorithmIdentifier(curveOid), new DerOctetString(BigIntegers.AsUnsignedByteArray(Ed25519.SecretKeySize, edSecretBcpgKey.X)))); else { if (!EdECObjectIdentifiers.id_Ed448.Equals(curveOid)) throw new InvalidOperationException(); privateKey = PrivateKeyFactory.CreateKey(new PrivateKeyInfo(new AlgorithmIdentifier(curveOid), new DerOctetString(BigIntegers.AsUnsignedByteArray(Ed448.SecretKeySize, edSecretBcpgKey.X)))); } break; } case PublicKeyAlgorithmTag.ElGamalEncrypt: case PublicKeyAlgorithmTag.ElGamalGeneral: { ElGamalPublicBcpgKey elGamalPublicBcpgKey = (ElGamalPublicBcpgKey)publicKeyPacket.Key; ElGamalSecretBcpgKey elGamalSecretBcpgKey = new ElGamalSecretBcpgKey(bcpgIn); privateKey = new ElGamalPrivateKeyParameters(parameters: new ElGamalParameters(elGamalPublicBcpgKey.P, elGamalPublicBcpgKey.G), x: elGamalSecretBcpgKey.X); break; } default: throw new PgpException("unknown public key algorithm encountered"); } } else { RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)publicKeyPacket.Key; RsaSecretBcpgKey rsaSecretBcpgKey = new RsaSecretBcpgKey(bcpgIn); privateKey = new RsaPrivateCrtKeyParameters(rsaSecretBcpgKey.Modulus, rsaPublicBcpgKey.PublicExponent, rsaSecretBcpgKey.PrivateExponent, rsaSecretBcpgKey.PrimeP, rsaSecretBcpgKey.PrimeQ, rsaSecretBcpgKey.PrimeExponentP, rsaSecretBcpgKey.PrimeExponentQ, rsaSecretBcpgKey.CrtCoefficient); } return new PgpPrivateKey(KeyId, publicKeyPacket, privateKey); } catch (PgpException) { throw; } catch (Exception innerException) { throw new PgpException("Exception constructing key", innerException); } } return null; } private static byte[] Checksum(bool useSha1, byte[] bytes, int length) { if (useSha1) try { IDigest digest = PgpUtilities.CreateDigest(HashAlgorithmTag.Sha1); digest.BlockUpdate(bytes, 0, length); return DigestUtilities.DoFinal(digest); } catch (Exception innerException) { throw new PgpException("Can't find SHA-1", innerException); } 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); } int num = 0; while (true) { if (num == pub.ids.Count) return; IUserDataPacket userDataPacket = pub.ids[num]; UserIdPacket userIdPacket = userDataPacket as UserIdPacket; if (userIdPacket != null) bcpgOutputStream.WritePacket(userIdPacket); else { PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector = userDataPacket as PgpUserAttributeSubpacketVector; if (pgpUserAttributeSubpacketVector == null) break; bcpgOutputStream.WritePacket(new UserAttributePacket(pgpUserAttributeSubpacketVector.ToSubpacketArray())); } TrustPacket trustPacket = pub.idTrusts[num]; if (trustPacket != null) bcpgOutputStream.WritePacket(trustPacket); foreach (PgpSignature item in pub.idSigs[num]) { item.Encode(bcpgOutputStream); } num++; } throw new InvalidOperationException(); } 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, false), PgpUtilities.EncodePassPhrase(newPassPhrase, false), true, newEncAlgorithm, rand); } public static PgpSecretKey CopyWithNewPasswordUtf8(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, true), PgpUtilities.EncodePassPhrase(newPassPhrase, true), true, newEncAlgorithm, rand); } public static PgpSecretKey CopyWithNewPasswordRaw(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, 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(false, array2, array2.Length - 2); array2[array2.Length - 2] = array3[0]; array2[array2.Length - 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) { throw; } catch (Exception innerException) { throw new PgpException("Exception encrypting key", innerException); } } 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] & 255) << 8) | (rawKeyData[num + 1] & 255)) + 7) / 8; array[num] = rawKeyData[num]; array[num + 1] = rawKeyData[num + 1]; if (num2 > rawKeyData.Length - (num + 2)) throw new PgpException("out of range encLen found in rawKeyData"); 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 { cipher = CipherUtilities.GetCipher(PgpUtilities.GetSymmetricCipherName(encAlgorithm) + "/CFB/NoPadding"); } catch (Exception innerException) { throw new PgpException("Exception creating cipher", innerException); } if (iv == null) iv = PgpUtilities.GenerateIV(cipher.GetBlockSize(), random); cipher.Init(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, false), true, pubKey); } public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true, pubKey); } public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase, PgpPublicKey pubKey) { return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false, pubKey); } internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey) { SXprUtilities.SkipOpenParenthesis(inputStream); if (SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("protected-private-key")) { SXprUtilities.SkipOpenParenthesis(inputStream); if (!SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("ecc")) throw new PgpException("no curve details found"); SXprUtilities.SkipOpenParenthesis(inputStream); SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); string curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); SXprUtilities.SkipCloseParenthesis(inputStream); SXprUtilities.SkipOpenParenthesis(inputStream); if (!SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("q")) throw new PgpException("no q value found"); 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("unknown key type found"); } public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true); } public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase) { return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true); } public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase) { return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false); } internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase) { SXprUtilities.SkipOpenParenthesis(inputStream); if (SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("protected-private-key")) { SXprUtilities.SkipOpenParenthesis(inputStream); if (!SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("ecc")) throw new PgpException("no curve details found"); SXprUtilities.SkipOpenParenthesis(inputStream); SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte()); if (Platform.StartsWith(text, "NIST ")) text = text.Substring("NIST ".Length); SXprUtilities.SkipCloseParenthesis(inputStream); SXprUtilities.SkipOpenParenthesis(inputStream); if (!SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("q")) throw new PgpException("no q value found"); byte[] bytes = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte()); PublicKeyPacket publicKeyPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow, new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(text), new BigInteger(1, bytes))); SXprUtilities.SkipCloseParenthesis(inputStream); byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, text); return new PgpSecretKey(new SecretKeyPacket(publicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(publicKeyPacket)); } throw new PgpException("unknown key type found"); } private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName) { SXprUtilities.SkipOpenParenthesis(inputStream); if (!SXprUtilities.ReadString(inputStream, inputStream.ReadByte()).Equals("protected")) throw new PgpException("protected block not found"); 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); MemoryStream memoryStream = new MemoryStream(RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, array, 0, array.Length), false); SXprUtilities.SkipOpenParenthesis(memoryStream); SXprUtilities.SkipOpenParenthesis(memoryStream); SXprUtilities.SkipOpenParenthesis(memoryStream); SXprUtilities.ReadString(memoryStream, memoryStream.ReadByte()); return SXprUtilities.ReadBytes(memoryStream, memoryStream.ReadByte()); } } }