diff --git a/crypto/src/util/encoders/Base64Encoder.cs b/crypto/src/util/encoders/Base64Encoder.cs
index 7ec79eaa0..6ba9e97a4 100644
--- a/crypto/src/util/encoders/Base64Encoder.cs
+++ b/crypto/src/util/encoders/Base64Encoder.cs
@@ -46,6 +46,9 @@ namespace Org.BouncyCastle.Utilities.Encoders
public int Encode(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Encode(inBuf.AsSpan(inOff, inLen), outBuf.AsSpan(outOff));
+#else
int inPos = inOff;
int inEnd = inOff + inLen - 2;
int outPos = outOff;
@@ -88,8 +91,57 @@ namespace Org.BouncyCastle.Utilities.Encoders
}
return outPos - outOff;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Encode(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int inPos = 0;
+ int inEnd = input.Length - 2;
+ int outPos = 0;
+
+ while (inPos < inEnd)
+ {
+ uint a1 = input[inPos++];
+ uint a2 = input[inPos++];
+ uint a3 = input[inPos++];
+
+ output[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
+ output[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
+ output[outPos++] = encodingTable[((a2 << 2) | (a3 >> 6)) & 0x3F];
+ output[outPos++] = encodingTable[a3 & 0x3F];
+ }
+
+ switch (input.Length - inPos)
+ {
+ case 1:
+ {
+ uint a1 = input[inPos++];
+
+ output[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
+ output[outPos++] = encodingTable[(a1 << 4) & 0x3F];
+ output[outPos++] = padding;
+ output[outPos++] = padding;
+ break;
+ }
+ case 2:
+ {
+ uint a1 = input[inPos++];
+ uint a2 = input[inPos++];
+
+ output[outPos++] = encodingTable[(a1 >> 2) & 0x3F];
+ output[outPos++] = encodingTable[((a1 << 4) | (a2 >> 4)) & 0x3F];
+ output[outPos++] = encodingTable[(a2 << 2) & 0x3F];
+ output[outPos++] = padding;
+ break;
+ }
+ }
+
+ return outPos;
+ }
+#endif
+
/**
* encode the input data producing a base 64 output stream.
*
@@ -97,6 +149,9 @@ namespace Org.BouncyCastle.Utilities.Encoders
*/
public int Encode(byte[] buf, int off, int len, Stream outStream)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Encode(buf.AsSpan(off, len), outStream);
+#else
if (len < 0)
return 0;
@@ -111,8 +166,25 @@ namespace Org.BouncyCastle.Utilities.Encoders
remaining -= inLen;
}
return (len + 2) / 3 * 4;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Encode(ReadOnlySpan<byte> data, Stream outStream)
+ {
+ Span<byte> tmp = stackalloc byte[72];
+ int result = (data.Length + 2) / 3 * 4;
+ while (!data.IsEmpty)
+ {
+ int inLen = System.Math.Min(54, data.Length);
+ int outLen = Encode(data[..inLen], tmp);
+ outStream.Write(tmp[..outLen]);
+ data = data[inLen..];
+ }
+ return result;
+ }
+#endif
+
private bool Ignore(char c)
{
return c == '\n' || c =='\r' || c == '\t' || c == ' ';
@@ -126,6 +198,9 @@ namespace Org.BouncyCastle.Utilities.Encoders
*/
public int Decode(byte[] data, int off, int length, Stream outStream)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Decode(data.AsSpan(off, length), outStream);
+#else
byte b1, b2, b3, b4;
byte[] outBuffer = new byte[54]; // S/MIME standard
int bufOff = 0;
@@ -140,10 +215,8 @@ namespace Org.BouncyCastle.Utilities.Encoders
end--;
}
- int i = off;
- int finish = end - 4;
-
- i = NextI(data, i, finish);
+ int finish = end - 4;
+ int i = NextI(data, off, finish);
while (i < finish)
{
@@ -192,12 +265,84 @@ namespace Org.BouncyCastle.Utilities.Encoders
outLen += DecodeLastBlock(outStream, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]);
return outLen;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Decode(ReadOnlySpan<byte> data, Stream outStream)
+ {
+ byte b1, b2, b3, b4;
+ Span<byte> outBuffer = stackalloc byte[54]; // S/MIME standard
+ int bufOff = 0;
+ int outLen = 0;
+ int end = data.Length;
+
+ while (end > 0)
+ {
+ if (!Ignore((char)data[end - 1]))
+ break;
+
+ end--;
+ }
+
+ int finish = end - 4;
+ int i = NextI(data, 0, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = NextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = NextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = NextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ if ((b1 | b2 | b3 | b4) >= 0x80)
+ throw new IOException("invalid characters encountered in base64 data");
+
+ outBuffer[bufOff++] = (byte)((b1 << 2) | (b2 >> 4));
+ outBuffer[bufOff++] = (byte)((b2 << 4) | (b3 >> 2));
+ outBuffer[bufOff++] = (byte)((b3 << 6) | b4);
+
+ if (bufOff == outBuffer.Length)
+ {
+ outStream.Write(outBuffer);
+ bufOff = 0;
+ }
+
+ outLen += 3;
+
+ i = NextI(data, i, finish);
+ }
+
+ if (bufOff > 0)
+ {
+ outStream.Write(outBuffer[..bufOff]);
+ }
+
+ int e0 = NextI(data, i, end);
+ int e1 = NextI(data, e0 + 1, end);
+ int e2 = NextI(data, e1 + 1, end);
+ int e3 = NextI(data, e2 + 1, end);
+
+ outLen += DecodeLastBlock(outStream, (char)data[e0], (char)data[e1], (char)data[e2], (char)data[e3]);
+
+ return outLen;
}
+#endif
- private int NextI(
- byte[] data,
- int i,
- int finish)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int NextI(ReadOnlySpan<byte> data, int i, int finish)
+#else
+ private int NextI(byte[] data, int i, int finish)
+#endif
{
while ((i < finish) && Ignore((char)data[i]))
{
@@ -232,10 +377,11 @@ namespace Org.BouncyCastle.Utilities.Encoders
end--;
}
- int i = 0;
- int finish = end - 4;
-
- i = NextI(data, i, finish);
+ int finish = end - 4;
+ int i = NextI(data, 0, finish);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> buf = stackalloc byte[3];
+#endif
while (i < finish)
{
@@ -256,9 +402,16 @@ namespace Org.BouncyCastle.Utilities.Encoders
if ((b1 | b2 | b3 | b4) >= 0x80)
throw new IOException("invalid characters encountered in base64 data");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ buf[0] = (byte)((b1 << 2) | (b2 >> 4));
+ buf[1] = (byte)((b2 << 4) | (b3 >> 2));
+ buf[2] = (byte)((b3 << 6) | b4);
+ outStream.Write(buf);
+#else
outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
outStream.WriteByte((byte)((b3 << 6) | b4));
+#endif
length += 3;
@@ -302,8 +455,16 @@ namespace Org.BouncyCastle.Utilities.Encoders
if ((b1 | b2 | b3) >= 0x80)
throw new IOException("invalid characters encountered at end of base64 data");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> buf = stackalloc byte[2] {
+ (byte)((b1 << 2) | (b2 >> 4)),
+ (byte)((b2 << 4) | (b3 >> 2)),
+ };
+ outStream.Write(buf);
+#else
outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+#endif
return 2;
}
@@ -317,9 +478,18 @@ namespace Org.BouncyCastle.Utilities.Encoders
if ((b1 | b2 | b3 | b4) >= 0x80)
throw new IOException("invalid characters encountered at end of base64 data");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> buf = stackalloc byte[3] {
+ (byte)((b1 << 2) | (b2 >> 4)),
+ (byte)((b2 << 4) | (b3 >> 2)),
+ (byte)((b3 << 6) | b4),
+ };
+ outStream.Write(buf);
+#else
outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
outStream.WriteByte((byte)((b3 << 6) | b4));
+#endif
return 3;
}
diff --git a/crypto/src/util/encoders/HexEncoder.cs b/crypto/src/util/encoders/HexEncoder.cs
index bf68aff9d..6ccb184d9 100644
--- a/crypto/src/util/encoders/HexEncoder.cs
+++ b/crypto/src/util/encoders/HexEncoder.cs
@@ -1,3 +1,4 @@
+using Org.BouncyCastle.Crypto;
using System;
using System.IO;
@@ -41,6 +42,9 @@ namespace Org.BouncyCastle.Utilities.Encoders
public int Encode(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Encode(inBuf.AsSpan(inOff, inLen), outBuf.AsSpan(outOff));
+#else
int inPos = inOff;
int inEnd = inOff + inLen;
int outPos = outOff;
@@ -54,8 +58,28 @@ namespace Org.BouncyCastle.Utilities.Encoders
}
return outPos - outOff;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Encode(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int inPos = 0;
+ int inEnd = input.Length;
+ int outPos = 0;
+
+ while (inPos < inEnd)
+ {
+ uint b = input[inPos++];
+
+ output[outPos++] = encodingTable[b >> 4];
+ output[outPos++] = encodingTable[b & 0xF];
+ }
+
+ return outPos;
+ }
+#endif
+
/**
* encode the input data producing a Hex output stream.
*
@@ -63,6 +87,9 @@ namespace Org.BouncyCastle.Utilities.Encoders
*/
public int Encode(byte[] buf, int off, int len, Stream outStream)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Encode(buf.AsSpan(off, len), outStream);
+#else
if (len < 0)
return 0;
@@ -77,8 +104,25 @@ namespace Org.BouncyCastle.Utilities.Encoders
remaining -= inLen;
}
return len * 2;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Encode(ReadOnlySpan<byte> data, Stream outStream)
+ {
+ Span<byte> tmp = stackalloc byte[72];
+ int result = data.Length * 2;
+ while (!data.IsEmpty)
+ {
+ int inLen = System.Math.Min(36, data.Length);
+ int outLen = Encode(data[..inLen], tmp);
+ outStream.Write(tmp[..outLen]);
+ data = data[inLen..];
+ }
+ return result;
+ }
+#endif
+
private static bool Ignore(char c)
{
return c == '\n' || c =='\r' || c == '\t' || c == ' ';
@@ -90,12 +134,11 @@ namespace Org.BouncyCastle.Utilities.Encoders
*
* @return the number of bytes produced.
*/
- public int Decode(
- byte[] data,
- int off,
- int length,
- Stream outStream)
+ public int Decode(byte[] data, int off, int length, Stream outStream)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Decode(data.AsSpan(off, length), outStream);
+#else
byte b1, b2;
int outLen = 0;
byte[] buf = new byte[36];
@@ -147,7 +190,65 @@ namespace Org.BouncyCastle.Utilities.Encoders
}
return outLen;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Decode(ReadOnlySpan<byte> data, Stream outStream)
+ {
+ byte b1, b2;
+ int outLen = 0;
+ Span<byte> buf = stackalloc byte[36];
+ int bufOff = 0;
+ int end = data.Length;
+
+ while (end > 0)
+ {
+ if (!Ignore((char)data[end - 1]))
+ break;
+
+ end--;
+ }
+
+ int i = 0;
+ while (i < end)
+ {
+ while (i < end && Ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && Ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ if ((b1 | b2) >= 0x80)
+ throw new IOException("invalid characters encountered in Hex data");
+
+ buf[bufOff++] = (byte)((b1 << 4) | b2);
+
+ if (bufOff == buf.Length)
+ {
+ outStream.Write(buf);
+ bufOff = 0;
+ }
+
+ outLen++;
+ }
+
+ if (bufOff > 0)
+ {
+ outStream.Write(buf[..bufOff]);
+ }
+
+ return outLen;
}
+#endif
/**
* decode the Hex encoded string data writing it to the given output stream,
@@ -155,13 +256,15 @@ namespace Org.BouncyCastle.Utilities.Encoders
*
* @return the number of bytes produced.
*/
- public int DecodeString(
- string data,
- Stream outStream)
+ public int DecodeString(string data, Stream outStream)
{
byte b1, b2;
int length = 0;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ Span<byte> buf = stackalloc byte[36];
+#else
byte[] buf = new byte[36];
+#endif
int bufOff = 0;
int end = data.Length;
@@ -197,7 +300,11 @@ namespace Org.BouncyCastle.Utilities.Encoders
if (bufOff == buf.Length)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ outStream.Write(buf);
+#else
outStream.Write(buf, 0, bufOff);
+#endif
bufOff = 0;
}
@@ -206,7 +313,11 @@ namespace Org.BouncyCastle.Utilities.Encoders
if (bufOff > 0)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ outStream.Write(buf[..bufOff]);
+#else
outStream.Write(buf, 0, bufOff);
+#endif
}
return length;
diff --git a/crypto/src/util/encoders/IEncoder.cs b/crypto/src/util/encoders/IEncoder.cs
index 5887d5daa..33a2cde18 100644
--- a/crypto/src/util/encoders/IEncoder.cs
+++ b/crypto/src/util/encoders/IEncoder.cs
@@ -11,8 +11,16 @@ namespace Org.BouncyCastle.Utilities.Encoders
{
int Encode(byte[] data, int off, int length, Stream outStream);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int Encode(ReadOnlySpan<byte> data, Stream outStream);
+#endif
+
int Decode(byte[] data, int off, int length, Stream outStream);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int Decode(ReadOnlySpan<byte> data, Stream outStream);
+#endif
+
int DecodeString(string data, Stream outStream);
}
}
|