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.cs47
-rw-r--r--crypto/src/util/io/BaseOutputStream.cs47
-rw-r--r--crypto/src/util/io/PushbackStream.cs52
-rw-r--r--crypto/src/util/io/StreamOverflowException.cs30
-rw-r--r--crypto/src/util/io/Streams.cs94
-rw-r--r--crypto/src/util/io/TeeInputStream.cs51
-rw-r--r--crypto/src/util/io/TeeOutputStream.cs39
-rw-r--r--crypto/src/util/io/pem/PemGenerationException.cs29
-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
14 files changed, 735 insertions, 0 deletions
diff --git a/crypto/src/util/io/BaseInputStream.cs b/crypto/src/util/io/BaseInputStream.cs
new file mode 100644
index 000000000..3ff4a1957
--- /dev/null
+++ b/crypto/src/util/io/BaseInputStream.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public abstract class BaseInputStream : Stream
+    {
+		private bool closed;
+
+		public sealed override bool CanRead { get { return !closed; } }
+        public sealed override bool CanSeek { get { return false; } }
+        public sealed override bool CanWrite { get { return false; } }
+		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
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            int pos = offset;
+            try
+            {
+                int end = offset + count;
+                while (pos < end)
+                {
+                    int b = ReadByte();
+                    if (b == -1) break;
+                    buffer[pos++] = (byte) b;
+                }
+            }
+            catch (IOException)
+            {
+                if (pos == offset) throw;
+            }
+            return pos - offset;
+        }
+
+        public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+        public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+        public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+    }
+}
diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs
new file mode 100644
index 000000000..6e6c6d346
--- /dev/null
+++ b/crypto/src/util/io/BaseOutputStream.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public abstract class BaseOutputStream : Stream
+    {
+		private bool closed;
+
+		public sealed override bool CanRead { get { return false; } }
+        public sealed override bool CanSeek { get { return false; } }
+        public sealed override bool CanWrite { get { return !closed; } }
+		public override void Close() { closed = true; }
+        public override void Flush() {}
+        public sealed override long Length { get { throw new NotSupportedException(); } }
+        public sealed override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+        public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+        public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+        public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            Debug.Assert(buffer != null);
+            Debug.Assert(0 <= offset && offset <= buffer.Length);
+            Debug.Assert(count >= 0);
+
+            int end = offset + count;
+
+            Debug.Assert(0 <= end && end <= buffer.Length);
+
+            for (int i = offset; i < end; ++i)
+            {
+                this.WriteByte(buffer[i]);
+            }
+        }
+
+		public virtual void Write(params byte[] buffer)
+		{
+			Write(buffer, 0, buffer.Length);
+		}
+	}
+}
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
new file mode 100644
index 000000000..d8fcb558c
--- /dev/null
+++ b/crypto/src/util/io/StreamOverflowException.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class StreamOverflowException
+		: IOException
+	{
+		public StreamOverflowException()
+			: base()
+		{
+		}
+
+		public StreamOverflowException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public StreamOverflowException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..373df4502
--- /dev/null
+++ b/crypto/src/util/io/TeeInputStream.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+	public class TeeInputStream
+		: BaseInputStream
+	{
+		private readonly Stream input, tee;
+
+		public TeeInputStream(Stream input, Stream tee)
+		{
+			Debug.Assert(input.CanRead);
+			Debug.Assert(tee.CanWrite);
+
+			this.input = input;
+			this.tee = tee;
+		}
+
+		public override void Close()
+		{
+			input.Close();
+			tee.Close();
+		}
+
+		public override int Read(byte[] buf, int off, int len)
+		{
+			int i = input.Read(buf, off, len);
+
+			if (i > 0)
+			{
+				tee.Write(buf, off, i);
+			}
+
+			return i;
+		}
+
+		public override int ReadByte()
+		{
+			int i = input.ReadByte();
+
+			if (i >= 0)
+			{
+				tee.WriteByte((byte)i);
+			}
+
+			return i;
+		}
+	}
+}
diff --git a/crypto/src/util/io/TeeOutputStream.cs b/crypto/src/util/io/TeeOutputStream.cs
new file mode 100644
index 000000000..fe3a7586a
--- /dev/null
+++ b/crypto/src/util/io/TeeOutputStream.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public class TeeOutputStream
+		: BaseOutputStream
+	{
+		private readonly Stream output, tee;
+
+		public TeeOutputStream(Stream output, Stream tee)
+		{
+			Debug.Assert(output.CanWrite);
+			Debug.Assert(tee.CanWrite);
+
+			this.output = output;
+			this.tee = tee;
+		}
+
+		public override void Close()
+		{
+			output.Close();
+			tee.Close();
+		}
+
+		public override void Write(byte[] buffer, int offset, int count)
+		{
+			output.Write(buffer, offset, count);
+			tee.Write(buffer, offset, count);
+		}
+
+		public override void WriteByte(byte b)
+		{
+			output.WriteByte(b);
+			tee.WriteByte(b);
+		}
+	}
+}
diff --git a/crypto/src/util/io/pem/PemGenerationException.cs b/crypto/src/util/io/pem/PemGenerationException.cs
new file mode 100644
index 000000000..b8edc622b
--- /dev/null
+++ b/crypto/src/util/io/pem/PemGenerationException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PemGenerationException
+		: Exception
+	{
+		public PemGenerationException()
+			: base()
+		{
+		}
+
+		public PemGenerationException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public PemGenerationException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
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 + "-----");
+		}
+	}
+}