PgpSecretKey
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());
}
}
}