diff --git a/Crypto/src/bcpg/SignaturePacket.cs b/Crypto/src/bcpg/SignaturePacket.cs
new file mode 100644
index 000000000..605ce84c4
--- /dev/null
+++ b/Crypto/src/bcpg/SignaturePacket.cs
@@ -0,0 +1,472 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// <remarks>Generic signature packet.</remarks>
+ public class SignaturePacket
+ : ContainedPacket //, PublicKeyAlgorithmTag
+ {
+ private int version;
+ private int signatureType;
+ private long creationTime;
+ private long keyId;
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private MPInteger[] signature;
+ private byte[] fingerprint;
+ private SignatureSubpacket[] hashedData;
+ private SignatureSubpacket[] unhashedData;
+ private byte[] signatureEncoding;
+
+ internal SignaturePacket(
+ BcpgInputStream bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+
+ if (version == 3 || version == 2)
+ {
+// int l =
+ bcpgIn.ReadByte();
+
+ signatureType = bcpgIn.ReadByte();
+ creationTime = (((long)bcpgIn.ReadByte() << 24) | ((long)bcpgIn.ReadByte() << 16)
+ | ((long)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte()) * 1000L;
+
+ keyId |= (long)bcpgIn.ReadByte() << 56;
+ keyId |= (long)bcpgIn.ReadByte() << 48;
+ keyId |= (long)bcpgIn.ReadByte() << 40;
+ keyId |= (long)bcpgIn.ReadByte() << 32;
+ keyId |= (long)bcpgIn.ReadByte() << 24;
+ keyId |= (long)bcpgIn.ReadByte() << 16;
+ keyId |= (long)bcpgIn.ReadByte() << 8;
+ keyId |= (uint)bcpgIn.ReadByte();
+
+ keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+ hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+ }
+ else if (version == 4)
+ {
+ signatureType = bcpgIn.ReadByte();
+ keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+ hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+
+ int hashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+ byte[] hashed = new byte[hashedLength];
+
+ bcpgIn.ReadFully(hashed);
+
+ //
+ // read the signature sub packet data.
+ //
+ SignatureSubpacketsParser sIn = new SignatureSubpacketsParser(
+ new MemoryStream(hashed, false));
+
+ IList v = Platform.CreateArrayList();
+ SignatureSubpacket sub;
+ while ((sub = sIn.ReadPacket()) != null)
+ {
+ v.Add(sub);
+ }
+
+ hashedData = new SignatureSubpacket[v.Count];
+
+ for (int i = 0; i != hashedData.Length; i++)
+ {
+ SignatureSubpacket p = (SignatureSubpacket)v[i];
+ if (p is IssuerKeyId)
+ {
+ keyId = ((IssuerKeyId)p).KeyId;
+ }
+ else if (p is SignatureCreationTime)
+ {
+ creationTime = DateTimeUtilities.DateTimeToUnixMs(
+ ((SignatureCreationTime)p).GetTime());
+ }
+
+ hashedData[i] = p;
+ }
+
+ int unhashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+ byte[] unhashed = new byte[unhashedLength];
+
+ bcpgIn.ReadFully(unhashed);
+
+ sIn = new SignatureSubpacketsParser(new MemoryStream(unhashed, false));
+
+ v.Clear();
+
+ while ((sub = sIn.ReadPacket()) != null)
+ {
+ v.Add(sub);
+ }
+
+ unhashedData = new SignatureSubpacket[v.Count];
+
+ for (int i = 0; i != unhashedData.Length; i++)
+ {
+ SignatureSubpacket p = (SignatureSubpacket)v[i];
+ if (p is IssuerKeyId)
+ {
+ keyId = ((IssuerKeyId)p).KeyId;
+ }
+
+ unhashedData[i] = p;
+ }
+ }
+ else
+ {
+ throw new Exception("unsupported version: " + version);
+ }
+
+ fingerprint = new byte[2];
+ bcpgIn.ReadFully(fingerprint);
+
+ switch (keyAlgorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ MPInteger v = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ v };
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ MPInteger r = new MPInteger(bcpgIn);
+ MPInteger s = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ r, s };
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes.
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ MPInteger p = new MPInteger(bcpgIn);
+ MPInteger g = new MPInteger(bcpgIn);
+ MPInteger y = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ p, g, y };
+ break;
+ default:
+ if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11)
+ {
+ signature = null;
+ MemoryStream bOut = new MemoryStream();
+ int ch;
+ while ((ch = bcpgIn.ReadByte()) >= 0)
+ {
+ bOut.WriteByte((byte) ch);
+ }
+ signatureEncoding = bOut.ToArray();
+ }
+ else
+ {
+ throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Generate a version 4 signature packet.
+ *
+ * @param signatureType
+ * @param keyAlgorithm
+ * @param hashAlgorithm
+ * @param hashedData
+ * @param unhashedData
+ * @param fingerprint
+ * @param signature
+ */
+ public SignaturePacket(
+ int signatureType,
+ long keyId,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ SignatureSubpacket[] hashedData,
+ SignatureSubpacket[] unhashedData,
+ byte[] fingerprint,
+ MPInteger[] signature)
+ : this(4, signatureType, keyId, keyAlgorithm, hashAlgorithm, hashedData, unhashedData, fingerprint, signature)
+ {
+ }
+
+ /**
+ * Generate a version 2/3 signature packet.
+ *
+ * @param signatureType
+ * @param keyAlgorithm
+ * @param hashAlgorithm
+ * @param fingerprint
+ * @param signature
+ */
+ public SignaturePacket(
+ int version,
+ int signatureType,
+ long keyId,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ long creationTime,
+ byte[] fingerprint,
+ MPInteger[] signature)
+ : this(version, signatureType, keyId, keyAlgorithm, hashAlgorithm, null, null, fingerprint, signature)
+ {
+ this.creationTime = creationTime;
+ }
+
+ public SignaturePacket(
+ int version,
+ int signatureType,
+ long keyId,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ SignatureSubpacket[] hashedData,
+ SignatureSubpacket[] unhashedData,
+ byte[] fingerprint,
+ MPInteger[] signature)
+ {
+ this.version = version;
+ this.signatureType = signatureType;
+ this.keyId = keyId;
+ this.keyAlgorithm = keyAlgorithm;
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashedData = hashedData;
+ this.unhashedData = unhashedData;
+ this.fingerprint = fingerprint;
+ this.signature = signature;
+
+ if (hashedData != null)
+ {
+ setCreationTime();
+ }
+ }
+
+ public int Version
+ {
+ get { return version; }
+ }
+
+ public int SignatureType
+ {
+ get { return signatureType; }
+ }
+
+ /**
+ * return the keyId
+ * @return the keyId that created the signature.
+ */
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ /**
+ * return the signature trailer that must be included with the data
+ * to reconstruct the signature
+ *
+ * @return byte[]
+ */
+ public byte[] GetSignatureTrailer()
+ {
+ byte[] trailer = null;
+
+ if (version == 3)
+ {
+ trailer = new byte[5];
+
+ long time = creationTime / 1000L;
+
+ trailer[0] = (byte)signatureType;
+ trailer[1] = (byte)(time >> 24);
+ trailer[2] = (byte)(time >> 16);
+ trailer[3] = (byte)(time >> 8);
+ trailer[4] = (byte)(time);
+ }
+ else
+ {
+ MemoryStream sOut = new MemoryStream();
+
+ sOut.WriteByte((byte)this.Version);
+ sOut.WriteByte((byte)this.SignatureType);
+ sOut.WriteByte((byte)this.KeyAlgorithm);
+ sOut.WriteByte((byte)this.HashAlgorithm);
+
+ MemoryStream hOut = new MemoryStream();
+ SignatureSubpacket[] hashed = this.GetHashedSubPackets();
+
+ for (int i = 0; i != hashed.Length; i++)
+ {
+ hashed[i].Encode(hOut);
+ }
+
+ byte[] data = hOut.ToArray();
+
+ sOut.WriteByte((byte)(data.Length >> 8));
+ sOut.WriteByte((byte)data.Length);
+ sOut.Write(data, 0, data.Length);
+
+ byte[] hData = sOut.ToArray();
+
+ sOut.WriteByte((byte)this.Version);
+ sOut.WriteByte((byte)0xff);
+ sOut.WriteByte((byte)(hData.Length>> 24));
+ sOut.WriteByte((byte)(hData.Length >> 16));
+ sOut.WriteByte((byte)(hData.Length >> 8));
+ sOut.WriteByte((byte)(hData.Length));
+
+ trailer = sOut.ToArray();
+ }
+
+ return trailer;
+ }
+
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return keyAlgorithm; }
+ }
+
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ /**
+ * return the signature as a set of integers - note this is normalised to be the
+ * ASN.1 encoding of what appears in the signature packet.
+ */
+ public MPInteger[] GetSignature()
+ {
+ return signature;
+ }
+
+ /**
+ * Return the byte encoding of the signature section.
+ * @return uninterpreted signature bytes.
+ */
+ public byte[] GetSignatureBytes()
+ {
+ if (signatureEncoding != null)
+ {
+ return (byte[]) signatureEncoding.Clone();
+ }
+
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream bcOut = new BcpgOutputStream(bOut);
+
+ foreach (MPInteger sigObj in signature)
+ {
+ try
+ {
+ bcOut.WriteObject(sigObj);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("internal error: " + e);
+ }
+ }
+
+ return bOut.ToArray();
+ }
+
+ public SignatureSubpacket[] GetHashedSubPackets()
+ {
+ return hashedData;
+ }
+
+ public SignatureSubpacket[] GetUnhashedSubPackets()
+ {
+ return unhashedData;
+ }
+
+ /// <summary>Return the creation time in milliseconds since 1 Jan., 1970 UTC.</summary>
+ public long CreationTime
+ {
+ get { return creationTime; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteByte((byte) version);
+
+ if (version == 3 || version == 2)
+ {
+ pOut.Write(
+ 5, // the length of the next block
+ (byte) signatureType);
+
+ pOut.WriteInt((int)(creationTime / 1000L));
+
+ pOut.WriteLong(keyId);
+
+ pOut.Write(
+ (byte) keyAlgorithm,
+ (byte) hashAlgorithm);
+ }
+ else if (version == 4)
+ {
+ pOut.Write(
+ (byte) signatureType,
+ (byte) keyAlgorithm,
+ (byte) hashAlgorithm);
+
+ EncodeLengthAndData(pOut, GetEncodedSubpackets(hashedData));
+
+ EncodeLengthAndData(pOut, GetEncodedSubpackets(unhashedData));
+ }
+ else
+ {
+ throw new IOException("unknown version: " + version);
+ }
+
+ pOut.Write(fingerprint);
+
+ if (signature != null)
+ {
+ pOut.WriteObjects(signature);
+ }
+ else
+ {
+ pOut.Write(signatureEncoding);
+ }
+
+ bcpgOut.WritePacket(PacketTag.Signature, bOut.ToArray(), true);
+ }
+
+ private static void EncodeLengthAndData(
+ BcpgOutputStream pOut,
+ byte[] data)
+ {
+ pOut.WriteShort((short) data.Length);
+ pOut.Write(data);
+ }
+
+ private static byte[] GetEncodedSubpackets(
+ SignatureSubpacket[] ps)
+ {
+ MemoryStream sOut = new MemoryStream();
+
+ foreach (SignatureSubpacket p in ps)
+ {
+ p.Encode(sOut);
+ }
+
+ return sOut.ToArray();
+ }
+
+ private void setCreationTime()
+ {
+ foreach (SignatureSubpacket p in hashedData)
+ {
+ if (p is SignatureCreationTime)
+ {
+ creationTime = DateTimeUtilities.DateTimeToUnixMs(
+ ((SignatureCreationTime)p).GetTime());
+ break;
+ }
+ }
+ }
+ }
+}
|