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