diff options
Diffstat (limited to 'crypto/src/bcpg')
66 files changed, 3350 insertions, 247 deletions
diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs index 0dcc948d3..3109dd4fd 100644 --- a/crypto/src/bcpg/ArmoredInputStream.cs +++ b/crypto/src/bcpg/ArmoredInputStream.cs @@ -504,14 +504,10 @@ namespace Org.BouncyCastle.Bcpg return pos - offset; } - protected override void Dispose(bool disposing) - { - if (disposing) - { - input.Dispose(); - } - - base.Dispose(disposing); - } + public override void Close() + { + input.Close(); + base.Close(); + } } } diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs index 7ee26886a..b3a32c6f5 100644 --- a/crypto/src/bcpg/ArmoredOutputStream.cs +++ b/crypto/src/bcpg/ArmoredOutputStream.cs @@ -97,7 +97,8 @@ namespace Org.BouncyCastle.Bcpg private static readonly string footerStart = "-----END PGP "; private static readonly string footerTail = "-----"; - private static readonly string version = "BCPG C# v" + AssemblyInfo.Version; + private static readonly string version = "BCPG C# v" + + Assembly.GetExecutingAssembly().GetName().Version; private readonly IDictionary headers; @@ -276,43 +277,39 @@ namespace Org.BouncyCastle.Bcpg } /** - * <b>Note</b>: Dispose does nor Dispose the underlying stream. So it is possible to write + * <b>Note</b>: close does nor close the underlying stream. So it is possible to write * multiple objects using armoring to a single stream. */ - protected override void Dispose(bool disposing) + public override void Close() { - if (disposing) + if (type != null) { - if (type != null) - { - if (bufPtr > 0) - { - Encode(outStream, buf, bufPtr); - } + if (bufPtr > 0) + { + Encode(outStream, buf, bufPtr); + } - DoWrite(nl + '='); + DoWrite(nl + '='); - int crcV = crc.Value; + int crcV = crc.Value; - buf[0] = ((crcV >> 16) & 0xff); - buf[1] = ((crcV >> 8) & 0xff); - buf[2] = (crcV & 0xff); + buf[0] = ((crcV >> 16) & 0xff); + buf[1] = ((crcV >> 8) & 0xff); + buf[2] = (crcV & 0xff); - Encode(outStream, buf, 3); + Encode(outStream, buf, 3); - DoWrite(nl); - DoWrite(footerStart); - DoWrite(type); - DoWrite(footerTail); - DoWrite(nl); - - outStream.Flush(); + DoWrite(nl); + DoWrite(footerStart); + DoWrite(type); + DoWrite(footerTail); + DoWrite(nl); - type = null; - start = true; - } + outStream.Flush(); - base.Dispose(disposing); + type = null; + start = true; + base.Close(); } } diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs index b4afab901..3c69fbdf5 100644 --- a/crypto/src/bcpg/BcpgInputStream.cs +++ b/crypto/src/bcpg/BcpgInputStream.cs @@ -250,15 +250,11 @@ namespace Org.BouncyCastle.Bcpg } } - protected override void Dispose(bool disposing) - { - if (disposing) - { - m_in.Dispose(); - } - - base.Dispose(disposing); - } + 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. diff --git a/crypto/src/bcpg/BcpgObject.cs b/crypto/src/bcpg/BcpgObject.cs index 92811c3d3..4807ad46e 100644 --- a/crypto/src/bcpg/BcpgObject.cs +++ b/crypto/src/bcpg/BcpgObject.cs @@ -3,7 +3,7 @@ using System.IO; namespace Org.BouncyCastle.Bcpg { - /// <remarks>Base class for a PGP object.</remarks> + /// <remarks>Base class for a PGP object.</remarks> public abstract class BcpgObject { public virtual byte[] GetEncoded() @@ -11,12 +11,12 @@ namespace Org.BouncyCastle.Bcpg MemoryStream bOut = new MemoryStream(); BcpgOutputStream pOut = new BcpgOutputStream(bOut); - pOut.WriteObject(this); + pOut.WriteObject(this); - return bOut.ToArray(); + return bOut.ToArray(); } - public abstract void Encode(BcpgOutputStream bcpgOut); + public abstract void Encode(BcpgOutputStream bcpgOut); } } diff --git a/crypto/src/bcpg/BcpgOutputStream.cs b/crypto/src/bcpg/BcpgOutputStream.cs index 365053e11..204f65b50 100644 --- a/crypto/src/bcpg/BcpgOutputStream.cs +++ b/crypto/src/bcpg/BcpgOutputStream.cs @@ -379,16 +379,12 @@ namespace Org.BouncyCastle.Bcpg } } - protected override void Dispose(bool disposing) + public override void Close() { - if (disposing) - { - this.Finish(); - outStr.Flush(); - outStr.Dispose(); - } - - base.Dispose(disposing); + this.Finish(); + outStr.Flush(); + outStr.Close(); + base.Close(); } } } diff --git a/crypto/src/bcpg/CompressedDataPacket.cs b/crypto/src/bcpg/CompressedDataPacket.cs new file mode 100644 index 000000000..2432825eb --- /dev/null +++ b/crypto/src/bcpg/CompressedDataPacket.cs @@ -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; } + } + } +} diff --git a/crypto/src/bcpg/CompressionAlgorithmTags.cs b/crypto/src/bcpg/CompressionAlgorithmTags.cs new file mode 100644 index 000000000..0e452298e --- /dev/null +++ b/crypto/src/bcpg/CompressionAlgorithmTags.cs @@ -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 + } +} diff --git a/crypto/src/bcpg/ContainedPacket.cs b/crypto/src/bcpg/ContainedPacket.cs new file mode 100644 index 000000000..e8f387ca4 --- /dev/null +++ b/crypto/src/bcpg/ContainedPacket.cs @@ -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); + } +} diff --git a/crypto/src/bcpg/Crc24.cs b/crypto/src/bcpg/Crc24.cs new file mode 100644 index 000000000..97846f4fb --- /dev/null +++ b/crypto/src/bcpg/Crc24.cs @@ -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; + } + } +} diff --git a/crypto/src/bcpg/DsaPublicBcpgKey.cs b/crypto/src/bcpg/DsaPublicBcpgKey.cs index 61159567c..11294cc22 100644 --- a/crypto/src/bcpg/DsaPublicBcpgKey.cs +++ b/crypto/src/bcpg/DsaPublicBcpgKey.cs @@ -4,46 +4,46 @@ using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Bcpg { - /// <remarks>Base class for a DSA public key.</remarks> - public class DsaPublicBcpgKey - : BcpgObject, IBcpgKey + /// <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); - } + /// <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); - } + 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>The format, as a string, always "PGP".</summary> + public string Format + { + get { return "PGP"; } + } - /// <summary>Return the standard PGP encoding of the key.</summary> + /// <summary>Return the standard PGP encoding of the key.</summary> public override byte[] GetEncoded() { try { - return base.GetEncoded(); + return base.GetEncoded(); } catch (Exception) { @@ -51,30 +51,30 @@ namespace Org.BouncyCastle.Bcpg } } - public override void Encode( - BcpgOutputStream bcpgOut) - { - bcpgOut.WriteObjects(p, q, g, y); - } + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WriteObjects(p, q, g, y); + } - public BigInteger G - { - get { return g.Value; } - } + public BigInteger G + { + get { return g.Value; } + } - public BigInteger P - { - get { return p.Value; } - } + public BigInteger P + { + get { return p.Value; } + } - public BigInteger Q - { - get { return q.Value; } - } + public BigInteger Q + { + get { return q.Value; } + } - public BigInteger Y - { - get { return y.Value; } - } + public BigInteger Y + { + get { return y.Value; } + } } } diff --git a/crypto/src/bcpg/DsaSecretBcpgKey.cs b/crypto/src/bcpg/DsaSecretBcpgKey.cs new file mode 100644 index 000000000..41835d419 --- /dev/null +++ b/crypto/src/bcpg/DsaSecretBcpgKey.cs @@ -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; } + } + } +} diff --git a/crypto/src/bcpg/ElGamalPublicBcpgKey.cs b/crypto/src/bcpg/ElGamalPublicBcpgKey.cs new file mode 100644 index 000000000..808e427b2 --- /dev/null +++ b/crypto/src/bcpg/ElGamalPublicBcpgKey.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/ElGamalSecretBcpgKey.cs b/crypto/src/bcpg/ElGamalSecretBcpgKey.cs new file mode 100644 index 000000000..2d95b29b1 --- /dev/null +++ b/crypto/src/bcpg/ElGamalSecretBcpgKey.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/ExperimentalPacket.cs b/crypto/src/bcpg/ExperimentalPacket.cs new file mode 100644 index 000000000..36a254be1 --- /dev/null +++ b/crypto/src/bcpg/ExperimentalPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/HashAlgorithmTags.cs b/crypto/src/bcpg/HashAlgorithmTags.cs new file mode 100644 index 000000000..96c009153 --- /dev/null +++ b/crypto/src/bcpg/HashAlgorithmTags.cs @@ -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 + } +} diff --git a/crypto/src/bcpg/IBcpgKey.cs b/crypto/src/bcpg/IBcpgKey.cs new file mode 100644 index 000000000..275461772 --- /dev/null +++ b/crypto/src/bcpg/IBcpgKey.cs @@ -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; } + } +} diff --git a/crypto/src/bcpg/InputStreamPacket.cs b/crypto/src/bcpg/InputStreamPacket.cs new file mode 100644 index 000000000..c45efab7b --- /dev/null +++ b/crypto/src/bcpg/InputStreamPacket.cs @@ -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; + } + } +} diff --git a/crypto/src/bcpg/LiteralDataPacket.cs b/crypto/src/bcpg/LiteralDataPacket.cs new file mode 100644 index 000000000..63a2c6d44 --- /dev/null +++ b/crypto/src/bcpg/LiteralDataPacket.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Bcpg +{ + /// <remarks>Generic literal data packet.</remarks> + public class LiteralDataPacket + : InputStreamPacket + { + private int format; + private byte[] fileName; + private long modDate; + + internal LiteralDataPacket( + BcpgInputStream bcpgIn) + : base(bcpgIn) + { + format = bcpgIn.ReadByte(); + int len = bcpgIn.ReadByte(); + + fileName = new byte[len]; + for (int i = 0; i != len; ++i) + { + fileName[i] = (byte)bcpgIn.ReadByte(); + } + + 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 Strings.FromUtf8ByteArray(fileName); } + } + + public byte[] GetRawFileName() + { + return Arrays.Clone(fileName); + } + } +} diff --git a/crypto/src/bcpg/MPInteger.cs b/crypto/src/bcpg/MPInteger.cs new file mode 100644 index 000000000..441407244 --- /dev/null +++ b/crypto/src/bcpg/MPInteger.cs @@ -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()); + } + } +} diff --git a/crypto/src/bcpg/MarkerPacket.cs b/crypto/src/bcpg/MarkerPacket.cs new file mode 100644 index 000000000..4dc4b5a83 --- /dev/null +++ b/crypto/src/bcpg/MarkerPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/ModDetectionCodePacket.cs b/crypto/src/bcpg/ModDetectionCodePacket.cs new file mode 100644 index 000000000..6bb23645a --- /dev/null +++ b/crypto/src/bcpg/ModDetectionCodePacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/OnePassSignaturePacket.cs b/crypto/src/bcpg/OnePassSignaturePacket.cs new file mode 100644 index 000000000..b67df0a52 --- /dev/null +++ b/crypto/src/bcpg/OnePassSignaturePacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/OutputStreamPacket.cs b/crypto/src/bcpg/OutputStreamPacket.cs new file mode 100644 index 000000000..aa8316dcb --- /dev/null +++ b/crypto/src/bcpg/OutputStreamPacket.cs @@ -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(); + } +} + diff --git a/crypto/src/bcpg/Packet.cs b/crypto/src/bcpg/Packet.cs new file mode 100644 index 000000000..83f6d1f74 --- /dev/null +++ b/crypto/src/bcpg/Packet.cs @@ -0,0 +1,7 @@ +namespace Org.BouncyCastle.Bcpg +{ + public class Packet + //: PacketTag + { + } +} diff --git a/crypto/src/bcpg/PacketTags.cs b/crypto/src/bcpg/PacketTags.cs new file mode 100644 index 000000000..5a53d4e95 --- /dev/null +++ b/crypto/src/bcpg/PacketTags.cs @@ -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 + } +} diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs new file mode 100644 index 000000000..85ae548eb --- /dev/null +++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs @@ -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, + } +} diff --git a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs new file mode 100644 index 000000000..d10605f1d --- /dev/null +++ b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs index 32d43149b..a45aeb469 100644 --- a/crypto/src/bcpg/PublicKeyPacket.cs +++ b/crypto/src/bcpg/PublicKeyPacket.cs @@ -5,11 +5,11 @@ using Org.BouncyCastle.Utilities.Date; namespace Org.BouncyCastle.Bcpg { - /// <remarks>Basic packet for a PGP public key.</remarks> + /// <remarks>Basic packet for a PGP public key.</remarks> public class PublicKeyPacket : ContainedPacket //, PublicKeyAlgorithmTag { - private int version; + private int version; private long time; private int validDays; private PublicKeyAlgorithmTag algorithm; @@ -49,44 +49,44 @@ namespace Org.BouncyCastle.Bcpg } } - /// <summary>Construct a version 4 public key packet.</summary> + /// <summary>Construct a version 4 public key packet.</summary> public PublicKeyPacket( PublicKeyAlgorithmTag algorithm, DateTime time, IBcpgKey key) { - this.version = 4; + this.version = 4; this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L; this.algorithm = algorithm; this.key = key; } - public int Version + public virtual int Version { - get { return version; } + get { return version; } } - public PublicKeyAlgorithmTag Algorithm + public virtual PublicKeyAlgorithmTag Algorithm { - get { return algorithm; } + get { return algorithm; } } - public int ValidDays + public virtual int ValidDays { - get { return validDays; } + get { return validDays; } } - public DateTime GetTime() + public virtual DateTime GetTime() { return DateTimeUtilities.UnixMsToDateTime(time * 1000L); } - public IBcpgKey Key + public virtual IBcpgKey Key { - get { return key; } + get { return key; } } - public byte[] GetEncodedContents() + public virtual byte[] GetEncodedContents() { MemoryStream bOut = new MemoryStream(); BcpgOutputStream pOut = new BcpgOutputStream(bOut); @@ -94,22 +94,22 @@ namespace Org.BouncyCastle.Bcpg pOut.WriteByte((byte) version); pOut.WriteInt((int) time); - if (version <= 3) + if (version <= 3) { pOut.WriteShort((short) validDays); } - pOut.WriteByte((byte) algorithm); + pOut.WriteByte((byte) algorithm); - pOut.WriteObject((BcpgObject)key); + pOut.WriteObject((BcpgObject)key); - return bOut.ToArray(); + return bOut.ToArray(); } - public override void Encode( - BcpgOutputStream bcpgOut) - { - bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true); - } - } + public override void Encode( + BcpgOutputStream bcpgOut) + { + bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true); + } + } } diff --git a/crypto/src/bcpg/PublicSubkeyPacket.cs b/crypto/src/bcpg/PublicSubkeyPacket.cs new file mode 100644 index 000000000..6e1aeda98 --- /dev/null +++ b/crypto/src/bcpg/PublicSubkeyPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/RsaPublicBcpgKey.cs b/crypto/src/bcpg/RsaPublicBcpgKey.cs new file mode 100644 index 000000000..fd2313c89 --- /dev/null +++ b/crypto/src/bcpg/RsaPublicBcpgKey.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/RsaSecretBcpgKey.cs b/crypto/src/bcpg/RsaSecretBcpgKey.cs new file mode 100644 index 000000000..5c04d9f85 --- /dev/null +++ b/crypto/src/bcpg/RsaSecretBcpgKey.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs new file mode 100644 index 000000000..de08c016c --- /dev/null +++ b/crypto/src/bcpg/S2k.cs @@ -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); + } + } + } +} diff --git a/crypto/src/bcpg/SecretKeyPacket.cs b/crypto/src/bcpg/SecretKeyPacket.cs new file mode 100644 index 000000000..d9ceab4f1 --- /dev/null +++ b/crypto/src/bcpg/SecretKeyPacket.cs @@ -0,0 +1,170 @@ +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) + { + if (this is SecretSubkeyPacket) + { + pubKeyPacket = new PublicSubkeyPacket(bcpgIn); + } + else + { + 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); + } + } +} diff --git a/crypto/src/bcpg/SecretSubkeyPacket.cs b/crypto/src/bcpg/SecretSubkeyPacket.cs new file mode 100644 index 000000000..8f1746942 --- /dev/null +++ b/crypto/src/bcpg/SecretSubkeyPacket.cs @@ -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); + } + } +} 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; + } + } + } + } +} diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs new file mode 100644 index 000000000..ac26f8a3c --- /dev/null +++ b/crypto/src/bcpg/SignatureSubpacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/SignatureSubpacketTags.cs b/crypto/src/bcpg/SignatureSubpacketTags.cs new file mode 100644 index 000000000..1a8e254c0 --- /dev/null +++ b/crypto/src/bcpg/SignatureSubpacketTags.cs @@ -0,0 +1,33 @@ +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 + Features = 30, // features + SignatureTarget = 31, // signature target + EmbeddedSignature = 32 // embedded signature + } +} diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs new file mode 100644 index 000000000..8dd1af332 --- /dev/null +++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/SymmetricEncDataPacket.cs b/crypto/src/bcpg/SymmetricEncDataPacket.cs new file mode 100644 index 000000000..17ee55bb7 --- /dev/null +++ b/crypto/src/bcpg/SymmetricEncDataPacket.cs @@ -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) + { + } + } +} diff --git a/crypto/src/bcpg/SymmetricEncIntegrityPacket.cs b/crypto/src/bcpg/SymmetricEncIntegrityPacket.cs new file mode 100644 index 000000000..a9b6d0678 --- /dev/null +++ b/crypto/src/bcpg/SymmetricEncIntegrityPacket.cs @@ -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(); + } + } +} diff --git a/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs b/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs index 7633b1dba..e05a48616 100644 --- a/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs +++ b/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs @@ -5,16 +5,19 @@ namespace Org.BouncyCastle.Bcpg */ 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 + 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 + Camellia128 = 11, // Reserved for AES with 128-bit key + Camellia192 = 12, // Reserved for AES with 192-bit key + Camellia256 = 13 // Reserved for AES with 256-bit key } } diff --git a/crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs b/crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs new file mode 100644 index 000000000..0381fa386 --- /dev/null +++ b/crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/TrustPacket.cs b/crypto/src/bcpg/TrustPacket.cs new file mode 100644 index 000000000..6f1969c2a --- /dev/null +++ b/crypto/src/bcpg/TrustPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/UserAttributePacket.cs b/crypto/src/bcpg/UserAttributePacket.cs new file mode 100644 index 000000000..20e3598ab --- /dev/null +++ b/crypto/src/bcpg/UserAttributePacket.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Utilities; + +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; + + IList v = Platform.CreateArrayList(); + 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); + } + } +} diff --git a/crypto/src/bcpg/UserAttributeSubpacket.cs b/crypto/src/bcpg/UserAttributeSubpacket.cs index bd49d2150..05f60ac17 100644 --- a/crypto/src/bcpg/UserAttributeSubpacket.cs +++ b/crypto/src/bcpg/UserAttributeSubpacket.cs @@ -10,40 +10,44 @@ namespace Org.BouncyCastle.Bcpg */ public class UserAttributeSubpacket { - private readonly UserAttributeSubpacketTag type; - private readonly byte[] data; + internal readonly UserAttributeSubpacketTag type; + private readonly bool longLength; // we preserve this as not everyone encodes length properly. + protected readonly byte[] data; - internal UserAttributeSubpacket( - UserAttributeSubpacketTag type, - byte[] data) + protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, byte[] data) + : this(type, false, data) + { + } + + protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, bool forceLongLength, byte[] data) { this.type = type; + this.longLength = forceLongLength; this.data = data; } - public UserAttributeSubpacketTag SubpacketType + public virtual UserAttributeSubpacketTag SubpacketType { get { return type; } } - /** + /** * return the generic data making up the packet. */ - public byte[] GetData() + public virtual byte[] GetData() { return data; } - public void Encode( - Stream os) + public virtual void Encode(Stream os) { int bodyLen = data.Length + 1; - if (bodyLen < 192) + if (bodyLen < 192 && !longLength) { os.WriteByte((byte)bodyLen); } - else if (bodyLen <= 8383) + else if (bodyLen <= 8383 && !longLength) { bodyLen -= 192; @@ -69,18 +73,18 @@ namespace Org.BouncyCastle.Bcpg if (obj == this) return true; - UserAttributeSubpacket other = obj as UserAttributeSubpacket; + UserAttributeSubpacket other = obj as UserAttributeSubpacket; - if (other == null) - return false; + if (other == null) + return false; - return type == other.type - && Arrays.AreEqual(data, other.data); + return type == other.type + && Arrays.AreEqual(data, other.data); } - public override int GetHashCode() + public override int GetHashCode() { - return type.GetHashCode() ^ Arrays.GetHashCode(data); + return type.GetHashCode() ^ Arrays.GetHashCode(data); } } } diff --git a/crypto/src/bcpg/UserAttributeSubpacketTags.cs b/crypto/src/bcpg/UserAttributeSubpacketTags.cs new file mode 100644 index 000000000..7a9cd1d5d --- /dev/null +++ b/crypto/src/bcpg/UserAttributeSubpacketTags.cs @@ -0,0 +1,10 @@ +namespace Org.BouncyCastle.Bcpg +{ + /** + * Basic PGP user attribute sub-packet tag types. + */ + public enum UserAttributeSubpacketTag + { + ImageAttribute = 1 + } +} diff --git a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs index 2e5ea0f3e..f0cc1b8e4 100644 --- a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs +++ b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs @@ -5,59 +5,61 @@ using Org.BouncyCastle.Utilities.IO; namespace Org.BouncyCastle.Bcpg { - /** - * reader for user attribute sub-packets - */ - public class UserAttributeSubpacketsParser - { - private readonly Stream input; + /** + * reader for user attribute sub-packets + */ + public class UserAttributeSubpacketsParser + { + private readonly Stream input; - public UserAttributeSubpacketsParser( - Stream input) - { - this.input = input; - } + public UserAttributeSubpacketsParser( + Stream input) + { + this.input = input; + } - public UserAttributeSubpacket ReadPacket() - { - int l = input.ReadByte(); - if (l < 0) - return null; + public virtual 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 bodyLen = 0; + bool longLength = false; + 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(); + longLength = true; + } + else + { + throw new IOException("unrecognised length reading user attribute sub packet"); + } - int tag = input.ReadByte(); - if (tag < 0) - throw new EndOfStreamException("unexpected EOF reading user attribute sub packet"); + 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(); + 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); - } - } + UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag; + switch (type) + { + case UserAttributeSubpacketTag.ImageAttribute: + return new ImageAttrib(longLength, data); + } + return new UserAttributeSubpacket(type, longLength, data); + } + } } diff --git a/crypto/src/bcpg/UserIdPacket.cs b/crypto/src/bcpg/UserIdPacket.cs new file mode 100644 index 000000000..a175e74a6 --- /dev/null +++ b/crypto/src/bcpg/UserIdPacket.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/attr/ImageAttrib.cs b/crypto/src/bcpg/attr/ImageAttrib.cs index 73490791c..2d0fef8b8 100644 --- a/crypto/src/bcpg/attr/ImageAttrib.cs +++ b/crypto/src/bcpg/attr/ImageAttrib.cs @@ -3,25 +3,29 @@ using System.IO; namespace Org.BouncyCastle.Bcpg.Attr { - /// <remarks>Basic type for a image attribute packet.</remarks> + /// <remarks>Basic type for a image attribute packet.</remarks> public class ImageAttrib - : UserAttributeSubpacket + : UserAttributeSubpacket { - public enum Format : byte - { - Jpeg = 1 - } + public enum Format : byte + { + Jpeg = 1 + } - private static readonly byte[] Zeroes = new byte[12]; + private static readonly byte[] Zeroes = new byte[12]; - private int hdrLength; + private int hdrLength; private int _version; private int _encoding; private byte[] imageData; - public ImageAttrib( - byte[] data) - : base(UserAttributeSubpacketTag.ImageAttribute, data) + public ImageAttrib(byte[] data) + : this(false, data) + { + } + + public ImageAttrib(bool forceLongLength, byte[] data) + : base(UserAttributeSubpacketTag.ImageAttribute, forceLongLength, data) { hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff); _version = data[2] & 0xff; @@ -31,36 +35,36 @@ namespace Org.BouncyCastle.Bcpg.Attr Array.Copy(data, hdrLength, imageData, 0, imageData.Length); } - public ImageAttrib( - Format imageType, - byte[] imageData) - : this(ToByteArray(imageType, imageData)) - { - } + 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(); - } + 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 + public virtual int Version { - get { return _version; } + get { return _version; } } - public int Encoding + public virtual int Encoding { - get { return _encoding; } + get { return _encoding; } } - public byte[] GetImageData() + public virtual byte[] GetImageData() { return imageData; } diff --git a/crypto/src/bcpg/sig/EmbeddedSignature.cs b/crypto/src/bcpg/sig/EmbeddedSignature.cs new file mode 100644 index 000000000..e47604ac8 --- /dev/null +++ b/crypto/src/bcpg/sig/EmbeddedSignature.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * Packet embedded signature + */ + public class EmbeddedSignature + : SignatureSubpacket + { + public EmbeddedSignature( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.EmbeddedSignature, critical, data) + { + } + } +} diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs new file mode 100644 index 000000000..4455c3814 --- /dev/null +++ b/crypto/src/bcpg/sig/Exportable.cs @@ -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; + } + } +} diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs new file mode 100644 index 000000000..91490d33b --- /dev/null +++ b/crypto/src/bcpg/sig/IssuerKeyId.cs @@ -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; + } + } + } +} diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs new file mode 100644 index 000000000..23b4cac29 --- /dev/null +++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs @@ -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; + } + } + } +} diff --git a/crypto/src/bcpg/sig/KeyFlags.cs b/crypto/src/bcpg/sig/KeyFlags.cs new file mode 100644 index 000000000..0592301b3 --- /dev/null +++ b/crypto/src/bcpg/sig/KeyFlags.cs @@ -0,0 +1,74 @@ +using System; + +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * Packet holding the key flag values. + */ + public class KeyFlags + : SignatureSubpacket + { + public const int CertifyOther = 0x01; + public const int SignData = 0x02; + public const int EncryptComms = 0x04; + public const int EncryptStorage = 0x08; + public const int Split = 0x10; + public const int Authentication = 0x20; + public const int Shared = 0x80; + + private static byte[] IntToByteArray( + int v) + { + byte[] tmp = new byte[4]; + int size = 0; + + for (int i = 0; i != 4; i++) + { + tmp[i] = (byte)(v >> (i * 8)); + if (tmp[i] != 0) + { + size = i; + } + } + + byte[] data = new byte[size + 1]; + Array.Copy(tmp, 0, data, 0, data.Length); + return data; + } + + public KeyFlags( + bool critical, + byte[] data) + : base(SignatureSubpacketTag.KeyFlags, critical, data) + { + } + + public KeyFlags( + bool critical, + int flags) + : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags)) + { + } + + /// <summary> + /// Return the flag values contained in the first 4 octets (note: at the moment + /// the standard only uses the first one). + /// </summary> + public int Flags + { + get + { + int flags = 0; + + for (int i = 0; i != data.Length; i++) + { + flags |= (data[i] & 0xff) << (i * 8); + } + + return flags; + } + } + } +} diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs new file mode 100644 index 000000000..ccc9aa745 --- /dev/null +++ b/crypto/src/bcpg/sig/NotationData.cs @@ -0,0 +1,112 @@ +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); + } + + public byte[] GetNotationValueBytes() + { + 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; + + byte[] bytes = new byte[valueLength]; + Array.Copy(data, valuePos, bytes, 0, valueLength); + return bytes; + } + } +} diff --git a/crypto/src/bcpg/sig/PreferredAlgorithms.cs b/crypto/src/bcpg/sig/PreferredAlgorithms.cs new file mode 100644 index 000000000..0f282a38c --- /dev/null +++ b/crypto/src/bcpg/sig/PreferredAlgorithms.cs @@ -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; + } + } +} diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs new file mode 100644 index 000000000..fc0353afd --- /dev/null +++ b/crypto/src/bcpg/sig/PrimaryUserId.cs @@ -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; + } + } +} diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs new file mode 100644 index 000000000..b5e94feec --- /dev/null +++ b/crypto/src/bcpg/sig/Revocable.cs @@ -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; + } + } +} diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs index 5e388246b..66982cb5a 100644 --- a/crypto/src/bcpg/sig/RevocationKey.cs +++ b/crypto/src/bcpg/sig/RevocationKey.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Text; namespace Org.BouncyCastle.Bcpg diff --git a/crypto/src/bcpg/sig/RevocationKeyTags.cs b/crypto/src/bcpg/sig/RevocationKeyTags.cs new file mode 100644 index 000000000..d76d1dcf4 --- /dev/null +++ b/crypto/src/bcpg/sig/RevocationKeyTags.cs @@ -0,0 +1,9 @@ +namespace Org.BouncyCastle.Bcpg +{ + public enum RevocationKeyTag + : byte + { + ClassDefault = 0x80, + ClassSensitive = 0x40 + } +} diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs index f32c1f64a..98e9b0a3d 100644 --- a/crypto/src/bcpg/sig/RevocationReason.cs +++ b/crypto/src/bcpg/sig/RevocationReason.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Text; using Org.BouncyCastle.Utilities; diff --git a/crypto/src/bcpg/sig/RevocationReasonTags.cs b/crypto/src/bcpg/sig/RevocationReasonTags.cs new file mode 100644 index 000000000..524a58c49 --- /dev/null +++ b/crypto/src/bcpg/sig/RevocationReasonTags.cs @@ -0,0 +1,14 @@ +namespace Org.BouncyCastle.Bcpg +{ + public enum RevocationReasonTag + : byte + { + NoReason = 0, // No reason specified (key revocations or cert revocations) + KeySuperseded = 1, // Key is superseded (key revocations) + KeyCompromised = 2, // Key material has been compromised (key revocations) + KeyRetired = 3, // Key is retired and no longer used (key revocations) + UserNoLongerValid = 32, // User ID information is no longer valid (cert revocations) + + // 100-110 - Private Use + } +} diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs new file mode 100644 index 000000000..e6f241f11 --- /dev/null +++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs new file mode 100644 index 000000000..7fddf5743 --- /dev/null +++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs @@ -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; + } + } + } +} diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs new file mode 100644 index 000000000..98cc808e7 --- /dev/null +++ b/crypto/src/bcpg/sig/SignerUserId.cs @@ -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); + } + } +} diff --git a/crypto/src/bcpg/sig/TrustSignature.cs b/crypto/src/bcpg/sig/TrustSignature.cs new file mode 100644 index 000000000..bbadd3067 --- /dev/null +++ b/crypto/src/bcpg/sig/TrustSignature.cs @@ -0,0 +1,43 @@ +using System; + +namespace Org.BouncyCastle.Bcpg.Sig +{ + /** + * packet giving trust. + */ + public class TrustSignature + : SignatureSubpacket + { + private static byte[] IntToByteArray( + int v1, + int v2) + { + return new byte[]{ (byte)v1, (byte)v2 }; + } + + 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; } + } + } +} |