Initial Commit

This commit is contained in:
2023-06-21 12:46:23 -04:00
commit c70248a520
1352 changed files with 336780 additions and 0 deletions

View File

@@ -0,0 +1,492 @@
using System;
using System.Collections;
using System.IO;
using System.Text;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/**
* reader for Base64 armored objects - read the headers and then start returning
* bytes when the data is reached. An IOException is thrown if the CRC check
* fails.
*/
public class ArmoredInputStream
: BaseInputStream
{
/*
* set up the decoding table.
*/
private readonly static byte[] decodingTable;
static ArmoredInputStream()
{
decodingTable = new byte[128];
for (int i = 'A'; i <= 'Z'; i++)
{
decodingTable[i] = (byte)(i - 'A');
}
for (int i = 'a'; i <= 'z'; i++)
{
decodingTable[i] = (byte)(i - 'a' + 26);
}
for (int i = '0'; i <= '9'; i++)
{
decodingTable[i] = (byte)(i - '0' + 52);
}
decodingTable['+'] = 62;
decodingTable['/'] = 63;
}
/**
* decode the base 64 encoded input data.
*
* @return the offset the data starts in out.
*/
private int Decode(
int in0,
int in1,
int in2,
int in3,
int[] result)
{
if (in3 < 0)
{
throw new EndOfStreamException("unexpected end of file in armored stream.");
}
int b1, b2, b3, b4;
if (in2 == '=')
{
b1 = decodingTable[in0] &0xff;
b2 = decodingTable[in1] & 0xff;
result[2] = ((b1 << 2) | (b2 >> 4)) & 0xff;
return 2;
}
else if (in3 == '=')
{
b1 = decodingTable[in0];
b2 = decodingTable[in1];
b3 = decodingTable[in2];
result[1] = ((b1 << 2) | (b2 >> 4)) & 0xff;
result[2] = ((b2 << 4) | (b3 >> 2)) & 0xff;
return 1;
}
else
{
b1 = decodingTable[in0];
b2 = decodingTable[in1];
b3 = decodingTable[in2];
b4 = decodingTable[in3];
result[0] = ((b1 << 2) | (b2 >> 4)) & 0xff;
result[1] = ((b2 << 4) | (b3 >> 2)) & 0xff;
result[2] = ((b3 << 6) | b4) & 0xff;
return 0;
}
}
Stream input;
bool start = true;
int[] outBuf = new int[3];
int bufPtr = 3;
Crc24 crc = new Crc24();
bool crcFound = false;
bool hasHeaders = true;
string header = null;
bool newLineFound = false;
bool clearText = false;
bool restart = false;
ArrayList headerList= new ArrayList();
int lastC = 0;
/**
* Create a stream for reading a PGP armoured message, parsing up to a header
* and then reading the data that follows.
*
* @param input
*/
public ArmoredInputStream(
Stream input)
: this(input, true)
{
}
/**
* Create an armoured input stream which will assume the data starts
* straight away, or parse for headers first depending on the value of
* hasHeaders.
*
* @param input
* @param hasHeaders true if headers are to be looked for, false otherwise.
*/
public ArmoredInputStream(
Stream input,
bool hasHeaders)
{
this.input = input;
this.hasHeaders = hasHeaders;
if (hasHeaders)
{
ParseHeaders();
}
start = false;
}
private bool ParseHeaders()
{
header = null;
int c;
int last = 0;
bool headerFound = false;
headerList = new ArrayList();
//
// if restart we already have a header
//
if (restart)
{
headerFound = true;
}
else
{
while ((c = input.ReadByte()) >= 0)
{
if (c == '-' && (last == 0 || last == '\n' || last == '\r'))
{
headerFound = true;
break;
}
last = c;
}
}
if (headerFound)
{
StringBuilder Buffer = new StringBuilder("-");
bool eolReached = false;
bool crLf = false;
if (restart) // we've had to look ahead two '-'
{
Buffer.Append('-');
}
while ((c = input.ReadByte()) >= 0)
{
if (last == '\r' && c == '\n')
{
crLf = true;
}
if (eolReached && (last != '\r' && c == '\n'))
{
break;
}
if (eolReached && c == '\r')
{
break;
}
if (c == '\r' || (last != '\r' && c == '\n'))
{
string line = Buffer.ToString();
if (line.Trim().Length < 1)
break;
headerList.Add(line);
Buffer.Length = 0;
}
if (c != '\n' && c != '\r')
{
Buffer.Append((char)c);
eolReached = false;
}
else
{
if (c == '\r' || (last != '\r' && c == '\n'))
{
eolReached = true;
}
}
last = c;
}
if (crLf)
{
input.ReadByte(); // skip last \n
}
}
if (headerList.Count > 0)
{
header = (string) headerList[0];
}
clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header);
newLineFound = true;
return headerFound;
}
/**
* @return true if we are inside the clear text section of a PGP
* signed message.
*/
public bool IsClearText()
{
return clearText;
}
/**
* Return the armor header line (if there is one)
* @return the armor header line, null if none present.
*/
public string GetArmorHeaderLine()
{
return header;
}
/**
* Return the armor headers (the lines after the armor header line),
* @return an array of armor headers, null if there aren't any.
*/
public string[] GetArmorHeaders()
{
if (headerList.Count <= 1)
{
return null;
}
string[] hdrs = new string[headerList.Count - 1];
for (int i = 0; i != hdrs.Length; i++)
{
hdrs[i] = (string) headerList[i + 1];
}
return hdrs;
}
private int ReadIgnoreSpace()
{
int c;
do
{
c = input.ReadByte();
}
while (c == ' ' || c == '\t');
return c;
}
private int ReadIgnoreWhitespace()
{
int c;
do
{
c = input.ReadByte();
}
while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
return c;
}
private int ReadByteClearText()
{
int c = input.ReadByte();
if (c == '\r' || (c == '\n' && lastC != '\r'))
{
newLineFound = true;
}
else if (newLineFound && c == '-')
{
c = input.ReadByte();
if (c == '-') // a header, not dash escaped
{
clearText = false;
start = true;
restart = true;
}
else // a space - must be a dash escape
{
c = input.ReadByte();
}
newLineFound = false;
}
else
{
if (c != '\n' && lastC != '\r')
{
newLineFound = false;
}
}
lastC = c;
return c;
}
private int ReadClearText(byte[] buffer, int offset, int count)
{
int pos = offset;
try
{
int end = offset + count;
while (pos < end)
{
int c = ReadByteClearText();
if (c == -1)
{
break;
}
buffer[pos++] = (byte) c;
}
}
catch (IOException ioe)
{
if (pos == offset) throw ioe;
}
return pos - offset;
}
private int DoReadByte()
{
if (bufPtr > 2 || crcFound)
{
int c = ReadIgnoreSpace();
if (c == '\n' || c == '\r')
{
c = ReadIgnoreWhitespace();
if (c == '=') // crc reached
{
bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
if (bufPtr != 0)
{
throw new IOException("no crc found in armored message.");
}
crcFound = true;
int i = ((outBuf[0] & 0xff) << 16)
| ((outBuf[1] & 0xff) << 8)
| (outBuf[2] & 0xff);
if (i != crc.Value)
{
throw new IOException("crc check failed in armored message.");
}
return ReadByte();
}
if (c == '-') // end of record reached
{
while ((c = input.ReadByte()) >= 0)
{
if (c == '\n' || c == '\r')
{
break;
}
}
if (!crcFound)
{
throw new IOException("crc check not found.");
}
crcFound = false;
start = true;
bufPtr = 3;
return -1;
}
}
if (c < 0)
{
return -1;
}
bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
}
return outBuf[bufPtr++];
}
public override int ReadByte()
{
if (start)
{
if (hasHeaders)
{
ParseHeaders();
}
crc.Reset();
start = false;
}
if (clearText)
{
return ReadByteClearText();
}
int c = DoReadByte();
crc.Update(c);
return c;
}
public override int Read(byte[] buffer, int offset, int count)
{
if (start && count > 0)
{
if (hasHeaders)
{
ParseHeaders();
}
start = false;
}
if (clearText)
{
return ReadClearText(buffer, offset, count);
}
int pos = offset;
try
{
int end = offset + count;
while (pos < end)
{
int c = DoReadByte();
crc.Update(c);
if (c == -1)
{
break;
}
buffer[pos++] = (byte) c;
}
}
catch (IOException ioe)
{
if (pos == offset) throw ioe;
}
return pos - offset;
}
public override void Close()
{
input.Close();
base.Close();
}
}
}

View File

