summary refs log tree commit diff
path: root/crypto/src/util/io
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/util/io')
-rw-r--r--crypto/src/util/io/BaseInputStream.cs11
-rw-r--r--crypto/src/util/io/BaseOutputStream.cs9
-rw-r--r--crypto/src/util/io/NullOutputStream.cs18
-rw-r--r--crypto/src/util/io/PushbackStream.cs52
-rw-r--r--crypto/src/util/io/StreamOverflowException.cs5
-rw-r--r--crypto/src/util/io/Streams.cs94
-rw-r--r--crypto/src/util/io/TeeInputStream.cs13
-rw-r--r--crypto/src/util/io/TeeOutputStream.cs13
-rw-r--r--crypto/src/util/io/pem/PemGenerationException.cs5
-rw-r--r--crypto/src/util/io/pem/PemHeader.cs55
-rw-r--r--crypto/src/util/io/pem/PemObject.cs47
-rw-r--r--crypto/src/util/io/pem/PemObjectGenerator.cs13
-rw-r--r--crypto/src/util/io/pem/PemObjectParser.cs17
-rw-r--r--crypto/src/util/io/pem/PemReader.cs94
-rw-r--r--crypto/src/util/io/pem/PemWriter.cs120
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 + "-----");
+		}
+	}
+}