PgpPublicKeyEncryptedData
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cryptlib;
using Org.BouncyCastle.Asn1.EdEC;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Agreement;
using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
public class PgpPublicKeyEncryptedData : PgpEncryptedData
{
private readonly PublicKeyEncSessionPacket m_keyData;
public long KeyId => m_keyData.KeyId;
internal PgpPublicKeyEncryptedData(PublicKeyEncSessionPacket keyData, InputStreamPacket encData)
: base(encData)
{
m_keyData = keyData;
}
private static IBufferedCipher GetKeyCipher(PublicKeyAlgorithmTag algorithm)
{
try {
if ((uint)(algorithm - 1) <= 1)
return CipherUtilities.GetCipher("RSA//PKCS1Padding");
if (algorithm != PublicKeyAlgorithmTag.ElGamalEncrypt && algorithm != PublicKeyAlgorithmTag.ElGamalGeneral)
throw new PgpException("unknown asymmetric algorithm: " + algorithm.ToString());
return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
} catch (PgpException) {
throw;
} catch (Exception innerException) {
throw new PgpException("Exception creating cipher", innerException);
}
}
public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(PgpPrivateKey privKey)
{
return (SymmetricKeyAlgorithmTag)RecoverSessionData(privKey)[0];
}
public Stream GetDataStream(PgpPrivateKey privKey)
{
byte[] array = RecoverSessionData(privKey);
if (!ConfirmCheckSum(array))
throw new PgpKeyValidationException("key checksum failed");
SymmetricKeyAlgorithmTag symmetricKeyAlgorithmTag = (SymmetricKeyAlgorithmTag)array[0];
if (symmetricKeyAlgorithmTag != 0) {
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag);
IBufferedCipher bufferedCipher;
try {
bufferedCipher = CreateBufferedCipher(symmetricCipherName);
} catch (PgpException) {
throw;
} catch (Exception innerException) {
throw new PgpException("exception creating cipher", innerException);
}
try {
KeyParameter parameters = ParameterUtilities.CreateKeyParameter(symmetricCipherName, array, 1, array.Length - 3);
bufferedCipher.Init(false, new ParametersWithIV(parameters, new byte[bufferedCipher.GetBlockSize()]));
Stream stream = InitDecStream(new CipherStream(GetInputStream(), bufferedCipher, null));
StreamUtilities.RequireBytes(stream, bufferedCipher.GetBlockSize() + 2);
return stream;
} catch (PgpException) {
throw;
} catch (Exception innerException2) {
throw new PgpException("Exception starting decryption", innerException2);
}
}
return GetInputStream();
}
private byte[] RecoverSessionData(PgpPrivateKey privKey)
{
byte[][] encSessionKey = m_keyData.GetEncSessionKey();
if (m_keyData.Algorithm != PublicKeyAlgorithmTag.ECDH) {
IBufferedCipher keyCipher = GetKeyCipher(m_keyData.Algorithm);
try {
keyCipher.Init(false, privKey.Key);
} catch (InvalidKeyException innerException) {
throw new PgpException("error setting asymmetric cipher", innerException);
}
if (m_keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt || m_keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral) {
byte[] array = encSessionKey[0];
keyCipher.ProcessBytes(array, 2, array.Length - 2);
} else {
int size = (((ElGamalPrivateKeyParameters)privKey.Key).Parameters.P.BitLength + 7) / 8;
ProcessEncodedMpi(keyCipher, size, encSessionKey[0]);
ProcessEncodedMpi(keyCipher, size, encSessionKey[1]);
}
try {
return keyCipher.DoFinal();
} catch (Exception innerException2) {
throw new PgpException("exception decrypting secret key", innerException2);
}
}
ECDHPublicBcpgKey obj = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key;
byte[] array2 = encSessionKey[0];
int num = (Pack.BE_To_UInt16(array2, 0) + 7) / 8;
if (2 + num + 1 > array2.Length)
throw new PgpException("encoded length out of range");
byte[] array3 = new byte[num];
Array.Copy(array2, 2, array3, 0, num);
int num2 = array2[num + 2];
if (2 + num + 1 + num2 > array2.Length)
throw new PgpException("encoded length out of range");
byte[] array4 = new byte[num2];
Array.Copy(array2, 2 + num + 1, array4, 0, array4.Length);
DerObjectIdentifier curveOid = obj.CurveOid;
byte[] array5;
if (EdECObjectIdentifiers.id_X25519.Equals(curveOid) || CryptlibObjectIdentifiers.curvey25519.Equals(curveOid)) {
if (array3.Length != 1 + X25519PublicKeyParameters.KeySize || 64 != array3[0])
throw new ArgumentException("Invalid X25519 public key");
X25519PublicKeyParameters publicKey = new X25519PublicKeyParameters(array3, 1);
X25519Agreement x25519Agreement = new X25519Agreement();
x25519Agreement.Init(privKey.Key);
array5 = new byte[x25519Agreement.AgreementSize];
x25519Agreement.CalculateAgreement(publicKey, array5, 0);
} else if (EdECObjectIdentifiers.id_X448.Equals(curveOid)) {
if (array3.Length != 1 + X448PublicKeyParameters.KeySize || 64 != array3[0])
throw new ArgumentException("Invalid X448 public key");
X448PublicKeyParameters publicKey2 = new X448PublicKeyParameters(array3, 1);
X448Agreement x448Agreement = new X448Agreement();
x448Agreement.Init(privKey.Key);
array5 = new byte[x448Agreement.AgreementSize];
x448Agreement.CalculateAgreement(publicKey2, array5, 0);
} else {
ECDomainParameters parameters = ((ECPrivateKeyParameters)privKey.Key).Parameters;
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(parameters.Curve.DecodePoint(array3), parameters);
ECDHBasicAgreement eCDHBasicAgreement = new ECDHBasicAgreement();
eCDHBasicAgreement.Init(privKey.Key);
array5 = BigIntegers.AsUnsignedByteArray(n: eCDHBasicAgreement.CalculateAgreement(pubKey), length: eCDHBasicAgreement.GetFieldSize());
}
KeyParameter parameters2 = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, array5));
IWrapper wrapper = PgpUtilities.CreateWrapper(obj.SymmetricKeyAlgorithm);
wrapper.Init(false, parameters2);
return PgpPad.UnpadSessionData(wrapper.Unwrap(array4, 0, array4.Length));
}
private static bool ConfirmCheckSum(byte[] sessionInfo)
{
int num = 0;
for (int i = 1; i < sessionInfo.Length - 2; i++) {
num += sessionInfo[i];
}
return Pack.BE_To_UInt16(sessionInfo, sessionInfo.Length - 2) == (ushort)num;
}
private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc)
{
if (mpiEnc.Length - 2 > size)
cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3);
else {
byte[] array = new byte[size];
Array.Copy(mpiEnc, 2, array, array.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2);
cipher.ProcessBytes(array, 0, array.Length);
}
}
}
}