@@ -0,0 +1,328 @@
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Text;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic output stream.
*/
public class ArmoredOutputStream
: BaseOutputStream
{
private static readonly byte[] encodingTable =
{
(byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
(byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
(byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
(byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
(byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
(byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
(byte)'v',
(byte)'w', (byte)'x', (byte)'y', (byte)'z',
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
(byte)'7', (byte)'8', (byte)'9',
(byte)'+', (byte)'/'
};
/**
* encode the input data producing a base 64 encoded byte array.
*/
private static void Encode(
Stream outStream,
int[] data,
int len)
{
Debug.Assert(len > 0);
Debug.Assert(len < 4);
byte[] bs = new byte[4];
int d1 = data[0];
bs[0] = encodingTable[(d1 >> 2) & 0x3f];
switch (len)
{
case 1:
{
bs[1] = encodingTable[(d1 << 4) & 0x3f];
bs[2] = (byte)'=';
bs[3] = (byte)'=';
break;
}
case 2:
{
int d2 = data[1];
bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
bs[2] = encodingTable[(d2 << 2) & 0x3f];
bs[3] = (byte)'=';
break;
}
case 3:
{
int d2 = data[1];
int d3 = data[2];
bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
bs[3] = encodingTable[d3 & 0x3f];
break;
}
}
outStream.Write(bs, 0, bs.Length);
}
private readonly Stream outStream;
private int[] buf = new int[3];
private int bufPtr = 0;
private Crc24 crc = new Crc24();
private int chunkCount = 0;
private int lastb;
private bool start = true;
private bool clearText = false;
private bool newLine = false;
private string nl = Platform.NewLine;
private string type;
private string headerStart = "-----BEGIN PGP ";
private string headerTail = "-----";
private string footerStart = "-----END PGP ";
private string footerTail = "-----";
private string version = "BCPG v1.32";
private readonly IDictionary headers;
public ArmoredOutputStream(Stream outStream)
{
this.outStream = outStream;
this.headers = new Hashtable();
this.headers["Version"] = version;
}
public ArmoredOutputStream(Stream outStream, IDictionary headers)
{
this.outStream = outStream;
this.headers = new Hashtable(headers);
this.headers["Version"] = version;
}
/**
* Set an additional header entry.
*
* @param name the name of the header entry.
* @param v the value of the header entry.
*/
public void SetHeader(
string name,
string v)
{
headers[name] = v;
}
/**
* Reset the headers to only contain a Version string.
*/
public void ResetHeaders()
{
headers.Clear();
headers["Version"] = version;
}
/**
* Start a clear text signed message.
* @param hashAlgorithm
*/
public void BeginClearText(
HashAlgorithmTag hashAlgorithm)
{
string hash;
switch (hashAlgorithm)
{
case HashAlgorithmTag.Sha1:
hash = "SHA1";
break;
case HashAlgorithmTag.Sha256:
hash = "SHA256";
break;
case HashAlgorithmTag.Sha384:
hash = "SHA384";
break;
case HashAlgorithmTag.Sha512:
hash = "SHA512";
break;
case HashAlgorithmTag.MD2:
hash = "MD2";
break;
case HashAlgorithmTag.MD5:
hash = "MD5";
break;
case HashAlgorithmTag.RipeMD160:
hash = "RIPEMD160";
break;
default:
throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
}
DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);
DoWrite("Hash: " + hash + nl + nl);
clearText = true;
newLine = true;
lastb = 0;
}
public void EndClearText()
{
clearText = false;
}
public override void WriteByte(
byte b)
{
if (clearText)
{
outStream.WriteByte(b);
if (newLine)
{
if (!(b == '\n' && lastb == '\r'))
{
newLine = false;
}
if (b == '-')
{
outStream.WriteByte((byte)' ');
outStream.WriteByte((byte)'-'); // dash escape
}
}
if (b == '\r' || (b == '\n' && lastb != '\r'))
{
newLine = true;
}
lastb = b;
return;
}
if (start)
{
bool newPacket = (b & 0x40) != 0;
int tag;
if (newPacket)
{
tag = b & 0x3f;
}
else
{
tag = (b & 0x3f) >> 2;
}
switch ((PacketTag)tag)
{
case PacketTag.PublicKey:
type = "PUBLIC KEY BLOCK";
break;
case PacketTag.SecretKey:
type = "PRIVATE KEY BLOCK";
break;
case PacketTag.Signature:
type = "SIGNATURE";
break;
default:
type = "MESSAGE";
break;
}
DoWrite(headerStart + type + headerTail + nl);
WriteHeaderEntry("Version", (string) headers["Version"]);
foreach (DictionaryEntry de in headers)
{
string k = (string) de.Key;
if (k != "Version")
{
string v = (string) de.Value;
WriteHeaderEntry(k, v);
}
}
DoWrite(nl);
start = false;
}
if (bufPtr == 3)
{
Encode(outStream, buf, bufPtr);
bufPtr = 0;
if ((++chunkCount & 0xf) == 0)
{
DoWrite(nl);
}
}
crc.Update(b);
buf[bufPtr++] = b & 0xff;
}
/**
* <b>Note</b>: close does nor close the underlying stream. So it is possible to write
* multiple objects using armoring to a single stream.
*/
public override void Close()
{
if (type != null)
{
if (bufPtr > 0)
{
Encode(outStream, buf, bufPtr);
}
DoWrite(nl + '=');
int crcV = crc.Value;
buf[0] = ((crcV >> 16) & 0xff);
buf[1] = ((crcV >> 8) & 0xff);
buf[2] = (crcV & 0xff);
Encode(outStream, buf, 3);
DoWrite(nl);
DoWrite(footerStart);
DoWrite(type);
DoWrite(footerTail);
DoWrite(nl);
outStream.Flush();
type = null;
start = true;
base.Close();
}
}
private void WriteHeaderEntry(
string name,
string v)
{
DoWrite(name + ": " + v + nl);
}
private void DoWrite(
string s)
{
byte[] bs = Encoding.ASCII.GetBytes(s);
outStream.Write(bs, 0, bs.Length);
}
}
}

View File

@@ -0,0 +1,355 @@
using System;
using System.IO;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Reader for PGP objects.</remarks>
public class BcpgInputStream
: BaseInputStream
{
private Stream m_in;
private bool next = false;
private int nextB;
internal static BcpgInputStream Wrap(
Stream inStr)
{
if (inStr is BcpgInputStream)
{
return (BcpgInputStream) inStr;
}
return new BcpgInputStream(inStr);
}
private BcpgInputStream(
Stream inputStream)
{
this.m_in = inputStream;
}
public override int ReadByte()
{
if (next)
{
next = false;
return nextB;
}
return m_in.ReadByte();
}
public override int Read(
byte[] buffer,
int offset,
int count)
{
// Strangely, when count == 0, we should still attempt to read a byte
// if (count == 0)
// return 0;
if (!next)
return m_in.Read(buffer, offset, count);
// We have next byte waiting, so return it
if (nextB < 0)
return 0; // EndOfStream
if (buffer == null)
throw new ArgumentNullException("buffer");
buffer[offset] = (byte) nextB;
next = false;
return 1;
}
public byte[] ReadAll()
{
return Streams.ReadAll(this);
}
public void ReadFully(
byte[] buffer,
int off,
int len)
{
if (Streams.ReadFully(this, buffer, off, len) < len)
throw new EndOfStreamException();
}
public void ReadFully(
byte[] buffer)
{
ReadFully(buffer, 0, buffer.Length);
}
/// <summary>Returns the next packet tag in the stream.</summary>
public PacketTag NextPacketTag()
{
if (!next)
{
try
{
nextB = m_in.ReadByte();
}
catch (EndOfStreamException)
{
nextB = -1;
}
next = true;
}
if (nextB >= 0)
{
if ((nextB & 0x40) != 0) // new
{
return (PacketTag)(nextB & 0x3f);
}
else // old
{
return (PacketTag)((nextB & 0x3f) >> 2);
}
}
return (PacketTag) nextB;
}
public Packet ReadPacket()
{
int hdr = this.ReadByte();
if (hdr < 0)
{
return null;
}
if ((hdr & 0x80) == 0)
{
throw new IOException("invalid header encountered");
}
bool newPacket = (hdr & 0x40) != 0;
PacketTag tag = 0;
int bodyLen = 0;
bool partial = false;
if (newPacket)
{
tag = (PacketTag)(hdr & 0x3f);
int l = this.ReadByte();
if (l < 192)
{
bodyLen = l;
}
else if (l <= 223)
{
int b = m_in.ReadByte();
bodyLen = ((l - 192) << 8) + (b) + 192;
}
else if (l == 255)
{
bodyLen = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16)
| (m_in.ReadByte() << 8) | m_in.ReadByte();
}
else
{
partial = true;
bodyLen = 1 << (l & 0x1f);
}
}
else
{
int lengthType = hdr & 0x3;
tag = (PacketTag)((hdr & 0x3f) >> 2);
switch (lengthType)
{
case 0:
bodyLen = this.ReadByte();
break;
case 1:
bodyLen = (this.ReadByte() << 8) | this.ReadByte();
break;
case 2:
bodyLen = (this.ReadByte() << 24) | (this.ReadByte() << 16)
| (this.ReadByte() << 8) | this.ReadByte();
break;
case 3:
partial = true;
break;
default:
throw new IOException("unknown length type encountered");
}
}
BcpgInputStream objStream;
if (bodyLen == 0 && partial)
{
objStream = this;
}
else
{
PartialInputStream pis = new PartialInputStream(this, partial, bodyLen);
objStream = new BcpgInputStream(pis);
}
switch (tag)
{
case PacketTag.Reserved:
return new InputStreamPacket(objStream);
case PacketTag.PublicKeyEncryptedSession:
return new PublicKeyEncSessionPacket(objStream);
case PacketTag.Signature:
return new SignaturePacket(objStream);
case PacketTag.SymmetricKeyEncryptedSessionKey:
return new SymmetricKeyEncSessionPacket(objStream);
case PacketTag.OnePassSignature:
return new OnePassSignaturePacket(objStream);
case PacketTag.SecretKey:
return new SecretKeyPacket(objStream);
case PacketTag.PublicKey:
return new PublicKeyPacket(objStream);
case PacketTag.SecretSubkey:
return new SecretSubkeyPacket(objStream);
case PacketTag.CompressedData:
return new CompressedDataPacket(objStream);
case PacketTag.SymmetricKeyEncrypted:
return new SymmetricEncDataPacket(objStream);
case PacketTag.Marker:
return new MarkerPacket(objStream);
case PacketTag.LiteralData:
return new LiteralDataPacket(objStream);
case PacketTag.Trust:
return new TrustPacket(objStream);
case PacketTag.UserId:
return new UserIdPacket(objStream);
case PacketTag.UserAttribute:
return new UserAttributePacket(objStream);
case PacketTag.PublicSubkey:
return new PublicSubkeyPacket(objStream);
case PacketTag.SymmetricEncryptedIntegrityProtected:
return new SymmetricEncIntegrityPacket(objStream);
case PacketTag.ModificationDetectionCode:
return new ModDetectionCodePacket(objStream);
case PacketTag.Experimental1:
case PacketTag.Experimental2:
case PacketTag.Experimental3:
case PacketTag.Experimental4:
return new ExperimentalPacket(tag, objStream);
default:
throw new IOException("unknown packet type encountered: " + tag);
}
}
public override void Close()
{
m_in.Close();
base.Close();
}
/// <summary>
/// A stream that overlays our input stream, allowing the user to only read a segment of it.
/// NB: dataLength will be negative if the segment length is in the upper range above 2**31.
/// </summary>
private class PartialInputStream
: BaseInputStream
{
private BcpgInputStream m_in;
private bool partial;
private int dataLength;
internal PartialInputStream(
BcpgInputStream bcpgIn,
bool partial,
int dataLength)
{
this.m_in = bcpgIn;
this.partial = partial;
this.dataLength = dataLength;
}
public override int ReadByte()
{
do
{
if (dataLength != 0)
{
int ch = m_in.ReadByte();
if (ch < 0)
{
throw new EndOfStreamException("Premature end of stream in PartialInputStream");
}
dataLength--;
return ch;
}
}
while (partial && ReadPartialDataLength() >= 0);
return -1;
}
public override int Read(byte[] buffer, int offset, int count)
{
do
{
if (dataLength != 0)
{
int readLen = (dataLength > count || dataLength < 0) ? count : dataLength;
int len = m_in.Read(buffer, offset, readLen);
if (len < 1)
{
throw new EndOfStreamException("Premature end of stream in PartialInputStream");
}
dataLength -= len;
return len;
}
}
while (partial && ReadPartialDataLength() >= 0);
return 0;
}
private int ReadPartialDataLength()
{
int l = m_in.ReadByte();
if (l < 0)
{
return -1;
}
partial = false;
if (l < 192)
{
dataLength = l;
}
else if (l <= 223)
{
dataLength = ((l - 192) << 8) + (m_in.ReadByte()) + 192;
}
else if (l == 255)
{
dataLength = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16)
| (m_in.ReadByte() << 8) | m_in.ReadByte();
}
else
{
partial = true;
dataLength = 1 << (l & 0x1f);
}
return 0;
}
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for a PGP object.</remarks>
public abstract class BcpgObject
{
public virtual byte[] GetEncoded()
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.WriteObject(this);
return bOut.ToArray();
}
public abstract void Encode(BcpgOutputStream bcpgOut);
}
}

View File

@@ -0,0 +1,390 @@
using System;
using System.IO;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic output stream.</remarks>
public class BcpgOutputStream
: BaseOutputStream
{
internal static BcpgOutputStream Wrap(
Stream outStr)
{
if (outStr is BcpgOutputStream)
{
return (BcpgOutputStream) outStr;
}
return new BcpgOutputStream(outStr);
}
private Stream outStr;
private byte[] partialBuffer;
private int partialBufferLength;
private int partialPower;
private int partialOffset;
private const int BufferSizePower = 16; // 2^16 size buffer on long files
/// <summary>Create a stream representing a general packet.</summary>
/// <param name="outStr">Output stream to write to.</param>
public BcpgOutputStream(
Stream outStr)
{
if (outStr == null)
throw new ArgumentNullException("outStr");
this.outStr = outStr;
}
/// <summary>Create a stream representing an old style partial object.</summary>
/// <param name="outStr">Output stream to write to.</param>
/// <param name="tag">The packet tag for the object.</param>
public BcpgOutputStream(
Stream outStr,
PacketTag tag)
{
if (outStr == null)
throw new ArgumentNullException("outStr");
this.outStr = outStr;
this.WriteHeader(tag, true, true, 0);
}
/// <summary>Create a stream representing a general packet.</summary>
/// <param name="outStr">Output stream to write to.</param>
/// <param name="tag">Packet tag.</param>
/// <param name="length">Size of chunks making up the packet.</param>
/// <param name="oldFormat">If true, the header is written out in old format.</param>
public BcpgOutputStream(
Stream outStr,
PacketTag tag,
long length,
bool oldFormat)
{
if (outStr == null)
throw new ArgumentNullException("outStr");
this.outStr = outStr;
if (length > 0xFFFFFFFFL)
{
this.WriteHeader(tag, false, true, 0);
this.partialBufferLength = 1 << BufferSizePower;
this.partialBuffer = new byte[partialBufferLength];
this.partialPower = BufferSizePower;
this.partialOffset = 0;
}
else
{
this.WriteHeader(tag, oldFormat, false, length);
}
}
/// <summary>Create a new style partial input stream buffered into chunks.</summary>
/// <param name="outStr">Output stream to write to.</param>
/// <param name="tag">Packet tag.</param>
/// <param name="length">Size of chunks making up the packet.</param>
public BcpgOutputStream(
Stream outStr,
PacketTag tag,
long length)
{
if (outStr == null)
throw new ArgumentNullException("outStr");
this.outStr = outStr;
this.WriteHeader(tag, false, false, length);
}
/// <summary>Create a new style partial input stream buffered into chunks.</summary>
/// <param name="outStr">Output stream to write to.</param>
/// <param name="tag">Packet tag.</param>
/// <param name="buffer">Buffer to use for collecting chunks.</param>
public BcpgOutputStream(
Stream outStr,
PacketTag tag,
byte[] buffer)
{
if (outStr == null)
throw new ArgumentNullException("outStr");
this.outStr = outStr;
this.WriteHeader(tag, false, true, 0);
this.partialBuffer = buffer;
uint length = (uint) partialBuffer.Length;
for (partialPower = 0; length != 1; partialPower++)
{
length >>= 1;
}
if (partialPower > 30)
{
throw new IOException("Buffer cannot be greater than 2^30 in length.");
}
this.partialBufferLength = 1 << partialPower;
this.partialOffset = 0;
}
private void WriteNewPacketLength(
long bodyLen)
{
if (bodyLen < 192)
{
outStr.WriteByte((byte)bodyLen);
}
else if (bodyLen <= 8383)
{
bodyLen -= 192;
outStr.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
outStr.WriteByte((byte)bodyLen);
}
else
{
outStr.WriteByte(0xff);
outStr.WriteByte((byte)(bodyLen >> 24));
outStr.WriteByte((byte)(bodyLen >> 16));
outStr.WriteByte((byte)(bodyLen >> 8));
outStr.WriteByte((byte)bodyLen);
}
}
private void WriteHeader(
PacketTag tag,
bool oldPackets,
bool partial,
long bodyLen)
{
int hdr = 0x80;
if (partialBuffer != null)
{
PartialFlush(true);
partialBuffer = null;
}
if (oldPackets)
{
hdr |= ((int) tag) << 2;
if (partial)
{
this.WriteByte((byte)(hdr | 0x03));
}
else
{
if (bodyLen <= 0xff)
{
this.WriteByte((byte) hdr);
this.WriteByte((byte)bodyLen);
}
else if (bodyLen <= 0xffff)
{
this.WriteByte((byte)(hdr | 0x01));
this.WriteByte((byte)(bodyLen >> 8));
this.WriteByte((byte)(bodyLen));
}
else
{
this.WriteByte((byte)(hdr | 0x02));
this.WriteByte((byte)(bodyLen >> 24));
this.WriteByte((byte)(bodyLen >> 16));
this.WriteByte((byte)(bodyLen >> 8));
this.WriteByte((byte)bodyLen);
}
}
}
else
{
hdr |= 0x40 | (int) tag;
this.WriteByte((byte) hdr);
if (partial)
{
partialOffset = 0;
}
else
{
this.WriteNewPacketLength(bodyLen);
}
}
}
private void PartialFlush(
bool isLast)
{
if (isLast)
{
WriteNewPacketLength(partialOffset);
outStr.Write(partialBuffer, 0, partialOffset);
}
else
{
outStr.WriteByte((byte)(0xE0 | partialPower));
outStr.Write(partialBuffer, 0, partialBufferLength);
}
partialOffset = 0;
}
private void WritePartial(
byte b)
{
if (partialOffset == partialBufferLength)
{
PartialFlush(false);
}
partialBuffer[partialOffset++] = b;
}
private void WritePartial(
byte[] buffer,
int off,
int len)
{
if (partialOffset == partialBufferLength)
{
PartialFlush(false);
}
if (len <= (partialBufferLength - partialOffset))
{
Array.Copy(buffer, off, partialBuffer, partialOffset, len);
partialOffset += len;
}
else
{
int diff = partialBufferLength - partialOffset;
Array.Copy(buffer, off, partialBuffer, partialOffset, diff);
off += diff;
len -= diff;
PartialFlush(false);
while (len > partialBufferLength)
{
Array.Copy(buffer, off, partialBuffer, 0, partialBufferLength);
off += partialBufferLength;
len -= partialBufferLength;
PartialFlush(false);
}
Array.Copy(buffer, off, partialBuffer, 0, len);
partialOffset += len;
}
}
public override void WriteByte(
byte value)
{
if (partialBuffer != null)
{
WritePartial(value);
}
else
{
outStr.WriteByte(value);
}
}
public override void Write(
byte[] buffer,
int offset,
int count)
{
if (partialBuffer != null)
{
WritePartial(buffer, offset, count);
}
else
{
outStr.Write(buffer, offset, count);
}
}
// Additional helper methods to write primitive types
internal virtual void WriteShort(
short n)
{
this.Write(
(byte)(n >> 8),
(byte)n);
}
internal virtual void WriteInt(
int n)
{
this.Write(
(byte)(n >> 24),
(byte)(n >> 16),
(byte)(n >> 8),
(byte)n);
}
internal virtual void WriteLong(
long n)
{
this.Write(
(byte)(n >> 56),
(byte)(n >> 48),
(byte)(n >> 40),
(byte)(n >> 32),
(byte)(n >> 24),
(byte)(n >> 16),
(byte)(n >> 8),
(byte)n);
}
public void WritePacket(
ContainedPacket p)
{
p.Encode(this);
}
internal void WritePacket(
PacketTag tag,
byte[] body,
bool oldFormat)
{
this.WriteHeader(tag, oldFormat, false, body.Length);
this.Write(body);
}
public void WriteObject(
BcpgObject bcpgObject)
{
bcpgObject.Encode(this);
}
public void WriteObjects(
params BcpgObject[] v)
{
foreach (BcpgObject o in v)
{
o.Encode(this);
}
}
/// <summary>Flush the underlying stream.</summary>
public override void Flush()
{
outStr.Flush();
}
/// <summary>Finish writing out the current packet without closing the underlying stream.</summary>
public void Finish()
{
if (partialBuffer != null)
{
PartialFlush(true);
partialBuffer = null;
}
}
public override void Close()
{
this.Finish();
outStr.Flush();
outStr.Close();
base.Close();
}
}
}

View File

@@ -0,0 +1,24 @@
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Generic compressed data object.</remarks>
public class CompressedDataPacket
: InputStreamPacket
{
private readonly CompressionAlgorithmTag algorithm;
internal CompressedDataPacket(
BcpgInputStream bcpgIn)
: base(bcpgIn)
{
this.algorithm = (CompressionAlgorithmTag) bcpgIn.ReadByte();
}
/// <summary>The algorithm tag value.</summary>
public CompressionAlgorithmTag Algorithm
{
get { return algorithm; }
}
}
}

