summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-10-07 21:23:45 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-10-07 21:23:45 +0700
commit18fe04a57aa29219d63fda4d8eb6a8586a1f8091 (patch)
tree524e80ee577220eefb92207764daa6ffe10c8d81 /crypto/src
parentSpan usage in Math.Raw (diff)
downloadBouncyCastle.NET-ed25519-18fe04a57aa29219d63fda4d8eb6a8586a1f8091.tar.xz
Span usage in encoders
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/util/encoders/Base64Encoder.cs194
-rw-r--r--crypto/src/util/encoders/HexEncoder.cs127
-rw-r--r--crypto/src/util/encoders/IEncoder.cs8
3 files changed, 309 insertions, 20 deletions
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);
 	}
 }