diff options
Diffstat (limited to 'crypto/src/util/io')
-rw-r--r-- | crypto/src/util/io/BaseInputStream.cs | 11 | ||||
-rw-r--r-- | crypto/src/util/io/BaseOutputStream.cs | 9 | ||||
-rw-r--r-- | crypto/src/util/io/NullOutputStream.cs | 18 | ||||
-rw-r--r-- | crypto/src/util/io/PushbackStream.cs | 52 | ||||
-rw-r--r-- | crypto/src/util/io/StreamOverflowException.cs | 5 | ||||
-rw-r--r-- | crypto/src/util/io/Streams.cs | 94 | ||||
-rw-r--r-- | crypto/src/util/io/TeeInputStream.cs | 13 | ||||
-rw-r--r-- | crypto/src/util/io/TeeOutputStream.cs | 13 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemGenerationException.cs | 5 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemHeader.cs | 55 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemObject.cs | 47 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemObjectGenerator.cs | 13 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemObjectParser.cs | 17 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemReader.cs | 94 | ||||
-rw-r--r-- | crypto/src/util/io/pem/PemWriter.cs | 120 |
15 files changed, 531 insertions, 35 deletions
diff --git a/crypto/src/util/io/BaseInputStream.cs b/crypto/src/util/io/BaseInputStream.cs index 08eedb160..3ff4a1957 100644 --- a/crypto/src/util/io/BaseInputStream.cs +++ b/crypto/src/util/io/BaseInputStream.cs @@ -11,15 +11,8 @@ namespace Org.BouncyCastle.Utilities.IO public sealed override bool CanRead { get { return !closed; } } public sealed override bool CanSeek { get { return false; } } public sealed override bool CanWrite { get { return false; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - closed = true; - } - - public sealed override void Flush() {} + public override void Close() { closed = true; } + public sealed override void Flush() {} public sealed override long Length { get { throw new NotSupportedException(); } } public sealed override long Position { diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs index 77233f68c..6e6c6d346 100644 --- a/crypto/src/util/io/BaseOutputStream.cs +++ b/crypto/src/util/io/BaseOutputStream.cs @@ -11,14 +11,7 @@ namespace Org.BouncyCastle.Utilities.IO public sealed override bool CanRead { get { return false; } } public sealed override bool CanSeek { get { return false; } } public sealed override bool CanWrite { get { return !closed; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - closed = true; - } - + public override void Close() { closed = true; } public override void Flush() {} public sealed override long Length { get { throw new NotSupportedException(); } } public sealed override long Position diff --git a/crypto/src/util/io/NullOutputStream.cs b/crypto/src/util/io/NullOutputStream.cs new file mode 100644 index 000000000..13877fa13 --- /dev/null +++ b/crypto/src/util/io/NullOutputStream.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Utilities.IO +{ + internal class NullOutputStream + : BaseOutputStream + { + public override void WriteByte(byte b) + { + // do nothing + } + + public override void Write(byte[] buffer, int offset, int count) + { + // do nothing + } + } +} diff --git a/crypto/src/util/io/PushbackStream.cs b/crypto/src/util/io/PushbackStream.cs new file mode 100644 index 000000000..954694259 --- /dev/null +++ b/crypto/src/util/io/PushbackStream.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1.Utilities; + +namespace Org.BouncyCastle.Utilities.IO +{ + public class PushbackStream + : FilterStream + { + private int buf = -1; + + public PushbackStream( + Stream s) + : base(s) + { + } + + public override int ReadByte() + { + if (buf != -1) + { + int tmp = buf; + buf = -1; + return tmp; + } + + return base.ReadByte(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (buf != -1 && count > 0) + { + // TODO Can this case be made more efficient? + buffer[offset] = (byte) buf; + buf = -1; + return 1; + } + + return base.Read(buffer, offset, count); + } + + public virtual void Unread(int b) + { + if (buf != -1) + throw new InvalidOperationException("Can only push back one byte"); + + buf = b & 0xFF; + } + } +} diff --git a/crypto/src/util/io/StreamOverflowException.cs b/crypto/src/util/io/StreamOverflowException.cs index a8e7432fa..d8fcb558c 100644 --- a/crypto/src/util/io/StreamOverflowException.cs +++ b/crypto/src/util/io/StreamOverflowException.cs @@ -3,7 +3,10 @@ using System.IO; namespace Org.BouncyCastle.Utilities.IO { - public class StreamOverflowException +#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT) + [Serializable] +#endif + public class StreamOverflowException : IOException { public StreamOverflowException() diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs new file mode 100644 index 000000000..ee95d3b01 --- /dev/null +++ b/crypto/src/util/io/Streams.cs @@ -0,0 +1,94 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.IO +{ + public sealed class Streams + { + private const int BufferSize = 512; + + private Streams() + { + } + + public static void Drain(Stream inStr) + { + byte[] bs = new byte[BufferSize]; + while (inStr.Read(bs, 0, bs.Length) > 0) + { + } + } + + public static byte[] ReadAll(Stream inStr) + { + MemoryStream buf = new MemoryStream(); + PipeAll(inStr, buf); + return buf.ToArray(); + } + + public static byte[] ReadAllLimited(Stream inStr, int limit) + { + MemoryStream buf = new MemoryStream(); + PipeAllLimited(inStr, limit, buf); + return buf.ToArray(); + } + + public static int ReadFully(Stream inStr, byte[] buf) + { + return ReadFully(inStr, buf, 0, buf.Length); + } + + public static int ReadFully(Stream inStr, byte[] buf, int off, int len) + { + int totalRead = 0; + while (totalRead < len) + { + int numRead = inStr.Read(buf, off + totalRead, len - totalRead); + if (numRead < 1) + break; + totalRead += numRead; + } + return totalRead; + } + + public static void PipeAll(Stream inStr, Stream outStr) + { + byte[] bs = new byte[BufferSize]; + int numRead; + while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0) + { + outStr.Write(bs, 0, numRead); + } + } + + /// <summary> + /// Pipe all bytes from <c>inStr</c> to <c>outStr</c>, throwing <c>StreamFlowException</c> if greater + /// than <c>limit</c> bytes in <c>inStr</c>. + /// </summary> + /// <param name="inStr"> + /// A <see cref="Stream"/> + /// </param> + /// <param name="limit"> + /// A <see cref="System.Int64"/> + /// </param> + /// <param name="outStr"> + /// A <see cref="Stream"/> + /// </param> + /// <returns>The number of bytes actually transferred, if not greater than <c>limit</c></returns> + /// <exception cref="IOException"></exception> + public static long PipeAllLimited(Stream inStr, long limit, Stream outStr) + { + byte[] bs = new byte[BufferSize]; + long total = 0; + int numRead; + while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0) + { + total += numRead; + if (total > limit) + throw new StreamOverflowException("Data Overflow"); + outStr.Write(bs, 0, numRead); + } + return total; + } + } +} diff --git a/crypto/src/util/io/TeeInputStream.cs b/crypto/src/util/io/TeeInputStream.cs index fed9823f0..373df4502 100644 --- a/crypto/src/util/io/TeeInputStream.cs +++ b/crypto/src/util/io/TeeInputStream.cs @@ -18,14 +18,11 @@ namespace Org.BouncyCastle.Utilities.IO this.tee = tee; } - protected override void Dispose(bool disposing) - { - if (disposing) - { - input.Dispose(); - tee.Dispose(); - } - } + public override void Close() + { + input.Close(); + tee.Close(); + } public override int Read(byte[] buf, int off, int len) { diff --git a/crypto/src/util/io/TeeOutputStream.cs b/crypto/src/util/io/TeeOutputStream.cs index 965ef23c8..fe3a7586a 100644 --- a/crypto/src/util/io/TeeOutputStream.cs +++ b/crypto/src/util/io/TeeOutputStream.cs @@ -18,14 +18,11 @@ namespace Org.BouncyCastle.Utilities.IO this.tee = tee; } - protected override void Dispose(bool disposing) - { - if (disposing) - { - output.Dispose(); - tee.Dispose(); - } - } + public override void Close() + { + output.Close(); + tee.Close(); + } public override void Write(byte[] buffer, int offset, int count) { diff --git a/crypto/src/util/io/pem/PemGenerationException.cs b/crypto/src/util/io/pem/PemGenerationException.cs index 22e83ac2d..b8edc622b 100644 --- a/crypto/src/util/io/pem/PemGenerationException.cs +++ b/crypto/src/util/io/pem/PemGenerationException.cs @@ -2,7 +2,10 @@ using System; namespace Org.BouncyCastle.Utilities.IO.Pem { - public class PemGenerationException +#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT) + [Serializable] +#endif + public class PemGenerationException : Exception { public PemGenerationException() diff --git a/crypto/src/util/io/pem/PemHeader.cs b/crypto/src/util/io/pem/PemHeader.cs new file mode 100644 index 000000000..72da8a4f7 --- /dev/null +++ b/crypto/src/util/io/pem/PemHeader.cs @@ -0,0 +1,55 @@ +using System; + +namespace Org.BouncyCastle.Utilities.IO.Pem +{ + public class PemHeader + { + private string name; + private string val; + + public PemHeader(string name, string val) + { + this.name = name; + this.val = val; + } + + public virtual string Name + { + get { return name; } + } + + public virtual string Value + { + get { return val; } + } + + public override int GetHashCode() + { + return GetHashCode(this.name) + 31 * GetHashCode(this.val); + } + + public override bool Equals(object obj) + { + if (obj == this) + return true; + + if (!(obj is PemHeader)) + return false; + + PemHeader other = (PemHeader)obj; + + return Platform.Equals(this.name, other.name) + && Platform.Equals(this.val, other.val); + } + + private int GetHashCode(string s) + { + if (s == null) + { + return 1; + } + + return s.GetHashCode(); + } + } +} diff --git a/crypto/src/util/io/pem/PemObject.cs b/crypto/src/util/io/pem/PemObject.cs new file mode 100644 index 000000000..41212f997 --- /dev/null +++ b/crypto/src/util/io/pem/PemObject.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities.Collections; + +namespace Org.BouncyCastle.Utilities.IO.Pem +{ + public class PemObject + : PemObjectGenerator + { + private string type; + private IList headers; + private byte[] content; + + public PemObject(string type, byte[] content) + : this(type, Platform.CreateArrayList(), content) + { + } + + public PemObject(String type, IList headers, byte[] content) + { + this.type = type; + this.headers = Platform.CreateArrayList(headers); + this.content = content; + } + + public string Type + { + get { return type; } + } + + public IList Headers + { + get { return headers; } + } + + public byte[] Content + { + get { return content; } + } + + public PemObject Generate() + { + return this; + } + } +} diff --git a/crypto/src/util/io/pem/PemObjectGenerator.cs b/crypto/src/util/io/pem/PemObjectGenerator.cs new file mode 100644 index 000000000..6f9bfc191 --- /dev/null +++ b/crypto/src/util/io/pem/PemObjectGenerator.cs @@ -0,0 +1,13 @@ +using System; + +namespace Org.BouncyCastle.Utilities.IO.Pem +{ + public interface PemObjectGenerator + { + /// <returns> + /// A <see cref="PemObject"/> + /// </returns> + /// <exception cref="PemGenerationException"></exception> + PemObject Generate(); + } +} diff --git a/crypto/src/util/io/pem/PemObjectParser.cs b/crypto/src/util/io/pem/PemObjectParser.cs new file mode 100644 index 000000000..91d26dc3a --- /dev/null +++ b/crypto/src/util/io/pem/PemObjectParser.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; + +namespace Org.BouncyCastle.Utilities.IO.Pem +{ + public interface PemObjectParser + { + /// <param name="obj"> + /// A <see cref="PemObject"/> + /// </param> + /// <returns> + /// A <see cref="System.Object"/> + /// </returns> + /// <exception cref="IOException"></exception> + object ParseObject(PemObject obj); + } +} diff --git a/crypto/src/util/io/pem/PemReader.cs b/crypto/src/util/io/pem/PemReader.cs new file mode 100644 index 000000000..b3284705d --- /dev/null +++ b/crypto/src/util/io/pem/PemReader.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Utilities.IO.Pem +{ + public class PemReader + { + private const string BeginString = "-----BEGIN "; + private const string EndString = "-----END "; + + private readonly TextReader reader; + + public PemReader(TextReader reader) + { + if (reader == null) + throw new ArgumentNullException("reader"); + + this.reader = reader; + } + + public TextReader Reader + { + get { return reader; } + } + + /// <returns> + /// A <see cref="PemObject"/> + /// </returns> + /// <exception cref="IOException"></exception> + public PemObject ReadPemObject() + { + string line = reader.ReadLine(); + + if (line != null && line.StartsWith(BeginString)) + { + line = line.Substring(BeginString.Length); + int index = line.IndexOf('-'); + string type = line.Substring(0, index); + + if (index > 0) + return LoadObject(type); + } + + return null; + } + + private PemObject LoadObject(string type) + { + string endMarker = EndString + type; + IList headers = Platform.CreateArrayList(); + StringBuilder buf = new StringBuilder(); + + string line; + while ((line = reader.ReadLine()) != null + && line.IndexOf(endMarker) == -1) + { + int colonPos = line.IndexOf(':'); + + if (colonPos == -1) + { + buf.Append(line.Trim()); + } + else + { + // Process field + string fieldName = line.Substring(0, colonPos).Trim(); + + if (fieldName.StartsWith("X-")) + fieldName = fieldName.Substring(2); + + string fieldValue = line.Substring(colonPos + 1).Trim(); + + headers.Add(new PemHeader(fieldName, fieldValue)); + } + } + + if (line == null) + { + throw new IOException(endMarker + " not found"); + } + + if (buf.Length % 4 != 0) + { + throw new IOException("base64 data appears to be truncated"); + } + + return new PemObject(type, headers, Base64.Decode(buf.ToString())); + } + } +} diff --git a/crypto/src/util/io/pem/PemWriter.cs b/crypto/src/util/io/pem/PemWriter.cs new file mode 100644 index 000000000..e85b31543 --- /dev/null +++ b/crypto/src/util/io/pem/PemWriter.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Utilities.IO.Pem +{ + /** + * A generic PEM writer, based on RFC 1421 + */ + public class PemWriter + { + private const int LineLength = 64; + + private readonly TextWriter writer; + private readonly int nlLength; + private char[] buf = new char[LineLength]; + + /** + * Base constructor. + * + * @param out output stream to use. + */ + public PemWriter(TextWriter writer) + { + if (writer == null) + throw new ArgumentNullException("writer"); + + this.writer = writer; + this.nlLength = Platform.NewLine.Length; + } + + public TextWriter Writer + { + get { return writer; } + } + + /** + * Return the number of bytes or characters required to contain the + * passed in object if it is PEM encoded. + * + * @param obj pem object to be output + * @return an estimate of the number of bytes + */ + public int GetOutputSize(PemObject obj) + { + // BEGIN and END boundaries. + int size = (2 * (obj.Type.Length + 10 + nlLength)) + 6 + 4; + + if (obj.Headers.Count > 0) + { + foreach (PemHeader header in obj.Headers) + { + size += header.Name.Length + ": ".Length + header.Value.Length + nlLength; + } + + size += nlLength; + } + + // base64 encoding + int dataLen = ((obj.Content.Length + 2) / 3) * 4; + + size += dataLen + (((dataLen + LineLength - 1) / LineLength) * nlLength); + + return size; + } + + public void WriteObject(PemObjectGenerator objGen) + { + PemObject obj = objGen.Generate(); + + WritePreEncapsulationBoundary(obj.Type); + + if (obj.Headers.Count > 0) + { + foreach (PemHeader header in obj.Headers) + { + writer.Write(header.Name); + writer.Write(": "); + writer.WriteLine(header.Value); + } + + writer.WriteLine(); + } + + WriteEncoded(obj.Content); + WritePostEncapsulationBoundary(obj.Type); + } + + private void WriteEncoded(byte[] bytes) + { + bytes = Base64.Encode(bytes); + + for (int i = 0; i < bytes.Length; i += buf.Length) + { + int index = 0; + while (index != buf.Length) + { + if ((i + index) >= bytes.Length) + break; + + buf[index] = (char)bytes[i + index]; + index++; + } + writer.WriteLine(buf, 0, index); + } + } + + private void WritePreEncapsulationBoundary(string type) + { + writer.WriteLine("-----BEGIN " + type + "-----"); + } + + private void WritePostEncapsulationBoundary(string type) + { + writer.WriteLine("-----END " + type + "-----"); + } + } +} |