View File

@@ -0,0 +1,11 @@
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic tags for compression algorithms.</remarks>
public enum CompressionAlgorithmTag
{
Uncompressed = 0, // Uncompressed
Zip = 1, // ZIP (RFC 1951)
ZLib = 2, // ZLIB (RFC 1950)
BZip2 = 3, // BZ2
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic type for a PGP packet.</remarks>
public abstract class ContainedPacket
: Packet
{
public byte[] GetEncoded()
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.WritePacket(this);
return bOut.ToArray();
}
public abstract void Encode(BcpgOutputStream bcpgOut);
}
}

View File

@@ -0,0 +1,46 @@
using System;
namespace Org.BouncyCastle.Bcpg
{
public class Crc24
{
private const int Crc24Init = 0x0b704ce;
private const int Crc24Poly = 0x1864cfb;
private int crc = Crc24Init;
public Crc24()
{
}
public void Update(
int b)
{
crc ^= b << 16;
for (int i = 0; i < 8; i++)
{
crc <<= 1;
if ((crc & 0x1000000) != 0)
{
crc ^= Crc24Poly;
}
}
}
[Obsolete("Use 'Value' property instead")]
public int GetValue()
{
return crc;
}
public int Value
{
get { return crc; }
}
public void Reset()
{
crc = Crc24Init;
}
}
}

