init commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public interface IStreamGenerator
|
||||
{
|
||||
void Close();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Apache.Bzip2;
|
||||
using Org.BouncyCastle.Utilities.Zlib;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpCompressedData : PgpObject
|
||||
{
|
||||
private readonly CompressedDataPacket data;
|
||||
|
||||
public CompressionAlgorithmTag Algorithm => data.Algorithm;
|
||||
|
||||
public PgpCompressedData(BcpgInputStream bcpgInput)
|
||||
{
|
||||
data = (CompressedDataPacket)bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
public Stream GetInputStream()
|
||||
{
|
||||
return data.GetInputStream();
|
||||
}
|
||||
|
||||
public Stream GetDataStream()
|
||||
{
|
||||
return Algorithm switch
|
||||
{
|
||||
CompressionAlgorithmTag.Uncompressed => GetInputStream(),
|
||||
CompressionAlgorithmTag.Zip => new ZInputStream(GetInputStream(), nowrap: true),
|
||||
CompressionAlgorithmTag.ZLib => new ZInputStream(GetInputStream()),
|
||||
CompressionAlgorithmTag.BZip2 => new CBZip2InputStream(GetInputStream()),
|
||||
_ => throw new PgpException("can't recognise compression algorithm: " + Algorithm),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Apache.Bzip2;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Zlib;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpCompressedDataGenerator : IStreamGenerator
|
||||
{
|
||||
private class SafeCBZip2OutputStream : CBZip2OutputStream
|
||||
{
|
||||
public SafeCBZip2OutputStream(Stream output)
|
||||
: base(output)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
|
||||
private class SafeZOutputStream : ZOutputStream
|
||||
{
|
||||
public SafeZOutputStream(Stream output, int level, bool nowrap)
|
||||
: base(output, level, nowrap)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Finish();
|
||||
End();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly CompressionAlgorithmTag algorithm;
|
||||
|
||||
private readonly int compression;
|
||||
|
||||
private Stream dOut;
|
||||
|
||||
private BcpgOutputStream pkOut;
|
||||
|
||||
public PgpCompressedDataGenerator(CompressionAlgorithmTag algorithm)
|
||||
: this(algorithm, -1)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpCompressedDataGenerator(CompressionAlgorithmTag algorithm, int compression)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
default:
|
||||
throw new ArgumentException("unknown compression algorithm", "algorithm");
|
||||
case CompressionAlgorithmTag.Uncompressed:
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
switch (compression)
|
||||
{
|
||||
default:
|
||||
throw new ArgumentException("unknown compression level: " + compression);
|
||||
case -1:
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
this.algorithm = algorithm;
|
||||
this.compression = compression;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr)
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData);
|
||||
doOpen();
|
||||
return new WrappedGeneratorStream(this, dOut);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, byte[] buffer)
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException("buffer");
|
||||
}
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData, buffer);
|
||||
doOpen();
|
||||
return new WrappedGeneratorStream(this, dOut);
|
||||
}
|
||||
|
||||
private void doOpen()
|
||||
{
|
||||
pkOut.WriteByte((byte)algorithm);
|
||||
switch (algorithm)
|
||||
{
|
||||
case CompressionAlgorithmTag.Uncompressed:
|
||||
dOut = pkOut;
|
||||
break;
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
dOut = new SafeZOutputStream(pkOut, compression, nowrap: true);
|
||||
break;
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
dOut = new SafeZOutputStream(pkOut, compression, nowrap: false);
|
||||
break;
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
dOut = new SafeCBZip2OutputStream(pkOut);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
if (dOut != pkOut)
|
||||
{
|
||||
Platform.Dispose(dOut);
|
||||
}
|
||||
dOut = null;
|
||||
pkOut.Finish();
|
||||
pkOut.Flush();
|
||||
pkOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
[Serializable]
|
||||
public class PgpDataValidationException : PgpException
|
||||
{
|
||||
public PgpDataValidationException()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpDataValidationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpDataValidationException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpEncryptedData
|
||||
{
|
||||
internal class TruncatedStream : BaseInputStream
|
||||
{
|
||||
private const int LookAheadSize = 22;
|
||||
|
||||
private const int LookAheadBufSize = 512;
|
||||
|
||||
private const int LookAheadBufLimit = 490;
|
||||
|
||||
private readonly Stream inStr;
|
||||
|
||||
private readonly byte[] lookAhead = new byte[512];
|
||||
|
||||
private int bufStart;
|
||||
|
||||
private int bufEnd;
|
||||
|
||||
internal TruncatedStream(Stream inStr)
|
||||
{
|
||||
int num = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length);
|
||||
if (num < 22)
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
this.inStr = inStr;
|
||||
bufStart = 0;
|
||||
bufEnd = num - 22;
|
||||
}
|
||||
|
||||
private int FillBuffer()
|
||||
{
|
||||
if (bufEnd < 490)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Array.Copy(lookAhead, 490, lookAhead, 0, 22);
|
||||
bufEnd = Streams.ReadFully(inStr, lookAhead, 22, 490);
|
||||
bufStart = 0;
|
||||
return bufEnd;
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (bufStart < bufEnd)
|
||||
{
|
||||
return lookAhead[bufStart++];
|
||||
}
|
||||
if (FillBuffer() < 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return lookAhead[bufStart++];
|
||||
}
|
||||
|
||||
public override int Read(byte[] buf, int off, int len)
|
||||
{
|
||||
int num = bufEnd - bufStart;
|
||||
int num2 = off;
|
||||
while (len > num)
|
||||
{
|
||||
Array.Copy(lookAhead, bufStart, buf, num2, num);
|
||||
bufStart += num;
|
||||
num2 += num;
|
||||
len -= num;
|
||||
if ((num = FillBuffer()) < 1)
|
||||
{
|
||||
return num2 - off;
|
||||
}
|
||||
}
|
||||
Array.Copy(lookAhead, bufStart, buf, num2, len);
|
||||
bufStart += len;
|
||||
return num2 + len - off;
|
||||
}
|
||||
|
||||
internal byte[] GetLookAhead()
|
||||
{
|
||||
byte[] array = new byte[22];
|
||||
Array.Copy(lookAhead, bufStart, array, 0, 22);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
internal InputStreamPacket encData;
|
||||
|
||||
internal Stream encStream;
|
||||
|
||||
internal TruncatedStream truncStream;
|
||||
|
||||
internal PgpEncryptedData(InputStreamPacket encData)
|
||||
{
|
||||
this.encData = encData;
|
||||
}
|
||||
|
||||
public virtual Stream GetInputStream()
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
|
||||
public bool IsIntegrityProtected()
|
||||
{
|
||||
return encData is SymmetricEncIntegrityPacket;
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
if (!IsIntegrityProtected())
|
||||
{
|
||||
throw new PgpException("data not integrity protected.");
|
||||
}
|
||||
DigestStream digestStream = (DigestStream)encStream;
|
||||
while (encStream.ReadByte() >= 0)
|
||||
{
|
||||
}
|
||||
byte[] lookAhead = truncStream.GetLookAhead();
|
||||
IDigest digest = digestStream.ReadDigest();
|
||||
digest.BlockUpdate(lookAhead, 0, 2);
|
||||
byte[] array = DigestUtilities.DoFinal(digest);
|
||||
byte[] array2 = new byte[array.Length];
|
||||
Array.Copy(lookAhead, 2, array2, 0, array2.Length);
|
||||
return Arrays.ConstantTimeAreEqual(array, array2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,423 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpEncryptedDataGenerator : IStreamGenerator
|
||||
{
|
||||
private abstract class EncMethod : ContainedPacket
|
||||
{
|
||||
protected byte[] sessionInfo;
|
||||
|
||||
protected SymmetricKeyAlgorithmTag encAlgorithm;
|
||||
|
||||
protected KeyParameter key;
|
||||
|
||||
public abstract void AddSessionInfo(byte[] si, SecureRandom random);
|
||||
}
|
||||
|
||||
private class PbeMethod : EncMethod
|
||||
{
|
||||
private S2k s2k;
|
||||
|
||||
internal PbeMethod(SymmetricKeyAlgorithmTag encAlgorithm, S2k s2k, KeyParameter key)
|
||||
{
|
||||
base.encAlgorithm = encAlgorithm;
|
||||
this.s2k = s2k;
|
||||
base.key = key;
|
||||
}
|
||||
|
||||
public KeyParameter GetKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
public override void AddSessionInfo(byte[] si, SecureRandom random)
|
||||
{
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
IBufferedCipher cipher = CipherUtilities.GetCipher(symmetricCipherName + "/CFB/NoPadding");
|
||||
byte[] iv = new byte[cipher.GetBlockSize()];
|
||||
cipher.Init(forEncryption: true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
|
||||
sessionInfo = cipher.DoFinal(si, 0, si.Length - 2);
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream pOut)
|
||||
{
|
||||
SymmetricKeyEncSessionPacket p = new SymmetricKeyEncSessionPacket(encAlgorithm, s2k, sessionInfo);
|
||||
pOut.WritePacket(p);
|
||||
}
|
||||
}
|
||||
|
||||
private class PubMethod : EncMethod
|
||||
{
|
||||
internal PgpPublicKey pubKey;
|
||||
|
||||
internal byte[][] data;
|
||||
|
||||
internal PubMethod(PgpPublicKey pubKey)
|
||||
{
|
||||
this.pubKey = pubKey;
|
||||
}
|
||||
|
||||
public override void AddSessionInfo(byte[] sessionInfo, SecureRandom random)
|
||||
{
|
||||
byte[] encryptedSessionInfo = EncryptSessionInfo(sessionInfo, random);
|
||||
data = ProcessSessionInfo(encryptedSessionInfo);
|
||||
}
|
||||
|
||||
private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
|
||||
{
|
||||
if (pubKey.Algorithm != PublicKeyAlgorithmTag.EC)
|
||||
{
|
||||
IBufferedCipher cipher;
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
cipher = CipherUtilities.GetCipher("RSA//PKCS1Padding");
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
cipher = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
throw new PgpException("Can't use DSA for encryption.");
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
throw new PgpException("Can't use ECDSA for encryption.");
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
|
||||
}
|
||||
AsymmetricKeyParameter parameters = pubKey.GetKey();
|
||||
cipher.Init(forEncryption: true, new ParametersWithRandom(parameters, random));
|
||||
return cipher.DoFinal(sessionInfo);
|
||||
}
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key;
|
||||
IAsymmetricCipherKeyPairGenerator keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator("ECDH");
|
||||
keyPairGenerator.Init(new ECKeyGenerationParameters(eCDHPublicBcpgKey.CurveOid, random));
|
||||
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.GenerateKeyPair();
|
||||
ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)asymmetricCipherKeyPair.Private;
|
||||
ECPublicKeyParameters eCPublicKeyParameters = (ECPublicKeyParameters)asymmetricCipherKeyPair.Public;
|
||||
ECPublicKeyParameters eCPublicKeyParameters2 = (ECPublicKeyParameters)pubKey.GetKey();
|
||||
ECPoint s = eCPublicKeyParameters2.Q.Multiply(eCPrivateKeyParameters.D).Normalize();
|
||||
KeyParameter parameters2 = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, s));
|
||||
IWrapper wrapper = PgpUtilities.CreateWrapper(eCDHPublicBcpgKey.SymmetricKeyAlgorithm);
|
||||
wrapper.Init(forWrapping: true, new ParametersWithRandom(parameters2, random));
|
||||
byte[] array = PgpPad.PadSessionData(sessionInfo);
|
||||
byte[] array2 = wrapper.Wrap(array, 0, array.Length);
|
||||
byte[] encoded = new MPInteger(new BigInteger(1, eCPublicKeyParameters.Q.GetEncoded(compressed: false))).GetEncoded();
|
||||
byte[] array3 = new byte[encoded.Length + 1 + array2.Length];
|
||||
Array.Copy(encoded, 0, array3, 0, encoded.Length);
|
||||
array3[encoded.Length] = (byte)array2.Length;
|
||||
Array.Copy(array2, 0, array3, encoded.Length + 1, array2.Length);
|
||||
return array3;
|
||||
}
|
||||
|
||||
private byte[][] ProcessSessionInfo(byte[] encryptedSessionInfo)
|
||||
{
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
return new byte[1][] { ConvertToEncodedMpi(encryptedSessionInfo) };
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
int num = encryptedSessionInfo.Length / 2;
|
||||
byte[] array = new byte[num];
|
||||
byte[] array2 = new byte[num];
|
||||
Array.Copy(encryptedSessionInfo, 0, array, 0, num);
|
||||
Array.Copy(encryptedSessionInfo, num, array2, 0, num);
|
||||
return new byte[2][]
|
||||
{
|
||||
ConvertToEncodedMpi(array),
|
||||
ConvertToEncodedMpi(array2)
|
||||
};
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
return new byte[1][] { encryptedSessionInfo };
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ConvertToEncodedMpi(byte[] encryptedSessionInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new MPInteger(new BigInteger(1, encryptedSessionInfo)).GetEncoded();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new PgpException("Invalid MPI encoding: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream pOut)
|
||||
{
|
||||
PublicKeyEncSessionPacket p = new PublicKeyEncSessionPacket(pubKey.KeyId, pubKey.Algorithm, data);
|
||||
pOut.WritePacket(p);
|
||||
}
|
||||
}
|
||||
|
||||
private BcpgOutputStream pOut;
|
||||
|
||||
private CipherStream cOut;
|
||||
|
||||
private IBufferedCipher c;
|
||||
|
||||
private bool withIntegrityPacket;
|
||||
|
||||
private bool oldFormat;
|
||||
|
||||
private DigestStream digestOut;
|
||||
|
||||
private readonly IList methods = Platform.CreateArrayList();
|
||||
|
||||
private readonly SymmetricKeyAlgorithmTag defAlgorithm;
|
||||
|
||||
private readonly SecureRandom rand;
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
rand = new SecureRandom();
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, bool withIntegrityPacket)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.withIntegrityPacket = withIntegrityPacket;
|
||||
rand = new SecureRandom();
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, SecureRandom rand)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, bool withIntegrityPacket, SecureRandom rand)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
this.withIntegrityPacket = withIntegrityPacket;
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag encAlgorithm, SecureRandom rand, bool oldFormat)
|
||||
{
|
||||
defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
this.oldFormat = oldFormat;
|
||||
}
|
||||
|
||||
[Obsolete("Use version that takes an explicit s2kDigest parameter")]
|
||||
public void AddMethod(char[] passPhrase)
|
||||
{
|
||||
AddMethod(passPhrase, HashAlgorithmTag.Sha1);
|
||||
}
|
||||
|
||||
public void AddMethod(char[] passPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true, s2kDigest);
|
||||
}
|
||||
|
||||
public void AddMethodUtf8(char[] passPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true, s2kDigest);
|
||||
}
|
||||
|
||||
public void AddMethodRaw(byte[] rawPassPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
DoAddMethod(rawPassPhrase, clearPassPhrase: false, s2kDigest);
|
||||
}
|
||||
|
||||
internal void DoAddMethod(byte[] rawPassPhrase, bool clearPassPhrase, HashAlgorithmTag s2kDigest)
|
||||
{
|
||||
S2k s2k = PgpUtilities.GenerateS2k(s2kDigest, 96, rand);
|
||||
methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.DoMakeKeyFromPassPhrase(defAlgorithm, s2k, rawPassPhrase, clearPassPhrase)));
|
||||
}
|
||||
|
||||
public void AddMethod(PgpPublicKey key)
|
||||
{
|
||||
if (!key.IsEncryptionKey)
|
||||
{
|
||||
throw new ArgumentException("passed in key not an encryption key!");
|
||||
}
|
||||
methods.Add(new PubMethod(key));
|
||||
}
|
||||
|
||||
private void AddCheckSum(byte[] sessionInfo)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 1; i < sessionInfo.Length - 2; i++)
|
||||
{
|
||||
num += sessionInfo[i];
|
||||
}
|
||||
sessionInfo[^2] = (byte)(num >> 8);
|
||||
sessionInfo[^1] = (byte)num;
|
||||
}
|
||||
|
||||
private byte[] CreateSessionInfo(SymmetricKeyAlgorithmTag algorithm, KeyParameter key)
|
||||
{
|
||||
byte[] key2 = key.GetKey();
|
||||
byte[] array = new byte[key2.Length + 3];
|
||||
array[0] = (byte)algorithm;
|
||||
key2.CopyTo(array, 1);
|
||||
AddCheckSum(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
private Stream Open(Stream outStr, long length, byte[] buffer)
|
||||
{
|
||||
if (cOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (methods.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No encryption methods specified");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
pOut = new BcpgOutputStream(outStr);
|
||||
KeyParameter keyParameter;
|
||||
if (methods.Count == 1)
|
||||
{
|
||||
if (methods[0] is PbeMethod)
|
||||
{
|
||||
PbeMethod pbeMethod = (PbeMethod)methods[0];
|
||||
keyParameter = pbeMethod.GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
keyParameter = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
|
||||
byte[] si = CreateSessionInfo(defAlgorithm, keyParameter);
|
||||
PubMethod pubMethod = (PubMethod)methods[0];
|
||||
try
|
||||
{
|
||||
pubMethod.AddSessionInfo(si, rand);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception encrypting session key", exception);
|
||||
}
|
||||
}
|
||||
pOut.WritePacket((ContainedPacket)methods[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
keyParameter = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
|
||||
byte[] si2 = CreateSessionInfo(defAlgorithm, keyParameter);
|
||||
for (int i = 0; i != methods.Count; i++)
|
||||
{
|
||||
EncMethod encMethod = (EncMethod)methods[i];
|
||||
try
|
||||
{
|
||||
encMethod.AddSessionInfo(si2, rand);
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("exception encrypting session key", exception2);
|
||||
}
|
||||
pOut.WritePacket(encMethod);
|
||||
}
|
||||
}
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(defAlgorithm);
|
||||
if (symmetricCipherName == null)
|
||||
{
|
||||
throw new PgpException("null cipher specified");
|
||||
}
|
||||
try
|
||||
{
|
||||
symmetricCipherName = ((!withIntegrityPacket) ? (symmetricCipherName + "/OpenPGPCFB/NoPadding") : (symmetricCipherName + "/CFB/NoPadding"));
|
||||
c = CipherUtilities.GetCipher(symmetricCipherName);
|
||||
byte[] iv = new byte[c.GetBlockSize()];
|
||||
c.Init(forEncryption: true, new ParametersWithRandom(new ParametersWithIV(keyParameter, iv), rand));
|
||||
if (buffer == null)
|
||||
{
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22);
|
||||
pOut.WriteByte(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat);
|
||||
}
|
||||
}
|
||||
else if (withIntegrityPacket)
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer);
|
||||
pOut.WriteByte(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer);
|
||||
}
|
||||
int blockSize = c.GetBlockSize();
|
||||
byte[] array = new byte[blockSize + 2];
|
||||
rand.NextBytes(array, 0, blockSize);
|
||||
Array.Copy(array, array.Length - 4, array, array.Length - 2, 2);
|
||||
Stream stream = (cOut = new CipherStream(pOut, null, c));
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
stream = (digestOut = new DigestStream(stream, null, digest));
|
||||
}
|
||||
stream.Write(array, 0, array.Length);
|
||||
return new WrappedGeneratorStream(this, stream);
|
||||
}
|
||||
catch (Exception exception3)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception3);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, long length)
|
||||
{
|
||||
return Open(outStr, length, null);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, byte[] buffer)
|
||||
{
|
||||
return Open(outStr, 0L, buffer);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (cOut != null)
|
||||
{
|
||||
if (digestOut != null)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(digestOut, PacketTag.ModificationDetectionCode, 20L);
|
||||
bcpgOutputStream.Flush();
|
||||
digestOut.Flush();
|
||||
byte[] array = DigestUtilities.DoFinal(digestOut.WriteDigest());
|
||||
cOut.Write(array, 0, array.Length);
|
||||
}
|
||||
cOut.Flush();
|
||||
try
|
||||
{
|
||||
pOut.Write(c.DoFinal());
|
||||
pOut.Finish();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IOException(ex.Message, ex);
|
||||
}
|
||||
cOut = null;
|
||||
pOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpEncryptedDataList : PgpObject
|
||||
{
|
||||
private IList list = Platform.CreateArrayList();
|
||||
|
||||
private InputStreamPacket data;
|
||||
|
||||
public PgpEncryptedData this[int index] => (PgpEncryptedData)list[index];
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => list.Count;
|
||||
|
||||
public int Count => list.Count;
|
||||
|
||||
public bool IsEmpty => list.Count == 0;
|
||||
|
||||
public PgpEncryptedDataList(BcpgInputStream bcpgInput)
|
||||
{
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.PublicKeyEncryptedSession || bcpgInput.NextPacketTag() == PacketTag.SymmetricKeyEncryptedSessionKey)
|
||||
{
|
||||
list.Add(bcpgInput.ReadPacket());
|
||||
}
|
||||
data = (InputStreamPacket)bcpgInput.ReadPacket();
|
||||
for (int i = 0; i != list.Count; i++)
|
||||
{
|
||||
if (list[i] is SymmetricKeyEncSessionPacket)
|
||||
{
|
||||
list[i] = new PgpPbeEncryptedData((SymmetricKeyEncSessionPacket)list[i], data);
|
||||
}
|
||||
else
|
||||
{
|
||||
list[i] = new PgpPublicKeyEncryptedData((PublicKeyEncSessionPacket)list[i], data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public object Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
|
||||
public IEnumerable GetEncryptedDataObjects()
|
||||
{
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
[Serializable]
|
||||
public class PgpException : Exception
|
||||
{
|
||||
[Obsolete("Use InnerException property")]
|
||||
public Exception UnderlyingException => base.InnerException;
|
||||
|
||||
public PgpException()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpExperimental : PgpObject
|
||||
{
|
||||
private readonly ExperimentalPacket p;
|
||||
|
||||
public PgpExperimental(BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = (ExperimentalPacket)bcpgIn.ReadPacket();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpKeyFlags
|
||||
{
|
||||
public const int CanCertify = 1;
|
||||
|
||||
public const int CanSign = 2;
|
||||
|
||||
public const int CanEncryptCommunications = 4;
|
||||
|
||||
public const int CanEncryptStorage = 8;
|
||||
|
||||
public const int MaybeSplit = 16;
|
||||
|
||||
public const int MaybeShared = 128;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpKeyPair
|
||||
{
|
||||
private readonly PgpPublicKey pub;
|
||||
|
||||
private readonly PgpPrivateKey priv;
|
||||
|
||||
public long KeyId => pub.KeyId;
|
||||
|
||||
public PgpPublicKey PublicKey => pub;
|
||||
|
||||
public PgpPrivateKey PrivateKey => priv;
|
||||
|
||||
public PgpKeyPair(PublicKeyAlgorithmTag algorithm, AsymmetricCipherKeyPair keyPair, DateTime time)
|
||||
: this(algorithm, keyPair.Public, keyPair.Private, time)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyPair(PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, AsymmetricKeyParameter privKey, DateTime time)
|
||||
{
|
||||
pub = new PgpPublicKey(algorithm, pubKey, time);
|
||||
priv = new PgpPrivateKey(pub.KeyId, pub.PublicKeyPacket, privKey);
|
||||
}
|
||||
|
||||
public PgpKeyPair(PgpPublicKey pub, PgpPrivateKey priv)
|
||||
{
|
||||
this.pub = pub;
|
||||
this.priv = priv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpKeyRing : PgpObject
|
||||
{
|
||||
internal PgpKeyRing()
|
||||
{
|
||||
}
|
||||
|
||||
internal static TrustPacket ReadOptionalTrustPacket(BcpgInputStream bcpgInput)
|
||||
{
|
||||
if (bcpgInput.NextPacketTag() != PacketTag.Trust)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (TrustPacket)bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
internal static IList ReadSignaturesAndTrust(BcpgInputStream bcpgInput)
|
||||
{
|
||||
try
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.Signature)
|
||||
{
|
||||
SignaturePacket sigPacket = (SignaturePacket)bcpgInput.ReadPacket();
|
||||
TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput);
|
||||
list.Add(new PgpSignature(sigPacket, trustPacket));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw new IOException("can't create signature object: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ReadUserIDs(BcpgInputStream bcpgInput, out IList ids, out IList idTrusts, out IList idSigs)
|
||||
{
|
||||
ids = Platform.CreateArrayList();
|
||||
idTrusts = Platform.CreateArrayList();
|
||||
idSigs = Platform.CreateArrayList();
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.UserId || bcpgInput.NextPacketTag() == PacketTag.UserAttribute)
|
||||
{
|
||||
Packet packet = bcpgInput.ReadPacket();
|
||||
if (packet is UserIdPacket)
|
||||
{
|
||||
UserIdPacket userIdPacket = (UserIdPacket)packet;
|
||||
ids.Add(userIdPacket.GetId());
|
||||
}
|
||||
else
|
||||
{
|
||||
UserAttributePacket userAttributePacket = (UserAttributePacket)packet;
|
||||
ids.Add(new PgpUserAttributeSubpacketVector(userAttributePacket.GetSubpackets()));
|
||||
}
|
||||
idTrusts.Add(ReadOptionalTrustPacket(bcpgInput));
|
||||
idSigs.Add(ReadSignaturesAndTrust(bcpgInput));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpKeyRingGenerator
|
||||
{
|
||||
private IList keys = Platform.CreateArrayList();
|
||||
|
||||
private string id;
|
||||
|
||||
private SymmetricKeyAlgorithmTag encAlgorithm;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private int certificationLevel;
|
||||
|
||||
private byte[] rawPassPhrase;
|
||||
|
||||
private bool useSha1;
|
||||
|
||||
private PgpKeyPair masterKey;
|
||||
|
||||
private PgpSignatureSubpacketVector hashedPacketVector;
|
||||
|
||||
private PgpSignatureSubpacketVector unhashedPacketVector;
|
||||
|
||||
private SecureRandom rand;
|
||||
|
||||
[Obsolete("Use version taking an explicit 'useSha1' parameter instead")]
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
{
|
||||
this.certificationLevel = certificationLevel;
|
||||
this.masterKey = masterKey;
|
||||
this.id = id;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.rawPassPhrase = rawPassPhrase;
|
||||
this.useSha1 = useSha1;
|
||||
hashedPacketVector = hashedPackets;
|
||||
unhashedPacketVector = unhashedPackets;
|
||||
this.rand = rand;
|
||||
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand));
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, utf8PassPhrase: false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, bool utf8PassPhrase, char[] passPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), useSha1, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyRingGenerator(int certificationLevel, PgpKeyPair masterKey, string id, SymmetricKeyAlgorithmTag encAlgorithm, HashAlgorithmTag hashAlgorithm, byte[] rawPassPhrase, bool useSha1, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
{
|
||||
this.certificationLevel = certificationLevel;
|
||||
this.masterKey = masterKey;
|
||||
this.id = id;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.rawPassPhrase = rawPassPhrase;
|
||||
this.useSha1 = useSha1;
|
||||
hashedPacketVector = hashedPackets;
|
||||
unhashedPacketVector = unhashedPackets;
|
||||
this.rand = rand;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, hashedPackets, unhashedPackets, rand));
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair)
|
||||
{
|
||||
AddSubKey(keyPair, hashedPacketVector, unhashedPacketVector);
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
AddSubKey(keyPair, hashedPacketVector, unhashedPacketVector, hashAlgorithm);
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
try
|
||||
{
|
||||
PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
|
||||
pgpSignatureGenerator.InitSign(24, masterKey.PrivateKey);
|
||||
pgpSignatureGenerator.SetHashedSubpackets(hashedPackets);
|
||||
pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets);
|
||||
IList list = Platform.CreateArrayList();
|
||||
list.Add(pgpSignatureGenerator.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
|
||||
keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, list), encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, rand, isMasterKey: false));
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception adding subkey: ", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSubKey(PgpKeyPair keyPair, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
try
|
||||
{
|
||||
PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm);
|
||||
pgpSignatureGenerator.InitSign(24, masterKey.PrivateKey);
|
||||
pgpSignatureGenerator.SetHashedSubpackets(hashedPackets);
|
||||
pgpSignatureGenerator.SetUnhashedSubpackets(unhashedPackets);
|
||||
IList list = Platform.CreateArrayList();
|
||||
list.Add(pgpSignatureGenerator.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
|
||||
keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, list), encAlgorithm, rawPassPhrase, clearPassPhrase: false, useSha1, rand, isMasterKey: false));
|
||||
}
|
||||
catch (PgpException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception adding subkey: ", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing GenerateSecretKeyRing()
|
||||
{
|
||||
return new PgpSecretKeyRing(keys);
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing GeneratePublicKeyRing()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
IEnumerator enumerator = keys.GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey)enumerator.Current;
|
||||
list.Add(pgpSecretKey.PublicKey);
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
pgpSecretKey = (PgpSecretKey)enumerator.Current;
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(pgpSecretKey.PublicKey);
|
||||
pgpPublicKey.publicPk = new PublicSubkeyPacket(pgpPublicKey.Algorithm, pgpPublicKey.CreationTime, pgpPublicKey.publicPk.Key);
|
||||
list.Add(pgpPublicKey);
|
||||
}
|
||||
return new PgpPublicKeyRing(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
[Serializable]
|
||||
public class PgpKeyValidationException : PgpException
|
||||
{
|
||||
public PgpKeyValidationException()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyValidationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpKeyValidationException(string message, Exception exception)
|
||||
: base(message, exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpLiteralData : PgpObject
|
||||
{
|
||||
public const char Binary = 'b';
|
||||
|
||||
public const char Text = 't';
|
||||
|
||||
public const char Utf8 = 'u';
|
||||
|
||||
public const string Console = "_CONSOLE";
|
||||
|
||||
private LiteralDataPacket data;
|
||||
|
||||
public int Format => data.Format;
|
||||
|
||||
public string FileName => data.FileName;
|
||||
|
||||
public DateTime ModificationTime => DateTimeUtilities.UnixMsToDateTime(data.ModificationTime);
|
||||
|
||||
public PgpLiteralData(BcpgInputStream bcpgInput)
|
||||
{
|
||||
data = (LiteralDataPacket)bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
public byte[] GetRawFileName()
|
||||
{
|
||||
return data.GetRawFileName();
|
||||
}
|
||||
|
||||
public Stream GetInputStream()
|
||||
{
|
||||
return data.GetInputStream();
|
||||
}
|
||||
|
||||
public Stream GetDataStream()
|
||||
{
|
||||
return GetInputStream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpLiteralDataGenerator : IStreamGenerator
|
||||
{
|
||||
public const char Binary = 'b';
|
||||
|
||||
public const char Text = 't';
|
||||
|
||||
public const char Utf8 = 'u';
|
||||
|
||||
public const string Console = "_CONSOLE";
|
||||
|
||||
private BcpgOutputStream pkOut;
|
||||
|
||||
private bool oldFormat;
|
||||
|
||||
public PgpLiteralDataGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
public PgpLiteralDataGenerator(bool oldFormat)
|
||||
{
|
||||
this.oldFormat = oldFormat;
|
||||
}
|
||||
|
||||
private void WriteHeader(BcpgOutputStream outStr, char format, byte[] encName, long modificationTime)
|
||||
{
|
||||
outStr.Write((byte)format, (byte)encName.Length);
|
||||
outStr.Write(encName);
|
||||
long num = modificationTime / 1000;
|
||||
outStr.Write((byte)(num >> 24), (byte)(num >> 16), (byte)(num >> 8), (byte)num);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, char format, string name, long length, DateTime modificationTime)
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
long modificationTime2 = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
|
||||
byte[] array = Strings.ToUtf8ByteArray(name);
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, length + 2 + array.Length + 4, oldFormat);
|
||||
WriteHeader(pkOut, format, array, modificationTime2);
|
||||
return new WrappedGeneratorStream(this, pkOut);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, char format, string name, DateTime modificationTime, byte[] buffer)
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
}
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
long modificationTime2 = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
|
||||
byte[] encName = Strings.ToUtf8ByteArray(name);
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
|
||||
WriteHeader(pkOut, format, encName, modificationTime2);
|
||||
return new WrappedGeneratorStream(this, pkOut);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStr, char format, FileInfo file)
|
||||
{
|
||||
return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
pkOut.Finish();
|
||||
pkOut.Flush();
|
||||
pkOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpMarker : PgpObject
|
||||
{
|
||||
private readonly MarkerPacket p;
|
||||
|
||||
public PgpMarker(BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = (MarkerPacket)bcpgIn.ReadPacket();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public abstract class PgpObject
|
||||
{
|
||||
internal PgpObject()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpObjectFactory
|
||||
{
|
||||
private readonly BcpgInputStream bcpgIn;
|
||||
|
||||
public PgpObjectFactory(Stream inputStream)
|
||||
{
|
||||
bcpgIn = BcpgInputStream.Wrap(inputStream);
|
||||
}
|
||||
|
||||
public PgpObjectFactory(byte[] bytes)
|
||||
: this(new MemoryStream(bytes, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpObject NextPgpObject()
|
||||
{
|
||||
PacketTag packetTag = bcpgIn.NextPacketTag();
|
||||
if (packetTag == (PacketTag)(-1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
switch (packetTag)
|
||||
{
|
||||
case PacketTag.Signature:
|
||||
{
|
||||
IList list2 = Platform.CreateArrayList();
|
||||
while (bcpgIn.NextPacketTag() == PacketTag.Signature)
|
||||
{
|
||||
try
|
||||
{
|
||||
list2.Add(new PgpSignature(bcpgIn));
|
||||
}
|
||||
catch (PgpException ex3)
|
||||
{
|
||||
throw new IOException("can't create signature object: " + ex3);
|
||||
}
|
||||
}
|
||||
PgpSignature[] array2 = new PgpSignature[list2.Count];
|
||||
for (int j = 0; j < list2.Count; j++)
|
||||
{
|
||||
array2[j] = (PgpSignature)list2[j];
|
||||
}
|
||||
return new PgpSignatureList(array2);
|
||||
}
|
||||
case PacketTag.SecretKey:
|
||||
try
|
||||
{
|
||||
return new PgpSecretKeyRing(bcpgIn);
|
||||
}
|
||||
catch (PgpException ex2)
|
||||
{
|
||||
throw new IOException("can't create secret key object: " + ex2);
|
||||
}
|
||||
case PacketTag.PublicKey:
|
||||
return new PgpPublicKeyRing(bcpgIn);
|
||||
case PacketTag.CompressedData:
|
||||
return new PgpCompressedData(bcpgIn);
|
||||
case PacketTag.LiteralData:
|
||||
return new PgpLiteralData(bcpgIn);
|
||||
case PacketTag.PublicKeyEncryptedSession:
|
||||
case PacketTag.SymmetricKeyEncryptedSessionKey:
|
||||
return new PgpEncryptedDataList(bcpgIn);
|
||||
case PacketTag.OnePassSignature:
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
|
||||
{
|
||||
try
|
||||
{
|
||||
list.Add(new PgpOnePassSignature(bcpgIn));
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw new IOException("can't create one pass signature object: " + ex);
|
||||
}
|
||||
}
|
||||
PgpOnePassSignature[] array = new PgpOnePassSignature[list.Count];
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
array[i] = (PgpOnePassSignature)list[i];
|
||||
}
|
||||
return new PgpOnePassSignatureList(array);
|
||||
}
|
||||
case PacketTag.Marker:
|
||||
return new PgpMarker(bcpgIn);
|
||||
case PacketTag.Experimental1:
|
||||
case PacketTag.Experimental2:
|
||||
case PacketTag.Experimental3:
|
||||
case PacketTag.Experimental4:
|
||||
return new PgpExperimental(bcpgIn);
|
||||
default:
|
||||
throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use NextPgpObject() instead")]
|
||||
public object NextObject()
|
||||
{
|
||||
return NextPgpObject();
|
||||
}
|
||||
|
||||
public IList AllPgpObjects()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
PgpObject value;
|
||||
while ((value = NextPgpObject()) != null)
|
||||
{
|
||||
list.Add(value);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpOnePassSignature
|
||||
{
|
||||
private OnePassSignaturePacket sigPack;
|
||||
|
||||
private int signatureType;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
public long KeyId => sigPack.KeyId;
|
||||
|
||||
public int SignatureType => sigPack.SignatureType;
|
||||
|
||||
public HashAlgorithmTag HashAlgorithm => sigPack.HashAlgorithm;
|
||||
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm => sigPack.KeyAlgorithm;
|
||||
|
||||
internal PgpOnePassSignature(BcpgInputStream bcpgInput)
|
||||
: this((OnePassSignaturePacket)bcpgInput.ReadPacket())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpOnePassSignature(OnePassSignaturePacket sigPack)
|
||||
{
|
||||
this.sigPack = sigPack;
|
||||
signatureType = sigPack.SignatureType;
|
||||
}
|
||||
|
||||
public void InitVerify(PgpPublicKey pubKey)
|
||||
{
|
||||
lastb = 0;
|
||||
try
|
||||
{
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("can't set up signature object.", exception);
|
||||
}
|
||||
try
|
||||
{
|
||||
sig.Init(forSigning: false, pubKey.GetKey());
|
||||
}
|
||||
catch (InvalidKeyException exception2)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception2);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sig.Update(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
sig.Update(13);
|
||||
sig.Update(10);
|
||||
}
|
||||
|
||||
public void Update(byte[] bytes)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
for (int i = 0; i != bytes.Length; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte[] bytes, int off, int length)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + length;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, off, length);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify(PgpSignature pgpSig)
|
||||
{
|
||||
byte[] signatureTrailer = pgpSig.GetSignatureTrailer();
|
||||
sig.BlockUpdate(signatureTrailer, 0, signatureTrailer.Length);
|
||||
return sig.VerifySignature(pgpSig.GetSignature());
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream.Wrap(outStr).WritePacket(sigPack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpOnePassSignatureList : PgpObject
|
||||
{
|
||||
private readonly PgpOnePassSignature[] sigs;
|
||||
|
||||
public PgpOnePassSignature this[int index] => sigs[index];
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => sigs.Length;
|
||||
|
||||
public int Count => sigs.Length;
|
||||
|
||||
public bool IsEmpty => sigs.Length == 0;
|
||||
|
||||
public PgpOnePassSignatureList(PgpOnePassSignature[] sigs)
|
||||
{
|
||||
this.sigs = (PgpOnePassSignature[])sigs.Clone();
|
||||
}
|
||||
|
||||
public PgpOnePassSignatureList(PgpOnePassSignature sig)
|
||||
{
|
||||
sigs = new PgpOnePassSignature[1] { sig };
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public PgpOnePassSignature Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class PgpPad
|
||||
{
|
||||
private PgpPad()
|
||||
{
|
||||
}
|
||||
|
||||
public static byte[] PadSessionData(byte[] sessionInfo)
|
||||
{
|
||||
byte[] array = new byte[40];
|
||||
Array.Copy(sessionInfo, 0, array, 0, sessionInfo.Length);
|
||||
byte b = (byte)(array.Length - sessionInfo.Length);
|
||||
for (int i = sessionInfo.Length; i != array.Length; i++)
|
||||
{
|
||||
array[i] = b;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static byte[] UnpadSessionData(byte[] encoded)
|
||||
{
|
||||
byte b = encoded[^1];
|
||||
for (int i = encoded.Length - b; i != encoded.Length; i++)
|
||||
{
|
||||
if (encoded[i] != b)
|
||||
{
|
||||
throw new PgpException("bad padding found in session data");
|
||||
}
|
||||
}
|
||||
byte[] array = new byte[encoded.Length - b];
|
||||
Array.Copy(encoded, 0, array, 0, array.Length);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPrivateKey
|
||||
{
|
||||
private readonly long keyID;
|
||||
|
||||
private readonly PublicKeyPacket publicKeyPacket;
|
||||
|
||||
private readonly AsymmetricKeyParameter privateKey;
|
||||
|
||||
public long KeyId => keyID;
|
||||
|
||||
public PublicKeyPacket PublicKeyPacket => publicKeyPacket;
|
||||
|
||||
public AsymmetricKeyParameter Key => privateKey;
|
||||
|
||||
public PgpPrivateKey(long keyID, PublicKeyPacket publicKeyPacket, AsymmetricKeyParameter privateKey)
|
||||
{
|
||||
if (!privateKey.IsPrivate)
|
||||
{
|
||||
throw new ArgumentException("Expected a private key", "privateKey");
|
||||
}
|
||||
this.keyID = keyID;
|
||||
this.publicKeyPacket = publicKeyPacket;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,738 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKey
|
||||
{
|
||||
private static readonly int[] MasterKeyCertificationTypes = new int[4] { 19, 18, 17, 16 };
|
||||
|
||||
private long keyId;
|
||||
|
||||
private byte[] fingerprint;
|
||||
|
||||
private int keyStrength;
|
||||
|
||||
internal PublicKeyPacket publicPk;
|
||||
|
||||
internal TrustPacket trustPk;
|
||||
|
||||
internal IList keySigs = Platform.CreateArrayList();
|
||||
|
||||
internal IList ids = Platform.CreateArrayList();
|
||||
|
||||
internal IList idTrusts = Platform.CreateArrayList();
|
||||
|
||||
internal IList idSigs = Platform.CreateArrayList();
|
||||
|
||||
internal IList subSigs;
|
||||
|
||||
public int Version => publicPk.Version;
|
||||
|
||||
public DateTime CreationTime => publicPk.GetTime();
|
||||
|
||||
[Obsolete("Use 'GetValidSeconds' instead")]
|
||||
public int ValidDays
|
||||
{
|
||||
get
|
||||
{
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
return publicPk.ValidDays;
|
||||
}
|
||||
long validSeconds = GetValidSeconds();
|
||||
if (validSeconds <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int val = (int)(validSeconds / 86400);
|
||||
return System.Math.Max(1, val);
|
||||
}
|
||||
}
|
||||
|
||||
public long KeyId => keyId;
|
||||
|
||||
public bool IsEncryptionKey
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (publicPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMasterKey => subSigs == null;
|
||||
|
||||
public PublicKeyAlgorithmTag Algorithm => publicPk.Algorithm;
|
||||
|
||||
public int BitStrength => keyStrength;
|
||||
|
||||
public PublicKeyPacket PublicKeyPacket => publicPk;
|
||||
|
||||
public static byte[] CalculateFingerprint(PublicKeyPacket publicPk)
|
||||
{
|
||||
IBcpgKey key = publicPk.Key;
|
||||
IDigest digest;
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)key;
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest("MD5");
|
||||
UpdateDigest(digest, rsaPublicBcpgKey.Modulus);
|
||||
UpdateDigest(digest, rsaPublicBcpgKey.PublicExponent);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new PgpException("can't encode key components: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] encodedContents = publicPk.GetEncodedContents();
|
||||
digest = DigestUtilities.GetDigest("SHA1");
|
||||
digest.Update(153);
|
||||
digest.Update((byte)(encodedContents.Length >> 8));
|
||||
digest.Update((byte)encodedContents.Length);
|
||||
digest.BlockUpdate(encodedContents, 0, encodedContents.Length);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new PgpException("can't encode key components: " + ex2.Message, ex2);
|
||||
}
|
||||
}
|
||||
return DigestUtilities.DoFinal(digest);
|
||||
}
|
||||
|
||||
private static void UpdateDigest(IDigest d, BigInteger b)
|
||||
{
|
||||
byte[] array = b.ToByteArrayUnsigned();
|
||||
d.BlockUpdate(array, 0, array.Length);
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
IBcpgKey key = publicPk.Key;
|
||||
fingerprint = CalculateFingerprint(publicPk);
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)key;
|
||||
keyId = rsaPublicBcpgKey.Modulus.LongValue;
|
||||
keyStrength = rsaPublicBcpgKey.Modulus.BitLength;
|
||||
return;
|
||||
}
|
||||
keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56) | ((ulong)fingerprint[fingerprint.Length - 7] << 48) | ((ulong)fingerprint[fingerprint.Length - 6] << 40) | ((ulong)fingerprint[fingerprint.Length - 5] << 32) | ((ulong)fingerprint[fingerprint.Length - 4] << 24) | ((ulong)fingerprint[fingerprint.Length - 3] << 16) | ((ulong)fingerprint[fingerprint.Length - 2] << 8) | fingerprint[fingerprint.Length - 1]);
|
||||
if (key is RsaPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
|
||||
}
|
||||
else if (key is DsaPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ((DsaPublicBcpgKey)key).P.BitLength;
|
||||
}
|
||||
else if (key is ElGamalPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
|
||||
}
|
||||
else if (key is ECPublicBcpgKey)
|
||||
{
|
||||
keyStrength = ECKeyPairGenerator.FindECCurveByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize;
|
||||
}
|
||||
}
|
||||
|
||||
public PgpPublicKey(PublicKeyAlgorithmTag algorithm, AsymmetricKeyParameter pubKey, DateTime time)
|
||||
{
|
||||
if (pubKey.IsPrivate)
|
||||
{
|
||||
throw new ArgumentException("Expected a public key", "pubKey");
|
||||
}
|
||||
IBcpgKey key;
|
||||
if (pubKey is RsaKeyParameters)
|
||||
{
|
||||
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)pubKey;
|
||||
key = new RsaPublicBcpgKey(rsaKeyParameters.Modulus, rsaKeyParameters.Exponent);
|
||||
}
|
||||
else if (pubKey is DsaPublicKeyParameters)
|
||||
{
|
||||
DsaPublicKeyParameters dsaPublicKeyParameters = (DsaPublicKeyParameters)pubKey;
|
||||
DsaParameters parameters = dsaPublicKeyParameters.Parameters;
|
||||
key = new DsaPublicBcpgKey(parameters.P, parameters.Q, parameters.G, dsaPublicKeyParameters.Y);
|
||||
}
|
||||
else if (pubKey is ECPublicKeyParameters)
|
||||
{
|
||||
ECPublicKeyParameters eCPublicKeyParameters = (ECPublicKeyParameters)pubKey;
|
||||
key = algorithm switch
|
||||
{
|
||||
PublicKeyAlgorithmTag.EC => new ECDHPublicBcpgKey(eCPublicKeyParameters.PublicKeyParamSet, eCPublicKeyParameters.Q, HashAlgorithmTag.Sha256, SymmetricKeyAlgorithmTag.Aes128),
|
||||
PublicKeyAlgorithmTag.ECDsa => new ECDsaPublicBcpgKey(eCPublicKeyParameters.PublicKeyParamSet, eCPublicKeyParameters.Q),
|
||||
_ => throw new PgpException("unknown EC algorithm"),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(pubKey is ElGamalPublicKeyParameters))
|
||||
{
|
||||
throw new PgpException("unknown key class");
|
||||
}
|
||||
ElGamalPublicKeyParameters elGamalPublicKeyParameters = (ElGamalPublicKeyParameters)pubKey;
|
||||
ElGamalParameters parameters2 = elGamalPublicKeyParameters.Parameters;
|
||||
key = new ElGamalPublicBcpgKey(parameters2.P, parameters2.G, elGamalPublicKeyParameters.Y);
|
||||
}
|
||||
publicPk = new PublicKeyPacket(algorithm, time, key);
|
||||
ids = Platform.CreateArrayList();
|
||||
idSigs = Platform.CreateArrayList();
|
||||
try
|
||||
{
|
||||
Init();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception calculating keyId", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpPublicKey(PublicKeyPacket publicPk)
|
||||
: this(publicPk, Platform.CreateArrayList(), Platform.CreateArrayList())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PublicKeyPacket publicPk, TrustPacket trustPk, IList sigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.trustPk = trustPk;
|
||||
subSigs = sigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PgpPublicKey key, TrustPacket trust, IList subSigs)
|
||||
{
|
||||
publicPk = key.publicPk;
|
||||
trustPk = trust;
|
||||
this.subSigs = subSigs;
|
||||
fingerprint = key.fingerprint;
|
||||
keyId = key.keyId;
|
||||
keyStrength = key.keyStrength;
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PgpPublicKey pubKey)
|
||||
{
|
||||
publicPk = pubKey.publicPk;
|
||||
keySigs = Platform.CreateArrayList(pubKey.keySigs);
|
||||
ids = Platform.CreateArrayList(pubKey.ids);
|
||||
idTrusts = Platform.CreateArrayList(pubKey.idTrusts);
|
||||
idSigs = Platform.CreateArrayList(pubKey.idSigs.Count);
|
||||
for (int i = 0; i != pubKey.idSigs.Count; i++)
|
||||
{
|
||||
idSigs.Add(Platform.CreateArrayList((IList)pubKey.idSigs[i]));
|
||||
}
|
||||
if (pubKey.subSigs != null)
|
||||
{
|
||||
subSigs = Platform.CreateArrayList(pubKey.subSigs.Count);
|
||||
for (int j = 0; j != pubKey.subSigs.Count; j++)
|
||||
{
|
||||
subSigs.Add(pubKey.subSigs[j]);
|
||||
}
|
||||
}
|
||||
fingerprint = pubKey.fingerprint;
|
||||
keyId = pubKey.keyId;
|
||||
keyStrength = pubKey.keyStrength;
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PublicKeyPacket publicPk, TrustPacket trustPk, IList keySigs, IList ids, IList idTrusts, IList idSigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.trustPk = trustPk;
|
||||
this.keySigs = keySigs;
|
||||
this.ids = ids;
|
||||
this.idTrusts = idTrusts;
|
||||
this.idSigs = idSigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
internal PgpPublicKey(PublicKeyPacket publicPk, IList ids, IList idSigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.ids = ids;
|
||||
this.idSigs = idSigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
public byte[] GetTrustData()
|
||||
{
|
||||
if (trustPk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Arrays.Clone(trustPk.GetLevelAndTrustAmount());
|
||||
}
|
||||
|
||||
public long GetValidSeconds()
|
||||
{
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
return (long)publicPk.ValidDays * 86400L;
|
||||
}
|
||||
if (IsMasterKey)
|
||||
{
|
||||
for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
|
||||
{
|
||||
long expirationTimeFromSig = GetExpirationTimeFromSig(selfSigned: true, MasterKeyCertificationTypes[i]);
|
||||
if (expirationTimeFromSig >= 0)
|
||||
{
|
||||
return expirationTimeFromSig;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long expirationTimeFromSig2 = GetExpirationTimeFromSig(selfSigned: false, 24);
|
||||
if (expirationTimeFromSig2 >= 0)
|
||||
{
|
||||
return expirationTimeFromSig2;
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private long GetExpirationTimeFromSig(bool selfSigned, int signatureType)
|
||||
{
|
||||
long num = -1L;
|
||||
long num2 = -1L;
|
||||
foreach (PgpSignature item in GetSignaturesOfType(signatureType))
|
||||
{
|
||||
if (selfSigned && item.KeyId != KeyId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PgpSignatureSubpacketVector hashedSubPackets = item.GetHashedSubPackets();
|
||||
if (hashedSubPackets == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
long keyExpirationTime = hashedSubPackets.GetKeyExpirationTime();
|
||||
if (item.KeyId == KeyId)
|
||||
{
|
||||
if (item.CreationTime.Ticks > num2)
|
||||
{
|
||||
num2 = item.CreationTime.Ticks;
|
||||
num = keyExpirationTime;
|
||||
}
|
||||
}
|
||||
else if (keyExpirationTime == 0 || keyExpirationTime > num)
|
||||
{
|
||||
num = keyExpirationTime;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public byte[] GetFingerprint()
|
||||
{
|
||||
return (byte[])fingerprint.Clone();
|
||||
}
|
||||
|
||||
public AsymmetricKeyParameter GetKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (publicPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)publicPk.Key;
|
||||
return new RsaKeyParameters(isPrivate: false, rsaPublicBcpgKey.Modulus, rsaPublicBcpgKey.PublicExponent);
|
||||
}
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
{
|
||||
DsaPublicBcpgKey dsaPublicBcpgKey = (DsaPublicBcpgKey)publicPk.Key;
|
||||
return new DsaPublicKeyParameters(dsaPublicBcpgKey.Y, new DsaParameters(dsaPublicBcpgKey.P, dsaPublicBcpgKey.Q, dsaPublicBcpgKey.G));
|
||||
}
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
return GetECKey("ECDSA");
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
return GetECKey("ECDH");
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
ElGamalPublicBcpgKey elGamalPublicBcpgKey = (ElGamalPublicBcpgKey)publicPk.Key;
|
||||
return new ElGamalPublicKeyParameters(elGamalPublicBcpgKey.Y, new ElGamalParameters(elGamalPublicBcpgKey.P, elGamalPublicBcpgKey.G));
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown public key algorithm encountered");
|
||||
}
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception constructing public key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private ECPublicKeyParameters GetECKey(string algorithm)
|
||||
{
|
||||
ECPublicBcpgKey eCPublicBcpgKey = (ECPublicBcpgKey)publicPk.Key;
|
||||
X9ECParameters x9ECParameters = ECKeyPairGenerator.FindECCurveByOid(eCPublicBcpgKey.CurveOid);
|
||||
ECPoint q = x9ECParameters.Curve.DecodePoint(BigIntegers.AsUnsignedByteArray(eCPublicBcpgKey.EncodedPoint));
|
||||
return new ECPublicKeyParameters(algorithm, q, eCPublicBcpgKey.CurveOid);
|
||||
}
|
||||
|
||||
public IEnumerable GetUserIds()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
foreach (object id in ids)
|
||||
{
|
||||
if (id is string)
|
||||
{
|
||||
list.Add(id);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetUserAttributes()
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
foreach (object id in ids)
|
||||
{
|
||||
if (id is PgpUserAttributeSubpacketVector)
|
||||
{
|
||||
list.Add(id);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetSignaturesForId(string id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
throw new ArgumentNullException("id");
|
||||
}
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(ids[i]))
|
||||
{
|
||||
return new EnumerableProxy((IList)idSigs[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable GetSignaturesForUserAttribute(PgpUserAttributeSubpacketVector userAttributes)
|
||||
{
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (userAttributes.Equals(ids[i]))
|
||||
{
|
||||
return new EnumerableProxy((IList)idSigs[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable GetSignaturesOfType(int signatureType)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
foreach (PgpSignature signature in GetSignatures())
|
||||
{
|
||||
if (signature.SignatureType == signatureType)
|
||||
{
|
||||
list.Add(signature);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetSignatures()
|
||||
{
|
||||
IList list = subSigs;
|
||||
if (list == null)
|
||||
{
|
||||
list = Platform.CreateArrayList(keySigs);
|
||||
foreach (ICollection idSig in idSigs)
|
||||
{
|
||||
CollectionUtilities.AddRange(list, idSig);
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeySignatures()
|
||||
{
|
||||
IList list = subSigs;
|
||||
if (list == null)
|
||||
{
|
||||
list = Platform.CreateArrayList(keySigs);
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = BcpgOutputStream.Wrap(outStr);
|
||||
bcpgOutputStream.WritePacket(publicPk);
|
||||
if (trustPk != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket(trustPk);
|
||||
}
|
||||
if (subSigs == null)
|
||||
{
|
||||
foreach (PgpSignature keySig in keySigs)
|
||||
{
|
||||
keySig.Encode(bcpgOutputStream);
|
||||
}
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (ids[i] is string)
|
||||
{
|
||||
string id = (string)ids[i];
|
||||
bcpgOutputStream.WritePacket(new UserIdPacket(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector = (PgpUserAttributeSubpacketVector)ids[i];
|
||||
bcpgOutputStream.WritePacket(new UserAttributePacket(pgpUserAttributeSubpacketVector.ToSubpacketArray()));
|
||||
}
|
||||
if (idTrusts[i] != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket((ContainedPacket)idTrusts[i]);
|
||||
}
|
||||
foreach (PgpSignature item in (IList)idSigs[i])
|
||||
{
|
||||
item.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
foreach (PgpSignature subSig in subSigs)
|
||||
{
|
||||
subSig.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRevoked()
|
||||
{
|
||||
int num = 0;
|
||||
bool flag = false;
|
||||
if (IsMasterKey)
|
||||
{
|
||||
while (!flag && num < keySigs.Count)
|
||||
{
|
||||
if (((PgpSignature)keySigs[num++]).SignatureType == 32)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!flag && num < subSigs.Count)
|
||||
{
|
||||
if (((PgpSignature)subSigs[num++]).SignatureType == 40)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static PgpPublicKey AddCertification(PgpPublicKey key, string id, PgpSignature certification)
|
||||
{
|
||||
return AddCert(key, id, certification);
|
||||
}
|
||||
|
||||
public static PgpPublicKey AddCertification(PgpPublicKey key, PgpUserAttributeSubpacketVector userAttributes, PgpSignature certification)
|
||||
{
|
||||
return AddCert(key, userAttributes, certification);
|
||||
}
|
||||
|
||||
private static PgpPublicKey AddCert(PgpPublicKey key, object id, PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
IList list = null;
|
||||
for (int i = 0; i != pgpPublicKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(pgpPublicKey.ids[i]))
|
||||
{
|
||||
list = (IList)pgpPublicKey.idSigs[i];
|
||||
}
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
list = Platform.CreateArrayList();
|
||||
list.Add(certification);
|
||||
pgpPublicKey.ids.Add(id);
|
||||
pgpPublicKey.idTrusts.Add(null);
|
||||
pgpPublicKey.idSigs.Add(list);
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpUserAttributeSubpacketVector userAttributes)
|
||||
{
|
||||
return RemoveCert(key, userAttributes);
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, string id)
|
||||
{
|
||||
return RemoveCert(key, id);
|
||||
}
|
||||
|
||||
private static PgpPublicKey RemoveCert(PgpPublicKey key, object id)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < pgpPublicKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(pgpPublicKey.ids[i]))
|
||||
{
|
||||
flag = true;
|
||||
pgpPublicKey.ids.RemoveAt(i);
|
||||
pgpPublicKey.idTrusts.RemoveAt(i);
|
||||
pgpPublicKey.idSigs.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, string id, PgpSignature certification)
|
||||
{
|
||||
return RemoveCert(key, id, certification);
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpUserAttributeSubpacketVector userAttributes, PgpSignature certification)
|
||||
{
|
||||
return RemoveCert(key, userAttributes, certification);
|
||||
}
|
||||
|
||||
private static PgpPublicKey RemoveCert(PgpPublicKey key, object id, PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < pgpPublicKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(pgpPublicKey.ids[i]))
|
||||
{
|
||||
IList list = (IList)pgpPublicKey.idSigs[i];
|
||||
flag = list.Contains(certification);
|
||||
if (flag)
|
||||
{
|
||||
list.Remove(certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey AddCertification(PgpPublicKey key, PgpSignature certification)
|
||||
{
|
||||
if (key.IsMasterKey)
|
||||
{
|
||||
if (certification.SignatureType == 40)
|
||||
{
|
||||
throw new ArgumentException("signature type incorrect for master key revocation.");
|
||||
}
|
||||
}
|
||||
else if (certification.SignatureType == 32)
|
||||
{
|
||||
throw new ArgumentException("signature type incorrect for sub-key revocation.");
|
||||
}
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
if (pgpPublicKey.subSigs != null)
|
||||
{
|
||||
pgpPublicKey.subSigs.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
pgpPublicKey.keySigs.Add(certification);
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
|
||||
public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = new PgpPublicKey(key);
|
||||
IList list = ((pgpPublicKey.subSigs != null) ? pgpPublicKey.subSigs : pgpPublicKey.keySigs);
|
||||
int num = list.IndexOf(certification);
|
||||
bool flag = num >= 0;
|
||||
if (flag)
|
||||
{
|
||||
list.RemoveAt(num);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string userId in key.GetUserIds())
|
||||
{
|
||||
foreach (object item in key.GetSignaturesForId(userId))
|
||||
{
|
||||
if (certification == item)
|
||||
{
|
||||
flag = true;
|
||||
pgpPublicKey = RemoveCertification(pgpPublicKey, userId, certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
foreach (PgpUserAttributeSubpacketVector userAttribute in key.GetUserAttributes())
|
||||
{
|
||||
foreach (object item2 in key.GetSignaturesForUserAttribute(userAttribute))
|
||||
{
|
||||
if (certification == item2)
|
||||
{
|
||||
flag = true;
|
||||
pgpPublicKey = RemoveCertification(pgpPublicKey, userAttribute, certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pgpPublicKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Generators;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKeyEncryptedData : PgpEncryptedData
|
||||
{
|
||||
private PublicKeyEncSessionPacket keyData;
|
||||
|
||||
public long KeyId => keyData.KeyId;
|
||||
|
||||
internal PgpPublicKeyEncryptedData(PublicKeyEncSessionPacket keyData, InputStreamPacket encData)
|
||||
: base(encData)
|
||||
{
|
||||
this.keyData = keyData;
|
||||
}
|
||||
|
||||
private static IBufferedCipher GetKeyCipher(PublicKeyAlgorithmTag algorithm)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
return CipherUtilities.GetCipher("RSA//PKCS1Padding");
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConfirmCheckSum(byte[] sessionInfo)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 1; i != sessionInfo.Length - 2; i++)
|
||||
{
|
||||
num += sessionInfo[i] & 0xFF;
|
||||
}
|
||||
if (sessionInfo[^2] == (byte)(num >> 8))
|
||||
{
|
||||
return sessionInfo[^1] == (byte)num;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(PgpPrivateKey privKey)
|
||||
{
|
||||
byte[] array = RecoverSessionData(privKey);
|
||||
return (SymmetricKeyAlgorithmTag)array[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 == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(symmetricKeyAlgorithmTag);
|
||||
string text = symmetricCipherName;
|
||||
IBufferedCipher cipher;
|
||||
try
|
||||
{
|
||||
text = ((!(encData is SymmetricEncIntegrityPacket)) ? (text + "/OpenPGPCFB/NoPadding") : (text + "/CFB/NoPadding"));
|
||||
cipher = CipherUtilities.GetCipher(text);
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("exception creating cipher", exception);
|
||||
}
|
||||
try
|
||||
{
|
||||
KeyParameter parameters = ParameterUtilities.CreateKeyParameter(symmetricCipherName, array, 1, array.Length - 3);
|
||||
byte[] array2 = new byte[cipher.GetBlockSize()];
|
||||
cipher.Init(forEncryption: false, new ParametersWithIV(parameters, array2));
|
||||
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, 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.");
|
||||
}
|
||||
return encStream;
|
||||
}
|
||||
catch (PgpException ex2)
|
||||
{
|
||||
throw ex2;
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("Exception starting decryption", exception2);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] RecoverSessionData(PgpPrivateKey privKey)
|
||||
{
|
||||
byte[][] encSessionKey = keyData.GetEncSessionKey();
|
||||
if (keyData.Algorithm == PublicKeyAlgorithmTag.EC)
|
||||
{
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key;
|
||||
X9ECParameters x9ECParameters = ECKeyPairGenerator.FindECCurveByOid(eCDHPublicBcpgKey.CurveOid);
|
||||
byte[] array = encSessionKey[0];
|
||||
int num = (((array[0] & 0xFF) << 8) + (array[1] & 0xFF) + 7) / 8;
|
||||
byte[] array2 = new byte[num];
|
||||
Array.Copy(array, 2, array2, 0, num);
|
||||
byte[] array3 = new byte[array[num + 2]];
|
||||
Array.Copy(array, 2 + num + 1, array3, 0, array3.Length);
|
||||
ECPoint eCPoint = x9ECParameters.Curve.DecodePoint(array2);
|
||||
ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)privKey.Key;
|
||||
ECPoint s = eCPoint.Multiply(eCPrivateKeyParameters.D).Normalize();
|
||||
KeyParameter parameters = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, s));
|
||||
IWrapper wrapper = PgpUtilities.CreateWrapper(eCDHPublicBcpgKey.SymmetricKeyAlgorithm);
|
||||
wrapper.Init(forWrapping: false, parameters);
|
||||
return PgpPad.UnpadSessionData(wrapper.Unwrap(array3, 0, array3.Length));
|
||||
}
|
||||
IBufferedCipher keyCipher = GetKeyCipher(keyData.Algorithm);
|
||||
try
|
||||
{
|
||||
keyCipher.Init(forEncryption: false, privKey.Key);
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("error setting asymmetric cipher", exception);
|
||||
}
|
||||
if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
|
||||
{
|
||||
byte[] array4 = encSessionKey[0];
|
||||
keyCipher.ProcessBytes(array4, 2, array4.Length - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ElGamalPrivateKeyParameters elGamalPrivateKeyParameters = (ElGamalPrivateKeyParameters)privKey.Key;
|
||||
int size = (elGamalPrivateKeyParameters.Parameters.P.BitLength + 7) / 8;
|
||||
ProcessEncodedMpi(keyCipher, size, encSessionKey[0]);
|
||||
ProcessEncodedMpi(keyCipher, size, encSessionKey[1]);
|
||||
}
|
||||
try
|
||||
{
|
||||
return keyCipher.DoFinal();
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("exception decrypting secret key", exception2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc)
|
||||
{
|
||||
if (mpiEnc.Length - 2 > size)
|
||||
{
|
||||
cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3);
|
||||
return;
|
||||
}
|
||||
byte[] array = new byte[size];
|
||||
Array.Copy(mpiEnc, 2, array, array.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2);
|
||||
cipher.ProcessBytes(array, 0, array.Length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKeyRing : PgpKeyRing
|
||||
{
|
||||
private readonly IList keys;
|
||||
|
||||
public PgpPublicKeyRing(byte[] encoding)
|
||||
: this(new MemoryStream(encoding, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpPublicKeyRing(IList pubKeys)
|
||||
{
|
||||
keys = pubKeys;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing(Stream inputStream)
|
||||
{
|
||||
keys = Platform.CreateArrayList();
|
||||
BcpgInputStream bcpgInputStream = BcpgInputStream.Wrap(inputStream);
|
||||
PacketTag packetTag = bcpgInputStream.NextPacketTag();
|
||||
if (packetTag != PacketTag.PublicKey && packetTag != PacketTag.PublicSubkey)
|
||||
{
|
||||
int num = (int)packetTag;
|
||||
throw new IOException("public key ring doesn't start with public key tag: tag 0x" + num.ToString("X"));
|
||||
}
|
||||
PublicKeyPacket publicPk = (PublicKeyPacket)bcpgInputStream.ReadPacket();
|
||||
TrustPacket trustPk = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList keySigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
PgpKeyRing.ReadUserIDs(bcpgInputStream, out var ids, out var idTrusts, out var idSigs);
|
||||
keys.Add(new PgpPublicKey(publicPk, trustPk, keySigs, ids, idTrusts, idSigs));
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.PublicSubkey)
|
||||
{
|
||||
keys.Add(ReadSubkey(bcpgInputStream));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual PgpPublicKey GetPublicKey()
|
||||
{
|
||||
return (PgpPublicKey)keys[0];
|
||||
}
|
||||
|
||||
public virtual PgpPublicKey GetPublicKey(long keyId)
|
||||
{
|
||||
foreach (PgpPublicKey key in keys)
|
||||
{
|
||||
if (keyId == key.KeyId)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual IEnumerable GetPublicKeys()
|
||||
{
|
||||
return new EnumerableProxy(keys);
|
||||
}
|
||||
|
||||
public virtual byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public virtual void Encode(Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
foreach (PgpPublicKey key in keys)
|
||||
{
|
||||
key.Encode(outStr);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRing InsertPublicKey(PgpPublicKeyRing pubRing, PgpPublicKey pubKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(pubRing.keys);
|
||||
bool flag = false;
|
||||
bool flag2 = false;
|
||||
for (int i = 0; i != list.Count; i++)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = (PgpPublicKey)list[i];
|
||||
if (pgpPublicKey.KeyId == pubKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list[i] = pubKey;
|
||||
}
|
||||
if (pgpPublicKey.IsMasterKey)
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
if (pubKey.IsMasterKey)
|
||||
{
|
||||
if (flag2)
|
||||
{
|
||||
throw new ArgumentException("cannot add a master key to a ring that already has one");
|
||||
}
|
||||
list.Insert(0, pubKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(pubKey);
|
||||
}
|
||||
}
|
||||
return new PgpPublicKeyRing(list);
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRing RemovePublicKey(PgpPublicKeyRing pubRing, PgpPublicKey pubKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(pubRing.keys);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
PgpPublicKey pgpPublicKey = (PgpPublicKey)list[i];
|
||||
if (pgpPublicKey.KeyId == pubKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new PgpPublicKeyRing(list);
|
||||
}
|
||||
|
||||
internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
|
||||
{
|
||||
PublicKeyPacket publicPk = (PublicKeyPacket)bcpgInput.ReadPacket();
|
||||
TrustPacket trustPk = PgpKeyRing.ReadOptionalTrustPacket(bcpgInput);
|
||||
IList sigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInput);
|
||||
return new PgpPublicKey(publicPk, trustPk, sigs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpPublicKeyRingBundle
|
||||
{
|
||||
private readonly IDictionary pubRings;
|
||||
|
||||
private readonly IList order;
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => order.Count;
|
||||
|
||||
public int Count => order.Count;
|
||||
|
||||
private PgpPublicKeyRingBundle(IDictionary pubRings, IList order)
|
||||
{
|
||||
this.pubRings = pubRings;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(byte[] encoding)
|
||||
: this(new MemoryStream(encoding, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(Stream inputStream)
|
||||
: this(new PgpObjectFactory(inputStream).AllPgpObjects())
|
||||
{
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(IEnumerable e)
|
||||
{
|
||||
pubRings = Platform.CreateHashtable();
|
||||
order = Platform.CreateArrayList();
|
||||
foreach (object item in e)
|
||||
{
|
||||
if (!(item is PgpPublicKeyRing pgpPublicKeyRing))
|
||||
{
|
||||
throw new PgpException(Platform.GetTypeName(item) + " found where PgpPublicKeyRing expected");
|
||||
}
|
||||
long keyId = pgpPublicKeyRing.GetPublicKey().KeyId;
|
||||
pubRings.Add(keyId, pgpPublicKeyRing);
|
||||
order.Add(keyId);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings()
|
||||
{
|
||||
return new EnumerableProxy(pubRings.Values);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial: false, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial, bool ignoreCase)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
if (ignoreCase)
|
||||
{
|
||||
userId = Platform.ToUpperInvariant(userId);
|
||||
}
|
||||
foreach (PgpPublicKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
foreach (string userId2 in keyRing.GetPublicKey().GetUserIds())
|
||||
{
|
||||
string text2 = userId2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
text2 = Platform.ToUpperInvariant(text2);
|
||||
}
|
||||
if (matchPartial)
|
||||
{
|
||||
if (Platform.IndexOf(text2, userId) > -1)
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
else if (text2.Equals(userId))
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public PgpPublicKey GetPublicKey(long keyId)
|
||||
{
|
||||
foreach (PgpPublicKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpPublicKey publicKey = keyRing.GetPublicKey(keyId);
|
||||
if (publicKey != null)
|
||||
{
|
||||
return publicKey;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing GetPublicKeyRing(long keyId)
|
||||
{
|
||||
if (pubRings.Contains(keyId))
|
||||
{
|
||||
return (PgpPublicKeyRing)pubRings[keyId];
|
||||
}
|
||||
foreach (PgpPublicKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpPublicKey publicKey = keyRing.GetPublicKey(keyId);
|
||||
if (publicKey != null)
|
||||
{
|
||||
return keyRing;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(long keyID)
|
||||
{
|
||||
return GetPublicKey(keyID) != null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream outStr2 = BcpgOutputStream.Wrap(outStr);
|
||||
foreach (object item in order)
|
||||
{
|
||||
long num = (long)item;
|
||||
PgpPublicKeyRing pgpPublicKeyRing = (PgpPublicKeyRing)pubRings[num];
|
||||
pgpPublicKeyRing.Encode(outStr2);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRingBundle AddPublicKeyRing(PgpPublicKeyRingBundle bundle, PgpPublicKeyRing publicKeyRing)
|
||||
{
|
||||
long keyId = publicKeyRing.GetPublicKey().KeyId;
|
||||
if (bundle.pubRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.pubRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary[keyId] = publicKeyRing;
|
||||
list.Add(keyId);
|
||||
return new PgpPublicKeyRingBundle(dictionary, list);
|
||||
}
|
||||
|
||||
public static PgpPublicKeyRingBundle RemovePublicKeyRing(PgpPublicKeyRingBundle bundle, PgpPublicKeyRing publicKeyRing)
|
||||
{
|
||||
long keyId = publicKeyRing.GetPublicKey().KeyId;
|
||||
if (!bundle.pubRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.pubRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary.Remove(keyId);
|
||||
list.Remove(keyId);
|
||||
return new PgpPublicKeyRingBundle(dictionary, list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,758 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1.X9;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSecretKey
|
||||
{
|
||||
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:
|
||||
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 UserIds => pub.GetUserIds();
|
||||
|
||||
public IEnumerable 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;
|
||||
BcpgObject bcpgObject;
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
{
|
||||
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = (RsaPrivateCrtKeyParameters)privKey.Key;
|
||||
bcpgObject = new RsaSecretBcpgKey(rsaPrivateCrtKeyParameters.Exponent, rsaPrivateCrtKeyParameters.P, rsaPrivateCrtKeyParameters.Q);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
{
|
||||
DsaPrivateKeyParameters dsaPrivateKeyParameters = (DsaPrivateKeyParameters)privKey.Key;
|
||||
bcpgObject = new DsaSecretBcpgKey(dsaPrivateKeyParameters.X);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
{
|
||||
ECPrivateKeyParameters eCPrivateKeyParameters = (ECPrivateKeyParameters)privKey.Key;
|
||||
bcpgObject = new ECSecretBcpgKey(eCPrivateKeyParameters.D);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
ElGamalPrivateKeyParameters elGamalPrivateKeyParameters = (ElGamalPrivateKeyParameters)privKey.Key;
|
||||
bcpgObject = new ElGamalSecretBcpgKey(elGamalPrivateKeyParameters.X);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown key class");
|
||||
}
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
BcpgOutputStream bcpgOutputStream = new BcpgOutputStream(memoryStream);
|
||||
bcpgOutputStream.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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
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 ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use the constructor taking an explicit 'useSha1' parameter instead")]
|
||||
public PgpSecretKey(int certificationLevel, PgpKeyPair keyPair, string id, SymmetricKeyAlgorithmTag encAlgorithm, char[] passPhrase, PgpSignatureSubpacketVector hashedPackets, PgpSignatureSubpacketVector unhashedPackets, SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, useSha1: false, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
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, utf8PassPhrase: 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), clearPassPhrase: 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, clearPassPhrase: 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, isMasterKey: 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, utf8PassPhrase: 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), clearPassPhrase: 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, clearPassPhrase: 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, isMasterKey: 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, useSha1: 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)
|
||||
{
|
||||
}
|
||||
|
||||
private byte[] ExtractKeyData(byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm;
|
||||
byte[] secretKeyData = secret.GetSecretKeyData();
|
||||
if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
return secretKeyData;
|
||||
}
|
||||
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 + " of " + array2.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array = new byte[secretKeyData.Length];
|
||||
iV = Arrays.Clone(iV);
|
||||
int num = 0;
|
||||
for (int j = 0; j != 4; j++)
|
||||
{
|
||||
int num2 = (((secretKeyData[num] << 8) | (secretKeyData[num + 1] & 0xFF)) + 7) / 8;
|
||||
array[num] = secretKeyData[num];
|
||||
array[num + 1] = secretKeyData[num + 1];
|
||||
num += 2;
|
||||
byte[] sourceArray = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iV, secretKeyData, num, num2);
|
||||
Array.Copy(sourceArray, 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) & 0xFF00) | (secretKeyData[num + 1] & 0xFF);
|
||||
int num4 = 0;
|
||||
for (int k = 0; k < num; k++)
|
||||
{
|
||||
num4 += array[k] & 0xFF;
|
||||
}
|
||||
num4 &= 0xFFFF;
|
||||
if (num4 != num3)
|
||||
{
|
||||
throw new PgpException("Checksum mismatch: passphrase wrong, expected " + num3.ToString("X") + " found " + num4.ToString("X"));
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception decrypting key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding, KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
|
||||
{
|
||||
IBufferedCipher cipher;
|
||||
try
|
||||
{
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
cipher = CipherUtilities.GetCipher(symmetricCipherName + modeAndPadding);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
cipher.Init(forEncryption: false, new ParametersWithIV(key, iv));
|
||||
return cipher.DoFinal(keyData, keyOff, keyLen);
|
||||
}
|
||||
|
||||
public PgpPrivateKey ExtractPrivateKey(char[] passPhrase)
|
||||
{
|
||||
return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public PgpPrivateKey ExtractPrivateKeyUtf8(char[] passPhrase)
|
||||
{
|
||||
return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public PgpPrivateKey ExtractPrivateKeyRaw(byte[] rawPassPhrase)
|
||||
{
|
||||
return DoExtractPrivateKey(rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal PgpPrivateKey DoExtractPrivateKey(byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
if (IsPrivateKeyEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PublicKeyPacket publicKeyPacket = secret.PublicKeyPacket;
|
||||
try
|
||||
{
|
||||
byte[] buffer = ExtractKeyData(rawPassPhrase, clearPassPhrase);
|
||||
BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(buffer, writable: false));
|
||||
AsymmetricKeyParameter privateKey;
|
||||
switch (publicKeyPacket.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
{
|
||||
RsaPublicBcpgKey rsaPublicBcpgKey = (RsaPublicBcpgKey)publicKeyPacket.Key;
|
||||
RsaSecretBcpgKey rsaSecretBcpgKey = new RsaSecretBcpgKey(bcpgIn);
|
||||
RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = new RsaPrivateCrtKeyParameters(rsaSecretBcpgKey.Modulus, rsaPublicBcpgKey.PublicExponent, rsaSecretBcpgKey.PrivateExponent, rsaSecretBcpgKey.PrimeP, rsaSecretBcpgKey.PrimeQ, rsaSecretBcpgKey.PrimeExponentP, rsaSecretBcpgKey.PrimeExponentQ, rsaSecretBcpgKey.CrtCoefficient);
|
||||
privateKey = rsaPrivateCrtKeyParameters;
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
{
|
||||
DsaPublicBcpgKey dsaPublicBcpgKey = (DsaPublicBcpgKey)publicKeyPacket.Key;
|
||||
DsaSecretBcpgKey dsaSecretBcpgKey = new DsaSecretBcpgKey(bcpgIn);
|
||||
DsaParameters parameters2 = new DsaParameters(dsaPublicBcpgKey.P, dsaPublicBcpgKey.Q, dsaPublicBcpgKey.G);
|
||||
privateKey = new DsaPrivateKeyParameters(dsaSecretBcpgKey.X, parameters2);
|
||||
break;
|
||||
}
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
privateKey = GetECKey("ECDH", bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
privateKey = GetECKey("ECDSA", bcpgIn);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
{
|
||||
ElGamalPublicBcpgKey elGamalPublicBcpgKey = (ElGamalPublicBcpgKey)publicKeyPacket.Key;
|
||||
ElGamalSecretBcpgKey elGamalSecretBcpgKey = new ElGamalSecretBcpgKey(bcpgIn);
|
||||
ElGamalParameters parameters = new ElGamalParameters(elGamalPublicBcpgKey.P, elGamalPublicBcpgKey.G);
|
||||
privateKey = new ElGamalPrivateKeyParameters(elGamalSecretBcpgKey.X, parameters);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown public key algorithm encountered");
|
||||
}
|
||||
return new PgpPrivateKey(KeyId, publicKeyPacket, privateKey);
|
||||
}
|
||||
catch (PgpException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception constructing key", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn)
|
||||
{
|
||||
ECPublicBcpgKey eCPublicBcpgKey = (ECPublicBcpgKey)secret.PublicKeyPacket.Key;
|
||||
ECSecretBcpgKey eCSecretBcpgKey = new ECSecretBcpgKey(bcpgIn);
|
||||
return new ECPrivateKeyParameters(algorithm, eCSecretBcpgKey.X, eCPublicBcpgKey.CurveOid);
|
||||
}
|
||||
|
||||
private static byte[] Checksum(bool useSha1, byte[] bytes, int length)
|
||||
{
|
||||
if (useSha1)
|
||||
{
|
||||
try
|
||||
{
|
||||
IDigest digest = DigestUtilities.GetDigest("SHA1");
|
||||
digest.BlockUpdate(bytes, 0, length);
|
||||
return DigestUtilities.DoFinal(digest);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Can't find SHA-1", exception);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
for (int i = 0; i != pub.ids.Count; i++)
|
||||
{
|
||||
object obj = pub.ids[i];
|
||||
if (obj is string)
|
||||
{
|
||||
string id = (string)obj;
|
||||
bcpgOutputStream.WritePacket(new UserIdPacket(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector = (PgpUserAttributeSubpacketVector)obj;
|
||||
bcpgOutputStream.WritePacket(new UserAttributePacket(pgpUserAttributeSubpacketVector.ToSubpacketArray()));
|
||||
}
|
||||
if (pub.idTrusts[i] != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket((ContainedPacket)pub.idTrusts[i]);
|
||||
}
|
||||
foreach (PgpSignature item in (IList)pub.idSigs[i])
|
||||
{
|
||||
item.Encode(bcpgOutputStream);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
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, utf8: false), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: false), clearPassPhrase: true, newEncAlgorithm, rand);
|
||||
}
|
||||
|
||||
public static PgpSecretKey CopyWithNewPasswordUtf8(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, utf8: true), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: true), clearPassPhrase: true, newEncAlgorithm, rand);
|
||||
}
|
||||
|
||||
public static PgpSecretKey CopyWithNewPasswordRaw(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
return DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, clearPassPhrase: 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(useSha1: false, array2, array2.Length - 2);
|
||||
array2[^2] = array3[0];
|
||||
array2[^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 ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", exception);
|
||||
}
|
||||
}
|
||||
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] << 8) | (rawKeyData[num + 1] & 0xFF)) + 7) / 8;
|
||||
array[num] = rawKeyData[num];
|
||||
array[num + 1] = rawKeyData[num + 1];
|
||||
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
|
||||
{
|
||||
string symmetricCipherName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
cipher = CipherUtilities.GetCipher(symmetricCipherName + "/CFB/NoPadding");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", exception);
|
||||
}
|
||||
if (iv == null)
|
||||
{
|
||||
iv = PgpUtilities.GenerateIV(cipher.GetBlockSize(), random);
|
||||
}
|
||||
cipher.Init(forEncryption: 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, utf8: false), clearPassPhrase: true, pubKey);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true, pubKey);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, clearPassPhrase: false, pubKey);
|
||||
}
|
||||
|
||||
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey)
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("protected-private-key"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text2 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text2.Equals("ecc"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
string curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("q"))
|
||||
{
|
||||
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("no q value found");
|
||||
}
|
||||
throw new PgpException("no curve details found");
|
||||
}
|
||||
throw new PgpException("unknown key type found");
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase)
|
||||
{
|
||||
return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("protected-private-key"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text2 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text2.Equals("ecc"))
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
string text3 = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (Platform.StartsWith(text3, "NIST "))
|
||||
{
|
||||
text3 = text3.Substring("NIST ".Length);
|
||||
}
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("q"))
|
||||
{
|
||||
byte[] bytes = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
|
||||
PublicKeyPacket publicKeyPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow, new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(text3), new BigInteger(1, bytes)));
|
||||
SXprUtilities.SkipCloseParenthesis(inputStream);
|
||||
byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, text3);
|
||||
return new PgpSecretKey(new SecretKeyPacket(publicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null, new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(publicKeyPacket));
|
||||
}
|
||||
throw new PgpException("no q value found");
|
||||
}
|
||||
throw new PgpException("no curve details found");
|
||||
}
|
||||
throw new PgpException("unknown key type found");
|
||||
}
|
||||
|
||||
private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName)
|
||||
{
|
||||
SXprUtilities.SkipOpenParenthesis(inputStream);
|
||||
string text = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
|
||||
if (text.Equals("protected"))
|
||||
{
|
||||
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);
|
||||
byte[] buffer = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, array, 0, array.Length);
|
||||
Stream stream = new MemoryStream(buffer, writable: false);
|
||||
SXprUtilities.SkipOpenParenthesis(stream);
|
||||
SXprUtilities.SkipOpenParenthesis(stream);
|
||||
SXprUtilities.SkipOpenParenthesis(stream);
|
||||
SXprUtilities.ReadString(stream, stream.ReadByte());
|
||||
return SXprUtilities.ReadBytes(stream, stream.ReadByte());
|
||||
}
|
||||
throw new PgpException("protected block not found");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSecretKeyRing : PgpKeyRing
|
||||
{
|
||||
private readonly IList keys;
|
||||
|
||||
private readonly IList extraPubKeys;
|
||||
|
||||
internal PgpSecretKeyRing(IList keys)
|
||||
: this(keys, Platform.CreateArrayList())
|
||||
{
|
||||
}
|
||||
|
||||
private PgpSecretKeyRing(IList keys, IList extraPubKeys)
|
||||
{
|
||||
this.keys = keys;
|
||||
this.extraPubKeys = extraPubKeys;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing(byte[] encoding)
|
||||
: this(new MemoryStream(encoding))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing(Stream inputStream)
|
||||
{
|
||||
keys = Platform.CreateArrayList();
|
||||
extraPubKeys = Platform.CreateArrayList();
|
||||
BcpgInputStream bcpgInputStream = BcpgInputStream.Wrap(inputStream);
|
||||
PacketTag packetTag = bcpgInputStream.NextPacketTag();
|
||||
if (packetTag != PacketTag.SecretKey && packetTag != PacketTag.SecretSubkey)
|
||||
{
|
||||
int num = (int)packetTag;
|
||||
throw new IOException("secret key ring doesn't start with secret key tag: tag 0x" + num.ToString("X"));
|
||||
}
|
||||
SecretKeyPacket secretKeyPacket = (SecretKeyPacket)bcpgInputStream.ReadPacket();
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.Experimental2)
|
||||
{
|
||||
bcpgInputStream.ReadPacket();
|
||||
}
|
||||
TrustPacket trustPk = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList keySigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
PgpKeyRing.ReadUserIDs(bcpgInputStream, out var ids, out var idTrusts, out var idSigs);
|
||||
keys.Add(new PgpSecretKey(secretKeyPacket, new PgpPublicKey(secretKeyPacket.PublicKeyPacket, trustPk, keySigs, ids, idTrusts, idSigs)));
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.SecretSubkey || bcpgInputStream.NextPacketTag() == PacketTag.PublicSubkey)
|
||||
{
|
||||
if (bcpgInputStream.NextPacketTag() == PacketTag.SecretSubkey)
|
||||
{
|
||||
SecretSubkeyPacket secretSubkeyPacket = (SecretSubkeyPacket)bcpgInputStream.ReadPacket();
|
||||
while (bcpgInputStream.NextPacketTag() == PacketTag.Experimental2)
|
||||
{
|
||||
bcpgInputStream.ReadPacket();
|
||||
}
|
||||
TrustPacket trustPk2 = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList sigs = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
keys.Add(new PgpSecretKey(secretSubkeyPacket, new PgpPublicKey(secretSubkeyPacket.PublicKeyPacket, trustPk2, sigs)));
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicSubkeyPacket publicPk = (PublicSubkeyPacket)bcpgInputStream.ReadPacket();
|
||||
TrustPacket trustPk3 = PgpKeyRing.ReadOptionalTrustPacket(bcpgInputStream);
|
||||
IList sigs2 = PgpKeyRing.ReadSignaturesAndTrust(bcpgInputStream);
|
||||
extraPubKeys.Add(new PgpPublicKey(publicPk, trustPk3, sigs2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PgpPublicKey GetPublicKey()
|
||||
{
|
||||
return ((PgpSecretKey)keys[0]).PublicKey;
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey()
|
||||
{
|
||||
return (PgpSecretKey)keys[0];
|
||||
}
|
||||
|
||||
public IEnumerable GetSecretKeys()
|
||||
{
|
||||
return new EnumerableProxy(keys);
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey(long keyId)
|
||||
{
|
||||
foreach (PgpSecretKey key in keys)
|
||||
{
|
||||
if (keyId == key.KeyId)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable GetExtraPublicKeys()
|
||||
{
|
||||
return new EnumerableProxy(extraPubKeys);
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStr");
|
||||
}
|
||||
foreach (PgpSecretKey key in keys)
|
||||
{
|
||||
key.Encode(outStr);
|
||||
}
|
||||
foreach (PgpPublicKey extraPubKey in extraPubKeys)
|
||||
{
|
||||
extraPubKey.Encode(outStr);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing ReplacePublicKeys(PgpSecretKeyRing secretRing, PgpPublicKeyRing publicRing)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(secretRing.keys.Count);
|
||||
foreach (PgpSecretKey key in secretRing.keys)
|
||||
{
|
||||
PgpPublicKey publicKey = publicRing.GetPublicKey(key.KeyId);
|
||||
list.Add(PgpSecretKey.ReplacePublicKey(key, publicKey));
|
||||
}
|
||||
return new PgpSecretKeyRing(list);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing CopyWithNewPassword(PgpSecretKeyRing ring, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(ring.keys.Count);
|
||||
foreach (PgpSecretKey secretKey in ring.GetSecretKeys())
|
||||
{
|
||||
if (secretKey.IsPrivateKeyEmpty)
|
||||
{
|
||||
list.Add(secretKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand));
|
||||
}
|
||||
}
|
||||
return new PgpSecretKeyRing(list, ring.extraPubKeys);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing InsertSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(secRing.keys);
|
||||
bool flag = false;
|
||||
bool flag2 = false;
|
||||
for (int i = 0; i != list.Count; i++)
|
||||
{
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey)list[i];
|
||||
if (pgpSecretKey.KeyId == secKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list[i] = secKey;
|
||||
}
|
||||
if (pgpSecretKey.IsMasterKey)
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
if (secKey.IsMasterKey)
|
||||
{
|
||||
if (flag2)
|
||||
{
|
||||
throw new ArgumentException("cannot add a master key to a ring that already has one");
|
||||
}
|
||||
list.Insert(0, secKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(secKey);
|
||||
}
|
||||
}
|
||||
return new PgpSecretKeyRing(list, secRing.extraPubKeys);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRing RemoveSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey)
|
||||
{
|
||||
IList list = Platform.CreateArrayList(secRing.keys);
|
||||
bool flag = false;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey)list[i];
|
||||
if (pgpSecretKey.KeyId == secKey.KeyId)
|
||||
{
|
||||
flag = true;
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new PgpSecretKeyRing(list, secRing.extraPubKeys);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSecretKeyRingBundle
|
||||
{
|
||||
private readonly IDictionary secretRings;
|
||||
|
||||
private readonly IList order;
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => order.Count;
|
||||
|
||||
public int Count => order.Count;
|
||||
|
||||
private PgpSecretKeyRingBundle(IDictionary secretRings, IList order)
|
||||
{
|
||||
this.secretRings = secretRings;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(byte[] encoding)
|
||||
: this(new MemoryStream(encoding, writable: false))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(Stream inputStream)
|
||||
: this(new PgpObjectFactory(inputStream).AllPgpObjects())
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(IEnumerable e)
|
||||
{
|
||||
secretRings = Platform.CreateHashtable();
|
||||
order = Platform.CreateArrayList();
|
||||
foreach (object item in e)
|
||||
{
|
||||
if (!(item is PgpSecretKeyRing pgpSecretKeyRing))
|
||||
{
|
||||
throw new PgpException(Platform.GetTypeName(item) + " found where PgpSecretKeyRing expected");
|
||||
}
|
||||
long keyId = pgpSecretKeyRing.GetPublicKey().KeyId;
|
||||
secretRings.Add(keyId, pgpSecretKeyRing);
|
||||
order.Add(keyId);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings()
|
||||
{
|
||||
return new EnumerableProxy(secretRings.Values);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial: false, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial, ignoreCase: false);
|
||||
}
|
||||
|
||||
public IEnumerable GetKeyRings(string userId, bool matchPartial, bool ignoreCase)
|
||||
{
|
||||
IList list = Platform.CreateArrayList();
|
||||
if (ignoreCase)
|
||||
{
|
||||
userId = Platform.ToUpperInvariant(userId);
|
||||
}
|
||||
foreach (PgpSecretKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
foreach (string userId2 in keyRing.GetSecretKey().UserIds)
|
||||
{
|
||||
string text2 = userId2;
|
||||
if (ignoreCase)
|
||||
{
|
||||
text2 = Platform.ToUpperInvariant(text2);
|
||||
}
|
||||
if (matchPartial)
|
||||
{
|
||||
if (Platform.IndexOf(text2, userId) > -1)
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
else if (text2.Equals(userId))
|
||||
{
|
||||
list.Add(keyRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey(long keyId)
|
||||
{
|
||||
foreach (PgpSecretKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpSecretKey secretKey = keyRing.GetSecretKey(keyId);
|
||||
if (secretKey != null)
|
||||
{
|
||||
return secretKey;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing GetSecretKeyRing(long keyId)
|
||||
{
|
||||
if (secretRings.Contains(keyId))
|
||||
{
|
||||
return (PgpSecretKeyRing)secretRings[keyId];
|
||||
}
|
||||
foreach (PgpSecretKeyRing keyRing in GetKeyRings())
|
||||
{
|
||||
PgpSecretKey secretKey = keyRing.GetSecretKey(keyId);
|
||||
if (secretKey != null)
|
||||
{
|
||||
return keyRing;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool Contains(long keyID)
|
||||
{
|
||||
return GetSecretKey(keyID) != null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStr)
|
||||
{
|
||||
BcpgOutputStream outStr2 = BcpgOutputStream.Wrap(outStr);
|
||||
foreach (object item in order)
|
||||
{
|
||||
long num = (long)item;
|
||||
PgpSecretKeyRing pgpSecretKeyRing = (PgpSecretKeyRing)secretRings[num];
|
||||
pgpSecretKeyRing.Encode(outStr2);
|
||||
}
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRingBundle AddSecretKeyRing(PgpSecretKeyRingBundle bundle, PgpSecretKeyRing secretKeyRing)
|
||||
{
|
||||
long keyId = secretKeyRing.GetPublicKey().KeyId;
|
||||
if (bundle.secretRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.secretRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary[keyId] = secretKeyRing;
|
||||
list.Add(keyId);
|
||||
return new PgpSecretKeyRingBundle(dictionary, list);
|
||||
}
|
||||
|
||||
public static PgpSecretKeyRingBundle RemoveSecretKeyRing(PgpSecretKeyRingBundle bundle, PgpSecretKeyRing secretKeyRing)
|
||||
{
|
||||
long keyId = secretKeyRing.GetPublicKey().KeyId;
|
||||
if (!bundle.secretRings.Contains(keyId))
|
||||
{
|
||||
throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
|
||||
}
|
||||
IDictionary dictionary = Platform.CreateHashtable(bundle.secretRings);
|
||||
IList list = Platform.CreateArrayList(bundle.order);
|
||||
dictionary.Remove(keyId);
|
||||
list.Remove(keyId);
|
||||
return new PgpSecretKeyRingBundle(dictionary, list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignature
|
||||
{
|
||||
public const int BinaryDocument = 0;
|
||||
|
||||
public const int CanonicalTextDocument = 1;
|
||||
|
||||
public const int StandAlone = 2;
|
||||
|
||||
public const int DefaultCertification = 16;
|
||||
|
||||
public const int NoCertification = 17;
|
||||
|
||||
public const int CasualCertification = 18;
|
||||
|
||||
public const int PositiveCertification = 19;
|
||||
|
||||
public const int SubkeyBinding = 24;
|
||||
|
||||
public const int PrimaryKeyBinding = 25;
|
||||
|
||||
public const int DirectKey = 31;
|
||||
|
||||
public const int KeyRevocation = 32;
|
||||
|
||||
public const int SubkeyRevocation = 40;
|
||||
|
||||
public const int CertificationRevocation = 48;
|
||||
|
||||
public const int Timestamp = 64;
|
||||
|
||||
private readonly SignaturePacket sigPck;
|
||||
|
||||
private readonly int signatureType;
|
||||
|
||||
private readonly TrustPacket trustPck;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
public int Version => sigPck.Version;
|
||||
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm => sigPck.KeyAlgorithm;
|
||||
|
||||
public HashAlgorithmTag HashAlgorithm => sigPck.HashAlgorithm;
|
||||
|
||||
public int SignatureType => sigPck.SignatureType;
|
||||
|
||||
public long KeyId => sigPck.KeyId;
|
||||
|
||||
public DateTime CreationTime => DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime);
|
||||
|
||||
public bool HasSubpackets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sigPck.GetHashedSubPackets() == null)
|
||||
{
|
||||
return sigPck.GetUnhashedSubPackets() != null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal PgpSignature(BcpgInputStream bcpgInput)
|
||||
: this((SignaturePacket)bcpgInput.ReadPacket())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpSignature(SignaturePacket sigPacket)
|
||||
: this(sigPacket, null)
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpSignature(SignaturePacket sigPacket, TrustPacket trustPacket)
|
||||
{
|
||||
if (sigPacket == null)
|
||||
{
|
||||
throw new ArgumentNullException("sigPacket");
|
||||
}
|
||||
sigPck = sigPacket;
|
||||
signatureType = sigPck.SignatureType;
|
||||
trustPck = trustPacket;
|
||||
}
|
||||
|
||||
private void GetSig()
|
||||
{
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm));
|
||||
}
|
||||
|
||||
public bool IsCertification()
|
||||
{
|
||||
return IsCertification(SignatureType);
|
||||
}
|
||||
|
||||
public void InitVerify(PgpPublicKey pubKey)
|
||||
{
|
||||
lastb = 0;
|
||||
if (sig == null)
|
||||
{
|
||||
GetSig();
|
||||
}
|
||||
try
|
||||
{
|
||||
sig.Init(forSigning: false, pubKey.GetKey());
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sig.Update(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
sig.Update(13);
|
||||
sig.Update(10);
|
||||
}
|
||||
|
||||
public void Update(params byte[] bytes)
|
||||
{
|
||||
Update(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public void Update(byte[] bytes, int off, int length)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + length;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, off, length);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
byte[] signatureTrailer = GetSignatureTrailer();
|
||||
sig.BlockUpdate(signatureTrailer, 0, signatureTrailer.Length);
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(int header, byte[] idBytes)
|
||||
{
|
||||
Update((byte)header, (byte)(idBytes.Length >> 24), (byte)(idBytes.Length >> 16), (byte)(idBytes.Length >> 8), (byte)idBytes.Length);
|
||||
Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(PgpPublicKey key)
|
||||
{
|
||||
byte[] encodedPublicKey = GetEncodedPublicKey(key);
|
||||
Update(153, (byte)(encodedPublicKey.Length >> 8), (byte)encodedPublicKey.Length);
|
||||
Update(encodedPublicKey);
|
||||
}
|
||||
|
||||
public bool VerifyCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey key)
|
||||
{
|
||||
UpdateWithPublicKey(key);
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
UserAttributeSubpacket[] array = userAttributes.ToSubpacketArray();
|
||||
foreach (UserAttributeSubpacket userAttributeSubpacket in array)
|
||||
{
|
||||
userAttributeSubpacket.Encode(memoryStream);
|
||||
}
|
||||
UpdateWithIdData(209, memoryStream.ToArray());
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", exception);
|
||||
}
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public bool VerifyCertification(string id, PgpPublicKey key)
|
||||
{
|
||||
UpdateWithPublicKey(key);
|
||||
UpdateWithIdData(180, Strings.ToUtf8ByteArray(id));
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public bool VerifyCertification(PgpPublicKey masterKey, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public bool VerifyCertification(PgpPublicKey pubKey)
|
||||
{
|
||||
if (SignatureType != 32 && SignatureType != 40)
|
||||
{
|
||||
throw new InvalidOperationException("signature is not a key signature");
|
||||
}
|
||||
UpdateWithPublicKey(pubKey);
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
[Obsolete("Use 'CreationTime' property instead")]
|
||||
public DateTime GetCreationTime()
|
||||
{
|
||||
return CreationTime;
|
||||
}
|
||||
|
||||
public byte[] GetSignatureTrailer()
|
||||
{
|
||||
return sigPck.GetSignatureTrailer();
|
||||
}
|
||||
|
||||
public PgpSignatureSubpacketVector GetHashedSubPackets()
|
||||
{
|
||||
return createSubpacketVector(sigPck.GetHashedSubPackets());
|
||||
}
|
||||
|
||||
public PgpSignatureSubpacketVector GetUnhashedSubPackets()
|
||||
{
|
||||
return createSubpacketVector(sigPck.GetUnhashedSubPackets());
|
||||
}
|
||||
|
||||
private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks)
|
||||
{
|
||||
if (pcks != null)
|
||||
{
|
||||
return new PgpSignatureSubpacketVector(pcks);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetSignature()
|
||||
{
|
||||
MPInteger[] signature = sigPck.GetSignature();
|
||||
if (signature != null)
|
||||
{
|
||||
if (signature.Length == 1)
|
||||
{
|
||||
return signature[0].Value.ToByteArrayUnsigned();
|
||||
}
|
||||
try
|
||||
{
|
||||
return new DerSequence(new DerInteger(signature[0].Value), new DerInteger(signature[1].Value)).GetEncoded();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception encoding DSA sig.", exception);
|
||||
}
|
||||
}
|
||||
return sigPck.GetSignatureBytes();
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
Encode(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(Stream outStream)
|
||||
{
|
||||
BcpgOutputStream bcpgOutputStream = BcpgOutputStream.Wrap(outStream);
|
||||
bcpgOutputStream.WritePacket(sigPck);
|
||||
if (trustPck != null)
|
||||
{
|
||||
bcpgOutputStream.WritePacket(trustPck);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsCertification(int signatureType)
|
||||
{
|
||||
switch (signatureType)
|
||||
{
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureGenerator
|
||||
{
|
||||
private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
|
||||
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private PgpPrivateKey privKey;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private IDigest dig;
|
||||
|
||||
private int signatureType;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
private SignatureSubpacket[] unhashed = EmptySignatureSubpackets;
|
||||
|
||||
private SignatureSubpacket[] hashed = EmptySignatureSubpackets;
|
||||
|
||||
public PgpSignatureGenerator(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key, SecureRandom random)
|
||||
{
|
||||
privKey = key;
|
||||
signatureType = sigType;
|
||||
try
|
||||
{
|
||||
ICipherParameters parameters = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
parameters = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
sig.Init(forSigning: true, parameters);
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception);
|
||||
}
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
doUpdateByte(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte(13);
|
||||
doUpdateByte(10);
|
||||
}
|
||||
|
||||
private void doUpdateByte(byte b)
|
||||
{
|
||||
sig.Update(b);
|
||||
dig.Update(b);
|
||||
}
|
||||
|
||||
public void Update(params byte[] b)
|
||||
{
|
||||
Update(b, 0, b.Length);
|
||||
}
|
||||
|
||||
public void Update(byte[] b, int off, int len)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + len;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, off, len);
|
||||
dig.BlockUpdate(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHashedSubpackets(PgpSignatureSubpacketVector hashedPackets)
|
||||
{
|
||||
hashed = ((hashedPackets == null) ? EmptySignatureSubpackets : hashedPackets.ToSubpacketArray());
|
||||
}
|
||||
|
||||
public void SetUnhashedSubpackets(PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
unhashed = ((unhashedPackets == null) ? EmptySignatureSubpackets : unhashedPackets.ToSubpacketArray());
|
||||
}
|
||||
|
||||
public PgpOnePassSignature GenerateOnePassVersion(bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
SignatureSubpacket[] array = hashed;
|
||||
SignatureSubpacket[] array2 = unhashed;
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
|
||||
{
|
||||
array = insertSubpacket(array, new SignatureCreationTime(critical: false, DateTime.UtcNow));
|
||||
}
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId) && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
|
||||
{
|
||||
array2 = insertSubpacket(array2, new IssuerKeyId(critical: false, privKey.KeyId));
|
||||
}
|
||||
int num = 4;
|
||||
byte[] array4;
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i].Encode(memoryStream);
|
||||
}
|
||||
byte[] array3 = memoryStream.ToArray();
|
||||
MemoryStream memoryStream2 = new MemoryStream(array3.Length + 6);
|
||||
memoryStream2.WriteByte((byte)num);
|
||||
memoryStream2.WriteByte((byte)signatureType);
|
||||
memoryStream2.WriteByte((byte)keyAlgorithm);
|
||||
memoryStream2.WriteByte((byte)hashAlgorithm);
|
||||
memoryStream2.WriteByte((byte)(array3.Length >> 8));
|
||||
memoryStream2.WriteByte((byte)array3.Length);
|
||||
memoryStream2.Write(array3, 0, array3.Length);
|
||||
array4 = memoryStream2.ToArray();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception encoding hashed data.", exception);
|
||||
}
|
||||
sig.BlockUpdate(array4, 0, array4.Length);
|
||||
dig.BlockUpdate(array4, 0, array4.Length);
|
||||
array4 = new byte[6]
|
||||
{
|
||||
(byte)num,
|
||||
255,
|
||||
(byte)(array4.Length >> 24),
|
||||
(byte)(array4.Length >> 16),
|
||||
(byte)(array4.Length >> 8),
|
||||
(byte)array4.Length
|
||||
};
|
||||
sig.BlockUpdate(array4, 0, array4.Length);
|
||||
dig.BlockUpdate(array4, 0, array4.Length);
|
||||
byte[] encoding = sig.GenerateSignature();
|
||||
byte[] array5 = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerprint = new byte[2]
|
||||
{
|
||||
array5[0],
|
||||
array5[1]
|
||||
};
|
||||
MPInteger[] signature = ((keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral) ? PgpUtilities.RsaSigToMpi(encoding) : PgpUtilities.DsaSigToMpi(encoding));
|
||||
return new PgpSignature(new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, array, array2, fingerprint, signature));
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(string id, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
UpdateWithIdData(180, Strings.ToUtf8ByteArray(id));
|
||||
return Generate();
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(PgpUserAttributeSubpacketVector userAttributes, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
try
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
UserAttributeSubpacket[] array = userAttributes.ToSubpacketArray();
|
||||
foreach (UserAttributeSubpacket userAttributeSubpacket in array)
|
||||
{
|
||||
userAttributeSubpacket.Encode(memoryStream);
|
||||
}
|
||||
UpdateWithIdData(209, memoryStream.ToArray());
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", exception);
|
||||
}
|
||||
return Generate();
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(PgpPublicKey masterKey, PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
return Generate();
|
||||
}
|
||||
|
||||
public PgpSignature GenerateCertification(PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
return Generate();
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private bool packetPresent(SignatureSubpacket[] packets, SignatureSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private SignatureSubpacket[] insertSubpacket(SignatureSubpacket[] packets, SignatureSubpacket subpacket)
|
||||
{
|
||||
SignatureSubpacket[] array = new SignatureSubpacket[packets.Length + 1];
|
||||
array[0] = subpacket;
|
||||
packets.CopyTo(array, 1);
|
||||
return array;
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(int header, byte[] idBytes)
|
||||
{
|
||||
Update((byte)header, (byte)(idBytes.Length >> 24), (byte)(idBytes.Length >> 16), (byte)(idBytes.Length >> 8), (byte)idBytes.Length);
|
||||
Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(PgpPublicKey key)
|
||||
{
|
||||
byte[] encodedPublicKey = GetEncodedPublicKey(key);
|
||||
Update(153, (byte)(encodedPublicKey.Length >> 8), (byte)encodedPublicKey.Length);
|
||||
Update(encodedPublicKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureList : PgpObject
|
||||
{
|
||||
private PgpSignature[] sigs;
|
||||
|
||||
public PgpSignature this[int index] => sigs[index];
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => sigs.Length;
|
||||
|
||||
public int Count => sigs.Length;
|
||||
|
||||
public bool IsEmpty => sigs.Length == 0;
|
||||
|
||||
public PgpSignatureList(PgpSignature[] sigs)
|
||||
{
|
||||
this.sigs = (PgpSignature[])sigs.Clone();
|
||||
}
|
||||
|
||||
public PgpSignatureList(PgpSignature sig)
|
||||
{
|
||||
sigs = new PgpSignature[1] { sig };
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public PgpSignature Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureSubpacketGenerator
|
||||
{
|
||||
private IList list = Platform.CreateArrayList();
|
||||
|
||||
public void SetRevocable(bool isCritical, bool isRevocable)
|
||||
{
|
||||
list.Add(new Revocable(isCritical, isRevocable));
|
||||
}
|
||||
|
||||
public void SetExportable(bool isCritical, bool isExportable)
|
||||
{
|
||||
list.Add(new Exportable(isCritical, isExportable));
|
||||
}
|
||||
|
||||
public void SetFeature(bool isCritical, byte feature)
|
||||
{
|
||||
list.Add(new Features(isCritical, feature));
|
||||
}
|
||||
|
||||
public void SetTrust(bool isCritical, int depth, int trustAmount)
|
||||
{
|
||||
list.Add(new TrustSignature(isCritical, depth, trustAmount));
|
||||
}
|
||||
|
||||
public void SetKeyExpirationTime(bool isCritical, long seconds)
|
||||
{
|
||||
list.Add(new KeyExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
public void SetSignatureExpirationTime(bool isCritical, long seconds)
|
||||
{
|
||||
list.Add(new SignatureExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
public void SetSignatureCreationTime(bool isCritical, DateTime date)
|
||||
{
|
||||
list.Add(new SignatureCreationTime(isCritical, date));
|
||||
}
|
||||
|
||||
public void SetPreferredHashAlgorithms(bool isCritical, int[] algorithms)
|
||||
{
|
||||
list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms));
|
||||
}
|
||||
|
||||
public void SetPreferredSymmetricAlgorithms(bool isCritical, int[] algorithms)
|
||||
{
|
||||
list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms));
|
||||
}
|
||||
|
||||
public void SetPreferredCompressionAlgorithms(bool isCritical, int[] algorithms)
|
||||
{
|
||||
list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms));
|
||||
}
|
||||
|
||||
public void SetKeyFlags(bool isCritical, int flags)
|
||||
{
|
||||
list.Add(new KeyFlags(isCritical, flags));
|
||||
}
|
||||
|
||||
public void SetSignerUserId(bool isCritical, string userId)
|
||||
{
|
||||
if (userId == null)
|
||||
{
|
||||
throw new ArgumentNullException("userId");
|
||||
}
|
||||
list.Add(new SignerUserId(isCritical, userId));
|
||||
}
|
||||
|
||||
public void SetSignerUserId(bool isCritical, byte[] rawUserId)
|
||||
{
|
||||
if (rawUserId == null)
|
||||
{
|
||||
throw new ArgumentNullException("rawUserId");
|
||||
}
|
||||
list.Add(new SignerUserId(isCritical, isLongLength: false, rawUserId));
|
||||
}
|
||||
|
||||
public void SetEmbeddedSignature(bool isCritical, PgpSignature pgpSignature)
|
||||
{
|
||||
byte[] encoded = pgpSignature.GetEncoded();
|
||||
byte[] array = ((encoded.Length - 1 <= 256) ? new byte[encoded.Length - 2] : new byte[encoded.Length - 3]);
|
||||
Array.Copy(encoded, encoded.Length - array.Length, array, 0, array.Length);
|
||||
list.Add(new EmbeddedSignature(isCritical, isLongLength: false, array));
|
||||
}
|
||||
|
||||
public void SetPrimaryUserId(bool isCritical, bool isPrimaryUserId)
|
||||
{
|
||||
list.Add(new PrimaryUserId(isCritical, isPrimaryUserId));
|
||||
}
|
||||
|
||||
public void SetNotationData(bool isCritical, bool isHumanReadable, string notationName, string notationValue)
|
||||
{
|
||||
list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue));
|
||||
}
|
||||
|
||||
public void SetRevocationReason(bool isCritical, RevocationReasonTag reason, string description)
|
||||
{
|
||||
list.Add(new RevocationReason(isCritical, reason, description));
|
||||
}
|
||||
|
||||
public void SetRevocationKey(bool isCritical, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint)
|
||||
{
|
||||
list.Add(new RevocationKey(isCritical, RevocationKeyTag.ClassDefault, keyAlgorithm, fingerprint));
|
||||
}
|
||||
|
||||
public void SetIssuerKeyID(bool isCritical, long keyID)
|
||||
{
|
||||
list.Add(new IssuerKeyId(isCritical, keyID));
|
||||
}
|
||||
|
||||
public PgpSignatureSubpacketVector Generate()
|
||||
{
|
||||
SignatureSubpacket[] array = new SignatureSubpacket[list.Count];
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
array[i] = (SignatureSubpacket)list[i];
|
||||
}
|
||||
return new PgpSignatureSubpacketVector(array);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpSignatureSubpacketVector
|
||||
{
|
||||
private readonly SignatureSubpacket[] packets;
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size => packets.Length;
|
||||
|
||||
public int Count => packets.Length;
|
||||
|
||||
internal PgpSignatureSubpacketVector(SignatureSubpacket[] packets)
|
||||
{
|
||||
this.packets = packets;
|
||||
}
|
||||
|
||||
public SignatureSubpacket GetSubpacket(SignatureSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return packets[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasSubpacket(SignatureSubpacketTag type)
|
||||
{
|
||||
return GetSubpacket(type) != null;
|
||||
}
|
||||
|
||||
public SignatureSubpacket[] GetSubpackets(SignatureSubpacketTag type)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
SignatureSubpacket[] array = new SignatureSubpacket[num];
|
||||
int num2 = 0;
|
||||
for (int j = 0; j < packets.Length; j++)
|
||||
{
|
||||
if (packets[j].SubpacketType == type)
|
||||
{
|
||||
array[num2++] = packets[j];
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public NotationData[] GetNotationDataOccurrences()
|
||||
{
|
||||
SignatureSubpacket[] subpackets = GetSubpackets(SignatureSubpacketTag.NotationData);
|
||||
NotationData[] array = new NotationData[subpackets.Length];
|
||||
for (int i = 0; i < subpackets.Length; i++)
|
||||
{
|
||||
array[i] = (NotationData)subpackets[i];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
[Obsolete("Use 'GetNotationDataOccurrences' instead")]
|
||||
public NotationData[] GetNotationDataOccurences()
|
||||
{
|
||||
return GetNotationDataOccurrences();
|
||||
}
|
||||
|
||||
public long GetIssuerKeyId()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((IssuerKeyId)subpacket).KeyId;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public bool HasSignatureCreationTime()
|
||||
{
|
||||
return GetSubpacket(SignatureSubpacketTag.CreationTime) != null;
|
||||
}
|
||||
|
||||
public DateTime GetSignatureCreationTime()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.CreationTime);
|
||||
if (subpacket == null)
|
||||
{
|
||||
throw new PgpException("SignatureCreationTime not available");
|
||||
}
|
||||
return ((SignatureCreationTime)subpacket).GetTime();
|
||||
}
|
||||
|
||||
public long GetSignatureExpirationTime()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.ExpireTime);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((SignatureExpirationTime)subpacket).Time;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public long GetKeyExpirationTime()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.KeyExpireTime);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((KeyExpirationTime)subpacket).Time;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public int[] GetPreferredHashAlgorithms()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((PreferredAlgorithms)subpacket).GetPreferences();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] GetPreferredSymmetricAlgorithms()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((PreferredAlgorithms)subpacket).GetPreferences();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int[] GetPreferredCompressionAlgorithms()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((PreferredAlgorithms)subpacket).GetPreferences();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int GetKeyFlags()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.KeyFlags);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((KeyFlags)subpacket).Flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string GetSignerUserId()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.SignerUserId);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return ((SignerUserId)subpacket).GetId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsPrimaryUserId()
|
||||
{
|
||||
return ((PrimaryUserId)GetSubpacket(SignatureSubpacketTag.PrimaryUserId))?.IsPrimaryUserId() ?? false;
|
||||
}
|
||||
|
||||
public SignatureSubpacketTag[] GetCriticalTags()
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].IsCritical())
|
||||
{
|
||||
num++;
|
||||
}
|
||||
}
|
||||
SignatureSubpacketTag[] array = new SignatureSubpacketTag[num];
|
||||
num = 0;
|
||||
for (int j = 0; j != packets.Length; j++)
|
||||
{
|
||||
if (packets[j].IsCritical())
|
||||
{
|
||||
array[num++] = packets[j].SubpacketType;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Features GetFeatures()
|
||||
{
|
||||
SignatureSubpacket subpacket = GetSubpacket(SignatureSubpacketTag.Features);
|
||||
if (subpacket == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new Features(subpacket.IsCritical(), subpacket.IsLongLength(), subpacket.GetData());
|
||||
}
|
||||
|
||||
internal SignatureSubpacket[] ToSubpacketArray()
|
||||
{
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using Org.BouncyCastle.Bcpg.Attr;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpUserAttributeSubpacketVector
|
||||
{
|
||||
private readonly UserAttributeSubpacket[] packets;
|
||||
|
||||
internal PgpUserAttributeSubpacketVector(UserAttributeSubpacket[] packets)
|
||||
{
|
||||
this.packets = packets;
|
||||
}
|
||||
|
||||
public UserAttributeSubpacket GetSubpacket(UserAttributeSubpacketTag type)
|
||||
{
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
return packets[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ImageAttrib GetImageAttribute()
|
||||
{
|
||||
UserAttributeSubpacket subpacket = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute);
|
||||
if (subpacket != null)
|
||||
{
|
||||
return (ImageAttrib)subpacket;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal UserAttributeSubpacket[] ToSubpacketArray()
|
||||
{
|
||||
return packets;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!(obj is PgpUserAttributeSubpacketVector pgpUserAttributeSubpacketVector))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (pgpUserAttributeSubpacketVector.packets.Length != packets.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (!pgpUserAttributeSubpacketVector.packets[i].Equals(packets[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int num = 0;
|
||||
UserAttributeSubpacket[] array = packets;
|
||||
foreach (object obj in array)
|
||||
{
|
||||
num ^= obj.GetHashCode();
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Org.BouncyCastle.Bcpg.Attr;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpUserAttributeSubpacketVectorGenerator
|
||||
{
|
||||
private IList list = Platform.CreateArrayList();
|
||||
|
||||
public virtual void SetImageAttribute(ImageAttrib.Format imageType, byte[] imageData)
|
||||
{
|
||||
if (imageData == null)
|
||||
{
|
||||
throw new ArgumentException("attempt to set null image", "imageData");
|
||||
}
|
||||
list.Add(new ImageAttrib(imageType, imageData));
|
||||
}
|
||||
|
||||
public virtual PgpUserAttributeSubpacketVector Generate()
|
||||
{
|
||||
UserAttributeSubpacket[] array = new UserAttributeSubpacket[list.Count];
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
array[i] = (UserAttributeSubpacket)list[i];
|
||||
}
|
||||
return new PgpUserAttributeSubpacketVector(array);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Encoders;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class PgpUtilities
|
||||
{
|
||||
private const int ReadAhead = 60;
|
||||
|
||||
private PgpUtilities()
|
||||
{
|
||||
}
|
||||
|
||||
public static MPInteger[] DsaSigToMpi(byte[] encoding)
|
||||
{
|
||||
DerInteger derInteger;
|
||||
DerInteger derInteger2;
|
||||
try
|
||||
{
|
||||
Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(encoding);
|
||||
derInteger = (DerInteger)asn1Sequence[0];
|
||||
derInteger2 = (DerInteger)asn1Sequence[1];
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
throw new PgpException("exception encoding signature", exception);
|
||||
}
|
||||
return new MPInteger[2]
|
||||
{
|
||||
new MPInteger(derInteger.Value),
|
||||
new MPInteger(derInteger2.Value)
|
||||
};
|
||||
}
|
||||
|
||||
public static MPInteger[] RsaSigToMpi(byte[] encoding)
|
||||
{
|
||||
return new MPInteger[1]
|
||||
{
|
||||
new MPInteger(new BigInteger(1, encoding))
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetDigestName(HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
return hashAlgorithm switch
|
||||
{
|
||||
HashAlgorithmTag.Sha1 => "SHA1",
|
||||
HashAlgorithmTag.MD2 => "MD2",
|
||||
HashAlgorithmTag.MD5 => "MD5",
|
||||
HashAlgorithmTag.RipeMD160 => "RIPEMD160",
|
||||
HashAlgorithmTag.Sha224 => "SHA224",
|
||||
HashAlgorithmTag.Sha256 => "SHA256",
|
||||
HashAlgorithmTag.Sha384 => "SHA384",
|
||||
HashAlgorithmTag.Sha512 => "SHA512",
|
||||
_ => throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm),
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetSignatureName(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
string text;
|
||||
switch (keyAlgorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
text = "RSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
text = "DSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.EC:
|
||||
text = "ECDH";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ECDsa:
|
||||
text = "ECDSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
text = "ElGamal";
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
|
||||
}
|
||||
return GetDigestName(hashAlgorithm) + "with" + text;
|
||||
}
|
||||
|
||||
public static string GetSymmetricCipherName(SymmetricKeyAlgorithmTag algorithm)
|
||||
{
|
||||
return algorithm switch
|
||||
{
|
||||
SymmetricKeyAlgorithmTag.Null => null,
|
||||
SymmetricKeyAlgorithmTag.TripleDes => "DESEDE",
|
||||
SymmetricKeyAlgorithmTag.Idea => "IDEA",
|
||||
SymmetricKeyAlgorithmTag.Cast5 => "CAST5",
|
||||
SymmetricKeyAlgorithmTag.Blowfish => "Blowfish",
|
||||
SymmetricKeyAlgorithmTag.Safer => "SAFER",
|
||||
SymmetricKeyAlgorithmTag.Des => "DES",
|
||||
SymmetricKeyAlgorithmTag.Aes128 => "AES",
|
||||
SymmetricKeyAlgorithmTag.Aes192 => "AES",
|
||||
SymmetricKeyAlgorithmTag.Aes256 => "AES",
|
||||
SymmetricKeyAlgorithmTag.Twofish => "Twofish",
|
||||
SymmetricKeyAlgorithmTag.Camellia128 => "Camellia",
|
||||
SymmetricKeyAlgorithmTag.Camellia192 => "Camellia",
|
||||
SymmetricKeyAlgorithmTag.Camellia256 => "Camellia",
|
||||
_ => throw new PgpException("unknown symmetric algorithm: " + algorithm),
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Des:
|
||||
return 64;
|
||||
case SymmetricKeyAlgorithmTag.Idea:
|
||||
case SymmetricKeyAlgorithmTag.Cast5:
|
||||
case SymmetricKeyAlgorithmTag.Blowfish:
|
||||
case SymmetricKeyAlgorithmTag.Safer:
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
case SymmetricKeyAlgorithmTag.Camellia128:
|
||||
return 128;
|
||||
case SymmetricKeyAlgorithmTag.TripleDes:
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
case SymmetricKeyAlgorithmTag.Camellia192:
|
||||
return 192;
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
case SymmetricKeyAlgorithmTag.Twofish:
|
||||
case SymmetricKeyAlgorithmTag.Camellia256:
|
||||
return 256;
|
||||
default:
|
||||
throw new PgpException("unknown symmetric algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKey(SymmetricKeyAlgorithmTag algorithm, byte[] keyBytes)
|
||||
{
|
||||
string symmetricCipherName = GetSymmetricCipherName(algorithm);
|
||||
return ParameterUtilities.CreateKeyParameter(symmetricCipherName, keyBytes);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeRandomKey(SymmetricKeyAlgorithmTag algorithm, SecureRandom random)
|
||||
{
|
||||
int keySize = GetKeySize(algorithm);
|
||||
byte[] array = new byte[(keySize + 7) / 8];
|
||||
random.NextBytes(array);
|
||||
return MakeKey(algorithm, array);
|
||||
}
|
||||
|
||||
internal static byte[] EncodePassPhrase(char[] passPhrase, bool utf8)
|
||||
{
|
||||
if (passPhrase != null)
|
||||
{
|
||||
if (!utf8)
|
||||
{
|
||||
return Strings.ToByteArray(passPhrase);
|
||||
}
|
||||
return Encoding.UTF8.GetBytes(passPhrase);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
|
||||
{
|
||||
return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, utf8: false), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhraseUtf8(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
|
||||
{
|
||||
return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, utf8: true), clearPassPhrase: true);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhraseRaw(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase)
|
||||
{
|
||||
return DoMakeKeyFromPassPhrase(algorithm, s2k, rawPassPhrase, clearPassPhrase: false);
|
||||
}
|
||||
|
||||
internal static KeyParameter DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase, bool clearPassPhrase)
|
||||
{
|
||||
int keySize = GetKeySize(algorithm);
|
||||
byte[] array = new byte[(keySize + 7) / 8];
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
while (num < array.Length)
|
||||
{
|
||||
IDigest digest;
|
||||
if (s2k != null)
|
||||
{
|
||||
string digestName = GetDigestName(s2k.HashAlgorithm);
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest(digestName);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
throw new PgpException("can't find S2k digest", exception);
|
||||
}
|
||||
for (int i = 0; i != num2; i++)
|
||||
{
|
||||
digest.Update(0);
|
||||
}
|
||||
byte[] iV = s2k.GetIV();
|
||||
switch (s2k.Type)
|
||||
{
|
||||
case 0:
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
break;
|
||||
case 1:
|
||||
digest.BlockUpdate(iV, 0, iV.Length);
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
long iterationCount = s2k.IterationCount;
|
||||
digest.BlockUpdate(iV, 0, iV.Length);
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
iterationCount -= iV.Length + rawPassPhrase.Length;
|
||||
while (iterationCount > 0)
|
||||
{
|
||||
if (iterationCount < iV.Length)
|
||||
{
|
||||
digest.BlockUpdate(iV, 0, (int)iterationCount);
|
||||
break;
|
||||
}
|
||||
digest.BlockUpdate(iV, 0, iV.Length);
|
||||
iterationCount -= iV.Length;
|
||||
if (iterationCount < rawPassPhrase.Length)
|
||||
{
|
||||
digest.BlockUpdate(rawPassPhrase, 0, (int)iterationCount);
|
||||
iterationCount = 0L;
|
||||
}
|
||||
else
|
||||
{
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
iterationCount -= rawPassPhrase.Length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new PgpException("unknown S2k type: " + s2k.Type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest("MD5");
|
||||
for (int j = 0; j != num2; j++)
|
||||
{
|
||||
digest.Update(0);
|
||||
}
|
||||
digest.BlockUpdate(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
}
|
||||
catch (Exception exception2)
|
||||
{
|
||||
throw new PgpException("can't find MD5 digest", exception2);
|
||||
}
|
||||
}
|
||||
byte[] array2 = DigestUtilities.DoFinal(digest);
|
||||
if (array2.Length > array.Length - num)
|
||||
{
|
||||
Array.Copy(array2, 0, array, num, array.Length - num);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(array2, 0, array, num, array2.Length);
|
||||
}
|
||||
num += array2.Length;
|
||||
num2++;
|
||||
}
|
||||
if (clearPassPhrase && rawPassPhrase != null)
|
||||
{
|
||||
Array.Clear(rawPassPhrase, 0, rawPassPhrase.Length);
|
||||
}
|
||||
return MakeKey(algorithm, array);
|
||||
}
|
||||
|
||||
public static void WriteFileToLiteralData(Stream output, char fileType, FileInfo file)
|
||||
{
|
||||
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
|
||||
Stream pOut = pgpLiteralDataGenerator.Open(output, fileType, file.Name, file.Length, file.LastWriteTime);
|
||||
PipeFileContents(file, pOut, 32768);
|
||||
}
|
||||
|
||||
public static void WriteFileToLiteralData(Stream output, char fileType, FileInfo file, byte[] buffer)
|
||||
{
|
||||
PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator();
|
||||
Stream pOut = pgpLiteralDataGenerator.Open(output, fileType, file.Name, file.LastWriteTime, buffer);
|
||||
PipeFileContents(file, pOut, buffer.Length);
|
||||
}
|
||||
|
||||
private static void PipeFileContents(FileInfo file, Stream pOut, int bufSize)
|
||||
{
|
||||
FileStream fileStream = file.OpenRead();
|
||||
byte[] array = new byte[bufSize];
|
||||
try
|
||||
{
|
||||
int count;
|
||||
while ((count = fileStream.Read(array, 0, array.Length)) > 0)
|
||||
{
|
||||
pOut.Write(array, 0, count);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Array.Clear(array, 0, array.Length);
|
||||
Platform.Dispose(pOut);
|
||||
Platform.Dispose(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsPossiblyBase64(int ch)
|
||||
{
|
||||
if ((ch < 65 || ch > 90) && (ch < 97 || ch > 122) && (ch < 48 || ch > 57) && ch != 43 && ch != 47 && ch != 13)
|
||||
{
|
||||
return ch == 10;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Stream GetDecoderStream(Stream inputStream)
|
||||
{
|
||||
if (!inputStream.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("inputStream must be seek-able", "inputStream");
|
||||
}
|
||||
long position = inputStream.Position;
|
||||
int num = inputStream.ReadByte();
|
||||
if ((num & 0x80) != 0)
|
||||
{
|
||||
inputStream.Position = position;
|
||||
return inputStream;
|
||||
}
|
||||
if (!IsPossiblyBase64(num))
|
||||
{
|
||||
inputStream.Position = position;
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
byte[] array = new byte[60];
|
||||
int i = 1;
|
||||
int num2 = 1;
|
||||
array[0] = (byte)num;
|
||||
for (; i != 60; i++)
|
||||
{
|
||||
if ((num = inputStream.ReadByte()) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!IsPossiblyBase64(num))
|
||||
{
|
||||
inputStream.Position = position;
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
if (num != 10 && num != 13)
|
||||
{
|
||||
array[num2++] = (byte)num;
|
||||
}
|
||||
}
|
||||
inputStream.Position = position;
|
||||
if (i < 4)
|
||||
{
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
byte[] array2 = new byte[8];
|
||||
Array.Copy(array, 0, array2, 0, array2.Length);
|
||||
try
|
||||
{
|
||||
byte[] array3 = Base64.Decode(array2);
|
||||
bool hasHeaders = (array3[0] & 0x80) == 0;
|
||||
return new ArmoredInputStream(inputStream, hasHeaders);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new IOException(ex2.Message);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm)
|
||||
{
|
||||
switch (encAlgorithm)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
return WrapperUtilities.GetWrapper("AESWRAP");
|
||||
case SymmetricKeyAlgorithmTag.Camellia128:
|
||||
case SymmetricKeyAlgorithmTag.Camellia192:
|
||||
case SymmetricKeyAlgorithmTag.Camellia256:
|
||||
return WrapperUtilities.GetWrapper("CAMELLIAWRAP");
|
||||
default:
|
||||
throw new PgpException("unknown wrap algorithm: " + encAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] GenerateIV(int length, SecureRandom random)
|
||||
{
|
||||
byte[] array = new byte[length];
|
||||
random.NextBytes(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static S2k GenerateS2k(HashAlgorithmTag hashAlgorithm, int s2kCount, SecureRandom random)
|
||||
{
|
||||
byte[] iv = GenerateIV(8, random);
|
||||
return new S2k(hashAlgorithm, iv, s2kCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class PgpV3SignatureGenerator
|
||||
{
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
|
||||
private PgpPrivateKey privKey;
|
||||
|
||||
private ISigner sig;
|
||||
|
||||
private IDigest dig;
|
||||
|
||||
private int signatureType;
|
||||
|
||||
private byte lastb;
|
||||
|
||||
public PgpV3SignatureGenerator(PublicKeyAlgorithmTag keyAlgorithm, HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
this.keyAlgorithm = keyAlgorithm;
|
||||
this.hashAlgorithm = hashAlgorithm;
|
||||
dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
|
||||
sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
public void InitSign(int sigType, PgpPrivateKey key, SecureRandom random)
|
||||
{
|
||||
privKey = key;
|
||||
signatureType = sigType;
|
||||
try
|
||||
{
|
||||
ICipherParameters parameters = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
parameters = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
sig.Init(forSigning: true, parameters);
|
||||
}
|
||||
catch (InvalidKeyException exception)
|
||||
{
|
||||
throw new PgpException("invalid key.", exception);
|
||||
}
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(byte b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(byte b)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 13:
|
||||
doUpdateCRLF();
|
||||
break;
|
||||
case 10:
|
||||
if (lastb != 13)
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
doUpdateByte(b);
|
||||
break;
|
||||
}
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte(13);
|
||||
doUpdateByte(10);
|
||||
}
|
||||
|
||||
private void doUpdateByte(byte b)
|
||||
{
|
||||
sig.Update(b);
|
||||
dig.Update(b);
|
||||
}
|
||||
|
||||
public void Update(byte[] b)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
for (int i = 0; i != b.Length; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, 0, b.Length);
|
||||
dig.BlockUpdate(b, 0, b.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(byte[] b, int off, int len)
|
||||
{
|
||||
if (signatureType == 1)
|
||||
{
|
||||
int num = off + len;
|
||||
for (int i = off; i != num; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, off, len);
|
||||
dig.BlockUpdate(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
public PgpOnePassSignature GenerateOnePassVersion(bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
long num = DateTimeUtilities.CurrentUnixMs() / 1000;
|
||||
byte[] array = new byte[5]
|
||||
{
|
||||
(byte)signatureType,
|
||||
(byte)(num >> 24),
|
||||
(byte)(num >> 16),
|
||||
(byte)(num >> 8),
|
||||
(byte)num
|
||||
};
|
||||
sig.BlockUpdate(array, 0, array.Length);
|
||||
dig.BlockUpdate(array, 0, array.Length);
|
||||
byte[] encoding = sig.GenerateSignature();
|
||||
byte[] array2 = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerprint = new byte[2]
|
||||
{
|
||||
array2[0],
|
||||
array2[1]
|
||||
};
|
||||
MPInteger[] signature = ((keyAlgorithm == PublicKeyAlgorithmTag.RsaSign || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral) ? PgpUtilities.RsaSigToMpi(encoding) : PgpUtilities.DsaSigToMpi(encoding));
|
||||
return new PgpSignature(new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm, hashAlgorithm, num * 1000, fingerprint, signature));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Nist;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Math.EC;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Encoders;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class Rfc6637Utilities
|
||||
{
|
||||
private static readonly byte[] ANONYMOUS_SENDER = Hex.Decode("416E6F6E796D6F75732053656E64657220202020");
|
||||
|
||||
private Rfc6637Utilities()
|
||||
{
|
||||
}
|
||||
|
||||
public static string GetAgreementAlgorithm(PublicKeyPacket pubKeyData)
|
||||
{
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKeyData.Key;
|
||||
return eCDHPublicBcpgKey.HashAlgorithm switch
|
||||
{
|
||||
HashAlgorithmTag.Sha256 => "ECCDHwithSHA256CKDF",
|
||||
HashAlgorithmTag.Sha384 => "ECCDHwithSHA384CKDF",
|
||||
HashAlgorithmTag.Sha512 => "ECCDHwithSHA512CKDF",
|
||||
_ => throw new ArgumentException("Unknown hash algorithm specified: " + eCDHPublicBcpgKey.HashAlgorithm),
|
||||
};
|
||||
}
|
||||
|
||||
public static DerObjectIdentifier GetKeyEncryptionOID(SymmetricKeyAlgorithmTag algID)
|
||||
{
|
||||
return algID switch
|
||||
{
|
||||
SymmetricKeyAlgorithmTag.Aes128 => NistObjectIdentifiers.IdAes128Wrap,
|
||||
SymmetricKeyAlgorithmTag.Aes192 => NistObjectIdentifiers.IdAes192Wrap,
|
||||
SymmetricKeyAlgorithmTag.Aes256 => NistObjectIdentifiers.IdAes256Wrap,
|
||||
_ => throw new PgpException("unknown symmetric algorithm ID: " + algID),
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetKeyLength(SymmetricKeyAlgorithmTag algID)
|
||||
{
|
||||
return algID switch
|
||||
{
|
||||
SymmetricKeyAlgorithmTag.Aes128 => 16,
|
||||
SymmetricKeyAlgorithmTag.Aes192 => 24,
|
||||
SymmetricKeyAlgorithmTag.Aes256 => 32,
|
||||
_ => throw new PgpException("unknown symmetric algorithm ID: " + algID),
|
||||
};
|
||||
}
|
||||
|
||||
public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s)
|
||||
{
|
||||
byte[] parameters = CreateUserKeyingMaterial(pubKeyData);
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKeyData.Key;
|
||||
return Kdf(eCDHPublicBcpgKey.HashAlgorithm, s, GetKeyLength(eCDHPublicBcpgKey.SymmetricKeyAlgorithm), parameters);
|
||||
}
|
||||
|
||||
public static byte[] CreateUserKeyingMaterial(PublicKeyPacket pubKeyData)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
ECDHPublicBcpgKey eCDHPublicBcpgKey = (ECDHPublicBcpgKey)pubKeyData.Key;
|
||||
byte[] encoded = eCDHPublicBcpgKey.CurveOid.GetEncoded();
|
||||
memoryStream.Write(encoded, 1, encoded.Length - 1);
|
||||
memoryStream.WriteByte((byte)pubKeyData.Algorithm);
|
||||
memoryStream.WriteByte(3);
|
||||
memoryStream.WriteByte(1);
|
||||
memoryStream.WriteByte((byte)eCDHPublicBcpgKey.HashAlgorithm);
|
||||
memoryStream.WriteByte((byte)eCDHPublicBcpgKey.SymmetricKeyAlgorithm);
|
||||
memoryStream.Write(ANONYMOUS_SENDER, 0, ANONYMOUS_SENDER.Length);
|
||||
byte[] array = PgpPublicKey.CalculateFingerprint(pubKeyData);
|
||||
memoryStream.Write(array, 0, array.Length);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters)
|
||||
{
|
||||
byte[] encoded = s.XCoord.GetEncoded();
|
||||
string digestName = PgpUtilities.GetDigestName(digestAlg);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
digest.Update(0);
|
||||
digest.Update(0);
|
||||
digest.Update(0);
|
||||
digest.Update(1);
|
||||
digest.BlockUpdate(encoded, 0, encoded.Length);
|
||||
digest.BlockUpdate(parameters, 0, parameters.Length);
|
||||
byte[] data = DigestUtilities.DoFinal(digest);
|
||||
return Arrays.CopyOfRange(data, 0, keyLen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public sealed class SXprUtilities
|
||||
{
|
||||
private class MyS2k : S2k
|
||||
{
|
||||
private readonly long mIterationCount64;
|
||||
|
||||
public override long IterationCount => mIterationCount64;
|
||||
|
||||
internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64)
|
||||
: base(algorithm, iv, (int)iterationCount64)
|
||||
{
|
||||
mIterationCount64 = iterationCount64;
|
||||
}
|
||||
}
|
||||
|
||||
private SXprUtilities()
|
||||
{
|
||||
}
|
||||
|
||||
private static int ReadLength(Stream input, int ch)
|
||||
{
|
||||
int num = ch - 48;
|
||||
while ((ch = input.ReadByte()) >= 0 && ch != 58)
|
||||
{
|
||||
num = num * 10 + ch - 48;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
internal static string ReadString(Stream input, int ch)
|
||||
{
|
||||
int num = ReadLength(input, ch);
|
||||
char[] array = new char[num];
|
||||
for (int i = 0; i != array.Length; i++)
|
||||
{
|
||||
array[i] = (char)input.ReadByte();
|
||||
}
|
||||
return new string(array);
|
||||
}
|
||||
|
||||
internal static byte[] ReadBytes(Stream input, int ch)
|
||||
{
|
||||
int num = ReadLength(input, ch);
|
||||
byte[] array = new byte[num];
|
||||
Streams.ReadFully(input, array);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static S2k ParseS2k(Stream input)
|
||||
{
|
||||
SkipOpenParenthesis(input);
|
||||
ReadString(input, input.ReadByte());
|
||||
byte[] iv = ReadBytes(input, input.ReadByte());
|
||||
long iterationCount = long.Parse(ReadString(input, input.ReadByte()));
|
||||
SkipCloseParenthesis(input);
|
||||
return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount);
|
||||
}
|
||||
|
||||
internal static void SkipOpenParenthesis(Stream input)
|
||||
{
|
||||
int num = input.ReadByte();
|
||||
if (num != 40)
|
||||
{
|
||||
throw new IOException("unknown character encountered");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SkipCloseParenthesis(Stream input)
|
||||
{
|
||||
int num = input.ReadByte();
|
||||
if (num != 41)
|
||||
{
|
||||
throw new IOException("unknown character encountered");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp;
|
||||
|
||||
public class WrappedGeneratorStream : FilterStream
|
||||
{
|
||||
private readonly IStreamGenerator gen;
|
||||
|
||||
public WrappedGeneratorStream(IStreamGenerator gen, Stream str)
|
||||
: base(str)
|
||||
{
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
gen.Close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user