Initial Commit
This commit is contained in:
7
iTechSharp/srcbc/openpgp/IStreamGenerator.cs
Normal file
7
iTechSharp/srcbc/openpgp/IStreamGenerator.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
public interface IStreamGenerator
|
||||
{
|
||||
void Close();
|
||||
}
|
||||
}
|
77
iTechSharp/srcbc/openpgp/PGPKeyRing.cs
Normal file
77
iTechSharp/srcbc/openpgp/PGPKeyRing.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
public abstract class PgpKeyRing
|
||||
: PgpObject
|
||||
{
|
||||
internal PgpKeyRing()
|
||||
{
|
||||
}
|
||||
|
||||
internal static TrustPacket ReadOptionalTrustPacket(
|
||||
BcpgInputStream bcpgInput)
|
||||
{
|
||||
return (bcpgInput.NextPacketTag() == PacketTag.Trust)
|
||||
? (TrustPacket) bcpgInput.ReadPacket()
|
||||
: null;
|
||||
}
|
||||
|
||||
internal static ArrayList ReadSignaturesAndTrust(
|
||||
BcpgInputStream bcpgInput)
|
||||
{
|
||||
try
|
||||
{
|
||||
ArrayList sigList = new ArrayList();
|
||||
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.Signature)
|
||||
{
|
||||
SignaturePacket signaturePacket = (SignaturePacket) bcpgInput.ReadPacket();
|
||||
TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput);
|
||||
|
||||
sigList.Add(new PgpSignature(signaturePacket, trustPacket));
|
||||
}
|
||||
|
||||
return sigList;
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw new IOException("can't create signature object: " + e.Message, e);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ReadUserIDs(
|
||||
BcpgInputStream bcpgInput,
|
||||
out ArrayList ids,
|
||||
out ArrayList idTrusts,
|
||||
out ArrayList idSigs)
|
||||
{
|
||||
ids = new ArrayList();
|
||||
idTrusts = new ArrayList();
|
||||
idSigs = new ArrayList();
|
||||
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.UserId
|
||||
|| bcpgInput.NextPacketTag() == PacketTag.UserAttribute)
|
||||
{
|
||||
Packet obj = bcpgInput.ReadPacket();
|
||||
if (obj is UserIdPacket)
|
||||
{
|
||||
UserIdPacket id = (UserIdPacket)obj;
|
||||
ids.Add(id.GetId());
|
||||
}
|
||||
else
|
||||
{
|
||||
UserAttributePacket user = (UserAttributePacket) obj;
|
||||
ids.Add(new PgpUserAttributeSubpacketVector(user.GetSubpackets()));
|
||||
}
|
||||
|
||||
idTrusts.Add(
|
||||
ReadOptionalTrustPacket(bcpgInput));
|
||||
|
||||
idSigs.Add(
|
||||
ReadSignaturesAndTrust(bcpgInput));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
iTechSharp/srcbc/openpgp/PGPObject.cs
Normal file
9
iTechSharp/srcbc/openpgp/PGPObject.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
public abstract class PgpObject
|
||||
{
|
||||
internal PgpObject()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Org.BouncyCastle.Bcpg.Attr;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
public class PgpUserAttributeSubpacketVectorGenerator
|
||||
{
|
||||
private ArrayList list = new ArrayList();
|
||||
|
||||
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()
|
||||
{
|
||||
return new PgpUserAttributeSubpacketVector(
|
||||
(UserAttributeSubpacket[]) list.ToArray(typeof(UserAttributeSubpacket)));
|
||||
}
|
||||
}
|
||||
}
|
50
iTechSharp/srcbc/openpgp/PgpCompressedData.cs
Normal file
50
iTechSharp/srcbc/openpgp/PgpCompressedData.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Apache.Bzip2;
|
||||
using Org.BouncyCastle.Utilities.Zlib;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Compressed data objects</remarks>
|
||||
public class PgpCompressedData
|
||||
: PgpObject
|
||||
{
|
||||
private readonly CompressedDataPacket data;
|
||||
|
||||
public PgpCompressedData(
|
||||
BcpgInputStream bcpgInput)
|
||||
{
|
||||
data = (CompressedDataPacket) bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
/// <summary>The algorithm used for compression</summary>
|
||||
public CompressionAlgorithmTag Algorithm
|
||||
{
|
||||
get { return data.Algorithm; }
|
||||
}
|
||||
|
||||
/// <summary>Get the raw input stream contained in the object.</summary>
|
||||
public Stream GetInputStream()
|
||||
{
|
||||
return data.GetInputStream();
|
||||
}
|
||||
|
||||
/// <summary>Return an uncompressed input stream which allows reading of the compressed data.</summary>
|
||||
public Stream GetDataStream()
|
||||
{
|
||||
switch (Algorithm)
|
||||
{
|
||||
case CompressionAlgorithmTag.Uncompressed:
|
||||
return GetInputStream();
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
return new ZInflaterInputStream(GetInputStream(), true);
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
return new ZInflaterInputStream(GetInputStream());
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
return new CBZip2InputStream(GetInputStream());
|
||||
default:
|
||||
throw new PgpException("can't recognise compression algorithm: " + Algorithm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
177
iTechSharp/srcbc/openpgp/PgpCompressedDataGenerator.cs
Normal file
177
iTechSharp/srcbc/openpgp/PgpCompressedDataGenerator.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Apache.Bzip2;
|
||||
using Org.BouncyCastle.Utilities.Zlib;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Class for producing compressed data packets.</remarks>
|
||||
public class PgpCompressedDataGenerator
|
||||
: IStreamGenerator
|
||||
{
|
||||
private readonly CompressionAlgorithmTag algorithm;
|
||||
private readonly int compression;
|
||||
|
||||
private Stream dOut;
|
||||
private BcpgOutputStream pkOut;
|
||||
|
||||
public PgpCompressedDataGenerator(
|
||||
CompressionAlgorithmTag algorithm)
|
||||
: this(algorithm, JZlib.Z_DEFAULT_COMPRESSION)
|
||||
{
|
||||
}
|
||||
|
||||
public PgpCompressedDataGenerator(
|
||||
CompressionAlgorithmTag algorithm,
|
||||
int compression)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case CompressionAlgorithmTag.Uncompressed:
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("unknown compression algorithm", "algorithm");
|
||||
}
|
||||
|
||||
if (compression != JZlib.Z_DEFAULT_COMPRESSION)
|
||||
{
|
||||
if ((compression < JZlib.Z_NO_COMPRESSION) || (compression > JZlib.Z_BEST_COMPRESSION))
|
||||
{
|
||||
throw new ArgumentException("unknown compression level: " + compression);
|
||||
}
|
||||
}
|
||||
|
||||
this.algorithm = algorithm;
|
||||
this.compression = compression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Return an output stream which will save the data being written to
|
||||
/// the compressed object.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
/// <param name="outStr">Stream to be used for output.</param>
|
||||
/// <returns>A Stream for output of the compressed data.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <exception cref="IOException"></exception>
|
||||
public Stream Open(
|
||||
Stream outStr)
|
||||
{
|
||||
if (dOut != null)
|
||||
throw new InvalidOperationException("generator already in open state");
|
||||
if (outStr == null)
|
||||
throw new ArgumentNullException("outStr");
|
||||
|
||||
this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData);
|
||||
|
||||
doOpen();
|
||||
|
||||
return new WrappedGeneratorStream(this, dOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Return an output stream which will compress the data as it is written to it.
|
||||
/// The stream will be written out in chunks according to the size of the passed in buffer.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// <b>Note</b>: if the buffer is not a power of 2 in length only the largest power of 2
|
||||
/// bytes worth of the buffer will be used.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// <b>Note</b>: using this may break compatibility with RFC 1991 compliant tools.
|
||||
/// Only recent OpenPGP implementations are capable of accepting these streams.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
/// <param name="outStr">Stream to be used for output.</param>
|
||||
/// <param name="buffer">The buffer to use.</param>
|
||||
/// <returns>A Stream for output of the compressed data.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <exception cref="IOException"></exception>
|
||||
/// <exception cref="PgpException"></exception>
|
||||
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");
|
||||
|
||||
this.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 ZDeflaterOutputStream(pkOut, compression, true);
|
||||
break;
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
dOut = new ZDeflaterOutputStream(pkOut, compression, false);
|
||||
break;
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
dOut = new CBZip2OutputStream(pkOut);
|
||||
break;
|
||||
default:
|
||||
// Constructor should guard against this possibility
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Close the compressed object.</summary>summary>
|
||||
public void Close()
|
||||
{
|
||||
if (dOut != null)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case CompressionAlgorithmTag.BZip2:
|
||||
((CBZip2OutputStream) dOut).Finish();
|
||||
break;
|
||||
case CompressionAlgorithmTag.Zip:
|
||||
case CompressionAlgorithmTag.ZLib:
|
||||
((ZDeflaterOutputStream) dOut).Finish();
|
||||
break;
|
||||
}
|
||||
|
||||
dOut.Flush();
|
||||
|
||||
pkOut.Finish();
|
||||
pkOut.Flush();
|
||||
|
||||
dOut = null;
|
||||
pkOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
iTechSharp/srcbc/openpgp/PgpDataValidationException.cs
Normal file
15
iTechSharp/srcbc/openpgp/PgpDataValidationException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Thrown if the IV at the start of a data stream indicates the wrong key is being used.
|
||||
/// </remarks>
|
||||
public class PgpDataValidationException
|
||||
: PgpException
|
||||
{
|
||||
public PgpDataValidationException() : base() {}
|
||||
public PgpDataValidationException(string message) : base(message) {}
|
||||
public PgpDataValidationException(string message, Exception exception) : base(message, exception) {}
|
||||
}
|
||||
}
|
151
iTechSharp/srcbc/openpgp/PgpEncryptedData.cs
Normal file
151
iTechSharp/srcbc/openpgp/PgpEncryptedData.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
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 = LookAheadBufSize - LookAheadSize;
|
||||
|
||||
private readonly Stream inStr;
|
||||
private readonly byte[] lookAhead = new byte[LookAheadBufSize];
|
||||
private int bufStart, bufEnd;
|
||||
|
||||
internal TruncatedStream(
|
||||
Stream inStr)
|
||||
{
|
||||
int numRead = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length);
|
||||
|
||||
if (numRead < LookAheadSize)
|
||||
throw new EndOfStreamException();
|
||||
|
||||
this.inStr = inStr;
|
||||
this.bufStart = 0;
|
||||
this.bufEnd = numRead - LookAheadSize;
|
||||
}
|
||||
|
||||
private int FillBuffer()
|
||||
{
|
||||
if (bufEnd < LookAheadBufLimit)
|
||||
return 0;
|
||||
|
||||
Debug.Assert(bufStart == LookAheadBufLimit);
|
||||
Debug.Assert(bufEnd == LookAheadBufLimit);
|
||||
|
||||
Array.Copy(lookAhead, LookAheadBufLimit, lookAhead, 0, LookAheadSize);
|
||||
bufEnd = Streams.ReadFully(inStr, lookAhead, LookAheadSize, LookAheadBufLimit);
|
||||
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 avail = bufEnd - bufStart;
|
||||
|
||||
int pos = off;
|
||||
while (len > avail)
|
||||
{
|
||||
Array.Copy(lookAhead, bufStart, buf, pos, avail);
|
||||
|
||||
bufStart += avail;
|
||||
pos += avail;
|
||||
len -= avail;
|
||||
|
||||
if ((avail = FillBuffer()) < 1)
|
||||
return pos - off;
|
||||
}
|
||||
|
||||
Array.Copy(lookAhead, bufStart, buf, pos, len);
|
||||
bufStart += len;
|
||||
|
||||
return pos + len - off;;
|
||||
}
|
||||
|
||||
internal byte[] GetLookAhead()
|
||||
{
|
||||
byte[] temp = new byte[LookAheadSize];
|
||||
Array.Copy(lookAhead, bufStart, temp, 0, LookAheadSize);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
internal InputStreamPacket encData;
|
||||
internal Stream encStream;
|
||||
internal TruncatedStream truncStream;
|
||||
|
||||
internal PgpEncryptedData(
|
||||
InputStreamPacket encData)
|
||||
{
|
||||
this.encData = encData;
|
||||
}
|
||||
|
||||
/// <summary>Return the raw input stream for the data stream.</summary>
|
||||
public virtual Stream GetInputStream()
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
|
||||
/// <summary>Return true if the message is integrity protected.</summary>
|
||||
/// <returns>True, if there is a modification detection code namespace associated
|
||||
/// with this stream.</returns>
|
||||
public bool IsIntegrityProtected()
|
||||
{
|
||||
return encData is SymmetricEncIntegrityPacket;
|
||||
}
|
||||
|
||||
/// <summary>Note: This can only be called after the message has been read.</summary>
|
||||
/// <returns>True, if the message verifies, false otherwise</returns>
|
||||
public bool Verify()
|
||||
{
|
||||
if (!IsIntegrityProtected())
|
||||
throw new PgpException("data not integrity protected.");
|
||||
|
||||
DigestStream dIn = (DigestStream) encStream;
|
||||
|
||||
//
|
||||
// make sure we are at the end.
|
||||
//
|
||||
while (encStream.ReadByte() >= 0)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
//
|
||||
// process the MDC packet
|
||||
//
|
||||
byte[] lookAhead = truncStream.GetLookAhead();
|
||||
|
||||
IDigest hash = dIn.ReadDigest();
|
||||
hash.BlockUpdate(lookAhead, 0, 2);
|
||||
byte[] digest = DigestUtilities.DoFinal(hash);
|
||||
|
||||
byte[] streamDigest = new byte[digest.Length];
|
||||
Array.Copy(lookAhead, 2, streamDigest, 0, streamDigest.Length);
|
||||
|
||||
return Arrays.AreEqual(digest, streamDigest);
|
||||
}
|
||||
}
|
||||
}
|
495
iTechSharp/srcbc/openpgp/PgpEncryptedDataGenerator.cs
Normal file
495
iTechSharp/srcbc/openpgp/PgpEncryptedDataGenerator.cs
Normal file
@@ -0,0 +1,495 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Generator for encrypted objects.</remarks>
|
||||
public class PgpEncryptedDataGenerator
|
||||
: IStreamGenerator
|
||||
{
|
||||
private BcpgOutputStream pOut;
|
||||
private CipherStream cOut;
|
||||
private IBufferedCipher c;
|
||||
private bool withIntegrityPacket;
|
||||
private bool oldFormat;
|
||||
private DigestStream digestOut;
|
||||
|
||||
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)
|
||||
{
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.s2k = s2k;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public KeyParameter GetKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
public override void AddSessionInfo(
|
||||
byte[] si,
|
||||
SecureRandom random)
|
||||
{
|
||||
string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
IBufferedCipher c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
|
||||
|
||||
byte[] iv = new byte[c.GetBlockSize()];
|
||||
c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
|
||||
|
||||
this.sessionInfo = c.DoFinal(si, 0, si.Length - 2);
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream pOut)
|
||||
{
|
||||
SymmetricKeyEncSessionPacket pk = new SymmetricKeyEncSessionPacket(
|
||||
encAlgorithm, s2k, sessionInfo);
|
||||
|
||||
pOut.WritePacket(pk);
|
||||
}
|
||||
}
|
||||
|
||||
private class PubMethod
|
||||
: EncMethod
|
||||
{
|
||||
internal PgpPublicKey pubKey;
|
||||
internal BigInteger[] data;
|
||||
|
||||
internal PubMethod(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
this.pubKey = pubKey;
|
||||
}
|
||||
|
||||
public override void AddSessionInfo(
|
||||
byte[] si,
|
||||
SecureRandom random)
|
||||
{
|
||||
IBufferedCipher c;
|
||||
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
c = 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 akp = pubKey.GetKey();
|
||||
|
||||
c.Init(true, new ParametersWithRandom(akp, random));
|
||||
|
||||
byte[] encKey = c.DoFinal(si);
|
||||
|
||||
switch (pubKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
data = new BigInteger[]{ new BigInteger(1, encKey) };
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
int halfLength = encKey.Length / 2;
|
||||
data = new BigInteger[]
|
||||
{
|
||||
new BigInteger(1, encKey, 0, halfLength),
|
||||
new BigInteger(1, encKey, halfLength, halfLength)
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Encode(BcpgOutputStream pOut)
|
||||
{
|
||||
PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(
|
||||
pubKey.KeyId, pubKey.Algorithm, data);
|
||||
|
||||
pOut.WritePacket(pk);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ArrayList methods = new ArrayList();
|
||||
private readonly SymmetricKeyAlgorithmTag defAlgorithm;
|
||||
private readonly SecureRandom rand;
|
||||
|
||||
public PgpEncryptedDataGenerator(
|
||||
SymmetricKeyAlgorithmTag encAlgorithm)
|
||||
{
|
||||
this.defAlgorithm = encAlgorithm;
|
||||
this.rand = new SecureRandom();
|
||||
}
|
||||
|
||||
public PgpEncryptedDataGenerator(
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
bool withIntegrityPacket)
|
||||
{
|
||||
this.defAlgorithm = encAlgorithm;
|
||||
this.withIntegrityPacket = withIntegrityPacket;
|
||||
this.rand = new SecureRandom();
|
||||
}
|
||||
|
||||
/// <summary>Existing SecureRandom constructor.</summary>
|
||||
/// <param name="encAlgorithm">The symmetric algorithm to use.</param>
|
||||
/// <param name="rand">Source of randomness.</param>
|
||||
public PgpEncryptedDataGenerator(
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
SecureRandom rand)
|
||||
{
|
||||
this.defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
}
|
||||
|
||||
/// <summary>Creates a cipher stream which will have an integrity packet associated with it.</summary>
|
||||
public PgpEncryptedDataGenerator(
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
bool withIntegrityPacket,
|
||||
SecureRandom rand)
|
||||
{
|
||||
this.defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
this.withIntegrityPacket = withIntegrityPacket;
|
||||
}
|
||||
|
||||
/// <summary>Base constructor.</summary>
|
||||
/// <param name="encAlgorithm">The symmetric algorithm to use.</param>
|
||||
/// <param name="rand">Source of randomness.</param>
|
||||
/// <param name="oldFormat">PGP 2.6.x compatibility required.</param>
|
||||
public PgpEncryptedDataGenerator(
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
SecureRandom rand,
|
||||
bool oldFormat)
|
||||
{
|
||||
this.defAlgorithm = encAlgorithm;
|
||||
this.rand = rand;
|
||||
this.oldFormat = oldFormat;
|
||||
}
|
||||
|
||||
/// <summary>Add a PBE encryption method to the encrypted object.</summary>
|
||||
public void AddMethod(
|
||||
char[] passPhrase)
|
||||
{
|
||||
byte[] iv = new byte[8];
|
||||
rand.NextBytes(iv);
|
||||
|
||||
S2k s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60);
|
||||
|
||||
methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.MakeKeyFromPassPhrase(defAlgorithm, s2k, passPhrase)));
|
||||
}
|
||||
|
||||
/// <summary>Add a public key encrypted session key to the encrypted object.</summary>
|
||||
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)
|
||||
{
|
||||
Debug.Assert(sessionInfo != null);
|
||||
Debug.Assert(sessionInfo.Length >= 3);
|
||||
|
||||
int check = 0;
|
||||
|
||||
for (int i = 1; i < sessionInfo.Length - 2; i++)
|
||||
{
|
||||
check += sessionInfo[i];
|
||||
}
|
||||
|
||||
sessionInfo[sessionInfo.Length - 2] = (byte)(check >> 8);
|
||||
sessionInfo[sessionInfo.Length - 1] = (byte)(check);
|
||||
}
|
||||
|
||||
private byte[] CreateSessionInfo(
|
||||
SymmetricKeyAlgorithmTag algorithm,
|
||||
KeyParameter key)
|
||||
{
|
||||
byte[] keyBytes = key.GetKey();
|
||||
byte[] sessionInfo = new byte[keyBytes.Length + 3];
|
||||
sessionInfo[0] = (byte) algorithm;
|
||||
keyBytes.CopyTo(sessionInfo, 1);
|
||||
AddCheckSum(sessionInfo);
|
||||
return sessionInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// If buffer is non null stream assumed to be partial, otherwise the length will be used
|
||||
/// to output a fixed length packet.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
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 key;
|
||||
|
||||
if (methods.Count == 1)
|
||||
{
|
||||
if (methods[0] is PbeMethod)
|
||||
{
|
||||
PbeMethod m = (PbeMethod)methods[0];
|
||||
|
||||
key = m.GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
|
||||
|
||||
byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
|
||||
PubMethod m = (PubMethod)methods[0];
|
||||
|
||||
try
|
||||
{
|
||||
m.AddSessionInfo(sessionInfo, rand);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("exception encrypting session key", e);
|
||||
}
|
||||
}
|
||||
|
||||
pOut.WritePacket((ContainedPacket)methods[0]);
|
||||
}
|
||||
else // multiple methods
|
||||
{
|
||||
key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
|
||||
byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
|
||||
|
||||
for (int i = 0; i != methods.Count; i++)
|
||||
{
|
||||
EncMethod m = (EncMethod)methods[i];
|
||||
|
||||
try
|
||||
{
|
||||
m.AddSessionInfo(sessionInfo, rand);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("exception encrypting session key", e);
|
||||
}
|
||||
|
||||
pOut.WritePacket(m);
|
||||
}
|
||||
}
|
||||
|
||||
string cName = PgpUtilities.GetSymmetricCipherName(defAlgorithm);
|
||||
if (cName == null)
|
||||
{
|
||||
throw new PgpException("null cipher specified");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
cName += "/CFB/NoPadding";
|
||||
}
|
||||
else
|
||||
{
|
||||
cName += "/OpenPGPCFB/NoPadding";
|
||||
}
|
||||
|
||||
c = CipherUtilities.GetCipher(cName);
|
||||
|
||||
// TODO Confirm the IV should be all zero bytes (not inLineIv - see below)
|
||||
byte[] iv = new byte[c.GetBlockSize()];
|
||||
c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), rand));
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
//
|
||||
// we have to Add block size + 2 for the Generated IV and + 1 + 22 if integrity protected
|
||||
//
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22);
|
||||
pOut.WriteByte(1); // version number
|
||||
}
|
||||
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); // version number
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
int blockSize = c.GetBlockSize();
|
||||
byte[] inLineIv = new byte[blockSize + 2];
|
||||
rand.NextBytes(inLineIv, 0, blockSize);
|
||||
Array.Copy(inLineIv, inLineIv.Length - 4, inLineIv, inLineIv.Length - 2, 2);
|
||||
|
||||
Stream myOut = cOut = new CipherStream(pOut, null, c);
|
||||
|
||||
if (withIntegrityPacket)
|
||||
{
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
myOut = digestOut = new DigestStream(myOut, null, digest);
|
||||
}
|
||||
|
||||
myOut.Write(inLineIv, 0, inLineIv.Length);
|
||||
|
||||
return new WrappedGeneratorStream(this, myOut);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Return an output stream which will encrypt the data as it is written to it.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
public Stream Open(
|
||||
Stream outStr,
|
||||
long length)
|
||||
{
|
||||
return Open(outStr, length, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Return an output stream which will encrypt the data as it is written to it.
|
||||
/// The stream will be written out in chunks according to the size of the passed in buffer.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// <b>Note</b>: if the buffer is not a power of 2 in length only the largest power of 2
|
||||
/// bytes worth of the buffer will be used.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
public Stream Open(
|
||||
Stream outStr,
|
||||
byte[] buffer)
|
||||
{
|
||||
return Open(outStr, 0, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Close off the encrypted object - this is equivalent to calling Close() on the stream
|
||||
/// returned by the Open() method.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// <b>Note</b>: This does not close the underlying output stream, only the stream on top of
|
||||
/// it created by the Open() method.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (cOut != null)
|
||||
{
|
||||
// TODO Should this all be under the try/catch block?
|
||||
if (digestOut != null)
|
||||
{
|
||||
//
|
||||
// hand code a mod detection packet
|
||||
//
|
||||
BcpgOutputStream bOut = new BcpgOutputStream(
|
||||
digestOut, PacketTag.ModificationDetectionCode, 20);
|
||||
|
||||
bOut.Flush();
|
||||
digestOut.Flush();
|
||||
|
||||
// TODO
|
||||
byte[] dig = DigestUtilities.DoFinal(digestOut.WriteDigest());
|
||||
cOut.Write(dig, 0, dig.Length);
|
||||
}
|
||||
|
||||
cOut.Flush();
|
||||
|
||||
try
|
||||
{
|
||||
pOut.Write(c.DoFinal());
|
||||
pOut.Finish();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException(e.Message, e);
|
||||
}
|
||||
|
||||
cOut = null;
|
||||
pOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
71
iTechSharp/srcbc/openpgp/PgpEncryptedDataList.cs
Normal file
71
iTechSharp/srcbc/openpgp/PgpEncryptedDataList.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>A holder for a list of PGP encryption method packets.</remarks>
|
||||
public class PgpEncryptedDataList
|
||||
: PgpObject
|
||||
{
|
||||
private ArrayList list = new ArrayList();
|
||||
private InputStreamPacket data;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PgpEncryptedData this[int index]
|
||||
{
|
||||
get { return (PgpEncryptedData) list[index]; }
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public object Get(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size
|
||||
{
|
||||
get { return list.Count; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return list.Count; }
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return list.Count == 0; }
|
||||
}
|
||||
|
||||
public IEnumerable GetEncryptedDataObjects()
|
||||
{
|
||||
return new EnumerableProxy(list);
|
||||
}
|
||||
}
|
||||
}
|
19
iTechSharp/srcbc/openpgp/PgpException.cs
Normal file
19
iTechSharp/srcbc/openpgp/PgpException.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Generic exception class for PGP encoding/decoding problems.</remarks>
|
||||
public class PgpException
|
||||
: Exception
|
||||
{
|
||||
public PgpException() : base() {}
|
||||
public PgpException(string message) : base(message) {}
|
||||
public PgpException(string message, Exception exception) : base(message, exception) {}
|
||||
|
||||
[Obsolete("Use InnerException property")]
|
||||
public Exception UnderlyingException
|
||||
{
|
||||
get { return InnerException; }
|
||||
}
|
||||
}
|
||||
}
|
16
iTechSharp/srcbc/openpgp/PgpExperimental.cs
Normal file
16
iTechSharp/srcbc/openpgp/PgpExperimental.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
public class PgpExperimental
|
||||
: PgpObject
|
||||
{
|
||||
private readonly ExperimentalPacket p;
|
||||
|
||||
public PgpExperimental(
|
||||
BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = (ExperimentalPacket) bcpgIn.ReadPacket();
|
||||
}
|
||||
}
|
||||
}
|
13
iTechSharp/srcbc/openpgp/PgpKeyFlags.cs
Normal file
13
iTechSharp/srcbc/openpgp/PgpKeyFlags.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Key flag values for the KeyFlags subpacket.</remarks>
|
||||
public abstract class PgpKeyFlags
|
||||
{
|
||||
public const int CanCertify = 0x01; // This key may be used to certify other keys.
|
||||
public const int CanSign = 0x02; // This key may be used to sign data.
|
||||
public const int CanEncryptCommunications = 0x04; // This key may be used to encrypt communications.
|
||||
public const int CanEncryptStorage = 0x08; // This key may be used to encrypt storage.
|
||||
public const int MaybeSplit = 0x10; // The private component of this key may have been split by a secret-sharing mechanism.
|
||||
public const int MaybeShared = 0x80; // The private component of this key may be in the possession of more than one person.
|
||||
}
|
||||
}
|
67
iTechSharp/srcbc/openpgp/PgpKeyPair.cs
Normal file
67
iTechSharp/srcbc/openpgp/PgpKeyPair.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// General class to handle JCA key pairs and convert them into OpenPGP ones.
|
||||
/// <p>
|
||||
/// A word for the unwary, the KeyId for an OpenPGP public key is calculated from
|
||||
/// a hash that includes the time of creation, if you pass a different date to the
|
||||
/// constructor below with the same public private key pair the KeyIs will not be the
|
||||
/// same as for previous generations of the key, so ideally you only want to do
|
||||
/// this once.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
public class PgpKeyPair
|
||||
{
|
||||
private readonly PgpPublicKey pub;
|
||||
private readonly PgpPrivateKey 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)
|
||||
{
|
||||
this.pub = new PgpPublicKey(algorithm, pubKey, time);
|
||||
this.priv = new PgpPrivateKey(privKey, pub.KeyId);
|
||||
}
|
||||
|
||||
/// <summary>Create a key pair from a PgpPrivateKey and a PgpPublicKey.</summary>
|
||||
/// <param name="pub">The public key.</param>
|
||||
/// <param name="priv">The private key.</param>
|
||||
public PgpKeyPair(
|
||||
PgpPublicKey pub,
|
||||
PgpPrivateKey priv)
|
||||
{
|
||||
this.pub = pub;
|
||||
this.priv = priv;
|
||||
}
|
||||
|
||||
/// <summary>The keyId associated with this key pair.</summary>
|
||||
public long KeyId
|
||||
{
|
||||
get { return pub.KeyId; }
|
||||
}
|
||||
|
||||
public PgpPublicKey PublicKey
|
||||
{
|
||||
get { return pub; }
|
||||
}
|
||||
|
||||
public PgpPrivateKey PrivateKey
|
||||
{
|
||||
get { return priv; }
|
||||
}
|
||||
}
|
||||
}
|
166
iTechSharp/srcbc/openpgp/PgpKeyRingGenerator.cs
Normal file
166
iTechSharp/srcbc/openpgp/PgpKeyRingGenerator.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Generator for a PGP master and subkey ring.
|
||||
/// This class will generate both the secret and public key rings
|
||||
/// </remarks>
|
||||
public class PgpKeyRingGenerator
|
||||
{
|
||||
private ArrayList keys = new ArrayList();
|
||||
private string id;
|
||||
private SymmetricKeyAlgorithmTag encAlgorithm;
|
||||
private int certificationLevel;
|
||||
private char[] passPhrase;
|
||||
private bool useSha1;
|
||||
private PgpKeyPair masterKey;
|
||||
private PgpSignatureSubpacketVector hashedPacketVector;
|
||||
private PgpSignatureSubpacketVector unhashedPacketVector;
|
||||
private SecureRandom rand;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new key ring generator using old style checksumming. It is recommended to use
|
||||
/// SHA1 checksumming where possible.
|
||||
/// </summary>
|
||||
/// <param name="certificationLevel">The certification level for keys on this ring.</param>
|
||||
/// <param name="masterKey">The master key pair.</param>
|
||||
/// <param name="id">The id to be associated with the ring.</param>
|
||||
/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
|
||||
/// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
|
||||
/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
|
||||
/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
|
||||
/// <param name="rand">input secured random.</param>
|
||||
public PgpKeyRingGenerator(
|
||||
int certificationLevel,
|
||||
PgpKeyPair masterKey,
|
||||
string id,
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
char[] passPhrase,
|
||||
PgpSignatureSubpacketVector hashedPackets,
|
||||
PgpSignatureSubpacketVector unhashedPackets,
|
||||
SecureRandom rand)
|
||||
: this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new key ring generator.
|
||||
/// </summary>
|
||||
/// <param name="certificationLevel">The certification level for keys on this ring.</param>
|
||||
/// <param name="masterKey">The master key pair.</param>
|
||||
/// <param name="id">The id to be associated with the ring.</param>
|
||||
/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
|
||||
/// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
|
||||
/// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
|
||||
/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
|
||||
/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
|
||||
/// <param name="rand">input secured random.</param>
|
||||
public PgpKeyRingGenerator(
|
||||
int certificationLevel,
|
||||
PgpKeyPair masterKey,
|
||||
string id,
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
char[] passPhrase,
|
||||
bool useSha1,
|
||||
PgpSignatureSubpacketVector hashedPackets,
|
||||
PgpSignatureSubpacketVector unhashedPackets,
|
||||
SecureRandom rand)
|
||||
{
|
||||
this.certificationLevel = certificationLevel;
|
||||
this.masterKey = masterKey;
|
||||
this.id = id;
|
||||
this.encAlgorithm = encAlgorithm;
|
||||
this.passPhrase = passPhrase;
|
||||
this.useSha1 = useSha1;
|
||||
this.hashedPacketVector = hashedPackets;
|
||||
this.unhashedPacketVector = unhashedPackets;
|
||||
this.rand = rand;
|
||||
|
||||
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
|
||||
}
|
||||
|
||||
/// <summary>Add a subkey to the key ring to be generated with default certification.</summary>
|
||||
public void AddSubKey(
|
||||
PgpKeyPair keyPair)
|
||||
{
|
||||
AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a subkey with specific hashed and unhashed packets associated with it and
|
||||
/// default certification.
|
||||
/// </summary>
|
||||
/// <param name="keyPair">Public/private key pair.</param>
|
||||
/// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
|
||||
/// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
|
||||
/// <exception cref="PgpException"></exception>
|
||||
public void AddSubKey(
|
||||
PgpKeyPair keyPair,
|
||||
PgpSignatureSubpacketVector hashedPackets,
|
||||
PgpSignatureSubpacketVector unhashedPackets)
|
||||
{
|
||||
try
|
||||
{
|
||||
PgpSignatureGenerator sGen = new PgpSignatureGenerator(
|
||||
masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
|
||||
|
||||
//
|
||||
// Generate the certification
|
||||
//
|
||||
sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
|
||||
|
||||
sGen.SetHashedSubpackets(hashedPackets);
|
||||
sGen.SetUnhashedSubpackets(unhashedPackets);
|
||||
|
||||
ArrayList subSigs = new ArrayList();
|
||||
|
||||
subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
|
||||
|
||||
keys.Add(new PgpSecretKey(keyPair, null, subSigs, encAlgorithm, passPhrase, useSha1, rand));
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("exception adding subkey: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Return the secret key ring.</summary>
|
||||
public PgpSecretKeyRing GenerateSecretKeyRing()
|
||||
{
|
||||
return new PgpSecretKeyRing(keys);
|
||||
}
|
||||
|
||||
/// <summary>Return the public key ring that corresponds to the secret key ring.</summary>
|
||||
public PgpPublicKeyRing GeneratePublicKeyRing()
|
||||
{
|
||||
ArrayList pubKeys = new ArrayList();
|
||||
|
||||
IEnumerator enumerator = keys.GetEnumerator();
|
||||
enumerator.MoveNext();
|
||||
|
||||
PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current;
|
||||
pubKeys.Add(pgpSecretKey.PublicKey);
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
pgpSecretKey = (PgpSecretKey) enumerator.Current;
|
||||
|
||||
PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey);
|
||||
k.publicPk = new PublicSubkeyPacket(
|
||||
k.Algorithm, k.CreationTime, k.publicPk.Key);
|
||||
|
||||
pubKeys.Add(k);
|
||||
}
|
||||
|
||||
return new PgpPublicKeyRing(pubKeys);
|
||||
}
|
||||
}
|
||||
}
|
15
iTechSharp/srcbc/openpgp/PgpKeyValidationException.cs
Normal file
15
iTechSharp/srcbc/openpgp/PgpKeyValidationException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Thrown if the key checksum is invalid.
|
||||
/// </remarks>
|
||||
public class PgpKeyValidationException
|
||||
: PgpException
|
||||
{
|
||||
public PgpKeyValidationException() : base() {}
|
||||
public PgpKeyValidationException(string message) : base(message) {}
|
||||
public PgpKeyValidationException(string message, Exception exception) : base(message, exception) {}
|
||||
}
|
||||
}
|
56
iTechSharp/srcbc/openpgp/PgpLiteralData.cs
Normal file
56
iTechSharp/srcbc/openpgp/PgpLiteralData.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <summary>Class for processing literal data objects.</summary>
|
||||
public class PgpLiteralData
|
||||
: PgpObject
|
||||
{
|
||||
public const char Binary = 'b';
|
||||
public const char Text = 't';
|
||||
|
||||
/// <summary>The special name indicating a "for your eyes only" packet.</summary>
|
||||
public const string Console = "_CONSOLE";
|
||||
|
||||
private LiteralDataPacket data;
|
||||
|
||||
public PgpLiteralData(
|
||||
BcpgInputStream bcpgInput)
|
||||
{
|
||||
data = (LiteralDataPacket) bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
/// <summary>The format of the data stream - Binary or Text</summary>
|
||||
public int Format
|
||||
{
|
||||
get { return data.Format; }
|
||||
}
|
||||
|
||||
/// <summary>The file name that's associated with the data stream.</summary>
|
||||
public string FileName
|
||||
{
|
||||
get { return data.FileName; }
|
||||
}
|
||||
|
||||
/// <summary>The modification time for the file.</summary>
|
||||
public DateTime ModificationTime
|
||||
{
|
||||
get { return DateTimeUtilities.UnixMsToDateTime(data.ModificationTime); }
|
||||
}
|
||||
|
||||
/// <summary>The raw input stream for the data stream.</summary>
|
||||
public Stream GetInputStream()
|
||||
{
|
||||
return data.GetInputStream();
|
||||
}
|
||||
|
||||
/// <summary>The input stream representing the data stream.</summary>
|
||||
public Stream GetDataStream()
|
||||
{
|
||||
return GetInputStream();
|
||||
}
|
||||
}
|
||||
}
|
177
iTechSharp/srcbc/openpgp/PgpLiteralDataGenerator.cs
Normal file
177
iTechSharp/srcbc/openpgp/PgpLiteralDataGenerator.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Class for producing literal data packets.</remarks>
|
||||
public class PgpLiteralDataGenerator
|
||||
: IStreamGenerator
|
||||
{
|
||||
public const char Binary = PgpLiteralData.Binary;
|
||||
public const char Text = PgpLiteralData.Text;
|
||||
|
||||
/// <summary>The special name indicating a "for your eyes only" packet.</summary>
|
||||
public const string Console = PgpLiteralData.Console;
|
||||
|
||||
private BcpgOutputStream pkOut;
|
||||
private bool oldFormat;
|
||||
|
||||
public PgpLiteralDataGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates literal data objects in the old format.
|
||||
/// This is important if you need compatibility with PGP 2.6.x.
|
||||
/// </summary>
|
||||
/// <param name="oldFormat">If true, uses old format.</param>
|
||||
public PgpLiteralDataGenerator(
|
||||
bool oldFormat)
|
||||
{
|
||||
this.oldFormat = oldFormat;
|
||||
}
|
||||
|
||||
private void WriteHeader(
|
||||
BcpgOutputStream outStr,
|
||||
char format,
|
||||
string name,
|
||||
long modificationTime)
|
||||
{
|
||||
byte[] asciiName = Strings.ToByteArray(name);
|
||||
|
||||
outStr.Write(
|
||||
(byte) format,
|
||||
(byte) asciiName.Length);
|
||||
|
||||
outStr.Write(asciiName);
|
||||
|
||||
long modDate = modificationTime / 1000L;
|
||||
|
||||
outStr.Write(
|
||||
(byte)(modDate >> 24),
|
||||
(byte)(modDate >> 16),
|
||||
(byte)(modDate >> 8),
|
||||
(byte)modDate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Open a literal data packet, returning a stream to store the data inside the packet.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
/// <param name="outStr">The stream we want the packet in.</param>
|
||||
/// <param name="format">The format we are using.</param>
|
||||
/// <param name="name">The name of the 'file'.</param>
|
||||
/// <param name="length">The length of the data we will write.</param>
|
||||
/// <param name="modificationTime">The time of last modification we want stored.</param>
|
||||
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");
|
||||
|
||||
// Do this first, since it might throw an exception
|
||||
long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
|
||||
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData,
|
||||
length + 2 + name.Length + 4, oldFormat);
|
||||
|
||||
WriteHeader(pkOut, format, name, unixMs);
|
||||
|
||||
return new WrappedGeneratorStream(this, pkOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Open a literal data packet, returning a stream to store the data inside the packet,
|
||||
/// as an indefinite length stream. The stream is written out as a series of partial
|
||||
/// packets with a chunk size determined by the size of the passed in buffer.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// <b>Note</b>: if the buffer is not a power of 2 in length only the largest power of 2
|
||||
/// bytes worth of the buffer will be used.</p>
|
||||
/// </summary>
|
||||
/// <param name="outStr">The stream we want the packet in.</param>
|
||||
/// <param name="format">The format we are using.</param>
|
||||
/// <param name="name">The name of the 'file'.</param>
|
||||
/// <param name="modificationTime">The time of last modification we want stored.</param>
|
||||
/// <param name="buffer">The buffer to use for collecting data to put into chunks.</param>
|
||||
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");
|
||||
|
||||
// Do this first, since it might throw an exception
|
||||
long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
|
||||
|
||||
pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
|
||||
|
||||
WriteHeader(pkOut, format, name, unixMs);
|
||||
|
||||
return new WrappedGeneratorStream(this, pkOut);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <p>
|
||||
/// Open a literal data packet for the passed in <c>FileInfo</c> object, returning
|
||||
/// an output stream for saving the file contents.
|
||||
/// </p>
|
||||
/// <p>
|
||||
/// The stream created can be closed off by either calling Close()
|
||||
/// on the stream or Close() on the generator. Closing the returned
|
||||
/// stream does not close off the Stream parameter <c>outStr</c>.
|
||||
/// </p>
|
||||
/// </summary>
|
||||
/// <param name="outStr">The stream we want the packet in.</param>
|
||||
/// <param name="format">The format we are using.</param>
|
||||
/// <param name="file">The <c>FileInfo</c> object containg the packet details.</param>
|
||||
public Stream Open(
|
||||
Stream outStr,
|
||||
char format,
|
||||
FileInfo file)
|
||||
{
|
||||
return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close the literal data packet - this is equivalent to calling Close()
|
||||
/// on the stream returned by the Open() method.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (pkOut != null)
|
||||
{
|
||||
pkOut.Finish();
|
||||
pkOut.Flush();
|
||||
pkOut = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
iTechSharp/srcbc/openpgp/PgpMarker.cs
Normal file
18
iTechSharp/srcbc/openpgp/PgpMarker.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// A PGP marker packet - in general these should be ignored other than where
|
||||
/// the idea is to preserve the original input stream.
|
||||
/// </remarks>
|
||||
public class PgpMarker
|
||||
: PgpObject
|
||||
{
|
||||
private readonly MarkerPacket p;
|
||||
|
||||
public PgpMarker(
|
||||
BcpgInputStream bcpgIn)
|
||||
{
|
||||
p = (MarkerPacket) bcpgIn.ReadPacket();
|
||||
}
|
||||
}
|
||||
}
|
130
iTechSharp/srcbc/openpgp/PgpObjectFactory.cs
Normal file
130
iTechSharp/srcbc/openpgp/PgpObjectFactory.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// General class for reading a PGP object stream.
|
||||
/// <p>
|
||||
/// Note: if this class finds a PgpPublicKey or a PgpSecretKey it
|
||||
/// will create a PgpPublicKeyRing, or a PgpSecretKeyRing for each
|
||||
/// key found. If all you are trying to do is read a key ring file use
|
||||
/// either PgpPublicKeyRingBundle or PgpSecretKeyRingBundle.</p>
|
||||
/// </remarks>
|
||||
public class PgpObjectFactory
|
||||
{
|
||||
private readonly BcpgInputStream bcpgIn;
|
||||
|
||||
public PgpObjectFactory(
|
||||
Stream inputStream)
|
||||
{
|
||||
this.bcpgIn = BcpgInputStream.Wrap(inputStream);
|
||||
}
|
||||
|
||||
public PgpObjectFactory(
|
||||
byte[] bytes)
|
||||
: this(new MemoryStream(bytes, false))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Return the next object in the stream, or null if the end is reached.</summary>
|
||||
/// <exception cref="IOException">On a parse error</exception>
|
||||
public PgpObject NextPgpObject()
|
||||
{
|
||||
PacketTag tag = bcpgIn.NextPacketTag();
|
||||
|
||||
if ((int) tag == -1) return null;
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
case PacketTag.Signature:
|
||||
{
|
||||
ArrayList l = new ArrayList();
|
||||
|
||||
while (bcpgIn.NextPacketTag() == PacketTag.Signature)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.Add(new PgpSignature(bcpgIn));
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw new IOException("can't create signature object: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
return new PgpSignatureList(
|
||||
(PgpSignature[]) l.ToArray(typeof(PgpSignature)));
|
||||
}
|
||||
case PacketTag.SecretKey:
|
||||
try
|
||||
{
|
||||
return new PgpSecretKeyRing(bcpgIn);
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw new IOException("can't create secret key object: " + e);
|
||||
}
|
||||
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:
|
||||
{
|
||||
ArrayList l = new ArrayList();
|
||||
|
||||
while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.Add(new PgpOnePassSignature(bcpgIn));
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw new IOException("can't create one pass signature object: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
return new PgpOnePassSignatureList(
|
||||
(PgpOnePassSignature[]) l.ToArray(typeof(PgpOnePassSignature)));
|
||||
}
|
||||
case PacketTag.Marker:
|
||||
return new PgpMarker(bcpgIn);
|
||||
case PacketTag.Experimental1:
|
||||
case PacketTag.Experimental2:
|
||||
case PacketTag.Experimental3:
|
||||
case PacketTag.Experimental4:
|
||||
return new PgpExperimental(bcpgIn);
|
||||
}
|
||||
|
||||
throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
|
||||
}
|
||||
|
||||
[Obsolete("Use NextPgpObject() instead")]
|
||||
public object NextObject()
|
||||
{
|
||||
return NextPgpObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return all available objects in a list.
|
||||
/// </summary>
|
||||
/// <returns>An <c>IList</c> containing all objects from this factory, in order.</returns>
|
||||
public IList AllPgpObjects()
|
||||
{
|
||||
ArrayList result = new ArrayList();
|
||||
PgpObject pgpObject;
|
||||
while ((pgpObject = NextPgpObject()) != null)
|
||||
{
|
||||
result.Add(pgpObject);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
179
iTechSharp/srcbc/openpgp/PgpOnePassSignature.cs
Normal file
179
iTechSharp/srcbc/openpgp/PgpOnePassSignature.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>A one pass signature object.</remarks>
|
||||
public class PgpOnePassSignature
|
||||
{
|
||||
private OnePassSignaturePacket sigPack;
|
||||
private int signatureType;
|
||||
private ISigner sig;
|
||||
private byte lastb;
|
||||
|
||||
internal PgpOnePassSignature(
|
||||
BcpgInputStream bcpgInput)
|
||||
: this((OnePassSignaturePacket) bcpgInput.ReadPacket())
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpOnePassSignature(
|
||||
OnePassSignaturePacket sigPack)
|
||||
{
|
||||
this.sigPack = sigPack;
|
||||
this.signatureType = sigPack.SignatureType;
|
||||
|
||||
try
|
||||
{
|
||||
this.sig = SignerUtilities.GetSigner(
|
||||
PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("can't set up signature object.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Initialise the signature object for verification.</summary>
|
||||
public void InitVerify(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
lastb = 0;
|
||||
|
||||
try
|
||||
{
|
||||
sig.Init(false, pubKey.GetKey());
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new PgpException("invalid key.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte b)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
if (b == '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
else if (b == '\n')
|
||||
{
|
||||
if (lastb != '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
sig.Update((byte)'\r');
|
||||
sig.Update((byte)'\n');
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte[] bytes)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
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 == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
int finish = off + length;
|
||||
|
||||
for (int i = off; i != finish; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, off, length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Verify the calculated signature against the passed in PgpSignature.</summary>
|
||||
public bool Verify(
|
||||
PgpSignature pgpSig)
|
||||
{
|
||||
byte[] trailer = pgpSig.GetSignatureTrailer();
|
||||
|
||||
sig.BlockUpdate(trailer, 0, trailer.Length);
|
||||
|
||||
return sig.VerifySignature(pgpSig.GetSignature());
|
||||
}
|
||||
|
||||
public long KeyId
|
||||
{
|
||||
get { return sigPack.KeyId; }
|
||||
}
|
||||
|
||||
public int SignatureType
|
||||
{
|
||||
get { return sigPack.SignatureType; }
|
||||
}
|
||||
|
||||
public HashAlgorithmTag HashAlgorithm
|
||||
{
|
||||
get { return sigPack.HashAlgorithm; }
|
||||
}
|
||||
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm
|
||||
{
|
||||
get { return sigPack.KeyAlgorithm; }
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
|
||||
Encode(bOut);
|
||||
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
BcpgOutputStream.Wrap(outStr).WritePacket(sigPack);
|
||||
}
|
||||
}
|
||||
}
|
51
iTechSharp/srcbc/openpgp/PgpOnePassSignatureList.cs
Normal file
51
iTechSharp/srcbc/openpgp/PgpOnePassSignatureList.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Holder for a list of PgpOnePassSignature objects.</remarks>
|
||||
public class PgpOnePassSignatureList
|
||||
: PgpObject
|
||||
{
|
||||
private readonly PgpOnePassSignature[] sigs;
|
||||
|
||||
public PgpOnePassSignatureList(
|
||||
PgpOnePassSignature[] sigs)
|
||||
{
|
||||
this.sigs = (PgpOnePassSignature[]) sigs.Clone();
|
||||
}
|
||||
|
||||
public PgpOnePassSignatureList(
|
||||
PgpOnePassSignature sig)
|
||||
{
|
||||
this.sigs = new PgpOnePassSignature[]{ sig };
|
||||
}
|
||||
|
||||
public PgpOnePassSignature this[int index]
|
||||
{
|
||||
get { return sigs[index]; }
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public PgpOnePassSignature Get(
|
||||
int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size
|
||||
{
|
||||
get { return sigs.Length; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return sigs.Length; }
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return (sigs.Length == 0); }
|
||||
}
|
||||
}
|
||||
}
|
135
iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs
Normal file
135
iTechSharp/srcbc/openpgp/PgpPbeEncryptedData.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>A password based encryption object.</remarks>
|
||||
public class PgpPbeEncryptedData
|
||||
: PgpEncryptedData
|
||||
{
|
||||
private readonly SymmetricKeyEncSessionPacket keyData;
|
||||
|
||||
internal PgpPbeEncryptedData(
|
||||
SymmetricKeyEncSessionPacket keyData,
|
||||
InputStreamPacket encData)
|
||||
: base(encData)
|
||||
{
|
||||
this.keyData = keyData;
|
||||
}
|
||||
|
||||
/// <summary>Return the raw input stream for the data stream.</summary>
|
||||
public override Stream GetInputStream()
|
||||
{
|
||||
return encData.GetInputStream();
|
||||
}
|
||||
|
||||
/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
|
||||
public Stream GetDataStream(
|
||||
char[] passPhrase)
|
||||
{
|
||||
try
|
||||
{
|
||||
SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm;
|
||||
|
||||
KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(
|
||||
keyAlgorithm, keyData.S2k, passPhrase);
|
||||
|
||||
|
||||
byte[] secKeyData = keyData.GetSecKeyData();
|
||||
if (secKeyData != null && secKeyData.Length > 0)
|
||||
{
|
||||
IBufferedCipher keyCipher = CipherUtilities.GetCipher(
|
||||
PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding");
|
||||
|
||||
keyCipher.Init(false,
|
||||
new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()]));
|
||||
|
||||
byte[] keyBytes = keyCipher.DoFinal(secKeyData);
|
||||
|
||||
keyAlgorithm = (SymmetricKeyAlgorithmTag) keyBytes[0];
|
||||
|
||||
key = ParameterUtilities.CreateKeyParameter(
|
||||
PgpUtilities.GetSymmetricCipherName(keyAlgorithm),
|
||||
keyBytes, 1, keyBytes.Length - 1);
|
||||
}
|
||||
|
||||
|
||||
IBufferedCipher c = CreateStreamCipher(keyAlgorithm);
|
||||
|
||||
byte[] iv = new byte[c.GetBlockSize()];
|
||||
|
||||
c.Init(false, new ParametersWithIV(key, iv));
|
||||
|
||||
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c, null));
|
||||
|
||||
if (encData is SymmetricEncIntegrityPacket)
|
||||
{
|
||||
truncStream = new TruncatedStream(encStream);
|
||||
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
|
||||
encStream = new DigestStream(truncStream, digest, null);
|
||||
}
|
||||
|
||||
if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
|
||||
int v1 = encStream.ReadByte();
|
||||
int v2 = encStream.ReadByte();
|
||||
|
||||
if (v1 < 0 || v2 < 0)
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
|
||||
|
||||
// Note: the oracle attack on the "quick check" bytes is not deemed
|
||||
// a security risk for PBE (see PgpPublicKeyEncryptedData)
|
||||
|
||||
bool repeatCheckPassed =
|
||||
iv[iv.Length - 2] == (byte)v1
|
||||
&& iv[iv.Length - 1] == (byte)v2;
|
||||
|
||||
// Note: some versions of PGP appear to produce 0 for the extra
|
||||
// bytes rather than repeating the two previous bytes
|
||||
bool zeroesCheckPassed =
|
||||
v1 == 0
|
||||
&& v2 == 0;
|
||||
|
||||
if (!repeatCheckPassed && !zeroesCheckPassed)
|
||||
{
|
||||
throw new PgpDataValidationException("quick check failed.");
|
||||
}
|
||||
|
||||
|
||||
return encStream;
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", e);
|
||||
}
|
||||
}
|
||||
|
||||
private IBufferedCipher CreateStreamCipher(
|
||||
SymmetricKeyAlgorithmTag keyAlgorithm)
|
||||
{
|
||||
string mode = (encData is SymmetricEncIntegrityPacket)
|
||||
? "CFB"
|
||||
: "OpenPGPCFB";
|
||||
|
||||
string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm)
|
||||
+ "/" + mode + "/NoPadding";
|
||||
|
||||
return CipherUtilities.GetCipher(cName);
|
||||
}
|
||||
}
|
||||
}
|
42
iTechSharp/srcbc/openpgp/PgpPrivateKey.cs
Normal file
42
iTechSharp/srcbc/openpgp/PgpPrivateKey.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks>
|
||||
public class PgpPrivateKey
|
||||
{
|
||||
private readonly long keyId;
|
||||
private readonly AsymmetricKeyParameter privateKey;
|
||||
|
||||
/// <summary>
|
||||
/// Create a PgpPrivateKey from a regular private key and the ID of its
|
||||
/// associated public key.
|
||||
/// </summary>
|
||||
/// <param name="privateKey">Private key to use.</param>
|
||||
/// <param name="keyId">ID of the corresponding public key.</param>
|
||||
public PgpPrivateKey(
|
||||
AsymmetricKeyParameter privateKey,
|
||||
long keyId)
|
||||
{
|
||||
if (!privateKey.IsPrivate)
|
||||
throw new ArgumentException("Expected a private key", "privateKey");
|
||||
|
||||
this.privateKey = privateKey;
|
||||
this.keyId = keyId;
|
||||
}
|
||||
|
||||
/// <summary>The keyId associated with the contained private key.</summary>
|
||||
public long KeyId
|
||||
{
|
||||
get { return keyId; }
|
||||
}
|
||||
|
||||
/// <summary>The contained private key.</summary>
|
||||
public AsymmetricKeyParameter Key
|
||||
{
|
||||
get { return privateKey; }
|
||||
}
|
||||
}
|
||||
}
|
835
iTechSharp/srcbc/openpgp/PgpPublicKey.cs
Normal file
835
iTechSharp/srcbc/openpgp/PgpPublicKey.cs
Normal file
@@ -0,0 +1,835 @@
|
||||
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.Security;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>General class to handle a PGP public key object.</remarks>
|
||||
public class PgpPublicKey
|
||||
{
|
||||
private static readonly int[] MasterKeyCertificationTypes = new int[]
|
||||
{
|
||||
PgpSignature.PositiveCertification,
|
||||
PgpSignature.CasualCertification,
|
||||
PgpSignature.NoCertification,
|
||||
PgpSignature.DefaultCertification
|
||||
};
|
||||
|
||||
private long keyId;
|
||||
private byte[] fingerprint;
|
||||
private int keyStrength;
|
||||
|
||||
internal PublicKeyPacket publicPk;
|
||||
private TrustPacket trustPk;
|
||||
private ArrayList keySigs = new ArrayList();
|
||||
private ArrayList ids = new ArrayList();
|
||||
private ArrayList idTrusts = new ArrayList();
|
||||
private ArrayList idSigs = new ArrayList();
|
||||
private ArrayList subSigs;
|
||||
|
||||
private void Init()
|
||||
{
|
||||
IBcpgKey key = publicPk.Key;
|
||||
|
||||
if (publicPk.Version <= 3)
|
||||
{
|
||||
RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
|
||||
|
||||
this.keyId = rK.Modulus.LongValue;
|
||||
|
||||
try
|
||||
{
|
||||
IDigest digest = DigestUtilities.GetDigest("MD5");
|
||||
|
||||
byte[] bytes = rK.Modulus.ToByteArrayUnsigned();
|
||||
digest.BlockUpdate(bytes, 0, bytes.Length);
|
||||
|
||||
bytes = rK.PublicExponent.ToByteArrayUnsigned();
|
||||
digest.BlockUpdate(bytes, 0, bytes.Length);
|
||||
|
||||
this.fingerprint = DigestUtilities.DoFinal(digest);
|
||||
}
|
||||
//catch (NoSuchAlgorithmException)
|
||||
catch (Exception)
|
||||
{
|
||||
throw new IOException("can't find MD5");
|
||||
}
|
||||
|
||||
this.keyStrength = rK.Modulus.BitLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] kBytes = publicPk.GetEncodedContents();
|
||||
|
||||
try
|
||||
{
|
||||
IDigest digest = DigestUtilities.GetDigest("SHA1");
|
||||
|
||||
digest.Update(0x99);
|
||||
digest.Update((byte)(kBytes.Length >> 8));
|
||||
digest.Update((byte)kBytes.Length);
|
||||
digest.BlockUpdate(kBytes, 0, kBytes.Length);
|
||||
this.fingerprint = DigestUtilities.DoFinal(digest);
|
||||
}
|
||||
//catch (NoSuchAlgorithmException)
|
||||
catch (Exception)
|
||||
{
|
||||
throw new IOException("can't find SHA1");
|
||||
}
|
||||
|
||||
this.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)
|
||||
| (ulong)fingerprint[fingerprint.Length - 1]);
|
||||
|
||||
if (key is RsaPublicBcpgKey)
|
||||
{
|
||||
this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
|
||||
}
|
||||
else if (key is DsaPublicBcpgKey)
|
||||
{
|
||||
this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength;
|
||||
}
|
||||
else if (key is ElGamalPublicBcpgKey)
|
||||
{
|
||||
this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a PgpPublicKey from the passed in lightweight one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note: the time passed in affects the value of the key's keyId, so you probably only want
|
||||
/// to do this once for a lightweight key, or make sure you keep track of the time you used.
|
||||
/// </remarks>
|
||||
/// <param name="algorithm">Asymmetric algorithm type representing the public key.</param>
|
||||
/// <param name="pubKey">Actual public key to associate.</param>
|
||||
/// <param name="time">Date of creation.</param>
|
||||
/// <exception cref="ArgumentException">If <c>pubKey</c> is not public.</exception>
|
||||
/// <exception cref="PgpException">On key creation problem.</exception>
|
||||
public PgpPublicKey(
|
||||
PublicKeyAlgorithmTag algorithm,
|
||||
AsymmetricKeyParameter pubKey,
|
||||
DateTime time)
|
||||
{
|
||||
if (pubKey.IsPrivate)
|
||||
throw new ArgumentException("Expected a public key", "pubKey");
|
||||
|
||||
IBcpgKey bcpgKey;
|
||||
if (pubKey is RsaKeyParameters)
|
||||
{
|
||||
RsaKeyParameters rK = (RsaKeyParameters) pubKey;
|
||||
|
||||
bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent);
|
||||
}
|
||||
else if (pubKey is DsaPublicKeyParameters)
|
||||
{
|
||||
DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey;
|
||||
DsaParameters dP = dK.Parameters;
|
||||
|
||||
bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
|
||||
}
|
||||
else if (pubKey is ElGamalPublicKeyParameters)
|
||||
{
|
||||
ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
|
||||
ElGamalParameters eS = eK.Parameters;
|
||||
|
||||
bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PgpException("unknown key class");
|
||||
}
|
||||
|
||||
this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey);
|
||||
this.ids = new ArrayList();
|
||||
this.idSigs = new ArrayList();
|
||||
|
||||
try
|
||||
{
|
||||
Init();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception calculating keyId", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Constructor for a sub-key.</summary>
|
||||
internal PgpPublicKey(
|
||||
PublicKeyPacket publicPk,
|
||||
TrustPacket trustPk,
|
||||
ArrayList sigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.trustPk = trustPk;
|
||||
this.subSigs = sigs;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
internal PgpPublicKey(
|
||||
PgpPublicKey key,
|
||||
TrustPacket trust,
|
||||
ArrayList subSigs)
|
||||
{
|
||||
this.publicPk = key.publicPk;
|
||||
this.trustPk = trust;
|
||||
this.subSigs = subSigs;
|
||||
|
||||
this.fingerprint = key.fingerprint;
|
||||
this.keyId = key.keyId;
|
||||
this.keyStrength = key.keyStrength;
|
||||
}
|
||||
|
||||
/// <summary>Copy constructor.</summary>
|
||||
/// <param name="pubKey">The public key to copy.</param>
|
||||
internal PgpPublicKey(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
this.publicPk = pubKey.publicPk;
|
||||
|
||||
this.keySigs = new ArrayList(pubKey.keySigs);
|
||||
this.ids = new ArrayList(pubKey.ids);
|
||||
this.idTrusts = new ArrayList(pubKey.idTrusts);
|
||||
this.idSigs = new ArrayList(pubKey.idSigs.Count);
|
||||
for (int i = 0; i != pubKey.idSigs.Count; i++)
|
||||
{
|
||||
this.idSigs.Add(new ArrayList((ArrayList)pubKey.idSigs[i]));
|
||||
}
|
||||
|
||||
if (pubKey.subSigs != null)
|
||||
{
|
||||
this.subSigs = new ArrayList(pubKey.subSigs.Count);
|
||||
for (int i = 0; i != pubKey.subSigs.Count; i++)
|
||||
{
|
||||
this.subSigs.Add(pubKey.subSigs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.fingerprint = pubKey.fingerprint;
|
||||
this.keyId = pubKey.keyId;
|
||||
this.keyStrength = pubKey.keyStrength;
|
||||
}
|
||||
|
||||
internal PgpPublicKey(
|
||||
PublicKeyPacket publicPk,
|
||||
TrustPacket trustPk,
|
||||
ArrayList keySigs,
|
||||
ArrayList ids,
|
||||
ArrayList idTrusts,
|
||||
ArrayList idSigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.trustPk = trustPk;
|
||||
this.keySigs = keySigs;
|
||||
this.ids = ids;
|
||||
this.idTrusts = idTrusts;
|
||||
this.idSigs = idSigs;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
internal PgpPublicKey(
|
||||
PublicKeyPacket publicPk,
|
||||
ArrayList ids,
|
||||
ArrayList idSigs)
|
||||
{
|
||||
this.publicPk = publicPk;
|
||||
this.ids = ids;
|
||||
this.idSigs = idSigs;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>The version of this key.</summary>
|
||||
public int Version
|
||||
{
|
||||
get { return publicPk.Version; }
|
||||
}
|
||||
|
||||
/// <summary>The creation time of this key.</summary>
|
||||
public DateTime CreationTime
|
||||
{
|
||||
get { return publicPk.GetTime(); }
|
||||
}
|
||||
|
||||
/// <summary>The number of valid days from creation time - zero means no expiry.</summary>
|
||||
public int ValidDays
|
||||
{
|
||||
get
|
||||
{
|
||||
if (publicPk.Version > 3)
|
||||
{
|
||||
return (int)(GetValidSeconds() / (24 * 60 * 60));
|
||||
}
|
||||
|
||||
return publicPk.ValidDays;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Return the trust data associated with the public key, if present.</summary>
|
||||
/// <returns>A byte array with trust data, null otherwise.</returns>
|
||||
public byte[] GetTrustData()
|
||||
{
|
||||
if (trustPk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return trustPk.GetLevelAndTrustAmount();
|
||||
}
|
||||
|
||||
/// <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
|
||||
public long GetValidSeconds()
|
||||
{
|
||||
if (publicPk.Version > 3)
|
||||
{
|
||||
if (IsMasterKey)
|
||||
{
|
||||
for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
|
||||
{
|
||||
long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
|
||||
|
||||
if (seconds >= 0)
|
||||
{
|
||||
return seconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
|
||||
|
||||
if (seconds >= 0)
|
||||
{
|
||||
return seconds;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (long) publicPk.ValidDays * 24 * 60 * 60;
|
||||
}
|
||||
|
||||
private long GetExpirationTimeFromSig(
|
||||
bool selfSigned,
|
||||
int signatureType)
|
||||
{
|
||||
foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
|
||||
{
|
||||
if (!selfSigned || sig.KeyId == KeyId)
|
||||
{
|
||||
PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
|
||||
|
||||
if (hashed != null)
|
||||
{
|
||||
return hashed.GetKeyExpirationTime();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>The keyId associated with the public key.</summary>
|
||||
public long KeyId
|
||||
{
|
||||
get { return keyId; }
|
||||
}
|
||||
|
||||
/// <summary>The fingerprint of the key</summary>
|
||||
public byte[] GetFingerprint()
|
||||
{
|
||||
return (byte[]) fingerprint.Clone();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>True, if this key is marked as suitable for encryption</summary>
|
||||
/// <returns>True, if this key is marked as suitable for using for encryption.</returns>
|
||||
public bool IsEncryptionKey
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (publicPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>True, if this is a master key.</summary>
|
||||
public bool IsMasterKey
|
||||
{
|
||||
get { return subSigs == null; }
|
||||
}
|
||||
|
||||
/// <summary>The algorithm code associated with the public key.</summary>
|
||||
public PublicKeyAlgorithmTag Algorithm
|
||||
{
|
||||
get { return publicPk.Algorithm; }
|
||||
}
|
||||
|
||||
/// <summary>The strength of the key in bits.</summary>
|
||||
public int BitStrength
|
||||
{
|
||||
get { return keyStrength; }
|
||||
}
|
||||
|
||||
/// <summary>The public key contained in the object.</summary>
|
||||
/// <returns>A lightweight public key.</returns>
|
||||
/// <exception cref="PgpException">If the key algorithm is not recognised.</exception>
|
||||
public AsymmetricKeyParameter GetKey()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (publicPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key;
|
||||
return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent);
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key;
|
||||
return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G));
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key;
|
||||
return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G));
|
||||
default:
|
||||
throw new PgpException("unknown public key algorithm encountered");
|
||||
}
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("exception constructing public key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of any user IDs associated with the key.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
|
||||
public IEnumerable GetUserIds()
|
||||
{
|
||||
ArrayList temp = new ArrayList();
|
||||
|
||||
foreach (object o in ids)
|
||||
{
|
||||
if (o is string)
|
||||
{
|
||||
temp.Add(o);
|
||||
}
|
||||
}
|
||||
|
||||
return new EnumerableProxy(temp);
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>PgpUserAttributeSubpacketVector</c> objects.</returns>
|
||||
public IEnumerable GetUserAttributes()
|
||||
{
|
||||
ArrayList temp = new ArrayList();
|
||||
|
||||
foreach (object o in ids)
|
||||
{
|
||||
if (o is PgpUserAttributeSubpacketVector)
|
||||
{
|
||||
temp.Add(o);
|
||||
}
|
||||
}
|
||||
|
||||
return new EnumerableProxy(temp);
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of any signatures associated with the passed in id.</summary>
|
||||
/// <param name="id">The ID to be matched.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
|
||||
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((ArrayList) idSigs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of signatures associated with the passed in user attributes.</summary>
|
||||
/// <param name="userAttributes">The vector of user attributes to be matched.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
|
||||
public IEnumerable GetSignaturesForUserAttribute(
|
||||
PgpUserAttributeSubpacketVector userAttributes)
|
||||
{
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (userAttributes.Equals(ids[i]))
|
||||
{
|
||||
return new EnumerableProxy((ArrayList) idSigs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of signatures of the passed in type that are on this key.</summary>
|
||||
/// <param name="signatureType">The type of the signature to be returned.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
|
||||
public IEnumerable GetSignaturesOfType(
|
||||
int signatureType)
|
||||
{
|
||||
ArrayList temp = new ArrayList();
|
||||
|
||||
foreach (PgpSignature sig in GetSignatures())
|
||||
{
|
||||
if (sig.SignatureType == signatureType)
|
||||
{
|
||||
temp.Add(sig);
|
||||
}
|
||||
}
|
||||
|
||||
return new EnumerableProxy(temp);
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of all signatures/certifications associated with this key.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> with all signatures/certifications.</returns>
|
||||
public IEnumerable GetSignatures()
|
||||
{
|
||||
ArrayList sigs;
|
||||
if (subSigs != null)
|
||||
{
|
||||
sigs = subSigs;
|
||||
}
|
||||
else
|
||||
{
|
||||
sigs = new ArrayList(keySigs);
|
||||
|
||||
foreach (ICollection extraSigs in idSigs)
|
||||
{
|
||||
sigs.AddRange(extraSigs);
|
||||
}
|
||||
}
|
||||
|
||||
return new EnumerableProxy(sigs);
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
Encode(bOut);
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
|
||||
|
||||
bcpgOut.WritePacket(publicPk);
|
||||
if (trustPk != null)
|
||||
{
|
||||
bcpgOut.WritePacket(trustPk);
|
||||
}
|
||||
|
||||
if (subSigs == null) // not a sub-key
|
||||
{
|
||||
foreach (PgpSignature keySig in keySigs)
|
||||
{
|
||||
keySig.Encode(bcpgOut);
|
||||
}
|
||||
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (ids[i] is string)
|
||||
{
|
||||
string id = (string) ids[i];
|
||||
|
||||
bcpgOut.WritePacket(new UserIdPacket(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i];
|
||||
bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
|
||||
}
|
||||
|
||||
if (idTrusts[i] != null)
|
||||
{
|
||||
bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
|
||||
}
|
||||
|
||||
foreach (PgpSignature sig in (ArrayList) idSigs[i])
|
||||
{
|
||||
sig.Encode(bcpgOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (PgpSignature subSig in subSigs)
|
||||
{
|
||||
subSig.Encode(bcpgOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Check whether this (sub)key has a revocation signature on it.</summary>
|
||||
/// <returns>True, if this (sub)key has been revoked.</returns>
|
||||
public bool IsRevoked()
|
||||
{
|
||||
int ns = 0;
|
||||
bool revoked = false;
|
||||
if (IsMasterKey) // Master key
|
||||
{
|
||||
while (!revoked && (ns < keySigs.Count))
|
||||
{
|
||||
if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation)
|
||||
{
|
||||
revoked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Sub-key
|
||||
{
|
||||
while (!revoked && (ns < subSigs.Count))
|
||||
{
|
||||
if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation)
|
||||
{
|
||||
revoked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return revoked;
|
||||
}
|
||||
|
||||
/// <summary>Add a certification for an id to the given public key.</summary>
|
||||
/// <param name="key">The key the certification is to be added to.</param>
|
||||
/// <param name="id">The ID the certification is associated with.</param>
|
||||
/// <param name="certification">The new certification.</param>
|
||||
/// <returns>The re-certified key.</returns>
|
||||
public static PgpPublicKey AddCertification(
|
||||
PgpPublicKey key,
|
||||
string id,
|
||||
PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey returnKey = new PgpPublicKey(key);
|
||||
ArrayList sigList = null;
|
||||
|
||||
for (int i = 0; i != returnKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(returnKey.ids[i]))
|
||||
{
|
||||
sigList = (ArrayList) returnKey.idSigs[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (sigList != null)
|
||||
{
|
||||
sigList.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
sigList = new ArrayList();
|
||||
|
||||
sigList.Add(certification);
|
||||
returnKey.ids.Add(id);
|
||||
returnKey.idTrusts.Add(null);
|
||||
returnKey.idSigs.Add(sigList);
|
||||
}
|
||||
|
||||
return returnKey;
|
||||
}
|
||||
|
||||
/// <summary>Add a certification for the given UserAttributeSubpackets to the given public key.</summary>
|
||||
/// <param name="key">The key the certification is to be added to.</param>
|
||||
/// <param name="userAttributes">The attributes the certification is associated with.</param>
|
||||
/// <param name="certification">The new certification.</param>
|
||||
/// <returns>The re-certified key.</returns>
|
||||
public static PgpPublicKey AddCertification(
|
||||
PgpPublicKey key,
|
||||
PgpUserAttributeSubpacketVector userAttributes,
|
||||
PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey returnKey = new PgpPublicKey(key);
|
||||
IList sigList = null;
|
||||
|
||||
for (int i = 0; i != returnKey.ids.Count; i++)
|
||||
{
|
||||
if (userAttributes.Equals(returnKey.ids[i]))
|
||||
{
|
||||
sigList = (IList) returnKey.idSigs[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (sigList != null)
|
||||
{
|
||||
sigList.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
sigList = new ArrayList();
|
||||
sigList.Add(certification);
|
||||
returnKey.ids.Add(userAttributes);
|
||||
returnKey.idTrusts.Add(null);
|
||||
returnKey.idSigs.Add(sigList);
|
||||
}
|
||||
|
||||
return returnKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove any certifications associated with a user attribute subpacket on a key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key the certifications are to be removed from.</param>
|
||||
/// <param name="userAttributes">The attributes to be removed.</param>
|
||||
/// <returns>
|
||||
/// The re-certified key, or null if the user attribute subpacket was not found on the key.
|
||||
/// </returns>
|
||||
public static PgpPublicKey RemoveCertification(
|
||||
PgpPublicKey key,
|
||||
PgpUserAttributeSubpacketVector userAttributes)
|
||||
{
|
||||
PgpPublicKey returnKey = new PgpPublicKey(key);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < returnKey.ids.Count; i++)
|
||||
{
|
||||
if (userAttributes.Equals(returnKey.ids[i]))
|
||||
{
|
||||
found = true;
|
||||
returnKey.ids.RemoveAt(i);
|
||||
returnKey.idTrusts.RemoveAt(i);
|
||||
returnKey.idSigs.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return returnKey;
|
||||
}
|
||||
|
||||
/// <summary>Remove any certifications associated with a given ID on a key.</summary>
|
||||
/// <param name="key">The key the certifications are to be removed from.</param>
|
||||
/// <param name="id">The ID that is to be removed.</param>
|
||||
/// <returns>The re-certified key, or null if the ID was not found on the key.</returns>
|
||||
public static PgpPublicKey RemoveCertification(
|
||||
PgpPublicKey key,
|
||||
string id)
|
||||
{
|
||||
PgpPublicKey returnKey = new PgpPublicKey(key);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < returnKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(returnKey.ids[i]))
|
||||
{
|
||||
found = true;
|
||||
returnKey.ids.RemoveAt(i);
|
||||
returnKey.idTrusts.RemoveAt(i);
|
||||
returnKey.idSigs.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return found ? returnKey : null;
|
||||
}
|
||||
|
||||
/// <summary>Remove any certifications associated with a given ID on a key.</summary>
|
||||
/// <param name="key">The key the certifications are to be removed from.</param>
|
||||
/// <param name="id">The ID that the certfication is to be removed from.</param>
|
||||
/// <param name="certification">The certfication to be removed.</param>
|
||||
/// <returns>The re-certified key, or null if the certification was not found.</returns>
|
||||
public static PgpPublicKey RemoveCertification(
|
||||
PgpPublicKey key,
|
||||
string id,
|
||||
PgpSignature certification)
|
||||
{
|
||||
PgpPublicKey returnKey = new PgpPublicKey(key);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < returnKey.ids.Count; i++)
|
||||
{
|
||||
if (id.Equals(returnKey.ids[i]))
|
||||
{
|
||||
ArrayList certs = (ArrayList) returnKey.idSigs[i];
|
||||
found = certs.Contains(certification);
|
||||
|
||||
if (found)
|
||||
{
|
||||
certs.Remove(certification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found ? returnKey : null;
|
||||
}
|
||||
|
||||
/// <summary>Add a revocation or some other key certification to a key.</summary>
|
||||
/// <param name="key">The key the revocation is to be added to.</param>
|
||||
/// <param name="certification">The key signature to be added.</param>
|
||||
/// <returns>The new changed public key object.</returns>
|
||||
public static PgpPublicKey AddCertification(
|
||||
PgpPublicKey key,
|
||||
PgpSignature certification)
|
||||
{
|
||||
if (key.IsMasterKey)
|
||||
{
|
||||
if (certification.SignatureType == PgpSignature.SubkeyRevocation)
|
||||
{
|
||||
throw new ArgumentException("signature type incorrect for master key revocation.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (certification.SignatureType == PgpSignature.KeyRevocation)
|
||||
{
|
||||
throw new ArgumentException("signature type incorrect for sub-key revocation.");
|
||||
}
|
||||
}
|
||||
|
||||
PgpPublicKey returnKey = new PgpPublicKey(key);
|
||||
|
||||
if (returnKey.subSigs != null)
|
||||
{
|
||||
returnKey.subSigs.Add(certification);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnKey.keySigs.Add(certification);
|
||||
}
|
||||
|
||||
return returnKey;
|
||||
}
|
||||
}
|
||||
}
|
233
iTechSharp/srcbc/openpgp/PgpPublicKeyEncryptedData.cs
Normal file
233
iTechSharp/srcbc/openpgp/PgpPublicKeyEncryptedData.cs
Normal file
@@ -0,0 +1,233 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>A public key encrypted data object.</remarks>
|
||||
public class PgpPublicKeyEncryptedData
|
||||
: PgpEncryptedData
|
||||
{
|
||||
private PublicKeyEncSessionPacket keyData;
|
||||
|
||||
internal PgpPublicKeyEncryptedData(
|
||||
PublicKeyEncSessionPacket keyData,
|
||||
InputStreamPacket encData)
|
||||
: base(encData)
|
||||
{
|
||||
this.keyData = keyData;
|
||||
}
|
||||
|
||||
private static IBufferedCipher GetKeyCipher(
|
||||
PublicKeyAlgorithmTag algorithm)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
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 e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", e);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConfirmCheckSum(
|
||||
byte[] sessionInfo)
|
||||
{
|
||||
int check = 0;
|
||||
|
||||
for (int i = 1; i != sessionInfo.Length - 2; i++)
|
||||
{
|
||||
check += sessionInfo[i] & 0xff;
|
||||
}
|
||||
|
||||
return (sessionInfo[sessionInfo.Length - 2] == (byte)(check >> 8))
|
||||
&& (sessionInfo[sessionInfo.Length - 1] == (byte)(check));
|
||||
}
|
||||
|
||||
/// <summary>The key ID for the key used to encrypt the data.</summary>
|
||||
public long KeyId
|
||||
{
|
||||
get { return keyData.KeyId; }
|
||||
}
|
||||
|
||||
/// <summary>Return the decrypted data stream for the packet.</summary>
|
||||
public Stream GetDataStream(
|
||||
PgpPrivateKey privKey)
|
||||
{
|
||||
IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm);
|
||||
|
||||
try
|
||||
{
|
||||
c1.Init(false, privKey.Key);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new PgpException("error setting asymmetric cipher", e);
|
||||
}
|
||||
|
||||
BigInteger[] keyD = keyData.GetEncSessionKey();
|
||||
|
||||
if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
|
||||
|| keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
|
||||
{
|
||||
c1.ProcessBytes(keyD[0].ToByteArrayUnsigned());
|
||||
}
|
||||
else
|
||||
{
|
||||
ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key;
|
||||
int size = (k.Parameters.P.BitLength + 7) / 8;
|
||||
|
||||
byte[] bi = keyD[0].ToByteArray();
|
||||
|
||||
int diff = bi.Length - size;
|
||||
if (diff >= 0)
|
||||
{
|
||||
c1.ProcessBytes(bi, diff, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] zeros = new byte[-diff];
|
||||
c1.ProcessBytes(zeros);
|
||||
c1.ProcessBytes(bi);
|
||||
}
|
||||
|
||||
bi = keyD[1].ToByteArray();
|
||||
|
||||
diff = bi.Length - size;
|
||||
if (diff >= 0)
|
||||
{
|
||||
c1.ProcessBytes(bi, diff, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] zeros = new byte[-diff];
|
||||
c1.ProcessBytes(zeros);
|
||||
c1.ProcessBytes(bi);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] plain;
|
||||
try
|
||||
{
|
||||
plain = c1.DoFinal();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("exception decrypting secret key", e);
|
||||
}
|
||||
|
||||
if (!ConfirmCheckSum(plain))
|
||||
throw new PgpKeyValidationException("key checksum failed");
|
||||
|
||||
IBufferedCipher c2;
|
||||
string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]);
|
||||
string cName = cipherName;
|
||||
|
||||
try
|
||||
{
|
||||
if (encData is SymmetricEncIntegrityPacket)
|
||||
{
|
||||
cName += "/CFB/NoPadding";
|
||||
}
|
||||
else
|
||||
{
|
||||
cName += "/OpenPGPCFB/NoPadding";
|
||||
}
|
||||
|
||||
c2 = CipherUtilities.GetCipher(cName);
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("exception creating cipher", e);
|
||||
}
|
||||
|
||||
if (c2 == null)
|
||||
return encData.GetInputStream();
|
||||
|
||||
try
|
||||
{
|
||||
KeyParameter key = ParameterUtilities.CreateKeyParameter(
|
||||
cipherName, plain, 1, plain.Length - 3);
|
||||
|
||||
byte[] iv = new byte[c2.GetBlockSize()];
|
||||
|
||||
c2.Init(false, new ParametersWithIV(key, iv));
|
||||
|
||||
encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null));
|
||||
|
||||
if (encData is SymmetricEncIntegrityPacket)
|
||||
{
|
||||
truncStream = new TruncatedStream(encStream);
|
||||
|
||||
string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
|
||||
IDigest digest = DigestUtilities.GetDigest(digestName);
|
||||
|
||||
encStream = new DigestStream(truncStream, digest, null);
|
||||
}
|
||||
|
||||
if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
|
||||
int v1 = encStream.ReadByte();
|
||||
int v2 = encStream.ReadByte();
|
||||
|
||||
if (v1 < 0 || v2 < 0)
|
||||
throw new EndOfStreamException("unexpected end of stream.");
|
||||
|
||||
// Note: the oracle attack on the "quick check" bytes is deemed
|
||||
// a security risk for typical public key encryption usages,
|
||||
// therefore we do not perform the check.
|
||||
|
||||
// bool repeatCheckPassed =
|
||||
// iv[iv.Length - 2] == (byte)v1
|
||||
// && iv[iv.Length - 1] == (byte)v2;
|
||||
//
|
||||
// // Note: some versions of PGP appear to produce 0 for the extra
|
||||
// // bytes rather than repeating the two previous bytes
|
||||
// bool zeroesCheckPassed =
|
||||
// v1 == 0
|
||||
// && v2 == 0;
|
||||
//
|
||||
// if (!repeatCheckPassed && !zeroesCheckPassed)
|
||||
// {
|
||||
// throw new PgpDataValidationException("quick check failed.");
|
||||
// }
|
||||
|
||||
return encStream;
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception starting decryption", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
187
iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs
Normal file
187
iTechSharp/srcbc/openpgp/PgpPublicKeyRing.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Class to hold a single master public key and its subkeys.
|
||||
/// <p>
|
||||
/// Often PGP keyring files consist of multiple master keys, if you are trying to process
|
||||
/// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
public class PgpPublicKeyRing
|
||||
: PgpKeyRing
|
||||
{
|
||||
private readonly ArrayList keys;
|
||||
|
||||
public PgpPublicKeyRing(
|
||||
byte[] encoding)
|
||||
: this(new MemoryStream(encoding, false))
|
||||
{
|
||||
}
|
||||
|
||||
internal PgpPublicKeyRing(
|
||||
ArrayList pubKeys)
|
||||
{
|
||||
this.keys = pubKeys;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRing(
|
||||
Stream inputStream)
|
||||
{
|
||||
this.keys = new ArrayList();
|
||||
|
||||
BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
|
||||
|
||||
PacketTag initialTag = bcpgInput.NextPacketTag();
|
||||
if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
|
||||
{
|
||||
throw new IOException("public key ring doesn't start with public key tag: "
|
||||
+ "tag 0x" + ((int)initialTag).ToString("X"));
|
||||
}
|
||||
|
||||
PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
|
||||
TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
|
||||
|
||||
// direct signatures and revocations
|
||||
ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput);
|
||||
|
||||
ArrayList ids, idTrusts, idSigs;
|
||||
ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
|
||||
|
||||
keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
|
||||
|
||||
|
||||
// Read subkeys
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
|
||||
{
|
||||
PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket();
|
||||
TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
|
||||
|
||||
// PGP 8 actually leaves out the signature.
|
||||
ArrayList sigList = ReadSignaturesAndTrust(bcpgInput);
|
||||
|
||||
keys.Add(new PgpPublicKey(pk, kTrust, sigList));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Return the first public key in the ring.</summary>
|
||||
public PgpPublicKey GetPublicKey()
|
||||
{
|
||||
return (PgpPublicKey) keys[0];
|
||||
}
|
||||
|
||||
/// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
|
||||
public PgpPublicKey GetPublicKey(
|
||||
long keyId)
|
||||
{
|
||||
foreach (PgpPublicKey k in keys)
|
||||
{
|
||||
if (keyId == k.KeyId)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of all the public keys.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
|
||||
public IEnumerable GetPublicKeys()
|
||||
{
|
||||
return new EnumerableProxy(keys);
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
|
||||
Encode(bOut);
|
||||
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
throw new ArgumentNullException("outStr");
|
||||
|
||||
foreach (PgpPublicKey k in keys)
|
||||
{
|
||||
k.Encode(outStr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new key ring with the public key passed in either added or
|
||||
/// replacing an existing one.
|
||||
/// </summary>
|
||||
/// <param name="pubRing">The public key ring to be modified.</param>
|
||||
/// <param name="pubKey">The public key to be inserted.</param>
|
||||
/// <returns>A new <c>PgpPublicKeyRing</c></returns>
|
||||
public static PgpPublicKeyRing InsertPublicKey(
|
||||
PgpPublicKeyRing pubRing,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
ArrayList keys = new ArrayList(pubRing.keys);
|
||||
bool found = false;
|
||||
bool masterFound = false;
|
||||
|
||||
for (int i = 0; i != keys.Count; i++)
|
||||
{
|
||||
PgpPublicKey key = (PgpPublicKey) keys[i];
|
||||
|
||||
if (key.KeyId == pubKey.KeyId)
|
||||
{
|
||||
found = true;
|
||||
keys[i] = pubKey;
|
||||
}
|
||||
if (key.IsMasterKey)
|
||||
{
|
||||
masterFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (pubKey.IsMasterKey && masterFound)
|
||||
throw new ArgumentException("cannot add a master key to a ring that already has one");
|
||||
|
||||
keys.Add(pubKey);
|
||||
}
|
||||
|
||||
return new PgpPublicKeyRing(keys);
|
||||
}
|
||||
|
||||
/// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
|
||||
/// <param name="pubRing">The public key ring to be modified.</param>
|
||||
/// <param name="pubKey">The public key to be removed.</param>
|
||||
/// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
|
||||
public static PgpPublicKeyRing RemovePublicKey(
|
||||
PgpPublicKeyRing pubRing,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
ArrayList keys = new ArrayList(pubRing.keys);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
PgpPublicKey key = (PgpPublicKey) keys[i];
|
||||
|
||||
if (key.KeyId == pubKey.KeyId)
|
||||
{
|
||||
found = true;
|
||||
keys.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return found ? new PgpPublicKeyRing(keys) : null;
|
||||
}
|
||||
}
|
||||
}
|
269
iTechSharp/srcbc/openpgp/PgpPublicKeyRingBundle.cs
Normal file
269
iTechSharp/srcbc/openpgp/PgpPublicKeyRingBundle.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
|
||||
/// If you want to read an entire public key file in one hit this is the class for you.
|
||||
/// </remarks>
|
||||
public class PgpPublicKeyRingBundle
|
||||
{
|
||||
private readonly IDictionary pubRings;
|
||||
private readonly ArrayList order;
|
||||
|
||||
private PgpPublicKeyRingBundle(
|
||||
IDictionary pubRings,
|
||||
ArrayList order)
|
||||
{
|
||||
this.pubRings = pubRings;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(
|
||||
byte[] encoding)
|
||||
: this(new MemoryStream(encoding, false))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Build a PgpPubliKeyRingBundle from the passed in input stream.</summary>
|
||||
/// <param name="inputStream">Input stream containing data.</param>
|
||||
/// <exception cref="IOException">If a problem parsing the stream occurs.</exception>
|
||||
/// <exception cref="PgpException">If an object is encountered which isn't a PgpPublicKeyRing.</exception>
|
||||
public PgpPublicKeyRingBundle(
|
||||
Stream inputStream)
|
||||
: this(new PgpObjectFactory(inputStream).AllPgpObjects())
|
||||
{
|
||||
}
|
||||
|
||||
public PgpPublicKeyRingBundle(
|
||||
IEnumerable e)
|
||||
{
|
||||
this.pubRings = new Hashtable();
|
||||
this.order = new ArrayList();
|
||||
|
||||
foreach (object obj in e)
|
||||
{
|
||||
PgpPublicKeyRing pgpPub = obj as PgpPublicKeyRing;
|
||||
|
||||
if (pgpPub == null)
|
||||
{
|
||||
throw new PgpException(obj.GetType().FullName + " found where PgpPublicKeyRing expected");
|
||||
}
|
||||
|
||||
long key = pgpPub.GetPublicKey().KeyId;
|
||||
pubRings.Add(key, pgpPub);
|
||||
order.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size
|
||||
{
|
||||
get { return order.Count; }
|
||||
}
|
||||
|
||||
/// <summary>Return the number of rings in this collection.</summary>
|
||||
public int Count
|
||||
{
|
||||
get { return order.Count; }
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the public key rings making up this collection.</summary>
|
||||
public IEnumerable GetKeyRings()
|
||||
{
|
||||
return new EnumerableProxy(pubRings.Values);
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
|
||||
/// <param name="userId">The user ID to be matched.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
|
||||
public IEnumerable GetKeyRings(
|
||||
string userId)
|
||||
{
|
||||
return GetKeyRings(userId, false, false);
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
|
||||
/// <param name="userId">The user ID to be matched.</param>
|
||||
/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
|
||||
public IEnumerable GetKeyRings(
|
||||
string userId,
|
||||
bool matchPartial)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial, false);
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
|
||||
/// <param name="userId">The user ID to be matched.</param>
|
||||
/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
|
||||
/// <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
|
||||
public IEnumerable GetKeyRings(
|
||||
string userId,
|
||||
bool matchPartial,
|
||||
bool ignoreCase)
|
||||
{
|
||||
IList rings = new ArrayList();
|
||||
|
||||
if (ignoreCase)
|
||||
{
|
||||
userId = userId.ToLower(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
foreach (PgpPublicKeyRing pubRing in GetKeyRings())
|
||||
{
|
||||
foreach (string nextUserID in pubRing.GetPublicKey().GetUserIds())
|
||||
{
|
||||
string next = nextUserID;
|
||||
if (ignoreCase)
|
||||
{
|
||||
next = next.ToLower(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (matchPartial)
|
||||
{
|
||||
if (next.IndexOf(userId) > -1)
|
||||
{
|
||||
rings.Add(pubRing);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next.Equals(userId))
|
||||
{
|
||||
rings.Add(pubRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new EnumerableProxy(rings);
|
||||
}
|
||||
|
||||
/// <summary>Return the PGP public key associated with the given key id.</summary>
|
||||
/// <param name="keyId">The ID of the public key to return.</param>
|
||||
public PgpPublicKey GetPublicKey(
|
||||
long keyId)
|
||||
{
|
||||
foreach (PgpPublicKeyRing pubRing in GetKeyRings())
|
||||
{
|
||||
PgpPublicKey pub = pubRing.GetPublicKey(keyId);
|
||||
|
||||
if (pub != null)
|
||||
{
|
||||
return pub;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Return the public key ring which contains the key referred to by keyId</summary>
|
||||
/// <param name="keyId">The ID of the public key</param>
|
||||
public PgpPublicKeyRing GetPublicKeyRing(
|
||||
long keyId)
|
||||
{
|
||||
if (pubRings.Contains(keyId))
|
||||
{
|
||||
return (PgpPublicKeyRing)pubRings[keyId];
|
||||
}
|
||||
|
||||
foreach (PgpPublicKeyRing pubRing in GetKeyRings())
|
||||
{
|
||||
PgpPublicKey pub = pubRing.GetPublicKey(keyId);
|
||||
|
||||
if (pub != null)
|
||||
{
|
||||
return pubRing;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
|
||||
Encode(bOut);
|
||||
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
|
||||
|
||||
foreach (long key in order)
|
||||
{
|
||||
PgpPublicKeyRing sec = (PgpPublicKeyRing) pubRings[key];
|
||||
|
||||
sec.Encode(bcpgOut);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a new bundle containing the contents of the passed in bundle and
|
||||
/// the passed in public key ring.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be added to.</param>
|
||||
/// <param name="publicKeyRing">The key ring to be added.</param>
|
||||
/// <returns>A new <c>PgpPublicKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
|
||||
/// <exception cref="ArgumentException">If the keyId for the passed in key ring is already present.</exception>
|
||||
public static PgpPublicKeyRingBundle AddPublicKeyRing(
|
||||
PgpPublicKeyRingBundle bundle,
|
||||
PgpPublicKeyRing publicKeyRing)
|
||||
{
|
||||
long key = publicKeyRing.GetPublicKey().KeyId;
|
||||
|
||||
if (bundle.pubRings.Contains(key))
|
||||
{
|
||||
throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
|
||||
}
|
||||
|
||||
IDictionary newPubRings = new Hashtable(bundle.pubRings);
|
||||
ArrayList newOrder = new ArrayList(bundle.order);
|
||||
|
||||
newPubRings[key] = publicKeyRing;
|
||||
|
||||
newOrder.Add(key);
|
||||
|
||||
return new PgpPublicKeyRingBundle(newPubRings, newOrder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a new bundle containing the contents of the passed in bundle with
|
||||
/// the passed in public key ring removed.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be removed from.</param>
|
||||
/// <param name="publicKeyRing">The key ring to be removed.</param>
|
||||
/// <returns>A new <c>PgpPublicKeyRingBundle</c> not containing the passed in key ring.</returns>
|
||||
/// <exception cref="ArgumentException">If the keyId for the passed in key ring is not present.</exception>
|
||||
public static PgpPublicKeyRingBundle RemovePublicKeyRing(
|
||||
PgpPublicKeyRingBundle bundle,
|
||||
PgpPublicKeyRing publicKeyRing)
|
||||
{
|
||||
long key = publicKeyRing.GetPublicKey().KeyId;
|
||||
|
||||
if (!bundle.pubRings.Contains(key))
|
||||
{
|
||||
throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
|
||||
}
|
||||
|
||||
IDictionary newPubRings = new Hashtable(bundle.pubRings);
|
||||
ArrayList newOrder = new ArrayList(bundle.order);
|
||||
|
||||
newPubRings.Remove(key);
|
||||
newOrder.Remove(key);
|
||||
|
||||
return new PgpPublicKeyRingBundle(newPubRings, newOrder);
|
||||
}
|
||||
}
|
||||
}
|
707
iTechSharp/srcbc/openpgp/PgpSecretKey.cs
Normal file
707
iTechSharp/srcbc/openpgp/PgpSecretKey.cs
Normal file
@@ -0,0 +1,707 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>General class to handle a PGP secret key object.</remarks>
|
||||
public class PgpSecretKey
|
||||
{
|
||||
private SecretKeyPacket secret;
|
||||
private TrustPacket trust;
|
||||
private ArrayList keySigs;
|
||||
private ArrayList ids;
|
||||
private ArrayList idTrusts;
|
||||
private ArrayList idSigs;
|
||||
private PgpPublicKey pub;
|
||||
private ArrayList subSigs;
|
||||
|
||||
/// <summary>Copy constructor - master key.</summary>
|
||||
private PgpSecretKey(
|
||||
SecretKeyPacket secret,
|
||||
TrustPacket trust,
|
||||
ArrayList keySigs,
|
||||
ArrayList ids,
|
||||
ArrayList idTrusts,
|
||||
ArrayList idSigs,
|
||||
PgpPublicKey pub)
|
||||
{
|
||||
this.secret = secret;
|
||||
this.trust = trust;
|
||||
this.keySigs = keySigs;
|
||||
this.ids = ids;
|
||||
this.idTrusts = idTrusts;
|
||||
this.idSigs = idSigs;
|
||||
this.pub = pub;
|
||||
}
|
||||
|
||||
/// <summary>Copy constructor - subkey.</summary>
|
||||
private PgpSecretKey(
|
||||
SecretKeyPacket secret,
|
||||
TrustPacket trust,
|
||||
ArrayList subSigs,
|
||||
PgpPublicKey pub)
|
||||
{
|
||||
this.secret = secret;
|
||||
this.trust = trust;
|
||||
this.subSigs = subSigs;
|
||||
this.pub = pub;
|
||||
}
|
||||
|
||||
internal PgpSecretKey(
|
||||
SecretKeyPacket secret,
|
||||
TrustPacket trust,
|
||||
ArrayList keySigs,
|
||||
ArrayList ids,
|
||||
ArrayList idTrusts,
|
||||
ArrayList idSigs)
|
||||
{
|
||||
this.secret = secret;
|
||||
this.trust = trust;
|
||||
this.keySigs = keySigs;
|
||||
this.ids = ids;
|
||||
this.idTrusts = idTrusts;
|
||||
this.idSigs = idSigs;
|
||||
this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs);
|
||||
}
|
||||
|
||||
internal PgpSecretKey(
|
||||
SecretKeyPacket secret,
|
||||
TrustPacket trust,
|
||||
ArrayList subSigs)
|
||||
{
|
||||
this.secret = secret;
|
||||
this.trust = trust;
|
||||
this.subSigs = subSigs;
|
||||
this.pub = new PgpPublicKey(secret.PublicKeyPacket, trust, subSigs);
|
||||
}
|
||||
|
||||
/// <summary>Create a subkey</summary>
|
||||
internal PgpSecretKey(
|
||||
PgpKeyPair keyPair,
|
||||
TrustPacket trust,
|
||||
ArrayList subSigs,
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
char[] passPhrase,
|
||||
bool useSHA1,
|
||||
SecureRandom rand)
|
||||
: this(keyPair, encAlgorithm, passPhrase, useSHA1, rand)
|
||||
{
|
||||
this.secret = new SecretSubkeyPacket(
|
||||
secret.PublicKeyPacket,
|
||||
secret.EncAlgorithm,
|
||||
secret.S2kUsage,
|
||||
secret.S2k,
|
||||
secret.GetIV(),
|
||||
secret.GetSecretKeyData());
|
||||
|
||||
this.trust = trust;
|
||||
this.subSigs = subSigs;
|
||||
this.pub = new PgpPublicKey(keyPair.PublicKey, trust, subSigs);
|
||||
}
|
||||
|
||||
internal PgpSecretKey(
|
||||
PgpKeyPair keyPair,
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
char[] passPhrase,
|
||||
bool useSHA1,
|
||||
SecureRandom rand)
|
||||
{
|
||||
PublicKeyPacket pubPk = keyPair.PublicKey.publicPk;
|
||||
|
||||
BcpgObject secKey;
|
||||
switch (keyPair.PublicKey.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) keyPair.PrivateKey.Key;
|
||||
secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) keyPair.PrivateKey.Key;
|
||||
secKey = new DsaSecretBcpgKey(dsK.X);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) keyPair.PrivateKey.Key;
|
||||
secKey = new ElGamalSecretBcpgKey(esK.X);
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown key class");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
|
||||
|
||||
pOut.WriteObject(secKey);
|
||||
|
||||
byte[] keyData = bOut.ToArray();
|
||||
byte[] checksumBytes = Checksum(useSHA1, keyData, keyData.Length);
|
||||
|
||||
pOut.Write(checksumBytes);
|
||||
|
||||
byte[] bOutData = bOut.ToArray();
|
||||
|
||||
if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
this.secret = new SecretKeyPacket(pubPk, encAlgorithm, null, null, bOutData);
|
||||
}
|
||||
else
|
||||
{
|
||||
S2k s2k;
|
||||
byte[] iv;
|
||||
byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv);
|
||||
|
||||
int usage = useSHA1
|
||||
? SecretKeyPacket.UsageSha1
|
||||
: SecretKeyPacket.UsageChecksum;
|
||||
|
||||
this.secret = new SecretKeyPacket(pubPk, encAlgorithm, usage, s2k, iv, encData);
|
||||
}
|
||||
|
||||
this.trust = null;
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", e);
|
||||
}
|
||||
|
||||
this.keySigs = new ArrayList();
|
||||
}
|
||||
|
||||
public PgpSecretKey(
|
||||
int certificationLevel,
|
||||
PgpKeyPair keyPair,
|
||||
string id,
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
char[] passPhrase,
|
||||
PgpSignatureSubpacketVector hashedPackets,
|
||||
PgpSignatureSubpacketVector unhashedPackets,
|
||||
SecureRandom rand)
|
||||
: this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, 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(keyPair, encAlgorithm, passPhrase, useSHA1, rand)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.trust = null;
|
||||
this.ids = new ArrayList();
|
||||
ids.Add(id);
|
||||
|
||||
this.idTrusts = new ArrayList();
|
||||
idTrusts.Add(null);
|
||||
|
||||
this.idSigs = new ArrayList();
|
||||
|
||||
PgpSignatureGenerator sGen = new PgpSignatureGenerator(
|
||||
keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
|
||||
|
||||
//
|
||||
// Generate the certification
|
||||
//
|
||||
sGen.InitSign(certificationLevel, keyPair.PrivateKey);
|
||||
|
||||
sGen.SetHashedSubpackets(hashedPackets);
|
||||
sGen.SetUnhashedSubpackets(unhashedPackets);
|
||||
|
||||
PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
|
||||
this.pub = PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
|
||||
|
||||
ArrayList sigList = new ArrayList();
|
||||
sigList.Add(certification);
|
||||
idSigs.Add(sigList);
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", e);
|
||||
}
|
||||
}
|
||||
|
||||
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, 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)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>True, if this key is marked as suitable for signature generation.</summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>True, if this is a master key.</summary>
|
||||
public bool IsMasterKey
|
||||
{
|
||||
get { return subSigs == null; }
|
||||
}
|
||||
|
||||
/// <summary>The algorithm the key is encrypted with.</summary>
|
||||
public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm
|
||||
{
|
||||
get { return secret.EncAlgorithm; }
|
||||
}
|
||||
|
||||
/// <summary>The key ID of the public key associated with this key.</summary>
|
||||
public long KeyId
|
||||
{
|
||||
get { return pub.KeyId; }
|
||||
}
|
||||
|
||||
/// <summary>The public key associated with this key.</summary>
|
||||
public PgpPublicKey PublicKey
|
||||
{
|
||||
get { return pub; }
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of any user IDs associated with the key.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
|
||||
public IEnumerable UserIds
|
||||
{
|
||||
get { return pub.GetUserIds(); }
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
|
||||
public IEnumerable UserAttributes
|
||||
{
|
||||
get { return pub.GetUserAttributes(); }
|
||||
}
|
||||
|
||||
private byte[] ExtractKeyData(
|
||||
char[] passPhrase)
|
||||
{
|
||||
SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm;
|
||||
byte[] encData = secret.GetSecretKeyData();
|
||||
|
||||
if (alg == SymmetricKeyAlgorithmTag.Null)
|
||||
return encData;
|
||||
|
||||
byte[] data;
|
||||
IBufferedCipher c = null;
|
||||
try
|
||||
{
|
||||
string cName = PgpUtilities.GetSymmetricCipherName(alg);
|
||||
c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", e);
|
||||
}
|
||||
|
||||
// TODO Factor this block out as 'encryptData'
|
||||
try
|
||||
{
|
||||
KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
|
||||
byte[] iv = secret.GetIV();
|
||||
|
||||
if (secret.PublicKeyPacket.Version == 4)
|
||||
{
|
||||
c.Init(false, new ParametersWithIV(key, iv));
|
||||
|
||||
data = c.DoFinal(encData);
|
||||
|
||||
bool useSHA1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
|
||||
byte[] check = Checksum(useSHA1, data, (useSHA1) ? data.Length - 20 : data.Length - 2);
|
||||
|
||||
for (int i = 0; i != check.Length; i++)
|
||||
{
|
||||
if (check[i] != data[data.Length - check.Length + i])
|
||||
{
|
||||
throw new PgpException("Checksum mismatch at " + i + " of " + check.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // version 2 or 3, RSA only.
|
||||
{
|
||||
data = new byte[encData.Length];
|
||||
|
||||
//
|
||||
// read in the four numbers
|
||||
//
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i != 4; i++)
|
||||
{
|
||||
c.Init(false, new ParametersWithIV(key, iv));
|
||||
|
||||
int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
|
||||
|
||||
data[pos] = encData[pos];
|
||||
data[pos + 1] = encData[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
c.DoFinal(encData, pos, encLen, data, pos);
|
||||
pos += encLen;
|
||||
|
||||
if (i != 3)
|
||||
{
|
||||
Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// verify Checksum
|
||||
//
|
||||
int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
|
||||
int calcCs = 0;
|
||||
for (int j=0; j < data.Length-2; j++)
|
||||
{
|
||||
calcCs += data[j] & 0xff;
|
||||
}
|
||||
|
||||
calcCs &= 0xffff;
|
||||
if (calcCs != cs)
|
||||
{
|
||||
throw new PgpException("Checksum mismatch: passphrase wrong, expected "
|
||||
+ cs.ToString("X")
|
||||
+ " found " + calcCs.ToString("X"));
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception decrypting key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
|
||||
public PgpPrivateKey ExtractPrivateKey(
|
||||
char[] passPhrase)
|
||||
{
|
||||
byte[] secKeyData = secret.GetSecretKeyData();
|
||||
if (secKeyData == null || secKeyData.Length < 1)
|
||||
return null;
|
||||
|
||||
PublicKeyPacket pubPk = secret.PublicKeyPacket;
|
||||
try
|
||||
{
|
||||
byte[] data = ExtractKeyData(passPhrase);
|
||||
BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false));
|
||||
AsymmetricKeyParameter privateKey;
|
||||
switch (pubPk.Algorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaEncrypt:
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key;
|
||||
RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn);
|
||||
RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters(
|
||||
rsaPriv.Modulus,
|
||||
rsaPub.PublicExponent,
|
||||
rsaPriv.PrivateExponent,
|
||||
rsaPriv.PrimeP,
|
||||
rsaPriv.PrimeQ,
|
||||
rsaPriv.PrimeExponentP,
|
||||
rsaPriv.PrimeExponentQ,
|
||||
rsaPriv.CrtCoefficient);
|
||||
privateKey = rsaPrivSpec;
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key;
|
||||
DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn);
|
||||
DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G);
|
||||
privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams);
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt:
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key;
|
||||
ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn);
|
||||
ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G);
|
||||
privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams);
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown public key algorithm encountered");
|
||||
}
|
||||
|
||||
return new PgpPrivateKey(privateKey, KeyId);
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception constructing key", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] Checksum(
|
||||
bool useSHA1,
|
||||
byte[] bytes,
|
||||
int length)
|
||||
{
|
||||
if (useSHA1)
|
||||
{
|
||||
try
|
||||
{
|
||||
IDigest dig = DigestUtilities.GetDigest("SHA1");
|
||||
dig.BlockUpdate(bytes, 0, length);
|
||||
return DigestUtilities.DoFinal(dig);
|
||||
}
|
||||
//catch (NoSuchAlgorithmException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Can't find SHA-1", e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int Checksum = 0;
|
||||
for (int i = 0; i != length; i++)
|
||||
{
|
||||
Checksum += bytes[i];
|
||||
}
|
||||
|
||||
return new byte[] { (byte)(Checksum >> 8), (byte)Checksum };
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
Encode(bOut);
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
|
||||
|
||||
bcpgOut.WritePacket(secret);
|
||||
if (trust != null)
|
||||
{
|
||||
bcpgOut.WritePacket(trust);
|
||||
}
|
||||
|
||||
if (subSigs == null) // is not a sub key
|
||||
{
|
||||
foreach (PgpSignature keySig in keySigs)
|
||||
{
|
||||
keySig.Encode(bcpgOut);
|
||||
}
|
||||
|
||||
for (int i = 0; i != ids.Count; i++)
|
||||
{
|
||||
if (ids[i] is string)
|
||||
{
|
||||
string id = (string) ids[i];
|
||||
|
||||
bcpgOut.WritePacket(new UserIdPacket(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i];
|
||||
bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
|
||||
}
|
||||
|
||||
if (idTrusts[i] != null)
|
||||
{
|
||||
bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
|
||||
}
|
||||
|
||||
foreach (PgpSignature sig in (ArrayList) idSigs[i])
|
||||
{
|
||||
sig.Encode(bcpgOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (PgpSignature subSig in subSigs)
|
||||
{
|
||||
subSig.Encode(bcpgOut);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Check that this is right/necessary
|
||||
//bcpgOut.Finish();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a copy of the passed in secret key, encrypted using a new password
|
||||
/// and the passed in algorithm.
|
||||
/// </summary>
|
||||
/// <param name="key">The PgpSecretKey to be copied.</param>
|
||||
/// <param name="oldPassPhrase">The current password for the key.</param>
|
||||
/// <param name="newPassPhrase">The new password for the key.</param>
|
||||
/// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
|
||||
/// <param name="rand">Source of randomness.</param>
|
||||
public static PgpSecretKey CopyWithNewPassword(
|
||||
PgpSecretKey key,
|
||||
char[] oldPassPhrase,
|
||||
char[] newPassPhrase,
|
||||
SymmetricKeyAlgorithmTag newEncAlgorithm,
|
||||
SecureRandom rand)
|
||||
{
|
||||
byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase);
|
||||
int s2kUsage = key.secret.S2kUsage;
|
||||
byte[] iv = null;
|
||||
S2k s2k = null;
|
||||
byte[] keyData;
|
||||
|
||||
if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
|
||||
{
|
||||
s2kUsage = SecretKeyPacket.UsageNone;
|
||||
if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum
|
||||
{
|
||||
keyData = new byte[rawKeyData.Length - 18];
|
||||
|
||||
Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);
|
||||
|
||||
byte[] check = Checksum(false, keyData, keyData.Length - 2);
|
||||
|
||||
keyData[keyData.Length - 2] = check[0];
|
||||
keyData[keyData.Length - 1] = check[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
keyData = rawKeyData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
|
||||
}
|
||||
catch (PgpException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception encrypting key", e);
|
||||
}
|
||||
}
|
||||
|
||||
SecretKeyPacket secret;
|
||||
if (key.secret is SecretSubkeyPacket)
|
||||
{
|
||||
secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
|
||||
newEncAlgorithm, s2kUsage, s2k, iv, keyData);
|
||||
}
|
||||
else
|
||||
{
|
||||
secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
|
||||
newEncAlgorithm, s2kUsage, s2k, iv, keyData);
|
||||
}
|
||||
|
||||
if (key.subSigs == null)
|
||||
{
|
||||
return new PgpSecretKey(secret, key.trust, key.keySigs, key.ids,
|
||||
key.idTrusts, key.idSigs, key.pub);
|
||||
}
|
||||
|
||||
return new PgpSecretKey(secret, key.trust, key.subSigs, key.pub);
|
||||
}
|
||||
|
||||
private static byte[] EncryptKeyData(
|
||||
byte[] rawKeyData,
|
||||
SymmetricKeyAlgorithmTag encAlgorithm,
|
||||
char[] passPhrase,
|
||||
SecureRandom random,
|
||||
out S2k s2k,
|
||||
out byte[] iv)
|
||||
{
|
||||
IBufferedCipher c;
|
||||
try
|
||||
{
|
||||
string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
|
||||
c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("Exception creating cipher", e);
|
||||
}
|
||||
|
||||
byte[] s2kIV = new byte[8];
|
||||
random.NextBytes(s2kIV);
|
||||
s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60);
|
||||
|
||||
KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);
|
||||
|
||||
iv = new byte[c.GetBlockSize()];
|
||||
random.NextBytes(iv);
|
||||
|
||||
c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random));
|
||||
|
||||
return c.DoFinal(rawKeyData);
|
||||
}
|
||||
}
|
||||
}
|
208
iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs
Normal file
208
iTechSharp/srcbc/openpgp/PgpSecretKeyRing.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Class to hold a single master secret key and its subkeys.
|
||||
/// <p>
|
||||
/// Often PGP keyring files consist of multiple master keys, if you are trying to process
|
||||
/// or construct one of these you should use the <c>PgpSecretKeyRingBundle</c> class.
|
||||
/// </p>
|
||||
/// </remarks>
|
||||
public class PgpSecretKeyRing
|
||||
: PgpKeyRing
|
||||
{
|
||||
private readonly ArrayList keys;
|
||||
|
||||
internal PgpSecretKeyRing(
|
||||
ArrayList keys)
|
||||
{
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing(
|
||||
byte[] encoding)
|
||||
: this(new MemoryStream(encoding))
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRing(
|
||||
Stream inputStream)
|
||||
{
|
||||
this.keys = new ArrayList();
|
||||
|
||||
BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
|
||||
|
||||
PacketTag initialTag = bcpgInput.NextPacketTag();
|
||||
if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey)
|
||||
{
|
||||
throw new IOException("secret key ring doesn't start with secret key tag: "
|
||||
+ "tag 0x" + ((int)initialTag).ToString("X"));
|
||||
}
|
||||
|
||||
SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket();
|
||||
|
||||
//
|
||||
// ignore GPG comment packets if found.
|
||||
//
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
|
||||
{
|
||||
bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
TrustPacket trust = ReadOptionalTrustPacket(bcpgInput);
|
||||
|
||||
// revocation and direct signatures
|
||||
ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput);
|
||||
|
||||
ArrayList ids, idTrusts, idSigs;
|
||||
ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
|
||||
|
||||
keys.Add(new PgpSecretKey(secret, trust, keySigs, ids, idTrusts, idSigs));
|
||||
|
||||
|
||||
// Read subkeys
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey)
|
||||
{
|
||||
SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket();
|
||||
|
||||
//
|
||||
// ignore GPG comment packets if found.
|
||||
//
|
||||
while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
|
||||
{
|
||||
bcpgInput.ReadPacket();
|
||||
}
|
||||
|
||||
TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
|
||||
ArrayList sigList = ReadSignaturesAndTrust(bcpgInput);
|
||||
|
||||
keys.Add(new PgpSecretKey(sub, subTrust, sigList));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Return the public key for the master key.</summary>
|
||||
public PgpPublicKey GetPublicKey()
|
||||
{
|
||||
return ((PgpSecretKey) keys[0]).PublicKey;
|
||||
}
|
||||
|
||||
/// <summary>Return the master private key.</summary>
|
||||
public PgpSecretKey GetSecretKey()
|
||||
{
|
||||
return (PgpSecretKey) keys[0];
|
||||
}
|
||||
|
||||
/// <summary>Allows enumeration of the secret keys.</summary>
|
||||
/// <returns>An <c>IEnumerable</c> of <c>PgpSecretKey</c> objects.</returns>
|
||||
public IEnumerable GetSecretKeys()
|
||||
{
|
||||
return new EnumerableProxy(keys);
|
||||
}
|
||||
|
||||
public PgpSecretKey GetSecretKey(
|
||||
long keyId)
|
||||
{
|
||||
foreach (PgpSecretKey k in keys)
|
||||
{
|
||||
if (keyId == k.KeyId)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
|
||||
Encode(bOut);
|
||||
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
if (outStr == null)
|
||||
throw new ArgumentNullException("outStr");
|
||||
|
||||
foreach (PgpSecretKey k in keys)
|
||||
{
|
||||
k.Encode(outStr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new key ring with the secret key passed in either added or
|
||||
/// replacing an existing one with the same key ID.
|
||||
/// </summary>
|
||||
/// <param name="secRing">The secret key ring to be modified.</param>
|
||||
/// <param name="secKey">The secret key to be inserted.</param>
|
||||
/// <returns>A new <c>PgpSecretKeyRing</c></returns>
|
||||
public static PgpSecretKeyRing InsertSecretKey(
|
||||
PgpSecretKeyRing secRing,
|
||||
PgpSecretKey secKey)
|
||||
{
|
||||
ArrayList keys = new ArrayList(secRing.keys);
|
||||
bool found = false;
|
||||
bool masterFound = false;
|
||||
|
||||
for (int i = 0; i != keys.Count; i++)
|
||||
{
|
||||
PgpSecretKey key = (PgpSecretKey) keys[i];
|
||||
|
||||
if (key.KeyId == secKey.KeyId)
|
||||
{
|
||||
found = true;
|
||||
keys[i] = secKey;
|
||||
}
|
||||
if (key.IsMasterKey)
|
||||
{
|
||||
masterFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (secKey.IsMasterKey && masterFound)
|
||||
throw new ArgumentException("cannot add a master key to a ring that already has one");
|
||||
|
||||
keys.Add(secKey);
|
||||
}
|
||||
|
||||
return new PgpSecretKeyRing(keys);
|
||||
}
|
||||
|
||||
/// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary>
|
||||
/// <param name="secRing">The secret key ring to be modified.</param>
|
||||
/// <param name="secKey">The secret key to be removed.</param>
|
||||
/// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns>
|
||||
public static PgpSecretKeyRing RemoveSecretKey(
|
||||
PgpSecretKeyRing secRing,
|
||||
PgpSecretKey secKey)
|
||||
{
|
||||
ArrayList keys = new ArrayList(secRing.keys);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
PgpSecretKey key = (PgpSecretKey)keys[i];
|
||||
|
||||
if (key.KeyId == secKey.KeyId)
|
||||
{
|
||||
found = true;
|
||||
keys.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return found ? new PgpSecretKeyRing(keys) : null;
|
||||
}
|
||||
}
|
||||
}
|
270
iTechSharp/srcbc/openpgp/PgpSecretKeyRingBundle.cs
Normal file
270
iTechSharp/srcbc/openpgp/PgpSecretKeyRingBundle.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>
|
||||
/// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
|
||||
/// If you want to read an entire secret key file in one hit this is the class for you.
|
||||
/// </remarks>
|
||||
public class PgpSecretKeyRingBundle
|
||||
{
|
||||
private readonly IDictionary secretRings;
|
||||
private readonly ArrayList order;
|
||||
|
||||
private PgpSecretKeyRingBundle(
|
||||
IDictionary secretRings,
|
||||
ArrayList order)
|
||||
{
|
||||
this.secretRings = secretRings;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(
|
||||
byte[] encoding)
|
||||
: this(new MemoryStream(encoding, false))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Build a PgpSecretKeyRingBundle from the passed in input stream.</summary>
|
||||
/// <param name="inputStream">Input stream containing data.</param>
|
||||
/// <exception cref="IOException">If a problem parsing the stream occurs.</exception>
|
||||
/// <exception cref="PgpException">If an object is encountered which isn't a PgpSecretKeyRing.</exception>
|
||||
public PgpSecretKeyRingBundle(
|
||||
Stream inputStream)
|
||||
: this(new PgpObjectFactory(inputStream).AllPgpObjects())
|
||||
{
|
||||
}
|
||||
|
||||
public PgpSecretKeyRingBundle(
|
||||
IEnumerable e)
|
||||
{
|
||||
this.secretRings = new Hashtable();
|
||||
this.order = new ArrayList();
|
||||
|
||||
foreach (object obj in e)
|
||||
{
|
||||
PgpSecretKeyRing pgpSecret = obj as PgpSecretKeyRing;
|
||||
|
||||
if (pgpSecret == null)
|
||||
{
|
||||
throw new PgpException(obj.GetType().FullName + " found where PgpSecretKeyRing expected");
|
||||
}
|
||||
|
||||
long key = pgpSecret.GetPublicKey().KeyId;
|
||||
secretRings.Add(key, pgpSecret);
|
||||
order.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size
|
||||
{
|
||||
get { return order.Count; }
|
||||
}
|
||||
|
||||
/// <summary>Return the number of rings in this collection.</summary>
|
||||
public int Count
|
||||
{
|
||||
get { return order.Count; }
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the secret key rings making up this collection.</summary>
|
||||
public IEnumerable GetKeyRings()
|
||||
{
|
||||
return new EnumerableProxy(secretRings.Values);
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
|
||||
/// <param name="userId">The user ID to be matched.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
|
||||
public IEnumerable GetKeyRings(
|
||||
string userId)
|
||||
{
|
||||
return GetKeyRings(userId, false, false);
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
|
||||
/// <param name="userId">The user ID to be matched.</param>
|
||||
/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
|
||||
public IEnumerable GetKeyRings(
|
||||
string userId,
|
||||
bool matchPartial)
|
||||
{
|
||||
return GetKeyRings(userId, matchPartial, false);
|
||||
}
|
||||
|
||||
/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
|
||||
/// <param name="userId">The user ID to be matched.</param>
|
||||
/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
|
||||
/// <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
|
||||
/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
|
||||
public IEnumerable GetKeyRings(
|
||||
string userId,
|
||||
bool matchPartial,
|
||||
bool ignoreCase)
|
||||
{
|
||||
IList rings = new ArrayList();
|
||||
|
||||
if (ignoreCase)
|
||||
{
|
||||
userId = userId.ToLower(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
foreach (PgpSecretKeyRing secRing in GetKeyRings())
|
||||
{
|
||||
foreach (string nextUserID in secRing.GetSecretKey().UserIds)
|
||||
{
|
||||
string next = nextUserID;
|
||||
if (ignoreCase)
|
||||
{
|
||||
next = next.ToLower(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (matchPartial)
|
||||
{
|
||||
if (next.IndexOf(userId) > -1)
|
||||
{
|
||||
rings.Add(secRing);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next.Equals(userId))
|
||||
{
|
||||
rings.Add(secRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new EnumerableProxy(rings);
|
||||
}
|
||||
|
||||
/// <summary>Return the PGP secret key associated with the given key id.</summary>
|
||||
/// <param name="keyId">The ID of the secret key to return.</param>
|
||||
public PgpSecretKey GetSecretKey(
|
||||
long keyId)
|
||||
{
|
||||
foreach (PgpSecretKeyRing secRing in GetKeyRings())
|
||||
{
|
||||
PgpSecretKey sec = secRing.GetSecretKey(keyId);
|
||||
|
||||
if (sec != null)
|
||||
{
|
||||
return sec;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Return the secret key ring which contains the key referred to by keyId</summary>
|
||||
/// <param name="keyId">The ID of the secret key</param>
|
||||
public PgpSecretKeyRing GetSecretKeyRing(
|
||||
long keyId)
|
||||
{
|
||||
long id = keyId;
|
||||
|
||||
if (secretRings.Contains(id))
|
||||
{
|
||||
return (PgpSecretKeyRing) secretRings[id];
|
||||
}
|
||||
|
||||
foreach (PgpSecretKeyRing secretRing in GetKeyRings())
|
||||
{
|
||||
PgpSecretKey secret = secretRing.GetSecretKey(keyId);
|
||||
|
||||
if (secret != null)
|
||||
{
|
||||
return secretRing;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
|
||||
Encode(bOut);
|
||||
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStr)
|
||||
{
|
||||
BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
|
||||
|
||||
foreach (long key in order)
|
||||
{
|
||||
PgpSecretKeyRing pub = (PgpSecretKeyRing) secretRings[key];
|
||||
|
||||
pub.Encode(bcpgOut);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a new bundle containing the contents of the passed in bundle and
|
||||
/// the passed in secret key ring.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be added to.</param>
|
||||
/// <param name="secretKeyRing">The key ring to be added.</param>
|
||||
/// <returns>A new <c>PgpSecretKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
|
||||
/// <exception cref="ArgumentException">If the keyId for the passed in key ring is already present.</exception>
|
||||
public static PgpSecretKeyRingBundle AddSecretKeyRing(
|
||||
PgpSecretKeyRingBundle bundle,
|
||||
PgpSecretKeyRing secretKeyRing)
|
||||
{
|
||||
long key = secretKeyRing.GetPublicKey().KeyId;
|
||||
|
||||
if (bundle.secretRings.Contains(key))
|
||||
{
|
||||
throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
|
||||
}
|
||||
|
||||
IDictionary newSecretRings = new Hashtable(bundle.secretRings);
|
||||
ArrayList newOrder = new ArrayList(bundle.order);
|
||||
|
||||
newSecretRings[key] = secretKeyRing;
|
||||
newOrder.Add(key);
|
||||
|
||||
return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a new bundle containing the contents of the passed in bundle with
|
||||
/// the passed in secret key ring removed.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be removed from.</param>
|
||||
/// <param name="secretKeyRing">The key ring to be removed.</param>
|
||||
/// <returns>A new <c>PgpSecretKeyRingBundle</c> not containing the passed in key ring.</returns>
|
||||
/// <exception cref="ArgumentException">If the keyId for the passed in key ring is not present.</exception>
|
||||
public static PgpSecretKeyRingBundle RemoveSecretKeyRing(
|
||||
PgpSecretKeyRingBundle bundle,
|
||||
PgpSecretKeyRing secretKeyRing)
|
||||
{
|
||||
long key = secretKeyRing.GetPublicKey().KeyId;
|
||||
|
||||
if (!bundle.secretRings.Contains(key))
|
||||
{
|
||||
throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
|
||||
}
|
||||
|
||||
IDictionary newSecretRings = new Hashtable(bundle.secretRings);
|
||||
ArrayList newOrder = new ArrayList(bundle.order);
|
||||
|
||||
newSecretRings.Remove(key);
|
||||
newOrder.Remove(key);
|
||||
|
||||
return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
|
||||
}
|
||||
}
|
||||
}
|
409
iTechSharp/srcbc/openpgp/PgpSignature.cs
Normal file
409
iTechSharp/srcbc/openpgp/PgpSignature.cs
Normal file
@@ -0,0 +1,409 @@
|
||||
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
|
||||
{
|
||||
/// <remarks>A PGP signature object.</remarks>
|
||||
public class PgpSignature
|
||||
{
|
||||
public const int BinaryDocument = 0x00;
|
||||
public const int CanonicalTextDocument = 0x01;
|
||||
public const int StandAlone = 0x02;
|
||||
|
||||
public const int DefaultCertification = 0x10;
|
||||
public const int NoCertification = 0x11;
|
||||
public const int CasualCertification = 0x12;
|
||||
public const int PositiveCertification = 0x13;
|
||||
|
||||
public const int SubkeyBinding = 0x18;
|
||||
public const int DirectKey = 0x1f;
|
||||
public const int KeyRevocation = 0x20;
|
||||
public const int SubkeyRevocation = 0x28;
|
||||
public const int CertificationRevocation = 0x30;
|
||||
public const int Timestamp = 0x40;
|
||||
|
||||
private readonly SignaturePacket sigPck;
|
||||
private readonly int signatureType;
|
||||
private readonly TrustPacket trustPck;
|
||||
|
||||
private ISigner sig;
|
||||
private byte lastb; // Initial value anything but '\r'
|
||||
|
||||
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");
|
||||
|
||||
this.sigPck = sigPacket;
|
||||
this.signatureType = sigPck.SignatureType;
|
||||
this.trustPck = trustPacket;
|
||||
}
|
||||
|
||||
private void GetSig()
|
||||
{
|
||||
this.sig = SignerUtilities.GetSigner(
|
||||
PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm));
|
||||
}
|
||||
|
||||
/// <summary>The OpenPGP version number for this signature.</summary>
|
||||
public int Version
|
||||
{
|
||||
get { return sigPck.Version; }
|
||||
}
|
||||
|
||||
/// <summary>The key algorithm associated with this signature.</summary>
|
||||
public PublicKeyAlgorithmTag KeyAlgorithm
|
||||
{
|
||||
get { return sigPck.KeyAlgorithm; }
|
||||
}
|
||||
|
||||
/// <summary>The hash algorithm associated with this signature.</summary>
|
||||
public HashAlgorithmTag HashAlgorithm
|
||||
{
|
||||
get { return sigPck.HashAlgorithm; }
|
||||
}
|
||||
|
||||
public void InitVerify(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
lastb = 0;
|
||||
if (sig == null)
|
||||
{
|
||||
GetSig();
|
||||
}
|
||||
try
|
||||
{
|
||||
sig.Init(false, pubKey.GetKey());
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new PgpException("invalid key.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte b)
|
||||
{
|
||||
if (signatureType == CanonicalTextDocument)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
if (b == '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
else if (b == '\n')
|
||||
{
|
||||
if (lastb != '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.Update(b);
|
||||
}
|
||||
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
sig.Update((byte)'\r');
|
||||
sig.Update((byte)'\n');
|
||||
}
|
||||
|
||||
public void Update(
|
||||
params byte[] bytes)
|
||||
{
|
||||
Update(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte[] bytes,
|
||||
int off,
|
||||
int length)
|
||||
{
|
||||
if (signatureType == CanonicalTextDocument)
|
||||
{
|
||||
int finish = off + length;
|
||||
|
||||
for (int i = off; i != finish; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(bytes, off, length);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
byte[] trailer = GetSignatureTrailer();
|
||||
sig.BlockUpdate(trailer, 0, trailer.Length);
|
||||
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(
|
||||
int header,
|
||||
byte[] idBytes)
|
||||
{
|
||||
this.Update(
|
||||
(byte) header,
|
||||
(byte)(idBytes.Length >> 24),
|
||||
(byte)(idBytes.Length >> 16),
|
||||
(byte)(idBytes.Length >> 8),
|
||||
(byte)(idBytes.Length));
|
||||
this.Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(
|
||||
PgpPublicKey key)
|
||||
{
|
||||
byte[] keyBytes = GetEncodedPublicKey(key);
|
||||
|
||||
this.Update(
|
||||
(byte) 0x99,
|
||||
(byte)(keyBytes.Length >> 8),
|
||||
(byte)(keyBytes.Length));
|
||||
this.Update(keyBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify the signature as certifying the passed in public key as associated
|
||||
/// with the passed in user attributes.
|
||||
/// </summary>
|
||||
/// <param name="userAttributes">User attributes the key was stored under.</param>
|
||||
/// <param name="key">The key to be verified.</param>
|
||||
/// <returns>True, if the signature matches, false otherwise.</returns>
|
||||
public bool VerifyCertification(
|
||||
PgpUserAttributeSubpacketVector userAttributes,
|
||||
PgpPublicKey key)
|
||||
{
|
||||
UpdateWithPublicKey(key);
|
||||
|
||||
//
|
||||
// hash in the userAttributes
|
||||
//
|
||||
try
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
|
||||
{
|
||||
packet.Encode(bOut);
|
||||
}
|
||||
UpdateWithIdData(0xd1, bOut.ToArray());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", e);
|
||||
}
|
||||
|
||||
this.Update(sigPck.GetSignatureTrailer());
|
||||
|
||||
return sig.VerifySignature(this.GetSignature());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify the signature as certifying the passed in public key as associated
|
||||
/// with the passed in ID.
|
||||
/// </summary>
|
||||
/// <param name="id">ID the key was stored under.</param>
|
||||
/// <param name="key">The key to be verified.</param>
|
||||
/// <returns>True, if the signature matches, false otherwise.</returns>
|
||||
public bool VerifyCertification(
|
||||
string id,
|
||||
PgpPublicKey key)
|
||||
{
|
||||
UpdateWithPublicKey(key);
|
||||
|
||||
//
|
||||
// hash in the id
|
||||
//
|
||||
UpdateWithIdData(0xb4, Strings.ToByteArray(id));
|
||||
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
/// <summary>Verify a certification for the passed in key against the passed in master key.</summary>
|
||||
/// <param name="masterKey">The key we are verifying against.</param>
|
||||
/// <param name="pubKey">The key we are verifying.</param>
|
||||
/// <returns>True, if the certification is valid, false otherwise.</returns>
|
||||
public bool VerifyCertification(
|
||||
PgpPublicKey masterKey,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
/// <summary>Verify a key certification, such as revocation, for the passed in key.</summary>
|
||||
/// <param name="pubKey">The key we are checking.</param>
|
||||
/// <returns>True, if the certification is valid, false otherwise.</returns>
|
||||
public bool VerifyCertification(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
if (SignatureType != KeyRevocation
|
||||
&& SignatureType != SubkeyRevocation)
|
||||
{
|
||||
throw new InvalidOperationException("signature is not a key signature");
|
||||
}
|
||||
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
Update(sigPck.GetSignatureTrailer());
|
||||
|
||||
return sig.VerifySignature(GetSignature());
|
||||
}
|
||||
|
||||
public int SignatureType
|
||||
{
|
||||
get { return sigPck.SignatureType; }
|
||||
}
|
||||
|
||||
/// <summary>The ID of the key that created the signature.</summary>
|
||||
public long KeyId
|
||||
{
|
||||
get { return sigPck.KeyId; }
|
||||
}
|
||||
|
||||
[Obsolete("Use 'CreationTime' property instead")]
|
||||
public DateTime GetCreationTime()
|
||||
{
|
||||
return CreationTime;
|
||||
}
|
||||
|
||||
/// <summary>The creation time of this signature.</summary>
|
||||
public DateTime CreationTime
|
||||
{
|
||||
get { return DateTimeUtilities.UnixMsToDateTime(sigPck.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)
|
||||
{
|
||||
return pcks == null ? null : new PgpSignatureSubpacketVector(pcks);
|
||||
}
|
||||
|
||||
public byte[] GetSignature()
|
||||
{
|
||||
MPInteger[] sigValues = sigPck.GetSignature();
|
||||
byte[] signature;
|
||||
|
||||
if (sigValues != null)
|
||||
{
|
||||
if (sigValues.Length == 1) // an RSA signature
|
||||
{
|
||||
signature = sigValues[0].Value.ToByteArrayUnsigned();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
signature = new DerSequence(
|
||||
new DerInteger(sigValues[0].Value),
|
||||
new DerInteger(sigValues[1].Value)).GetEncoded();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception encoding DSA sig.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
signature = sigPck.GetSignatureBytes();
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
// TODO Handle the encoding stuff by subclassing BcpgObject?
|
||||
public byte[] GetEncoded()
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
|
||||
Encode(bOut);
|
||||
|
||||
return bOut.ToArray();
|
||||
}
|
||||
|
||||
public void Encode(
|
||||
Stream outStream)
|
||||
{
|
||||
BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream);
|
||||
|
||||
bcpgOut.WritePacket(sigPck);
|
||||
|
||||
if (trustPck != null)
|
||||
{
|
||||
bcpgOut.WritePacket(trustPck);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
393
iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs
Normal file
393
iTechSharp/srcbc/openpgp/PgpSignatureGenerator.cs
Normal file
@@ -0,0 +1,393 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
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
|
||||
{
|
||||
/// <remarks>Generator for PGP signatures.</remarks>
|
||||
// TODO Should be able to implement ISigner?
|
||||
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;
|
||||
|
||||
/// <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>Initialise the generator for signing.</summary>
|
||||
public void InitSign(
|
||||
int sigType,
|
||||
PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
/// <summary>Initialise the generator for signing.</summary>
|
||||
public void InitSign(
|
||||
int sigType,
|
||||
PgpPrivateKey key,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.privKey = key;
|
||||
this.signatureType = sigType;
|
||||
|
||||
try
|
||||
{
|
||||
ICipherParameters cp = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
cp = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
|
||||
sig.Init(true, cp);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new PgpException("invalid key.", e);
|
||||
}
|
||||
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte b)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
if (b == '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
else if (b == '\n')
|
||||
{
|
||||
if (lastb != '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte((byte)'\r');
|
||||
doUpdateByte((byte)'\n');
|
||||
}
|
||||
|
||||
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 == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
int finish = off + len;
|
||||
|
||||
for (int i = off; i != finish; 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();
|
||||
}
|
||||
|
||||
/// <summary>Return the one pass header associated with the current signature.</summary>
|
||||
public PgpOnePassSignature GenerateOnePassVersion(
|
||||
bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(
|
||||
new OnePassSignaturePacket(
|
||||
signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
/// <summary>Return a signature object containing the current signature state.</summary>
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed;
|
||||
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
|
||||
{
|
||||
hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
|
||||
}
|
||||
|
||||
if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
|
||||
&& !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
|
||||
{
|
||||
unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
|
||||
}
|
||||
|
||||
int version = 4;
|
||||
byte[] hData;
|
||||
|
||||
try
|
||||
{
|
||||
MemoryStream hOut = new MemoryStream();
|
||||
|
||||
for (int i = 0; i != hPkts.Length; i++)
|
||||
{
|
||||
hPkts[i].Encode(hOut);
|
||||
}
|
||||
|
||||
byte[] data = hOut.ToArray();
|
||||
|
||||
MemoryStream sOut = new MemoryStream(data.Length + 6);
|
||||
sOut.WriteByte((byte)version);
|
||||
sOut.WriteByte((byte)signatureType);
|
||||
sOut.WriteByte((byte)keyAlgorithm);
|
||||
sOut.WriteByte((byte)hashAlgorithm);
|
||||
sOut.WriteByte((byte)(data.Length >> 8));
|
||||
sOut.WriteByte((byte)data.Length);
|
||||
sOut.Write(data, 0, data.Length);
|
||||
|
||||
hData = sOut.ToArray();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception encoding hashed data.", e);
|
||||
}
|
||||
|
||||
sig.BlockUpdate(hData, 0, hData.Length);
|
||||
dig.BlockUpdate(hData, 0, hData.Length);
|
||||
|
||||
hData = new byte[]
|
||||
{
|
||||
(byte) version,
|
||||
0xff,
|
||||
(byte)(hData.Length >> 24),
|
||||
(byte)(hData.Length >> 16),
|
||||
(byte)(hData.Length >> 8),
|
||||
(byte) hData.Length
|
||||
};
|
||||
|
||||
sig.BlockUpdate(hData, 0, hData.Length);
|
||||
dig.BlockUpdate(hData, 0, hData.Length);
|
||||
|
||||
byte[] sigBytes = sig.GenerateSignature();
|
||||
byte[] digest = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerPrint = new byte[] { digest[0], digest[1] };
|
||||
|
||||
// an RSA signature
|
||||
bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
|
||||
|| keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
|
||||
|
||||
MPInteger[] sigValues = isRsa
|
||||
? PgpUtilities.RsaSigToMpi(sigBytes)
|
||||
: PgpUtilities.DsaSigToMpi(sigBytes);
|
||||
|
||||
return new PgpSignature(
|
||||
new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm,
|
||||
hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues));
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification for the passed in ID and key.</summary>
|
||||
/// <param name="id">The ID we are certifying against the public key.</param>
|
||||
/// <param name="pubKey">The key we are certifying against the ID.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
string id,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
//
|
||||
// hash in the id
|
||||
//
|
||||
UpdateWithIdData(0xb4, Strings.ToByteArray(id));
|
||||
|
||||
return Generate();
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification for the passed in userAttributes.</summary>
|
||||
/// <param name="userAttributes">The ID we are certifying against the public key.</param>
|
||||
/// <param name="pubKey">The key we are certifying against the ID.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
PgpUserAttributeSubpacketVector userAttributes,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
//
|
||||
// hash in the attributes
|
||||
//
|
||||
try
|
||||
{
|
||||
MemoryStream bOut = new MemoryStream();
|
||||
foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
|
||||
{
|
||||
packet.Encode(bOut);
|
||||
}
|
||||
UpdateWithIdData(0xd1, bOut.ToArray());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("cannot encode subpacket array", e);
|
||||
}
|
||||
|
||||
return this.Generate();
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification for the passed in key against the passed in master key.</summary>
|
||||
/// <param name="masterKey">The key we are certifying against.</param>
|
||||
/// <param name="pubKey">The key we are certifying.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
PgpPublicKey masterKey,
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(masterKey);
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
return Generate();
|
||||
}
|
||||
|
||||
/// <summary>Generate a certification, such as a revocation, for the passed in key.</summary>
|
||||
/// <param name="pubKey">The key we are certifying.</param>
|
||||
/// <returns>The certification.</returns>
|
||||
public PgpSignature GenerateCertification(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
UpdateWithPublicKey(pubKey);
|
||||
|
||||
return Generate();
|
||||
}
|
||||
|
||||
private byte[] GetEncodedPublicKey(
|
||||
PgpPublicKey pubKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
return pubKey.publicPk.GetEncodedContents();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception preparing key.", e);
|
||||
}
|
||||
}
|
||||
|
||||
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[] tmp = new SignatureSubpacket[packets.Length + 1];
|
||||
tmp[0] = subpacket;
|
||||
packets.CopyTo(tmp, 1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void UpdateWithIdData(
|
||||
int header,
|
||||
byte[] idBytes)
|
||||
{
|
||||
this.Update(
|
||||
(byte) header,
|
||||
(byte)(idBytes.Length >> 24),
|
||||
(byte)(idBytes.Length >> 16),
|
||||
(byte)(idBytes.Length >> 8),
|
||||
(byte)(idBytes.Length));
|
||||
this.Update(idBytes);
|
||||
}
|
||||
|
||||
private void UpdateWithPublicKey(
|
||||
PgpPublicKey key)
|
||||
{
|
||||
byte[] keyBytes = GetEncodedPublicKey(key);
|
||||
|
||||
this.Update(
|
||||
(byte) 0x99,
|
||||
(byte)(keyBytes.Length >> 8),
|
||||
(byte)(keyBytes.Length));
|
||||
this.Update(keyBytes);
|
||||
}
|
||||
}
|
||||
}
|
51
iTechSharp/srcbc/openpgp/PgpSignatureList.cs
Normal file
51
iTechSharp/srcbc/openpgp/PgpSignatureList.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>A list of PGP signatures - normally in the signature block after literal data.</remarks>
|
||||
public class PgpSignatureList
|
||||
: PgpObject
|
||||
{
|
||||
private PgpSignature[] sigs;
|
||||
|
||||
public PgpSignatureList(
|
||||
PgpSignature[] sigs)
|
||||
{
|
||||
this.sigs = (PgpSignature[]) sigs.Clone();
|
||||
}
|
||||
|
||||
public PgpSignatureList(
|
||||
PgpSignature sig)
|
||||
{
|
||||
this.sigs = new PgpSignature[]{ sig };
|
||||
}
|
||||
|
||||
public PgpSignature this[int index]
|
||||
{
|
||||
get { return sigs[index]; }
|
||||
}
|
||||
|
||||
[Obsolete("Use 'object[index]' syntax instead")]
|
||||
public PgpSignature Get(
|
||||
int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size
|
||||
{
|
||||
get { return sigs.Length; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return sigs.Length; }
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return (sigs.Length == 0); }
|
||||
}
|
||||
}
|
||||
}
|
141
iTechSharp/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs
Normal file
141
iTechSharp/srcbc/openpgp/PgpSignatureSubpacketGenerator.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Generator for signature subpackets.</remarks>
|
||||
public class PgpSignatureSubpacketGenerator
|
||||
{
|
||||
private ArrayList list = new ArrayList();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a TrustSignature packet to the signature. The values for depth and trust are largely
|
||||
/// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13.
|
||||
/// </summary>
|
||||
/// <param name="isCritical">true if the packet is critical.</param>
|
||||
/// <param name="depth">depth level.</param>
|
||||
/// <param name="trustAmount">trust amount.</param>
|
||||
public void SetTrust(
|
||||
bool isCritical,
|
||||
int depth,
|
||||
int trustAmount)
|
||||
{
|
||||
list.Add(new TrustSignature(isCritical, depth, trustAmount));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the number of seconds a key is valid for after the time of its creation.
|
||||
/// A value of zero means the key never expires.
|
||||
/// </summary>
|
||||
/// <param name="isCritical">True, if should be treated as critical, false otherwise.</param>
|
||||
/// <param name="seconds">The number of seconds the key is valid, or zero if no expiry.</param>
|
||||
public void SetKeyExpirationTime(
|
||||
bool isCritical,
|
||||
long seconds)
|
||||
{
|
||||
list.Add(new KeyExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the number of seconds a signature is valid for after the time of its creation.
|
||||
/// A value of zero means the signature never expires.
|
||||
/// </summary>
|
||||
/// <param name="isCritical">True, if should be treated as critical, false otherwise.</param>
|
||||
/// <param name="seconds">The number of seconds the signature is valid, or zero if no expiry.</param>
|
||||
public void SetSignatureExpirationTime(
|
||||
bool isCritical,
|
||||
long seconds)
|
||||
{
|
||||
list.Add(new SignatureExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the creation time for the signature.
|
||||
/// <p>
|
||||
/// Note: this overrides the generation of a creation time when the signature
|
||||
/// is generated.</p>
|
||||
/// </summary>
|
||||
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 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 PgpSignatureSubpacketVector Generate()
|
||||
{
|
||||
return new PgpSignatureSubpacketVector(
|
||||
(SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket)));
|
||||
}
|
||||
}
|
||||
}
|
193
iTechSharp/srcbc/openpgp/PgpSignatureSubpacketVector.cs
Normal file
193
iTechSharp/srcbc/openpgp/PgpSignatureSubpacketVector.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Org.BouncyCastle.Bcpg.Sig;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Container for a list of signature subpackets.</remarks>
|
||||
public class PgpSignatureSubpacketVector
|
||||
{
|
||||
private readonly SignatureSubpacket[] packets;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all signature subpackets of the passed in type.
|
||||
* @param type subpacket type code
|
||||
* @return an array of zero or more matching subpackets.
|
||||
*/
|
||||
public SignatureSubpacket[] GetSubpackets(
|
||||
SignatureSubpacketTag type)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].SubpacketType == type)
|
||||
{
|
||||
list.Add(packets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return (SignatureSubpacket[]) list.ToArray(typeof(SignatureSubpacket));
|
||||
}
|
||||
|
||||
public NotationData[] GetNotationDataOccurences()
|
||||
{
|
||||
SignatureSubpacket[] notations = GetSubpackets(SignatureSubpacketTag.NotationData);
|
||||
NotationData[] vals = new NotationData[notations.Length];
|
||||
|
||||
for (int i = 0; i < notations.Length; i++)
|
||||
{
|
||||
vals[i] = (NotationData) notations[i];
|
||||
}
|
||||
|
||||
return vals;
|
||||
}
|
||||
|
||||
public long GetIssuerKeyId()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
|
||||
|
||||
return p == null ? 0 : ((IssuerKeyId) p).KeyId;
|
||||
}
|
||||
|
||||
public bool HasSignatureCreationTime()
|
||||
{
|
||||
return GetSubpacket(SignatureSubpacketTag.CreationTime) != null;
|
||||
}
|
||||
|
||||
public DateTime GetSignatureCreationTime()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.CreationTime);
|
||||
|
||||
if (p == null)
|
||||
{
|
||||
throw new PgpException("SignatureCreationTime not available");
|
||||
}
|
||||
|
||||
return ((SignatureCreationTime)p).GetTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the number of seconds a signature is valid for after its creation date.
|
||||
/// A value of zero means the signature never expires.
|
||||
/// </summary>
|
||||
/// <returns>Seconds a signature is valid for.</returns>
|
||||
public long GetSignatureExpirationTime()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.ExpireTime);
|
||||
|
||||
return p == null ? 0 : ((SignatureExpirationTime) p).Time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the number of seconds a key is valid for after its creation date.
|
||||
/// A value of zero means the key never expires.
|
||||
/// </summary>
|
||||
/// <returns>Seconds a signature is valid for.</returns>
|
||||
public long GetKeyExpirationTime()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyExpireTime);
|
||||
|
||||
return p == null ? 0 : ((KeyExpirationTime) p).Time;
|
||||
}
|
||||
|
||||
public int[] GetPreferredHashAlgorithms()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms);
|
||||
|
||||
return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
|
||||
}
|
||||
|
||||
public int[] GetPreferredSymmetricAlgorithms()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms);
|
||||
|
||||
return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
|
||||
}
|
||||
|
||||
public int[] GetPreferredCompressionAlgorithms()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms);
|
||||
|
||||
return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
|
||||
}
|
||||
|
||||
public int GetKeyFlags()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyFlags);
|
||||
|
||||
return p == null ? 0 : ((KeyFlags) p).Flags;
|
||||
}
|
||||
|
||||
public string GetSignerUserId()
|
||||
{
|
||||
SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.SignerUserId);
|
||||
|
||||
return p == null ? null : ((SignerUserId) p).GetId();
|
||||
}
|
||||
|
||||
public SignatureSubpacketTag[] GetCriticalTags()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].IsCritical())
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
SignatureSubpacketTag[] list = new SignatureSubpacketTag[count];
|
||||
|
||||
count = 0;
|
||||
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (packets[i].IsCritical())
|
||||
{
|
||||
list[count++] = packets[i].SubpacketType;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[Obsolete("Use 'Count' property instead")]
|
||||
public int Size
|
||||
{
|
||||
get { return packets.Length; }
|
||||
}
|
||||
|
||||
/// <summary>Return the number of packets this vector contains.</summary>
|
||||
public int Count
|
||||
{
|
||||
get { return packets.Length; }
|
||||
}
|
||||
|
||||
internal SignatureSubpacket[] ToSubpacketArray()
|
||||
{
|
||||
return packets;
|
||||
}
|
||||
}
|
||||
}
|
81
iTechSharp/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs
Normal file
81
iTechSharp/srcbc/openpgp/PgpUserAttributeSubpacketVector.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using Org.BouncyCastle.Bcpg.Attr;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Container for a list of user attribute subpackets.</remarks>
|
||||
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 p = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute);
|
||||
|
||||
return p == null ? null : (ImageAttrib) p;
|
||||
}
|
||||
|
||||
internal UserAttributeSubpacket[] ToSubpacketArray()
|
||||
{
|
||||
return packets;
|
||||
}
|
||||
|
||||
public override bool Equals(
|
||||
object obj)
|
||||
{
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
PgpUserAttributeSubpacketVector other = obj as PgpUserAttributeSubpacketVector;
|
||||
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
if (other.packets.Length != packets.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i != packets.Length; i++)
|
||||
{
|
||||
if (!other.packets[i].Equals(packets[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int code = 0;
|
||||
|
||||
foreach (object o in packets)
|
||||
{
|
||||
code ^= o.GetHashCode();
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
431
iTechSharp/srcbc/openpgp/PgpUtilities.cs
Normal file
431
iTechSharp/srcbc/openpgp/PgpUtilities.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
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;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Basic utility class.</remarks>
|
||||
public sealed class PgpUtilities
|
||||
{
|
||||
private PgpUtilities()
|
||||
{
|
||||
}
|
||||
|
||||
public static MPInteger[] DsaSigToMpi(
|
||||
byte[] encoding)
|
||||
{
|
||||
DerInteger i1, i2;
|
||||
|
||||
try
|
||||
{
|
||||
Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
|
||||
|
||||
i1 = (DerInteger) s[0];
|
||||
i2 = (DerInteger) s[1];
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new PgpException("exception encoding signature", e);
|
||||
}
|
||||
|
||||
return new MPInteger[]{ new MPInteger(i1.Value), new MPInteger(i2.Value) };
|
||||
}
|
||||
|
||||
public static MPInteger[] RsaSigToMpi(
|
||||
byte[] encoding)
|
||||
{
|
||||
return new MPInteger[]{ new MPInteger(new BigInteger(1, encoding)) };
|
||||
}
|
||||
|
||||
public static string GetDigestName(
|
||||
HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
switch (hashAlgorithm)
|
||||
{
|
||||
case HashAlgorithmTag.Sha1:
|
||||
return "SHA1";
|
||||
case HashAlgorithmTag.MD2:
|
||||
return "MD2";
|
||||
case HashAlgorithmTag.MD5:
|
||||
return "MD5";
|
||||
case HashAlgorithmTag.RipeMD160:
|
||||
return "RIPEMD160";
|
||||
case HashAlgorithmTag.Sha224:
|
||||
return "SHA224";
|
||||
case HashAlgorithmTag.Sha256:
|
||||
return "SHA256";
|
||||
case HashAlgorithmTag.Sha384:
|
||||
return "SHA384";
|
||||
case HashAlgorithmTag.Sha512:
|
||||
return "SHA512";
|
||||
default:
|
||||
throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSignatureName(
|
||||
PublicKeyAlgorithmTag keyAlgorithm,
|
||||
HashAlgorithmTag hashAlgorithm)
|
||||
{
|
||||
string encAlg;
|
||||
switch (keyAlgorithm)
|
||||
{
|
||||
case PublicKeyAlgorithmTag.RsaGeneral:
|
||||
case PublicKeyAlgorithmTag.RsaSign:
|
||||
encAlg = "RSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.Dsa:
|
||||
encAlg = "DSA";
|
||||
break;
|
||||
case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
|
||||
case PublicKeyAlgorithmTag.ElGamalGeneral:
|
||||
encAlg = "ElGamal";
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
|
||||
}
|
||||
|
||||
return GetDigestName(hashAlgorithm) + "with" + encAlg;
|
||||
}
|
||||
|
||||
public static string GetSymmetricCipherName(
|
||||
SymmetricKeyAlgorithmTag algorithm)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Null:
|
||||
return null;
|
||||
case SymmetricKeyAlgorithmTag.TripleDes:
|
||||
return "DESEDE";
|
||||
case SymmetricKeyAlgorithmTag.Idea:
|
||||
return "IDEA";
|
||||
case SymmetricKeyAlgorithmTag.Cast5:
|
||||
return "CAST5";
|
||||
case SymmetricKeyAlgorithmTag.Blowfish:
|
||||
return "Blowfish";
|
||||
case SymmetricKeyAlgorithmTag.Safer:
|
||||
return "SAFER";
|
||||
case SymmetricKeyAlgorithmTag.Des:
|
||||
return "DES";
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
return "AES";
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
return "AES";
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
return "AES";
|
||||
case SymmetricKeyAlgorithmTag.Twofish:
|
||||
return "Twofish";
|
||||
default:
|
||||
throw new PgpException("unknown symmetric algorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
|
||||
{
|
||||
int keySize;
|
||||
switch (algorithm)
|
||||
{
|
||||
case SymmetricKeyAlgorithmTag.Des:
|
||||
keySize = 64;
|
||||
break;
|
||||
case SymmetricKeyAlgorithmTag.Idea:
|
||||
case SymmetricKeyAlgorithmTag.Cast5:
|
||||
case SymmetricKeyAlgorithmTag.Blowfish:
|
||||
case SymmetricKeyAlgorithmTag.Safer:
|
||||
case SymmetricKeyAlgorithmTag.Aes128:
|
||||
keySize = 128;
|
||||
break;
|
||||
case SymmetricKeyAlgorithmTag.TripleDes:
|
||||
case SymmetricKeyAlgorithmTag.Aes192:
|
||||
keySize = 192;
|
||||
break;
|
||||
case SymmetricKeyAlgorithmTag.Aes256:
|
||||
case SymmetricKeyAlgorithmTag.Twofish:
|
||||
keySize = 256;
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown symmetric algorithm: " + algorithm);
|
||||
}
|
||||
|
||||
return keySize;
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKey(
|
||||
SymmetricKeyAlgorithmTag algorithm,
|
||||
byte[] keyBytes)
|
||||
{
|
||||
string algName = GetSymmetricCipherName(algorithm);
|
||||
|
||||
return ParameterUtilities.CreateKeyParameter(algName, keyBytes);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeRandomKey(
|
||||
SymmetricKeyAlgorithmTag algorithm,
|
||||
SecureRandom random)
|
||||
{
|
||||
int keySize = GetKeySize(algorithm);
|
||||
byte[] keyBytes = new byte[(keySize + 7) / 8];
|
||||
random.NextBytes(keyBytes);
|
||||
return MakeKey(algorithm, keyBytes);
|
||||
}
|
||||
|
||||
public static KeyParameter MakeKeyFromPassPhrase(
|
||||
SymmetricKeyAlgorithmTag algorithm,
|
||||
S2k s2k,
|
||||
char[] passPhrase)
|
||||
{
|
||||
int keySize = GetKeySize(algorithm);
|
||||
byte[] pBytes = Strings.ToByteArray(new string(passPhrase));
|
||||
byte[] keyBytes = new byte[(keySize + 7) / 8];
|
||||
|
||||
int generatedBytes = 0;
|
||||
int loopCount = 0;
|
||||
|
||||
while (generatedBytes < keyBytes.Length)
|
||||
{
|
||||
IDigest digest;
|
||||
if (s2k != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (s2k.HashAlgorithm)
|
||||
{
|
||||
case HashAlgorithmTag.Sha1:
|
||||
digest = DigestUtilities.GetDigest("SHA1");
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown hash algorithm: " + s2k.HashAlgorithm);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("can't find S2k digest", e);
|
||||
}
|
||||
|
||||
for (int i = 0; i != loopCount; i++)
|
||||
{
|
||||
digest.Update(0);
|
||||
}
|
||||
|
||||
byte[] iv = s2k.GetIV();
|
||||
|
||||
switch (s2k.Type)
|
||||
{
|
||||
case S2k.Simple:
|
||||
digest.BlockUpdate(pBytes, 0, pBytes.Length);
|
||||
break;
|
||||
case S2k.Salted:
|
||||
digest.BlockUpdate(iv, 0, iv.Length);
|
||||
digest.BlockUpdate(pBytes, 0, pBytes.Length);
|
||||
break;
|
||||
case S2k.SaltedAndIterated:
|
||||
long count = s2k.IterationCount;
|
||||
digest.BlockUpdate(iv, 0, iv.Length);
|
||||
digest.BlockUpdate(pBytes, 0, pBytes.Length);
|
||||
|
||||
count -= iv.Length + pBytes.Length;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
if (count < iv.Length)
|
||||
{
|
||||
digest.BlockUpdate(iv, 0, (int)count);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
digest.BlockUpdate(iv, 0, iv.Length);
|
||||
count -= iv.Length;
|
||||
}
|
||||
|
||||
if (count < pBytes.Length)
|
||||
{
|
||||
digest.BlockUpdate(pBytes, 0, (int)count);
|
||||
count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
digest.BlockUpdate(pBytes, 0, pBytes.Length);
|
||||
count -= pBytes.Length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new PgpException("unknown S2k type: " + s2k.Type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
digest = DigestUtilities.GetDigest("MD5");
|
||||
|
||||
for (int i = 0; i != loopCount; i++)
|
||||
{
|
||||
digest.Update(0);
|
||||
}
|
||||
|
||||
digest.BlockUpdate(pBytes, 0, pBytes.Length);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new PgpException("can't find MD5 digest", e);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] dig = DigestUtilities.DoFinal(digest);
|
||||
|
||||
if (dig.Length > (keyBytes.Length - generatedBytes))
|
||||
{
|
||||
Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
|
||||
}
|
||||
|
||||
generatedBytes += dig.Length;
|
||||
|
||||
loopCount++;
|
||||
}
|
||||
|
||||
Array.Clear(pBytes, 0, pBytes.Length);
|
||||
|
||||
return MakeKey(algorithm, keyBytes);
|
||||
}
|
||||
|
||||
/// <summary>Write out the passed in file as a literal data packet.</summary>
|
||||
public static void WriteFileToLiteralData(
|
||||
Stream outputStream,
|
||||
char fileType,
|
||||
FileInfo file)
|
||||
{
|
||||
Stream inStr = file.OpenRead();
|
||||
Stream outStr = new PgpLiteralDataGenerator().Open(
|
||||
outputStream, fileType, file.Name, file.Length, file.LastWriteTime);
|
||||
|
||||
Streams.PipeAll(inStr, outStr);
|
||||
|
||||
inStr.Close();
|
||||
outStr.Close();
|
||||
}
|
||||
|
||||
/// <summary>Write out the passed in file as a literal data packet in partial packet format.</summary>
|
||||
public static void WriteFileToLiteralData(
|
||||
Stream outputStream,
|
||||
char fileType,
|
||||
FileInfo file,
|
||||
byte[] buffer)
|
||||
{
|
||||
PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
|
||||
Stream pOut = lData.Open(outputStream, fileType, file.Name, file.LastWriteTime, buffer);
|
||||
FileStream inputStream = file.OpenRead();
|
||||
byte[] buf = new byte[buffer.Length];
|
||||
|
||||
int len;
|
||||
while ((len = inputStream.Read(buf, 0, buf.Length)) > 0)
|
||||
{
|
||||
pOut.Write(buf, 0, len);
|
||||
}
|
||||
|
||||
lData.Close();
|
||||
inputStream.Close();
|
||||
}
|
||||
|
||||
private const int ReadAhead = 60;
|
||||
|
||||
private static bool IsPossiblyBase64(
|
||||
int ch)
|
||||
{
|
||||
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '/')
|
||||
|| (ch == '\r') || (ch == '\n');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return either an ArmoredInputStream or a BcpgInputStream based on whether
|
||||
/// the initial characters of the stream are binary PGP encodings or not.
|
||||
/// </summary>
|
||||
public static Stream GetDecoderStream(
|
||||
Stream inputStream)
|
||||
{
|
||||
// TODO Remove this restriction?
|
||||
if (!inputStream.CanSeek)
|
||||
throw new ArgumentException("inputStream must be seek-able", "inputStream");
|
||||
|
||||
long markedPos = inputStream.Position;
|
||||
|
||||
int ch = inputStream.ReadByte();
|
||||
if ((ch & 0x80) != 0)
|
||||
{
|
||||
inputStream.Position = markedPos;
|
||||
|
||||
return inputStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!IsPossiblyBase64(ch))
|
||||
{
|
||||
inputStream.Position = markedPos;
|
||||
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
|
||||
byte[] buf = new byte[ReadAhead];
|
||||
int count = 1;
|
||||
int index = 1;
|
||||
|
||||
buf[0] = (byte)ch;
|
||||
while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0)
|
||||
{
|
||||
if (!IsPossiblyBase64(ch))
|
||||
{
|
||||
inputStream.Position = markedPos;
|
||||
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
|
||||
if (ch != '\n' && ch != '\r')
|
||||
{
|
||||
buf[index++] = (byte)ch;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
inputStream.Position = markedPos;
|
||||
|
||||
//
|
||||
// nothing but new lines, little else, assume regular armoring
|
||||
//
|
||||
if (count < 4)
|
||||
{
|
||||
return new ArmoredInputStream(inputStream);
|
||||
}
|
||||
|
||||
//
|
||||
// test our non-blank data
|
||||
//
|
||||
byte[] firstBlock = new byte[8];
|
||||
Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length);
|
||||
byte[] decoded = Base64.Decode(firstBlock);
|
||||
|
||||
//
|
||||
// it's a base64 PGP block.
|
||||
//
|
||||
bool hasHeaders = (decoded[0] & 0x80) == 0;
|
||||
|
||||
return new ArmoredInputStream(inputStream, hasHeaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
199
iTechSharp/srcbc/openpgp/PgpV3SignatureGenerator.cs
Normal file
199
iTechSharp/srcbc/openpgp/PgpV3SignatureGenerator.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities.Date;
|
||||
|
||||
namespace Org.BouncyCastle.Bcpg.OpenPgp
|
||||
{
|
||||
/// <remarks>Generator for old style PGP V3 Signatures.</remarks>
|
||||
// TODO Should be able to implement ISigner?
|
||||
public class PgpV3SignatureGenerator
|
||||
{
|
||||
private PublicKeyAlgorithmTag keyAlgorithm;
|
||||
private HashAlgorithmTag hashAlgorithm;
|
||||
private PgpPrivateKey privKey;
|
||||
private ISigner sig;
|
||||
private IDigest dig;
|
||||
private int signatureType;
|
||||
private byte lastb;
|
||||
|
||||
/// <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>Initialise the generator for signing.</summary>
|
||||
public void InitSign(
|
||||
int sigType,
|
||||
PgpPrivateKey key)
|
||||
{
|
||||
InitSign(sigType, key, null);
|
||||
}
|
||||
|
||||
/// <summary>Initialise the generator for signing.</summary>
|
||||
public void InitSign(
|
||||
int sigType,
|
||||
PgpPrivateKey key,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.privKey = key;
|
||||
this.signatureType = sigType;
|
||||
|
||||
try
|
||||
{
|
||||
ICipherParameters cp = key.Key;
|
||||
if (random != null)
|
||||
{
|
||||
cp = new ParametersWithRandom(key.Key, random);
|
||||
}
|
||||
|
||||
sig.Init(true, cp);
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
throw new PgpException("invalid key.", e);
|
||||
}
|
||||
|
||||
dig.Reset();
|
||||
lastb = 0;
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte b)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
doCanonicalUpdateByte(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCanonicalUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
if (b == '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
else if (b == '\n')
|
||||
{
|
||||
if (lastb != '\r')
|
||||
{
|
||||
doUpdateCRLF();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
doUpdateByte(b);
|
||||
}
|
||||
|
||||
lastb = b;
|
||||
}
|
||||
|
||||
private void doUpdateCRLF()
|
||||
{
|
||||
doUpdateByte((byte)'\r');
|
||||
doUpdateByte((byte)'\n');
|
||||
}
|
||||
|
||||
private void doUpdateByte(
|
||||
byte b)
|
||||
{
|
||||
sig.Update(b);
|
||||
dig.Update(b);
|
||||
}
|
||||
|
||||
public void Update(
|
||||
byte[] b)
|
||||
{
|
||||
if (signatureType == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
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 == PgpSignature.CanonicalTextDocument)
|
||||
{
|
||||
int finish = off + len;
|
||||
|
||||
for (int i = off; i != finish; i++)
|
||||
{
|
||||
doCanonicalUpdateByte(b[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig.BlockUpdate(b, off, len);
|
||||
dig.BlockUpdate(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Return the one pass header associated with the current signature.</summary>
|
||||
public PgpOnePassSignature GenerateOnePassVersion(
|
||||
bool isNested)
|
||||
{
|
||||
return new PgpOnePassSignature(
|
||||
new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
|
||||
}
|
||||
|
||||
/// <summary>Return a V3 signature object containing the current signature state.</summary>
|
||||
public PgpSignature Generate()
|
||||
{
|
||||
long creationTime = DateTimeUtilities.CurrentUnixMs() / 1000L;
|
||||
|
||||
byte[] hData = new byte[]
|
||||
{
|
||||
(byte) signatureType,
|
||||
(byte)(creationTime >> 24),
|
||||
(byte)(creationTime >> 16),
|
||||
(byte)(creationTime >> 8),
|
||||
(byte) creationTime
|
||||
};
|
||||
|
||||
sig.BlockUpdate(hData, 0, hData.Length);
|
||||
dig.BlockUpdate(hData, 0, hData.Length);
|
||||
|
||||
byte[] sigBytes = sig.GenerateSignature();
|
||||
byte[] digest = DigestUtilities.DoFinal(dig);
|
||||
byte[] fingerPrint = new byte[]{ digest[0], digest[1] };
|
||||
|
||||
// an RSA signature
|
||||
bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
|
||||
|| keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
|
||||
|
||||
MPInteger[] sigValues = isRsa
|
||||
? PgpUtilities.RsaSigToMpi(sigBytes)
|
||||
: PgpUtilities.DsaSigToMpi(sigBytes);
|
||||
|
||||
return new PgpSignature(
|
||||
new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm,
|
||||
hashAlgorithm, creationTime * 1000L, fingerPrint, sigValues));
|
||||
}
|
||||
}
|
||||
}
|
25
iTechSharp/srcbc/openpgp/WrappedGeneratorStream.cs
Normal file
25
iTechSharp/srcbc/openpgp/WrappedGeneratorStream.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Asn1.Utilities;
|
||||
|
||||
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