View File

@@ -0,0 +1,80 @@
using System;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for a DSA public key.</remarks>
public class DsaPublicBcpgKey
: BcpgObject, IBcpgKey
{
private readonly MPInteger p, q, g, y;
/// <param name="bcpgIn">The stream to read the packet from.</param>
public DsaPublicBcpgKey(
BcpgInputStream bcpgIn)
{
this.p = new MPInteger(bcpgIn);
this.q = new MPInteger(bcpgIn);
this.g = new MPInteger(bcpgIn);
this.y = new MPInteger(bcpgIn);
}
public DsaPublicBcpgKey(
BigInteger p,
BigInteger q,
BigInteger g,
BigInteger y)
{
this.p = new MPInteger(p);
this.q = new MPInteger(q);
this.g = new MPInteger(g);
this.y = new MPInteger(y);
}
/// <summary>The format, as a string, always "PGP".</summary>
public string Format
{
get { return "PGP"; }
}
/// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
return base.GetEncoded();
}
catch (Exception)
{
return null;
}
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteObjects(p, q, g, y);
}
public BigInteger G
{
get { return g.Value; }
}
public BigInteger P
{
get { return p.Value; }
}
public BigInteger Q
{
get { return q.Value; }
}
public BigInteger Y
{
get { return y.Value; }
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for a DSA secret key.</remarks>
public class DsaSecretBcpgKey
: BcpgObject, IBcpgKey
{
internal MPInteger x;
/**
* @param in
*/
public DsaSecretBcpgKey(
BcpgInputStream bcpgIn)
{
this.x = new MPInteger(bcpgIn);
}
public DsaSecretBcpgKey(
BigInteger x)
{
this.x = new MPInteger(x);
}
/// <summary>The format, as a string, always "PGP".</summary>
public string Format
{
get { return "PGP"; }
}
/// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
return base.GetEncoded();
}
catch (Exception)
{
return null;
}
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteObject(x);
}
/**
* @return x
*/
public BigInteger X
{
get { return x.Value; }
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for an ElGamal public key.</remarks>
public class ElGamalPublicBcpgKey
: BcpgObject, IBcpgKey
{
internal MPInteger p, g, y;
public ElGamalPublicBcpgKey(
BcpgInputStream bcpgIn)
{
this.p = new MPInteger(bcpgIn);
this.g = new MPInteger(bcpgIn);
this.y = new MPInteger(bcpgIn);
}
public ElGamalPublicBcpgKey(
BigInteger p,
BigInteger g,
BigInteger y)
{
this.p = new MPInteger(p);
this.g = new MPInteger(g);
this.y = new MPInteger(y);
}
/// <summary>The format, as a string, always "PGP".</summary>
public string Format
{
get { return "PGP"; }
}
/// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
return base.GetEncoded();
}
catch (Exception)
{
return null;
}
}
public BigInteger P
{
get { return p.Value; }
}
public BigInteger G
{
get { return g.Value; }
}
public BigInteger Y
{
get { return y.Value; }
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteObjects(p, g, y);
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for an ElGamal secret key.</remarks>
public class ElGamalSecretBcpgKey
: BcpgObject, IBcpgKey
{
internal MPInteger x;
/**
* @param in
*/
public ElGamalSecretBcpgKey(
BcpgInputStream bcpgIn)
{
this.x = new MPInteger(bcpgIn);
}
/**
* @param x
*/
public ElGamalSecretBcpgKey(
BigInteger x)
{
this.x = new MPInteger(x);
}
/// <summary>The format, as a string, always "PGP".</summary>
public string Format
{
get { return "PGP"; }
}
public BigInteger X
{
get { return x.Value; }
}
/// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
return base.GetEncoded();
}
catch (Exception)
{
return null;
}
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteObject(x);
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for an experimental packet.</remarks>
public class ExperimentalPacket
: ContainedPacket //, PublicKeyAlgorithmTag
{
private readonly PacketTag tag;
private readonly byte[] contents;
internal ExperimentalPacket(
PacketTag tag,
BcpgInputStream bcpgIn)
{
this.tag = tag;
this.contents = bcpgIn.ReadAll();
}
public PacketTag Tag
{
get { return tag; }
}
public byte[] GetContents()
{
return (byte[]) contents.Clone();
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(tag, contents, true);
}
}
}

View File

@@ -0,0 +1,19 @@
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic tags for hash algorithms.</remarks>
public enum HashAlgorithmTag
{
MD5 = 1, // MD5
Sha1 = 2, // SHA-1
RipeMD160 = 3, // RIPE-MD/160
DoubleSha = 4, // Reserved for double-width SHA (experimental)
MD2 = 5, // MD2
Tiger192 = 6, // Reserved for TIGER/192
Haval5pass160 = 7, // Reserved for HAVAL (5 pass, 160-bit)
Sha256 = 8, // SHA-256
Sha384 = 9, // SHA-384
Sha512 = 10, // SHA-512
Sha224 = 11, // SHA-224
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base interface for a PGP key.</remarks>
public interface IBcpgKey
{
/// <summary>
/// The base format for this key - in the case of the symmetric keys it will generally
/// be raw indicating that the key is just a straight byte representation, for an asymmetric
/// key the format will be PGP, indicating the key is a string of MPIs encoded in PGP format.
/// </summary>
/// <returns>"RAW" or "PGP".</returns>
string Format { get; }
}
}

View File

