<PackageReference Include="BouncyCastle.Cryptography" Version="2.7.0-beta.98" />

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