102 lines
3.5 KiB
C#
102 lines
3.5 KiB
C#
using System;
|
|
using System.IO;
|
|
using Org.BouncyCastle.Crypto;
|
|
using Org.BouncyCastle.Crypto.IO;
|
|
using Org.BouncyCastle.Crypto.Parameters;
|
|
using Org.BouncyCastle.Security;
|
|
using Org.BouncyCastle.Utilities.IO;
|
|
|
|
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
|
|
|
public class PgpPbeEncryptedData : PgpEncryptedData
|
|
{
|
|
private readonly SymmetricKeyEncSessionPacket keyData;
|
|
|
|
internal PgpPbeEncryptedData(SymmetricKeyEncSessionPacket keyData, InputStreamPacket encData)
|
|
: base(encData)
|
|
{
|
|
this.keyData = keyData;
|
|
}
|
|
|
|
public override Stream GetInputStream()
|
|
{
|
|
return encData.GetInputStream();
|
|
}
|
|
|
|
public Stream GetDataStream(char[] passPhrase)
|
|
{
|
|
return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
|
}
|
|
|
|
public Stream GetDataStreamUtf8(char[] passPhrase)
|
|
{
|
|
return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
|
}
|
|
|
|
public Stream GetDataStreamRaw(byte[] rawPassPhrase)
|
|
{
|
|
return DoGetDataStream(rawPassPhrase, clearPassPhrase: false);
|
|
}
|
|
|
|
internal Stream DoGetDataStream(byte[] rawPassPhrase, bool clearPassPhrase)
|
|
{
|
|
try
|
|
{
|
|
SymmetricKeyAlgorithmTag symmetricKeyAlgorithmTag = keyData.EncAlgorithm;
|
|
KeyParameter parameters = PgpUtilities.DoMakeKeyFromPassPhrase(symmetricKeyAlgorithmTag, keyData.S2k, rawPassPhrase, clearPassPhrase);
|
|
byte[] secKeyData = keyData.GetSecKeyData();
|
|
if (secKeyData != null && secKeyData.Length > 0)
|
|
{
|
|
IBufferedCipher cipher = CipherUtilities.GetCipher(PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag) + "/CFB/NoPadding");
|
|
cipher.Init(forEncryption: false, new ParametersWithIV(parameters, new byte[cipher.GetBlockSize()]));
|
|
byte[] array = cipher.DoFinal(secKeyData);
|
|
symmetricKeyAlgorithmTag = (SymmetricKeyAlgorithmTag)array[0];
|
|
parameters = ParameterUtilities.CreateKeyParameter(PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag), array, 1, array.Length - 1);
|
|
}
|
|
IBufferedCipher bufferedCipher = CreateStreamCipher(symmetricKeyAlgorithmTag);
|
|
byte[] array2 = new byte[bufferedCipher.GetBlockSize()];
|
|
bufferedCipher.Init(forEncryption: false, new ParametersWithIV(parameters, array2));
|
|
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), bufferedCipher, null));
|
|
if (encData is SymmetricEncIntegrityPacket)
|
|
{
|
|
truncStream = new TruncatedStream(encStream);
|
|
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
|
IDigest digest = DigestUtilities.GetDigest(digestName);
|
|
encStream = new DigestStream(truncStream, digest, null);
|
|
}
|
|
if (Streams.ReadFully(encStream, array2, 0, array2.Length) < array2.Length)
|
|
{
|
|
throw new EndOfStreamException("unexpected end of stream.");
|
|
}
|
|
int num = encStream.ReadByte();
|
|
int num2 = encStream.ReadByte();
|
|
if (num < 0 || num2 < 0)
|
|
{
|
|
throw new EndOfStreamException("unexpected end of stream.");
|
|
}
|
|
bool flag = array2[^2] == (byte)num && array2[^1] == (byte)num2;
|
|
bool flag2 = num == 0 && num2 == 0;
|
|
if (!flag && !flag2)
|
|
{
|
|
throw new PgpDataValidationException("quick check failed.");
|
|
}
|
|
return encStream;
|
|
}
|
|
catch (PgpException ex)
|
|
{
|
|
throw ex;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
throw new PgpException("Exception creating cipher", exception);
|
|
}
|
|
}
|
|
|
|
private IBufferedCipher CreateStreamCipher(SymmetricKeyAlgorithmTag keyAlgorithm)
|
|
{
|
|
string text = ((encData is SymmetricEncIntegrityPacket) ? "CFB" : "OpenPGPCFB");
|
|
string algorithm = PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/" + text + "/NoPadding";
|
|
return CipherUtilities.GetCipher(algorithm);
|
|
}
|
|
}
|