@@ -0,0 +1,20 @@
namespace Org.BouncyCastle.Bcpg
{
public class InputStreamPacket
: Packet
{
private readonly BcpgInputStream bcpgIn;
public InputStreamPacket(
BcpgInputStream bcpgIn)
{
this.bcpgIn = bcpgIn;
}
/// <summary>Note: you can only read from this once...</summary>
public BcpgInputStream GetInputStream()
{
return bcpgIn;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Generic literal data packet.</remarks>
public class LiteralDataPacket
: InputStreamPacket
{
private int format;
private string fileName;
private long modDate;
internal LiteralDataPacket(
BcpgInputStream bcpgIn)
: base(bcpgIn)
{
format = bcpgIn.ReadByte();
int l = bcpgIn.ReadByte();
char[] fileNameChars = new char[l];
for (int i = 0; i != fileNameChars.Length; i++)
{
fileNameChars[i] = (char)bcpgIn.ReadByte();
}
fileName = new string(fileNameChars);
modDate = (((uint)bcpgIn.ReadByte() << 24)
| ((uint)bcpgIn.ReadByte() << 16)
| ((uint)bcpgIn.ReadByte() << 8)
| (uint)bcpgIn.ReadByte()) * 1000L;
}
/// <summary>The format tag value.</summary>
public int Format
{
get { return format; }
}
/// <summary>The modification time of the file in milli-seconds (since Jan 1, 1970 UTC)</summary>
public long ModificationTime
{
get { return modDate; }
}
public string FileName
{
get { return fileName; }
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.IO;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>A multiple precision integer</remarks>
public class MPInteger
: BcpgObject
{
private readonly BigInteger val;
public MPInteger(
BcpgInputStream bcpgIn)
{
if (bcpgIn == null)
throw new ArgumentNullException("bcpgIn");
int length = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
byte[] bytes = new byte[(length + 7) / 8];
bcpgIn.ReadFully(bytes);
this.val = new BigInteger(1, bytes);
}
public MPInteger(
BigInteger val)
{
if (val == null)
throw new ArgumentNullException("val");
if (val.SignValue < 0)
throw new ArgumentException("Values must be positive", "val");
this.val = val;
}
public BigInteger Value
{
get { return val; }
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteShort((short) val.BitLength);
bcpgOut.Write(val.ToByteArrayUnsigned());
}
internal static void Encode(
BcpgOutputStream bcpgOut,
BigInteger val)
{
bcpgOut.WriteShort((short) val.BitLength);
bcpgOut.Write(val.ToByteArrayUnsigned());
}
}
}

View File

@@ -0,0 +1,24 @@
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic type for a marker packet.</remarks>
public class MarkerPacket
: ContainedPacket
{
// "PGP"
byte[] marker = { (byte)0x50, (byte)0x47, (byte)0x50 };
public MarkerPacket(
BcpgInputStream bcpgIn)
{
bcpgIn.ReadFully(marker);
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.Marker, marker, true);
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for a modification detection code packet.</remarks>
public class ModDetectionCodePacket
: ContainedPacket
{
private readonly byte[] digest;
internal ModDetectionCodePacket(
BcpgInputStream bcpgIn)
{
if (bcpgIn == null)
throw new ArgumentNullException("bcpgIn");
this.digest = new byte[20];
bcpgIn.ReadFully(this.digest);
}
public ModDetectionCodePacket(
byte[] digest)
{
if (digest == null)
throw new ArgumentNullException("digest");
this.digest = (byte[]) digest.Clone();
}
public byte[] GetDigest()
{
return (byte[]) digest.Clone();
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.ModificationDetectionCode, digest, false);
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Generic signature object</remarks>
public class OnePassSignaturePacket
: ContainedPacket
{
private int version;
private int sigType;
private HashAlgorithmTag hashAlgorithm;
private PublicKeyAlgorithmTag keyAlgorithm;
private long keyId;
private int nested;
internal OnePassSignaturePacket(
BcpgInputStream bcpgIn)
{
version = bcpgIn.ReadByte();
sigType = bcpgIn.ReadByte();
hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
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();
nested = bcpgIn.ReadByte();
}
public OnePassSignaturePacket(
int sigType,
HashAlgorithmTag hashAlgorithm,
PublicKeyAlgorithmTag keyAlgorithm,
long keyId,
bool isNested)
{
this.version = 3;
this.sigType = sigType;
this.hashAlgorithm = hashAlgorithm;
this.keyAlgorithm = keyAlgorithm;
this.keyId = keyId;
this.nested = (isNested) ? 0 : 1;
}
public int SignatureType
{
get { return sigType; }
}
/// <summary>The encryption algorithm tag.</summary>
public PublicKeyAlgorithmTag KeyAlgorithm
{
get { return keyAlgorithm; }
}
/// <summary>The hash algorithm tag.</summary>
public HashAlgorithmTag HashAlgorithm
{
get { return hashAlgorithm; }
}
public long KeyId
{
get { return keyId; }
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.Write(
(byte) version,
(byte) sigType,
(byte) hashAlgorithm,
(byte) keyAlgorithm);
pOut.WriteLong(keyId);
pOut.WriteByte((byte) nested);
bcpgOut.WritePacket(PacketTag.OnePassSignature, bOut.ToArray(), true);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
public abstract class OutputStreamPacket
{
private readonly BcpgOutputStream bcpgOut;
internal OutputStreamPacket(
BcpgOutputStream bcpgOut)
{
if (bcpgOut == null)
throw new ArgumentNullException("bcpgOut");
this.bcpgOut = bcpgOut;
}
public abstract BcpgOutputStream Open();
public abstract void Close();
}
}

View File

@@ -0,0 +1,7 @@
namespace Org.BouncyCastle.Bcpg
{
public class Packet
//: PacketTag
{
}
}

View File

@@ -0,0 +1,30 @@
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic PGP packet tag types.</remarks>
public enum PacketTag
{
Reserved = 0, // Reserved - a packet tag must not have this value
PublicKeyEncryptedSession = 1, // Public-Key Encrypted Session Key Packet
Signature = 2, // Signature Packet
SymmetricKeyEncryptedSessionKey = 3, // Symmetric-Key Encrypted Session Key Packet
OnePassSignature = 4, // One-Pass Signature Packet
SecretKey = 5, // Secret Key Packet
PublicKey = 6, // Public Key Packet
SecretSubkey = 7, // Secret Subkey Packet
CompressedData = 8, // Compressed Data Packet
SymmetricKeyEncrypted = 9, // Symmetrically Encrypted Data Packet
Marker = 10, // Marker Packet
LiteralData = 11, // Literal Data Packet
Trust = 12, // Trust Packet
UserId = 13, // User ID Packet
PublicSubkey = 14, // Public Subkey Packet
UserAttribute = 17, // User attribute
SymmetricEncryptedIntegrityProtected = 18, // Symmetric encrypted, integrity protected
ModificationDetectionCode = 19, // Modification detection code
Experimental1 = 60, // Private or Experimental Values
Experimental2 = 61,
Experimental3 = 62,
Experimental4 = 63
}
}

View File

@@ -0,0 +1,28 @@
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Public Key Algorithm tag numbers.</remarks>
public enum PublicKeyAlgorithmTag
{
RsaGeneral = 1, // RSA (Encrypt or Sign)
RsaEncrypt = 2, // RSA Encrypt-Only
RsaSign = 3, // RSA Sign-Only
ElGamalEncrypt = 16, // Elgamal (Encrypt-Only), see [ELGAMAL]
Dsa = 17, // DSA (Digital Signature Standard)
EC = 18, // Reserved for Elliptic Curve
ECDsa = 19, // Reserved for ECDSA
ElGamalGeneral = 20, // Elgamal (Encrypt or Sign)
DiffieHellman = 21, // Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME)
Experimental_1 = 100,
Experimental_2 = 101,
Experimental_3 = 102,
Experimental_4 = 103,
Experimental_5 = 104,
Experimental_6 = 105,
Experimental_7 = 106,
Experimental_8 = 107,
Experimental_9 = 108,
Experimental_10 = 109,
Experimental_11 = 110,
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.IO;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for a PGP public key.</remarks>
public class PublicKeyEncSessionPacket
: ContainedPacket //, PublicKeyAlgorithmTag
{
private int version;
private long keyId;
private PublicKeyAlgorithmTag algorithm;
private BigInteger[] data;
internal PublicKeyEncSessionPacket(
BcpgInputStream bcpgIn)
{
version = bcpgIn.ReadByte();
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();
algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
switch ((PublicKeyAlgorithmTag) algorithm)
{
case PublicKeyAlgorithmTag.RsaEncrypt:
case PublicKeyAlgorithmTag.RsaGeneral:
data = new BigInteger[]{ new MPInteger(bcpgIn).Value };
break;
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
data = new BigInteger[]
{
new MPInteger(bcpgIn).Value,
new MPInteger(bcpgIn).Value
};
break;
default:
throw new IOException("unknown PGP public key algorithm encountered");
}
}
public PublicKeyEncSessionPacket(
long keyId,
PublicKeyAlgorithmTag algorithm,
BigInteger[] data)
{
this.version = 3;
this.keyId = keyId;
this.algorithm = algorithm;
this.data = (BigInteger[]) data.Clone();
}
public int Version
{
get { return version; }
}
public long KeyId
{
get { return keyId; }
}
public PublicKeyAlgorithmTag Algorithm
{
get { return algorithm; }
}
public BigInteger[] GetEncSessionKey()
{
return (BigInteger[]) data.Clone();
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.WriteByte((byte) version);
pOut.WriteLong(keyId);
pOut.WriteByte((byte)algorithm);
for (int i = 0; i != data.Length; i++)
{
MPInteger.Encode(pOut, data[i]);
}
bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
}
}
}

View File

@@ -0,0 +1,115 @@
using System;
using System.IO;
using Org.BouncyCastle.Utilities.Date;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for a PGP public key.</remarks>
public class PublicKeyPacket
: ContainedPacket //, PublicKeyAlgorithmTag
{
private int version;
private long time;
private int validDays;
private PublicKeyAlgorithmTag algorithm;
private IBcpgKey key;
internal PublicKeyPacket(
BcpgInputStream bcpgIn)
{
version = bcpgIn.ReadByte();
time = ((uint)bcpgIn.ReadByte() << 24) | ((uint)bcpgIn.ReadByte() << 16)
| ((uint)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte();
if (version <= 3)
{
validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
}
algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
switch ((PublicKeyAlgorithmTag) algorithm)
{
case PublicKeyAlgorithmTag.RsaEncrypt:
case PublicKeyAlgorithmTag.RsaGeneral:
case PublicKeyAlgorithmTag.RsaSign:
key = new RsaPublicBcpgKey(bcpgIn);
break;
case PublicKeyAlgorithmTag.Dsa:
key = new DsaPublicBcpgKey(bcpgIn);
break;
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
key = new ElGamalPublicBcpgKey(bcpgIn);
break;
default:
throw new IOException("unknown PGP public key algorithm encountered");
}
}
/// <summary>Construct a version 4 public key packet.</summary>
public PublicKeyPacket(
PublicKeyAlgorithmTag algorithm,
DateTime time,
IBcpgKey key)
{
this.version = 4;
this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
this.algorithm = algorithm;
this.key = key;
}
public int Version
{
get { return version; }
}
public PublicKeyAlgorithmTag Algorithm
{
get { return algorithm; }
}
public int ValidDays
{
get { return validDays; }
}
public DateTime GetTime()
{
return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
}
public IBcpgKey Key
{
get { return key; }
}
public byte[] GetEncodedContents()
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.WriteByte((byte) version);
pOut.WriteInt((int) time);
if (version <= 3)
{
pOut.WriteShort((short) validDays);
}
pOut.WriteByte((byte) algorithm);
pOut.WriteObject((BcpgObject)key);
return bOut.ToArray();
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for a PGP public subkey</remarks>
public class PublicSubkeyPacket
: PublicKeyPacket
{
internal PublicSubkeyPacket(
BcpgInputStream bcpgIn)
: base(bcpgIn)
{
}
/// <summary>Construct a version 4 public subkey packet.</summary>
public PublicSubkeyPacket(
PublicKeyAlgorithmTag algorithm,
DateTime time,
IBcpgKey key)
: base(algorithm, time, key)
{
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.PublicSubkey, GetEncodedContents(), true);
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for an RSA public key.</remarks>
public class RsaPublicBcpgKey
: BcpgObject, IBcpgKey
{
private readonly MPInteger n, e;
/// <summary>Construct an RSA public key from the passed in stream.</summary>
public RsaPublicBcpgKey(
BcpgInputStream bcpgIn)
{
this.n = new MPInteger(bcpgIn);
this.e = new MPInteger(bcpgIn);
}
/// <param name="n">The modulus.</param>
/// <param name="e">The public exponent.</param>
public RsaPublicBcpgKey(
BigInteger n,
BigInteger e)
{
this.n = new MPInteger(n);
this.e = new MPInteger(e);
}
public BigInteger PublicExponent
{
get { return e.Value; }
}
public BigInteger Modulus
{
get { return n.Value; }
}
/// <summary>The format, as a string, always "PGP".</summary>
public string Format
{
get { return "PGP"; }
}
/// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
return base.GetEncoded();
}
catch (Exception)
{
return null;
}
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteObjects(n, e);
}
}
}

View File

@@ -0,0 +1,114 @@
using System;
using Org.BouncyCastle.Math;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Base class for an RSA secret (or priate) key.</remarks>
public class RsaSecretBcpgKey
: BcpgObject, IBcpgKey
{
private readonly MPInteger d, p, q, u;
private readonly BigInteger expP, expQ, crt;
public RsaSecretBcpgKey(
BcpgInputStream bcpgIn)
{
this.d = new MPInteger(bcpgIn);
this.p = new MPInteger(bcpgIn);
this.q = new MPInteger(bcpgIn);
this.u = new MPInteger(bcpgIn);
this.expP = d.Value.Remainder(p.Value.Subtract(BigInteger.One));
this.expQ = d.Value.Remainder(q.Value.Subtract(BigInteger.One));
this.crt = q.Value.ModInverse(p.Value);
}
public RsaSecretBcpgKey(
BigInteger d,
BigInteger p,
BigInteger q)
{
// PGP requires (p < q)
int cmp = p.CompareTo(q);
if (cmp >= 0)
{
if (cmp == 0)
throw new ArgumentException("p and q cannot be equal");
BigInteger tmp = p;
p = q;
q = tmp;
}
this.d = new MPInteger(d);
this.p = new MPInteger(p);
this.q = new MPInteger(q);
this.u = new MPInteger(p.ModInverse(q));
this.expP = d.Remainder(p.Subtract(BigInteger.One));
this.expQ = d.Remainder(q.Subtract(BigInteger.One));
this.crt = q.ModInverse(p);
}
public BigInteger Modulus
{
get { return p.Value.Multiply(q.Value); }
}
public BigInteger PrivateExponent
{
get { return d.Value; }
}
public BigInteger PrimeP
{
get { return p.Value; }
}
public BigInteger PrimeQ
{
get { return q.Value; }
}
public BigInteger PrimeExponentP
{
get { return expP; }
}
public BigInteger PrimeExponentQ
{
get { return expQ; }
}
public BigInteger CrtCoefficient
{
get { return crt; }
}
/// <summary>The format, as a string, always "PGP".</summary>
public string Format
{
get { return "PGP"; }
}
/// <summary>Return the standard PGP encoding of the key.</summary>
public override byte[] GetEncoded()
{
try
{
return base.GetEncoded();
}
catch (Exception)
{
return null;
}
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteObjects(d, p, q, u);
}
}
}

View File

@@ -0,0 +1,147 @@
using System;
using System.IO;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>The string to key specifier class.</remarks>
public class S2k
: BcpgObject
{
private const int ExpBias = 6;
public const int Simple = 0;
public const int Salted = 1;
public const int SaltedAndIterated = 3;
public const int GnuDummyS2K = 101;
internal int type;
internal HashAlgorithmTag algorithm;
internal byte[] iv;
internal int itCount = -1;
internal int protectionMode = -1;
internal S2k(
Stream inStr)
{
type = inStr.ReadByte();
algorithm = (HashAlgorithmTag) inStr.ReadByte();
//
// if this happens we have a dummy-S2k packet.
//
if (type != GnuDummyS2K)
{
if (type != 0)
{
iv = new byte[8];
if (Streams.ReadFully(inStr, iv, 0, iv.Length) < iv.Length)
throw new EndOfStreamException();
if (type == 3)
{
itCount = inStr.ReadByte();
}
}
}
else
{
inStr.ReadByte(); // G
inStr.ReadByte(); // N
inStr.ReadByte(); // U
protectionMode = inStr.ReadByte(); // protection mode
}
}
public S2k(
HashAlgorithmTag algorithm)
{
this.type = 0;
this.algorithm = algorithm;
}
public S2k(
HashAlgorithmTag algorithm,
byte[] iv)
{
this.type = 1;
this.algorithm = algorithm;
this.iv = iv;
}
public S2k(
HashAlgorithmTag algorithm,
byte[] iv,
int itCount)
{
this.type = 3;
this.algorithm = algorithm;
this.iv = iv;
this.itCount = itCount;
}
public int Type
{
get { return type; }
}
/// <summary>The hash algorithm.</summary>
public HashAlgorithmTag HashAlgorithm
{
get { return algorithm; }
}
/// <summary>The IV for the key generation algorithm.</summary>
public byte[] GetIV()
{
return Arrays.Clone(iv);
}
[Obsolete("Use 'IterationCount' property instead")]
public long GetIterationCount()
{
return IterationCount;
}
/// <summary>The iteration count</summary>
public long IterationCount
{
get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); }
}
/// <summary>The protection mode - only if GnuDummyS2K</summary>
public int ProtectionMode
{
get { return protectionMode; }
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WriteByte((byte) type);
bcpgOut.WriteByte((byte) algorithm);
if (type != GnuDummyS2K)
{
if (type != 0)
{
bcpgOut.Write(iv);
}
if (type == 3)
{
bcpgOut.WriteByte((byte) itCount);
}
}
else
{
bcpgOut.WriteByte((byte) 'G');
bcpgOut.WriteByte((byte) 'N');
bcpgOut.WriteByte((byte) 'U');
bcpgOut.WriteByte((byte) protectionMode);
}
}
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.IO;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for a PGP secret key.</remarks>
public class SecretKeyPacket
: ContainedPacket //, PublicKeyAlgorithmTag
{
public const int UsageNone = 0x00;
public const int UsageChecksum = 0xff;
public const int UsageSha1 = 0xfe;
private PublicKeyPacket pubKeyPacket;
private readonly byte[] secKeyData;
private int s2kUsage;
private SymmetricKeyAlgorithmTag encAlgorithm;
private S2k s2k;
private byte[] iv;
internal SecretKeyPacket(
BcpgInputStream bcpgIn)
{
pubKeyPacket = new PublicKeyPacket(bcpgIn);
s2kUsage = bcpgIn.ReadByte();
if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
{
encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte();
s2k = new S2k(bcpgIn);
}
else
{
encAlgorithm = (SymmetricKeyAlgorithmTag) s2kUsage;
}
if (!(s2k != null && s2k.Type == S2k.GnuDummyS2K && s2k.ProtectionMode == 0x01))
{
if (s2kUsage != 0)
{
if (((int) encAlgorithm) < 7)
{
iv = new byte[8];
}
else
{
iv = new byte[16];
}
bcpgIn.ReadFully(iv);
}
}
secKeyData = bcpgIn.ReadAll();
}
public SecretKeyPacket(
PublicKeyPacket pubKeyPacket,
SymmetricKeyAlgorithmTag encAlgorithm,
S2k s2k,
byte[] iv,
byte[] secKeyData)
{
this.pubKeyPacket = pubKeyPacket;
this.encAlgorithm = encAlgorithm;
if (encAlgorithm != SymmetricKeyAlgorithmTag.Null)
{
this.s2kUsage = UsageChecksum;
}
else
{
this.s2kUsage = UsageNone;
}
this.s2k = s2k;
this.iv = Arrays.Clone(iv);
this.secKeyData = secKeyData;
}
public SecretKeyPacket(
PublicKeyPacket pubKeyPacket,
SymmetricKeyAlgorithmTag encAlgorithm,
int s2kUsage,
S2k s2k,
byte[] iv,
byte[] secKeyData)
{
this.pubKeyPacket = pubKeyPacket;
this.encAlgorithm = encAlgorithm;
this.s2kUsage = s2kUsage;
this.s2k = s2k;
this.iv = Arrays.Clone(iv);
this.secKeyData = secKeyData;
}
public SymmetricKeyAlgorithmTag EncAlgorithm
{
get { return encAlgorithm; }
}
public int S2kUsage
{
get { return s2kUsage; }
}
public byte[] GetIV()
{
return Arrays.Clone(iv);
}
public S2k S2k
{
get { return s2k; }
}
public PublicKeyPacket PublicKeyPacket
{
get { return pubKeyPacket; }
}
public byte[] GetSecretKeyData()
{
return secKeyData;
}
public byte[] GetEncodedContents()
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.Write(pubKeyPacket.GetEncodedContents());
pOut.WriteByte((byte) s2kUsage);
if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
{
pOut.WriteByte((byte) encAlgorithm);
pOut.WriteObject(s2k);
}
if (iv != null)
{
pOut.Write(iv);
}
if (secKeyData != null && secKeyData.Length > 0)
{
pOut.Write(secKeyData);
}
return bOut.ToArray();
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.SecretKey, GetEncodedContents(), true);
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic packet for a PGP secret key.</remarks>
public class SecretSubkeyPacket
: SecretKeyPacket
{
internal SecretSubkeyPacket(
BcpgInputStream bcpgIn)
: base(bcpgIn)
{
}
public SecretSubkeyPacket(
PublicKeyPacket pubKeyPacket,
SymmetricKeyAlgorithmTag encAlgorithm,
S2k s2k,
byte[] iv,
byte[] secKeyData)
: base(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData)
{
}
public SecretSubkeyPacket(
PublicKeyPacket pubKeyPacket,
SymmetricKeyAlgorithmTag encAlgorithm,
int s2kUsage,
S2k s2k,
byte[] iv,
byte[] secKeyData)
: base(pubKeyPacket, encAlgorithm, s2kUsage, s2k, iv, secKeyData)
{
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.SecretSubkey, GetEncodedContents(), true);
}
}
}

View File

@@ -0,0 +1,459 @@
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));
ArrayList v = new ArrayList();
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;
}
else if (p is SignatureCreationTime)
{
creationTime = DateTimeUtilities.DateTimeToUnixMs(
((SignatureCreationTime)p).GetTime());
}
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;
}
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();
}
}
}

