diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs
index 739d78083..b493d04fc 100644
--- a/crypto/src/bcpg/ArmoredInputStream.cs
+++ b/crypto/src/bcpg/ArmoredInputStream.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.IO;
@@ -396,36 +397,30 @@ namespace Org.BouncyCastle.Bcpg
newLineFound = false;
}
}
-
+
lastC = c;
if (c < 0)
{
isEndOfStream = true;
}
-
+
return c;
}
if (bufPtr > 2 || crcFound)
{
c = ReadIgnoreSpace();
-
+
if (c == '\r' || c == '\n')
{
c = ReadIgnoreSpace();
-
+
while (c == '\n' || c == '\r')
{
c = ReadIgnoreSpace();
}
- if (c < 0) // EOF
- {
- isEndOfStream = true;
- return -1;
- }
-
if (c == '=') // crc reached
{
bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
@@ -434,28 +429,23 @@ namespace Org.BouncyCastle.Bcpg
crcFound = true;
- int i = ((outBuf[0] & 0xff) << 16)
- | ((outBuf[1] & 0xff) << 8)
- | (outBuf[2] & 0xff);
+ int i = (int)Pack.BE_To_UInt24(outBuf);
if (i != crc.Value)
throw new IOException("crc check failed in armored message.");
return ReadByte();
}
- else if (c == '-') // end of record reached
+
+ if (c == '-') // end of record reached
{
while ((c = input.ReadByte()) >= 0)
{
if (c == '\n' || c == '\r')
- {
break;
- }
}
if (!crcFound && detectMissingChecksum)
- {
throw new IOException("crc check not found");
- }
crcFound = false;
start = true;
@@ -468,30 +458,30 @@ namespace Org.BouncyCastle.Bcpg
return -1;
}
- else // data
- {
- bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
- }
+ }
+
+ if (c < 0)
+ {
+ isEndOfStream = true;
+ return -1;
+ }
+
+ bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
+
+ if (bufPtr == 0)
+ {
+ crc.Update3(outBuf, 0);
}
else
{
- if (c >= 0)
+ for (int i = bufPtr; i < 3; ++i)
{
- bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
- }
- else
- {
- isEndOfStream = true;
- return -1;
+ crc.Update(outBuf[i]);
}
}
}
- c = outBuf[bufPtr++];
-
- crc.Update((byte)c);
-
- return c;
+ return (int)outBuf[bufPtr++];
}
protected override void Dispose(bool disposing)
diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs
index bfed1972a..37dcf2340 100644
--- a/crypto/src/bcpg/ArmoredOutputStream.cs
+++ b/crypto/src/bcpg/ArmoredOutputStream.cs
@@ -4,6 +4,7 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.Utilities.IO;
@@ -37,51 +38,81 @@ namespace Org.BouncyCastle.Bcpg
/**
* encode the input data producing a base 64 encoded byte array.
*/
- private static void Encode(
- Stream outStream,
- int[] data,
- int len)
+ private static void Encode(Stream outStream, byte[] data, int len)
{
Debug.Assert(len > 0);
Debug.Assert(len < 4);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> bs = stackalloc byte[4];
+#else
byte[] bs = new byte[4];
+#endif
+
int d1 = data[0];
bs[0] = encodingTable[(d1 >> 2) & 0x3f];
switch (len)
{
- case 1:
- {
- bs[1] = encodingTable[(d1 << 4) & 0x3f];
- bs[2] = (byte)'=';
- bs[3] = (byte)'=';
- break;
- }
- case 2:
- {
- int d2 = data[1];
- bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
- bs[2] = encodingTable[(d2 << 2) & 0x3f];
- bs[3] = (byte)'=';
- break;
- }
- case 3:
- {
- int d2 = data[1];
- int d3 = data[2];
- bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
- bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
- bs[3] = encodingTable[d3 & 0x3f];
- break;
- }
+ case 1:
+ {
+ bs[1] = encodingTable[(d1 << 4) & 0x3f];
+ bs[2] = (byte)'=';
+ bs[3] = (byte)'=';
+ break;
+ }
+ case 2:
+ {
+ int d2 = data[1];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[(d2 << 2) & 0x3f];
+ bs[3] = (byte)'=';
+ break;
+ }
+ case 3:
+ {
+ int d2 = data[1];
+ int d3 = data[2];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+ bs[3] = encodingTable[d3 & 0x3f];
+ break;
+ }
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ outStream.Write(bs);
+#else
outStream.Write(bs, 0, bs.Length);
+#endif
+ }
+
+ private static void Encode3(Stream outStream, byte[] data)
+ {
+ int d1 = data[0];
+ int d2 = data[1];
+ int d3 = data[2];
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> bs = stackalloc byte[4];
+#else
+ byte[] bs = new byte[4];
+#endif
+
+ bs[0] = encodingTable[(d1 >> 2) & 0x3f];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+ bs[3] = encodingTable[d3 & 0x3f];
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ outStream.Write(bs);
+#else
+ outStream.Write(bs, 0, bs.Length);
+#endif
}
private readonly Stream outStream;
- private int[] buf = new int[3];
+ private byte[] buf = new byte[3];
private int bufPtr = 0;
private Crc24 crc = new Crc24();
private int chunkCount = 0;
@@ -324,7 +355,8 @@ namespace Org.BouncyCastle.Bcpg
if (bufPtr == 3)
{
- Encode(outStream, buf, bufPtr);
+ crc.Update3(buf, 0);
+ Encode3(outStream, buf);
bufPtr = 0;
if ((++chunkCount & 0xf) == 0)
{
@@ -332,8 +364,7 @@ namespace Org.BouncyCastle.Bcpg
}
}
- crc.Update(value);
- buf[bufPtr++] = value & 0xff;
+ buf[bufPtr++] = value;
}
/**
@@ -359,18 +390,17 @@ namespace Org.BouncyCastle.Bcpg
{
if (bufPtr > 0)
{
+ for (int i = 0; i < bufPtr; ++i)
+ {
+ crc.Update(buf[i]);
+ }
Encode(outStream, buf, bufPtr);
}
DoWrite(NewLine + '=');
- int crcV = crc.Value;
-
- buf[0] = ((crcV >> 16) & 0xff);
- buf[1] = ((crcV >> 8) & 0xff);
- buf[2] = (crcV & 0xff);
-
- Encode(outStream, buf, 3);
+ Pack.UInt24_To_BE((uint)crc.Value, buf);
+ Encode3(outStream, buf);
DoWrite(NewLine);
DoWrite(footerStart);
diff --git a/crypto/src/bcpg/Crc24.cs b/crypto/src/bcpg/Crc24.cs
index 54c9f2f5a..66cea0b06 100644
--- a/crypto/src/bcpg/Crc24.cs
+++ b/crypto/src/bcpg/Crc24.cs
@@ -1,5 +1,3 @@
-using System;
-
namespace Org.BouncyCastle.Bcpg
{
public sealed class Crc24
@@ -7,6 +5,41 @@ namespace Org.BouncyCastle.Bcpg
private const int Crc24Init = 0x0b704ce;
private const int Crc24Poly = 0x1864cfb;
+ private static readonly int[] Table0, Table8, Table16;
+
+ static Crc24()
+ {
+ int[] table0 = new int[256];
+ int[] table8 = new int[256];
+ int[] table16 = new int[256];
+
+ int crc = 0x800000;
+ for (int i = 1; i < 256; i <<= 1)
+ {
+ int carry = ((crc << 8) >> 31) & Crc24Poly;
+ crc = (crc << 1) ^ carry;
+
+ for (int j = 0; j < i; ++j)
+ {
+ table0[i + j] = crc ^ table0[j];
+ }
+ }
+
+ for (int i = 1; i < 256; ++i)
+ {
+ int crc0 = table0[i];
+ int crc8 = ((crc0 & 0xFFFF) << 8) ^ table0[(crc0 >> 16) & 255];
+ int crc16 = ((crc8 & 0xFFFF) << 8) ^ table0[(crc8 >> 16) & 255];
+
+ table8[i] = crc8;
+ table16[i] = crc16;
+ }
+
+ Table0 = table0;
+ Table8 = table8;
+ Table16 = table16;
+ }
+
private int m_crc = Crc24Init;
public Crc24()
@@ -15,17 +48,18 @@ namespace Org.BouncyCastle.Bcpg
public void Update(byte b)
{
- m_crc ^= (int)b << 16;
- for (int i = 0; i < 8; i++)
- {
- int carry = -((m_crc >> 23) & 1) & Crc24Poly;
+ int index = (b ^ (m_crc >> 16)) & 255;
+ m_crc = (m_crc << 8) ^ Table0[index];
+ }
- m_crc <<= 1;
- m_crc ^= carry;
- }
+ public void Update3(byte[] buf, int off)
+ {
+ m_crc = Table16[(buf[off + 0] ^ (m_crc >> 16)) & 255]
+ ^ Table8[(buf[off + 1] ^ (m_crc >> 8)) & 255]
+ ^ Table0[(buf[off + 2] ^ m_crc) & 255];
}
- public int Value => m_crc;
+ public int Value => m_crc & 0xFFFFFF;
public void Reset()
{
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index e00ba39fa..cd8010f5a 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -102,6 +102,34 @@ namespace Org.BouncyCastle.Crypto.Utilities
return ns;
}
+ internal static void UInt24_To_BE(uint n, byte[] bs)
+ {
+ bs[0] = (byte)(n >> 16);
+ bs[1] = (byte)(n >> 8);
+ bs[2] = (byte)n;
+ }
+
+ internal static void UInt24_To_BE(uint n, byte[] bs, int off)
+ {
+ bs[off + 0] = (byte)(n >> 16);
+ bs[off + 1] = (byte)(n >> 8);
+ bs[off + 2] = (byte)n;
+ }
+
+ internal static uint BE_To_UInt24(byte[] bs)
+ {
+ return (uint)bs[0] << 16
+ | (uint)bs[1] << 8
+ | bs[2];
+ }
+
+ internal static uint BE_To_UInt24(byte[] bs, int off)
+ {
+ return (uint)bs[off] << 16
+ | (uint)bs[off + 1] << 8
+ | bs[off + 2];
+ }
+
internal static void UInt32_To_BE(uint n, byte[] bs)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
|