diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-02-28 12:09:51 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2023-02-28 12:09:51 +0700 |
commit | d67160cc62739b62d852820c015e3af57f9f4736 (patch) | |
tree | 97f0b63f00c602f7e703cd03df48852d1fded90c | |
parent | Exception on malformed checksum (diff) | |
download | BouncyCastle.NET-ed25519-d67160cc62739b62d852820c015e3af57f9f4736.tar.xz |
CRC24 perf. opts.
-rw-r--r-- | crypto/src/bcpg/ArmoredInputStream.cs | 58 | ||||
-rw-r--r-- | crypto/src/bcpg/ArmoredOutputStream.cs | 108 | ||||
-rw-r--r-- | crypto/src/bcpg/Crc24.cs | 54 | ||||
-rw-r--r-- | crypto/src/crypto/util/Pack.cs | 28 |
4 files changed, 165 insertions, 83 deletions
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 |