Initial Commit
This commit is contained in:
135
iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs
Normal file
135
iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
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
|
||||
{
|
||||
/// <remarks>A password based encryption object.</remarks>
|
||||
public class PgpPbeEncryptedData
|
||||
: PgpEncryptedData
|
||||
{
|
||||
private readonly SymmetricKeyEncSessionPacket keyData;
|
||||
|
||||
internal PgpPbeEncryptedData(
|
||||
SymmetricKeyEncSessionPacket keyData,
|
||||
InputStreamPacket encData)
|
||||
: base(encData)
|
||||
{
|
||||
this.keyData = keyData;
|
||||
}
|
||||
|
||||
/// <summary>Return the raw input stream for the data stream.</summary>
|
||||
public override Stream GetInputStream()
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
|
||||
/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
|
||||
public Stream GetDataStream(
|
||||
char[] passPhrase)
|
||||
{
|
||||
try
|
||||
{
|
||||
SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm;
|
||||
|
||||
KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(
|
||||
keyAlgorithm, keyData.S2k, passPhrase);
|
||||
|
||||
|
||||
byte[] secKeyData = keyData.GetSecKeyData();
|
||||
if (secKeyData != null && secKeyData.Length > 0)
|
||||
{
|
||||
IBufferedCipher keyCipher = CipherUtilities.GetCipher(
|
||||
PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding");
|
||||
|
||||
keyCipher.Init(false,
|
||||
new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()]));
|
||||
|
||||
byte[] keyBytes = keyCipher.DoFinal(secKeyData);
|
||||
|
||||
keyAlgorithm = (SymmetricKeyAlgorithmTag) keyBytes[0];
|
||||
|
||||
key = ParameterUtilities.CreateKeyParameter(
|
||||
PgpUtilities.GetSymmetricCipherName(keyAlgorithm),
|
||||
keyBytes, 1, keyBytes.Length - 1);
|
||||
}
|
||||
|
||||
|
||||
IBufferedCipher c = CreateStreamCipher(keyAlgorithm);
|
||||
|
||||
byte[] iv = new byte[c.GetBlockSize()];
|
||||
|
||||
c.Init(false, new ParametersWithIV(key, iv));
|
||||
|
||||
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c, 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, iv, 0, iv.Length) < iv.Length)
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
|
||||
int v1 = encStream.ReadByte();
|
||||
int v2 = encStream.ReadByte();
|
||||
|
||||
if (v1 < 0 || v2 < 0)
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
|
||||
|
||||
// Note: the oracle attack on the "quick check" bytes is not deemed
|
||||
// a security risk for PBE (see PgpPublicKeyEncryptedData)
|
||||
|
||||
bool repeatCheckPassed =
|
||||
iv[iv.Length - 2] == (byte)v1
|
||||
&& iv[iv.Length - 1] == (byte)v2;
|
||||
|
||||
// Note: some versions of PGP appear to produce 0 for the extra
|
||||
// bytes rather than repeating the two previous bytes
|
||||
bool zeroesCheckPassed =
|
||||
v1 == 0
|
||||
&& v2 == 0;
|
||||
|
||||
if (!repeatCheckPassed && !zeroesCheckPassed)
|
||||
{
|
||||
throw new PgpDataValidationException("quick check failed.");
|
||||
}
|
||||
|
||||
|
||||
return encStream;
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", e);
|
||||
}
|
||||
}
|
||||
|
||||
private IBufferedCipher CreateStreamCipher(
|
||||
SymmetricKeyAlgorithmTag keyAlgorithm)
|
||||
{
|
||||
string mode = (encData is SymmetricEncIntegrityPacket)
|
||||
? "CFB"
|
||||
: "OpenPGPCFB";
|
||||
|
||||
string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm)
|
||||
+ "/" + mode + "/NoPadding";
|
||||
|
||||
return CipherUtilities.GetCipher(cName);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user