View File

@@ -0,0 +1,76 @@
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic type for a PGP Signature sub-packet.</remarks>
public class SignatureSubpacket
{
private readonly SignatureSubpacketTag type;
private readonly bool critical;
internal readonly byte[] data;
protected internal SignatureSubpacket(
SignatureSubpacketTag type,
bool critical,
byte[] data)
{
this.type = type;
this.critical = critical;
this.data = data;
}
public SignatureSubpacketTag SubpacketType
{
get { return type; }
}
public bool IsCritical()
{
return critical;
}
/// <summary>Return the generic data making up the packet.</summary>
public byte[] GetData()
{
return (byte[]) data.Clone();
}
public void Encode(
Stream os)
{
int bodyLen = data.Length + 1;
if (bodyLen < 192)
{
os.WriteByte((byte)bodyLen);
}
else if (bodyLen <= 8383)
{
bodyLen -= 192;
os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
os.WriteByte((byte)bodyLen);
}
else
{
os.WriteByte(0xff);
os.WriteByte((byte)(bodyLen >> 24));
os.WriteByte((byte)(bodyLen >> 16));
os.WriteByte((byte)(bodyLen >> 8));
os.WriteByte((byte)bodyLen);
}
if (critical)
{
os.WriteByte((byte)(0x80 | (int) type));
}
else
{
os.WriteByte((byte) type);
}
os.Write(data, 0, data.Length);
}
}
}

View File

@@ -0,0 +1,30 @@
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic PGP signature sub-packet tag types.
*/
public enum SignatureSubpacketTag
{
CreationTime = 2, // signature creation time
ExpireTime = 3, // signature expiration time
Exportable = 4, // exportable certification
TrustSig = 5, // trust signature
RegExp = 6, // regular expression
Revocable = 7, // revocable
KeyExpireTime = 9, // key expiration time
Placeholder = 10, // placeholder for backward compatibility
PreferredSymmetricAlgorithms = 11, // preferred symmetric algorithms
RevocationKey = 12, // revocation key
IssuerKeyId = 16, // issuer key ID
NotationData = 20, // notation data
PreferredHashAlgorithms = 21, // preferred hash algorithms
PreferredCompressionAlgorithms = 22, // preferred compression algorithms
KeyServerPreferences = 23, // key server preferences
PreferredKeyServer = 24, // preferred key server
PrimaryUserId = 25, // primary user id
PolicyUrl = 26, // policy URL
KeyFlags = 27, // key flags
SignerUserId = 28, // signer's user id
RevocationReason = 29 // reason for revocation
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.IO;
using Org.BouncyCastle.Bcpg.Sig;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/**
* reader for signature sub-packets
*/
public class SignatureSubpacketsParser
{
private readonly Stream input;
public SignatureSubpacketsParser(
Stream input)
{
this.input = input;
}
public SignatureSubpacket ReadPacket()
{
int l = input.ReadByte();
if (l < 0)
return null;
int bodyLen = 0;
if (l < 192)
{
bodyLen = l;
}
else if (l <= 223)
{
bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
}
else if (l == 255)
{
bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
| (input.ReadByte() << 8) | input.ReadByte();
}
else
{
// TODO Error?
}
int tag = input.ReadByte();
if (tag < 0)
throw new EndOfStreamException("unexpected EOF reading signature sub packet");
byte[] data = new byte[bodyLen - 1];
if (Streams.ReadFully(input, data) < data.Length)
throw new EndOfStreamException();
bool isCritical = ((tag & 0x80) != 0);
SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
switch (type)
{
case SignatureSubpacketTag.CreationTime:
return new SignatureCreationTime(isCritical, data);
case SignatureSubpacketTag.KeyExpireTime:
return new KeyExpirationTime(isCritical, data);
case SignatureSubpacketTag.ExpireTime:
return new SignatureExpirationTime(isCritical, data);
case SignatureSubpacketTag.Revocable:
return new Revocable(isCritical, data);
case SignatureSubpacketTag.Exportable:
return new Exportable(isCritical, data);
case SignatureSubpacketTag.IssuerKeyId:
return new IssuerKeyId(isCritical, data);
case SignatureSubpacketTag.TrustSig:
return new TrustSignature(isCritical, data);
case SignatureSubpacketTag.PreferredCompressionAlgorithms:
case SignatureSubpacketTag.PreferredHashAlgorithms:
case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
return new PreferredAlgorithms(type, isCritical, data);
case SignatureSubpacketTag.KeyFlags:
return new KeyFlags(isCritical, data);
case SignatureSubpacketTag.PrimaryUserId:
return new PrimaryUserId(isCritical, data);
case SignatureSubpacketTag.SignerUserId:
return new SignerUserId(isCritical, data);
case SignatureSubpacketTag.NotationData:
return new NotationData(isCritical, data);
}
return new SignatureSubpacket(type, isCritical, data);
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace Org.BouncyCastle.Bcpg
{
/// <remarks>Basic type for a symmetric key encrypted packet.</remarks>
public class SymmetricEncDataPacket
: InputStreamPacket
{
public SymmetricEncDataPacket(
BcpgInputStream bcpgIn)
: base(bcpgIn)
{
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
public class SymmetricEncIntegrityPacket
: InputStreamPacket
{
internal readonly int version;
internal SymmetricEncIntegrityPacket(
BcpgInputStream bcpgIn)
: base(bcpgIn)
{
version = bcpgIn.ReadByte();
}
}
}

View File

@@ -0,0 +1,20 @@
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic tags for symmetric key algorithms
*/
public enum SymmetricKeyAlgorithmTag
{
Null = 0, // Plaintext or unencrypted data
Idea = 1, // IDEA [IDEA]
TripleDes = 2, // Triple-DES (DES-EDE, as per spec -168 bit key derived from 192)
Cast5 = 3, // Cast5 (128 bit key, as per RFC 2144)
Blowfish = 4, // Blowfish (128 bit key, 16 rounds) [Blowfish]
Safer = 5, // Safer-SK128 (13 rounds) [Safer]
Des = 6, // Reserved for DES/SK
Aes128 = 7, // Reserved for AES with 128-bit key
Aes192 = 8, // Reserved for AES with 192-bit key
Aes256 = 9, // Reserved for AES with 256-bit key
Twofish = 10 // Reserved for Twofish
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic type for a symmetric encrypted session key packet
*/
public class SymmetricKeyEncSessionPacket
: ContainedPacket
{
private int version;
private SymmetricKeyAlgorithmTag encAlgorithm;
private S2k s2k;
private readonly byte[] secKeyData;
public SymmetricKeyEncSessionPacket(
BcpgInputStream bcpgIn)
{
version = bcpgIn.ReadByte();
encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte();
s2k = new S2k(bcpgIn);
secKeyData = bcpgIn.ReadAll();
}
public SymmetricKeyEncSessionPacket(
SymmetricKeyAlgorithmTag encAlgorithm,
S2k s2k,
byte[] secKeyData)
{
this.version = 4;
this.encAlgorithm = encAlgorithm;
this.s2k = s2k;
this.secKeyData = secKeyData;
}
/**
* @return int
*/
public SymmetricKeyAlgorithmTag EncAlgorithm
{
get { return encAlgorithm; }
}
/**
* @return S2k
*/
public S2k S2k
{
get { return s2k; }
}
/**
* @return byte[]
*/
public byte[] GetSecKeyData()
{
return secKeyData;
}
/**
* @return int
*/
public int Version
{
get { return version; }
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
MemoryStream bOut = new MemoryStream();
BcpgOutputStream pOut = new BcpgOutputStream(bOut);
pOut.Write(
(byte) version,
(byte) encAlgorithm);
pOut.WriteObject(s2k);
if (secKeyData != null && secKeyData.Length > 0)
{
pOut.Write(secKeyData);
}
bcpgOut.WritePacket(PacketTag.SymmetricKeyEncryptedSessionKey, bOut.ToArray(), true);
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/// <summary>Basic type for a trust packet.</summary>
public class TrustPacket
: ContainedPacket
{
private readonly byte[] levelAndTrustAmount;
public TrustPacket(
BcpgInputStream bcpgIn)
{
MemoryStream bOut = new MemoryStream();
int ch;
while ((ch = bcpgIn.ReadByte()) >= 0)
{
bOut.WriteByte((byte) ch);
}
levelAndTrustAmount = bOut.ToArray();
}
public TrustPacket(
int trustCode)
{
this.levelAndTrustAmount = new byte[]{ (byte) trustCode };
}
public byte[] GetLevelAndTrustAmount()
{
return (byte[]) levelAndTrustAmount.Clone();
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.Trust, levelAndTrustAmount, true);
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections;
using System.IO;
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic type for a user attribute packet.
*/
public class UserAttributePacket
: ContainedPacket
{
private readonly UserAttributeSubpacket[] subpackets;
public UserAttributePacket(
BcpgInputStream bcpgIn)
{
UserAttributeSubpacketsParser sIn = new UserAttributeSubpacketsParser(bcpgIn);
UserAttributeSubpacket sub;
ArrayList v = new ArrayList();
while ((sub = sIn.ReadPacket()) != null)
{
v.Add(sub);
}
subpackets = new UserAttributeSubpacket[v.Count];
for (int i = 0; i != subpackets.Length; i++)
{
subpackets[i] = (UserAttributeSubpacket)v[i];
}
}
public UserAttributePacket(
UserAttributeSubpacket[] subpackets)
{
this.subpackets = subpackets;
}
public UserAttributeSubpacket[] GetSubpackets()
{
return subpackets;
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
MemoryStream bOut = new MemoryStream();
for (int i = 0; i != subpackets.Length; i++)
{
subpackets[i].Encode(bOut);
}
bcpgOut.WritePacket(PacketTag.UserAttribute, bOut.ToArray(), false);
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.IO;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic type for a user attribute sub-packet.
*/
public class UserAttributeSubpacket
{
private readonly UserAttributeSubpacketTag type;
private readonly byte[] data;
internal UserAttributeSubpacket(
UserAttributeSubpacketTag type,
byte[] data)
{
this.type = type;
this.data = data;
}
public UserAttributeSubpacketTag SubpacketType
{
get { return type; }
}
/**
* return the generic data making up the packet.
*/
public byte[] GetData()
{
return data;
}
public void Encode(
Stream os)
{
int bodyLen = data.Length + 1;
if (bodyLen < 192)
{
os.WriteByte((byte)bodyLen);
}
else if (bodyLen <= 8383)
{
bodyLen -= 192;
os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
os.WriteByte((byte)bodyLen);
}
else
{
os.WriteByte(0xff);
os.WriteByte((byte)(bodyLen >> 24));
os.WriteByte((byte)(bodyLen >> 16));
os.WriteByte((byte)(bodyLen >> 8));
os.WriteByte((byte)bodyLen);
}
os.WriteByte((byte) type);
os.Write(data, 0, data.Length);
}
public override bool Equals(
object obj)
{
if (obj == this)
return true;
UserAttributeSubpacket other = obj as UserAttributeSubpacket;
if (other == null)
return false;
return type == other.type
&& Arrays.AreEqual(data, other.data);
}
public override int GetHashCode()
{
return type.GetHashCode() ^ Arrays.GetHashCode(data);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic PGP user attribute sub-packet tag types.
*/
public enum UserAttributeSubpacketTag
{
ImageAttribute = 1
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.IO;
using Org.BouncyCastle.Bcpg.Attr;
using Org.BouncyCastle.Utilities.IO;
namespace Org.BouncyCastle.Bcpg
{
/**
* reader for user attribute sub-packets
*/
public class UserAttributeSubpacketsParser
{
private readonly Stream input;
public UserAttributeSubpacketsParser(
Stream input)
{
this.input = input;
}
public UserAttributeSubpacket ReadPacket()
{
int l = input.ReadByte();
if (l < 0)
return null;
int bodyLen = 0;
if (l < 192)
{
bodyLen = l;
}
else if (l <= 223)
{
bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
}
else if (l == 255)
{
bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
| (input.ReadByte() << 8) | input.ReadByte();
}
else
{
// TODO Error?
}
int tag = input.ReadByte();
if (tag < 0)
throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
byte[] data = new byte[bodyLen - 1];
if (Streams.ReadFully(input, data) < data.Length)
throw new EndOfStreamException();
UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
switch (type)
{
case UserAttributeSubpacketTag.ImageAttribute:
return new ImageAttrib(data);
}
return new UserAttributeSubpacket(type, data);
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Text;
namespace Org.BouncyCastle.Bcpg
{
/**
* Basic type for a user ID packet.
*/
public class UserIdPacket
: ContainedPacket
{
private readonly byte[] idData;
public UserIdPacket(
BcpgInputStream bcpgIn)
{
this.idData = bcpgIn.ReadAll();
}
public UserIdPacket(
string id)
{
this.idData = Encoding.UTF8.GetBytes(id);
}
public string GetId()
{
return Encoding.UTF8.GetString(idData, 0, idData.Length);
}
public override void Encode(
BcpgOutputStream bcpgOut)
{
bcpgOut.WritePacket(PacketTag.UserId, idData, true);
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.IO;
namespace Org.BouncyCastle.Bcpg.Attr
{
/// <remarks>Basic type for a image attribute packet.</remarks>
public class ImageAttrib
: UserAttributeSubpacket
{
public enum Format : byte
{
Jpeg = 1
}
private static readonly byte[] Zeroes = new byte[12];
private int hdrLength;
private int _version;
private int _encoding;
private byte[] imageData;
public ImageAttrib(
byte[] data)
: base(UserAttributeSubpacketTag.ImageAttribute, data)
{
hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff);
_version = data[2] & 0xff;
_encoding = data[3] & 0xff;
imageData = new byte[data.Length - hdrLength];
Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
}
public ImageAttrib(
Format imageType,
byte[] imageData)
: this(ToByteArray(imageType, imageData))
{
}
private static byte[] ToByteArray(
Format imageType,
byte[] imageData)
{
MemoryStream bOut = new MemoryStream();
bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
bOut.WriteByte((byte) imageType);
bOut.Write(Zeroes, 0, Zeroes.Length);
bOut.Write(imageData, 0, imageData.Length);
return bOut.ToArray();
}
public int Version
{
get { return _version; }
}
public int Encoding
{
get { return _encoding; }
}
public byte[] GetImageData()
{
return imageData;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving signature creation time.
*/
public class Exportable
: SignatureSubpacket
{
private static byte[] BooleanToByteArray(bool val)
{
byte[] data = new byte[1];
if (val)
{
data[0] = 1;
return data;
}
else
{
return data;
}
}
public Exportable(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.Exportable, critical, data)
{
}
public Exportable(
bool critical,
bool isExportable)
: base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable))
{
}
public bool IsExportable()
{
return data[0] != 0;
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving signature creation time.
*/
public class IssuerKeyId
: SignatureSubpacket
{
protected static byte[] KeyIdToBytes(
long keyId)
{
byte[] data = new byte[8];
data[0] = (byte)(keyId >> 56);
data[1] = (byte)(keyId >> 48);
data[2] = (byte)(keyId >> 40);
data[3] = (byte)(keyId >> 32);
data[4] = (byte)(keyId >> 24);
data[5] = (byte)(keyId >> 16);
data[6] = (byte)(keyId >> 8);
data[7] = (byte)keyId;
return data;
}
public IssuerKeyId(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.IssuerKeyId, critical, data)
{
}
public IssuerKeyId(
bool critical,
long keyId)
: base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId))
{
}
public long KeyId
{
get
{
long keyId = ((long)(data[0] & 0xff) << 56)
| ((long)(data[1] & 0xff) << 48)
| ((long)(data[2] & 0xff) << 40)
| ((long)(data[3] & 0xff) << 32)
| ((long)(data[4] & 0xff) << 24)
| ((long)(data[5] & 0xff) << 16)
| ((long)(data[6] & 0xff) << 8)
| ((long)data[7] & 0xff);
return keyId;
}
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving time after creation at which the key expires.
*/
public class KeyExpirationTime
: SignatureSubpacket
{
protected static byte[] TimeToBytes(
long t)
{
byte[] data = new byte[4];
data[0] = (byte)(t >> 24);
data[1] = (byte)(t >> 16);
data[2] = (byte)(t >> 8);
data[3] = (byte)t;
return data;
}
public KeyExpirationTime(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.KeyExpireTime, critical, data)
{
}
public KeyExpirationTime(
bool critical,
long seconds)
: base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds))
{
}
/**
* Return the number of seconds after creation time a key is valid for.
*
* @return second count for key validity.
*/
public long Time
{
get
{
long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
| ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
return time;
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* Packet holding the key flag values.
*/
public class KeyFlags
: SignatureSubpacket
{
private static byte[] IntToByteArray(
int v)
{
return new byte[]{ (byte) v };
}
public KeyFlags(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.KeyFlags, critical, data)
{
}
public KeyFlags(
bool critical,
int flags)
: base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags))
{
}
public int Flags
{
get { return data[0] & 0xff; }
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.IO;
using System.Text;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* Class provided a NotationData object according to
* RFC2440, Chapter 5.2.3.15. Notation Data
*/
public class NotationData
: SignatureSubpacket
{
public const int HeaderFlagLength = 4;
public const int HeaderNameLength = 2;
public const int HeaderValueLength = 2;
public NotationData(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.NotationData, critical, data)
{
}
public NotationData(
bool critical,
bool humanReadable,
string notationName,
string notationValue)
: base(SignatureSubpacketTag.NotationData, critical,
createData(humanReadable, notationName, notationValue))
{
}
private static byte[] createData(
bool humanReadable,
string notationName,
string notationValue)
{
MemoryStream os = new MemoryStream();
// (4 octets of flags, 2 octets of name length (M),
// 2 octets of value length (N),
// M octets of name data,
// N octets of value data)
// flags
os.WriteByte(humanReadable ? (byte)0x80 : (byte)0x00);
os.WriteByte(0x0);
os.WriteByte(0x0);
os.WriteByte(0x0);
byte[] nameData, valueData = null;
int nameLength, valueLength;
nameData = Encoding.UTF8.GetBytes(notationName);
nameLength = System.Math.Min(nameData.Length, 0xFF);
valueData = Encoding.UTF8.GetBytes(notationValue);
valueLength = System.Math.Min(valueData.Length, 0xFF);
// name length
os.WriteByte((byte)(nameLength >> 8));
os.WriteByte((byte)(nameLength >> 0));
// value length
os.WriteByte((byte)(valueLength >> 8));
os.WriteByte((byte)(valueLength >> 0));
// name
os.Write(nameData, 0, nameLength);
// value
os.Write(valueData, 0, valueLength);
return os.ToArray();
}
public bool IsHumanReadable
{
get { return data[0] == (byte)0x80; }
}
public string GetNotationName()
{
int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
int namePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength;
return Encoding.UTF8.GetString(data, namePos, nameLength);
}
public string GetNotationValue()
{
int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0));
int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength;
return Encoding.UTF8.GetString(data, valuePos, valueLength);
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving signature creation time.
*/
public class PreferredAlgorithms
: SignatureSubpacket
{
private static byte[] IntToByteArray(
int[] v)
{
byte[] data = new byte[v.Length];
for (int i = 0; i != v.Length; i++)
{
data[i] = (byte)v[i];
}
return data;
}
public PreferredAlgorithms(
SignatureSubpacketTag type,
bool critical,
byte[] data)
: base(type, critical, data)
{
}
public PreferredAlgorithms(
SignatureSubpacketTag type,
bool critical,
int[] preferences)
: base(type, critical, IntToByteArray(preferences))
{
}
public int[] GetPreferences()
{
int[] v = new int[data.Length];
for (int i = 0; i != v.Length; i++)
{
v[i] = data[i] & 0xff;
}
return v;
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving whether or not the signature is signed using the primary user ID for the key.
*/
public class PrimaryUserId
: SignatureSubpacket
{
private static byte[] BooleanToByteArray(
bool val)
{
byte[] data = new byte[1];
if (val)
{
data[0] = 1;
return data;
}
else
{
return data;
}
}
public PrimaryUserId(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.PrimaryUserId, critical, data)
{
}
public PrimaryUserId(
bool critical,
bool isPrimaryUserId)
: base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId))
{
}
public bool IsPrimaryUserId()
{
return data[0] != 0;
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving whether or not is revocable.
*/
public class Revocable
: SignatureSubpacket
{
private static byte[] BooleanToByteArray(
bool value)
{
byte[] data = new byte[1];
if (value)
{
data[0] = 1;
return data;
}
else
{
return data;
}
}
public Revocable(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.Revocable, critical, data)
{
}
public Revocable(
bool critical,
bool isRevocable)
: base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable))
{
}
public bool IsRevocable()
{
return data[0] != 0;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using Org.BouncyCastle.Utilities.Date;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving signature creation time.
*/
public class SignatureCreationTime
: SignatureSubpacket
{
protected static byte[] TimeToBytes(
DateTime time)
{
long t = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
byte[] data = new byte[4];
data[0] = (byte)(t >> 24);
data[1] = (byte)(t >> 16);
data[2] = (byte)(t >> 8);
data[3] = (byte)t;
return data;
}
public SignatureCreationTime(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.CreationTime, critical, data)
{
}
public SignatureCreationTime(
bool critical,
DateTime date)
: base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date))
{
}
public DateTime GetTime()
{
long time = (long)(
((uint)data[0] << 24)
| ((uint)data[1] << 16)
| ((uint)data[2] << 8)
| ((uint)data[3])
);
return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving signature expiration time.
*/
public class SignatureExpirationTime
: SignatureSubpacket
{
protected static byte[] TimeToBytes(
long t)
{
byte[] data = new byte[4];
data[0] = (byte)(t >> 24);
data[1] = (byte)(t >> 16);
data[2] = (byte)(t >> 8);
data[3] = (byte)t;
return data;
}
public SignatureExpirationTime(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.ExpireTime, critical, data)
{
}
public SignatureExpirationTime(
bool critical,
long seconds)
: base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds))
{
}
/**
* return time in seconds before signature expires after creation time.
*/
public long Time
{
get
{
long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
| ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
return time;
}
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving the User ID of the signer.
*/
public class SignerUserId
: SignatureSubpacket
{
private static byte[] UserIdToBytes(
string id)
{
byte[] idData = new byte[id.Length];
for (int i = 0; i != id.Length; i++)
{
idData[i] = (byte)id[i];
}
return idData;
}
public SignerUserId(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.SignerUserId, critical, data)
{
}
public SignerUserId(
bool critical,
string userId)
: base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId))
{
}
public string GetId()
{
char[] chars = new char[data.Length];
for (int i = 0; i != chars.Length; i++)
{
chars[i] = (char)(data[i] & 0xff);
}
return new string(chars);
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
namespace Org.BouncyCastle.Bcpg.Sig
{
/**
* packet giving signature creation time.
*/
public class TrustSignature
: SignatureSubpacket
{
private static byte[] IntToByteArray(
int v1,
int v2)
{
byte[] data = new byte[2];
data[0] = (byte)v1;
data[1] = (byte)v2;
return data;
}
public TrustSignature(
bool critical,
byte[] data)
: base(SignatureSubpacketTag.TrustSig, critical, data)
{
}
public TrustSignature(
bool critical,
int depth,
int trustAmount)
: base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount))
{
}
public int Depth
{
get
{
return data[0] & 0xff;
}
}
public int TrustAmount
{
get
{
return data[1] & 0xff;
}
}
}
}