summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-08-26 14:45:57 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-08-26 14:45:57 +0700
commit5187c2eabdadc912ed98deca4d36fb134c185d91 (patch)
tree3407f87cd08eb3f90a0785ce3891109d347611f9
parentRefactoring around rotates (diff)
downloadBouncyCastle.NET-ed25519-5187c2eabdadc912ed98deca4d36fb134c185d91.tar.xz
Span-based variants for IBlockCipherPadding
-rw-r--r--crypto/src/crypto/paddings/BlockCipherPadding.cs54
-rw-r--r--crypto/src/crypto/paddings/ISO10126d2Padding.cs53
-rw-r--r--crypto/src/crypto/paddings/ISO7816d4Padding.cs60
-rw-r--r--crypto/src/crypto/paddings/Pkcs7Padding.cs54
-rw-r--r--crypto/src/crypto/paddings/TbcPadding.cs67
-rw-r--r--crypto/src/crypto/paddings/X923Padding.cs62
-rw-r--r--crypto/src/crypto/paddings/ZeroBytePadding.cs40
-rw-r--r--crypto/test/src/test/BlockCipherTest.cs8
8 files changed, 255 insertions, 143 deletions
diff --git a/crypto/src/crypto/paddings/BlockCipherPadding.cs b/crypto/src/crypto/paddings/BlockCipherPadding.cs
index 33a5f9f0f..235b61886 100644
--- a/crypto/src/crypto/paddings/BlockCipherPadding.cs
+++ b/crypto/src/crypto/paddings/BlockCipherPadding.cs
@@ -1,43 +1,43 @@
 using System;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Security;
 
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Paddings
 {
-    /**
-     * Block cipher padders are expected to conform to this interface
-     */
+    /// <summary>Block cipher padders are expected to conform to this interface.</summary>
     public interface IBlockCipherPadding
     {
-        /**
-         * Initialise the padder.
-         *
-         * @param param parameters, if any required.
-         */
+        /// <summary>Initialise the padder.</summary>
+        /// <param name="random">A source of randomness, if any required.</param>
         void Init(SecureRandom random);
-            //throws ArgumentException;
 
-        /**
-         * Return the name of the algorithm the cipher implements.
-         *
-         * @return the name of the algorithm the cipher implements.
-         */
+        /// <summary>The name of the algorithm this padder implements.</summary>
         string PaddingName { get; }
 
-		/**
-         * add the pad bytes to the passed in block, returning the
-         * number of bytes added.
-         */
+        /// <summary>Add padding to the passed in block.</summary>
+        /// <param name="input">the block to add padding to.</param>
+        /// <param name="inOff">the offset into the block the padding is to start at.</param>
+        /// <returns>the number of bytes of padding added.</returns>
         int AddPadding(byte[] input, int inOff);
 
-        /**
-         * return the number of pad bytes present in the block.
-         * @exception InvalidCipherTextException if the padding is badly formed
-         * or invalid.
-         */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>Add padding to the passed in block.</summary>
+        /// <param name="block">the block to add padding to.</param>
+        /// <param name="position">the offset into the block the padding is to start at.</param>
+        /// <returns>the number of bytes of padding added.</returns>
+        int AddPadding(Span<byte> block, int position);
+#endif
+
+        /// <summary>Determine the length of padding present in the passed in block.</summary>
+        /// <param name="input">the block to check padding for.</param>
+        /// <returns>the number of bytes of padding present.</returns>
         int PadCount(byte[] input);
-        //throws InvalidCipherTextException;
-    }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>Determine the length of padding present in the passed in block.</summary>
+        /// <param name="block">the block to check padding for.</param>
+        /// <returns>the number of bytes of padding present.</returns>
+        int PadCount(ReadOnlySpan<byte> block);
+#endif
+    }
 }
diff --git a/crypto/src/crypto/paddings/ISO10126d2Padding.cs b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
index 92845f165..317b5db8c 100644
--- a/crypto/src/crypto/paddings/ISO10126d2Padding.cs
+++ b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
@@ -1,7 +1,6 @@
 using System;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Security;
 
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Paddings
 {
@@ -35,42 +34,56 @@ namespace Org.BouncyCastle.Crypto.Paddings
             get { return "ISO10126-2"; }
         }
 
-		/**
-        * add the pad bytes to the passed in block, returning the
-        * number of bytes added.
-        */
-        public int AddPadding(
-            byte[]	input,
-            int		inOff)
+        public int AddPadding(byte[] input, int inOff)
         {
-            byte code = (byte)(input.Length - inOff);
-
-            while (inOff < (input.Length - 1))
+            int count = input.Length - inOff;
+            if (count > 1)
             {
-                input[inOff] = (byte)random.NextInt();
-                inOff++;
+                random.NextBytes(input, inOff, count - 1);
             }
+            input[input.Length - 1] = (byte)count;
 
-            input[inOff] = code;
+            return count;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int AddPadding(Span<byte> block, int position)
+        {
+            int count = block.Length - position;
+            if (count > 1)
+            {
+                random.NextBytes(block[position..(block.Length - 1)]);
+            }
+            block[block.Length - 1] = (byte)count;
 
-            return code;
+            return count;
         }
+#endif
 
-        /**
-        * return the number of pad bytes present in the block.
-        */
         public int PadCount(byte[] input)
         {
             int count = input[input.Length -1];
             int position = input.Length - count;
 
-            // constant time version
             int failed = (position | (count - 1)) >> 31;
+            if (failed != 0)
+                throw new InvalidCipherTextException("pad block corrupted");
 
+            return count;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int PadCount(ReadOnlySpan<byte> block)
+        {
+            int count = block[block.Length - 1];
+            int position = block.Length - count;
+
+            int failed = (position | (count - 1)) >> 31;
             if (failed != 0)
                 throw new InvalidCipherTextException("pad block corrupted");
 
             return count;
         }
+#endif
     }
 }
diff --git a/crypto/src/crypto/paddings/ISO7816d4Padding.cs b/crypto/src/crypto/paddings/ISO7816d4Padding.cs
index 533b9d421..7b1834626 100644
--- a/crypto/src/crypto/paddings/ISO7816d4Padding.cs
+++ b/crypto/src/crypto/paddings/ISO7816d4Padding.cs
@@ -33,32 +33,30 @@ namespace Org.BouncyCastle.Crypto.Paddings
 			get { return "ISO7816-4"; }
 		}
 
-		/**
-		 * add the pad bytes to the passed in block, returning the
-		 * number of bytes added.
-		 */
-		public int AddPadding(
-			byte[]	input,
-			int		inOff)
+		public int AddPadding(byte[] input, int inOff)
 		{
-			int added = (input.Length - inOff);
-
-			input[inOff]= (byte) 0x80;
-			inOff ++;
+			int count = input.Length - inOff;
 
-			while (inOff < input.Length)
+			input[inOff]= 0x80;
+			while (++inOff < input.Length)
 			{
-				input[inOff] = (byte) 0;
-				inOff++;
+				input[inOff] = 0x00;
 			}
 
-			return added;
+			return count;
 		}
 
-		/**
-		 * return the number of pad bytes present in the block.
-		 */
-		public int PadCount(byte[] input)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int AddPadding(Span<byte> block, int position)
+        {
+            int count = block.Length - position;
+			block[position++] = 0x80;
+            block[position..].Fill(0x00);
+            return count;
+        }
+#endif
+
+        public int PadCount(byte[] input)
 		{
 			int position = -1, still00Mask = -1;
 			int i = input.Length;
@@ -67,7 +65,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 				int next = input[i];
 				int match00Mask = ((next ^ 0x00) - 1) >> 31;
 				int match80Mask = ((next ^ 0x80) - 1) >> 31;
-				position ^= (i ^ position) & (still00Mask & match80Mask);
+				position ^= (i ^ position) & still00Mask & match80Mask;
 				still00Mask &= match00Mask;
 			}
 			if (position < 0)
@@ -75,5 +73,25 @@ namespace Org.BouncyCastle.Crypto.Paddings
 
 			return input.Length - position;
 		}
-	}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int PadCount(ReadOnlySpan<byte> block)
+		{
+            int position = -1, still00Mask = -1;
+            int i = block.Length;
+            while (--i >= 0)
+            {
+                int next = block[i];
+                int match00Mask = ((next ^ 0x00) - 1) >> 31;
+                int match80Mask = ((next ^ 0x80) - 1) >> 31;
+                position ^= (i ^ position) & still00Mask & match80Mask;
+                still00Mask &= match00Mask;
+            }
+            if (position < 0)
+                throw new InvalidCipherTextException("pad block corrupted");
+
+            return block.Length - position;
+        }
+#endif
+    }
 }
diff --git a/crypto/src/crypto/paddings/Pkcs7Padding.cs b/crypto/src/crypto/paddings/Pkcs7Padding.cs
index 4c192fcdf..46d97c9eb 100644
--- a/crypto/src/crypto/paddings/Pkcs7Padding.cs
+++ b/crypto/src/crypto/paddings/Pkcs7Padding.cs
@@ -32,43 +32,63 @@ namespace Org.BouncyCastle.Crypto.Paddings
             get { return "PKCS7"; }
         }
 
-        /**
-        * add the pad bytes to the passed in block, returning the
-        * number of bytes added.
-        */
-        public int AddPadding(
-            byte[]  input,
-            int     inOff)
+        public int AddPadding(byte[] input, int inOff)
         {
-            byte code = (byte)(input.Length - inOff);
+            int count = input.Length - inOff;
+            byte padValue = (byte)count;
 
             while (inOff < input.Length)
             {
-                input[inOff] = code;
-                inOff++;
+                input[inOff++] = padValue;
             }
 
-            return code;
+            return count;
         }
 
-        /**
-        * return the number of pad bytes present in the block.
-        */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int AddPadding(Span<byte> block, int position)
+        {
+            int count = block.Length - position;
+            byte padValue = (byte)count;
+            block[position..].Fill(padValue);
+            return count;
+        }
+#endif
+
         public int PadCount(byte[] input)
         {
-            byte countAsByte = input[input.Length - 1];
-            int count = countAsByte;
+            byte padValue = input[input.Length - 1];
+            int count = padValue;
             int position = input.Length - count;
 
             int failed = (position | (count - 1)) >> 31;
             for (int i = 0; i < input.Length; ++i)
             {
-                failed |= (input[i] ^ countAsByte) & ~((i - position) >> 31);
+                failed |= (input[i] ^ padValue) & ~((i - position) >> 31);
+            }
+            if (failed != 0)
+                throw new InvalidCipherTextException("pad block corrupted");
+
+            return count;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int PadCount(ReadOnlySpan<byte> block)
+        {
+            byte padValue = block[block.Length - 1];
+            int count = padValue;
+            int position = block.Length - count;
+
+            int failed = (position | (count - 1)) >> 31;
+            for (int i = 0; i < block.Length; ++i)
+            {
+                failed |= (block[i] ^ padValue) & ~((i - position) >> 31);
             }
             if (failed != 0)
                 throw new InvalidCipherTextException("pad block corrupted");
 
             return count;
         }
+#endif
     }
 }
diff --git a/crypto/src/crypto/paddings/TbcPadding.cs b/crypto/src/crypto/paddings/TbcPadding.cs
index 8034dc8ba..b54c5f4d0 100644
--- a/crypto/src/crypto/paddings/TbcPadding.cs
+++ b/crypto/src/crypto/paddings/TbcPadding.cs
@@ -1,5 +1,5 @@
 using System;
-using Org.BouncyCastle.Crypto;
+
 using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Paddings
@@ -30,39 +30,44 @@ namespace Org.BouncyCastle.Crypto.Paddings
             // nothing to do.
         }
 
-        /// <summary> add the pad bytes to the passed in block, returning the
-        /// number of bytes added.
-        /// <p>
-        /// Note: this assumes that the last block of plain text is always
-        /// passed to it inside in. i.e. if inOff is zero, indicating the
-        /// entire block is to be overwritten with padding the value of in
-        /// should be the same as the last block of plain text.
-        /// </p>
-        /// </summary>
+        /// <summary> add the pad bytes to the passed in block, returning the number of bytes added.</summary>
+        /// <remarks>
+        /// This assumes that the last block of plain text is always passed to it inside <paramref name="input"/>.
+        /// i.e. if <paramref name="inOff"/> is zero, indicating the padding will fill the entire block,the value of
+        /// <paramref name="input"/> should be the same as the last block of plain text.
+        /// </remarks>
         public virtual int AddPadding(byte[] input, int inOff)
         {
             int count = input.Length - inOff;
-            byte code;
-
-            if (inOff > 0)
-            {
-                code = (byte)((input[inOff - 1] & 0x01) == 0?0xff:0x00);
-            }
-            else
-            {
-                code = (byte)((input[input.Length - 1] & 0x01) == 0?0xff:0x00);
-            }
+            byte lastByte = inOff > 0 ? input[inOff - 1] : input[input.Length - 1];
+            byte padValue = (byte)((lastByte & 1) - 1);
 
             while (inOff < input.Length)
             {
-                input[inOff] = code;
-                inOff++;
+                input[inOff++] = padValue;
             }
 
             return count;
         }
 
-        /// <summary> return the number of pad bytes present in the block.</summary>
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary> add the pad bytes to the passed in block, returning the number of bytes added.</summary>
+        /// <remarks>
+        /// This assumes that the last block of plain text is always passed to it inside <paramref name="block"/>.
+        /// i.e. if <paramref name="position"/> is zero, indicating the padding will fill the entire block,the value of
+        /// <paramref name="block"/> should be the same as the last block of plain text.
+        /// </remarks>
+        public virtual int AddPadding(Span<byte> block, int position)
+        {
+            byte lastByte = position > 0 ? block[position - 1] : block[block.Length - 1];
+            byte padValue = (byte)((lastByte & 1) - 1);
+
+            var padding = block[position..];
+            padding.Fill(padValue);
+            return padding.Length;
+        }
+#endif
+
         public virtual int PadCount(byte[] input)
         {
             int i = input.Length;
@@ -76,5 +81,21 @@ namespace Org.BouncyCastle.Crypto.Paddings
             }
             return count;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public virtual int PadCount(ReadOnlySpan<byte> block)
+        {
+            int i = block.Length;
+            int code = block[--i], count = 1, countingMask = -1;
+            while (--i >= 0)
+            {
+                int next = block[i];
+                int matchMask = ((next ^ code) - 1) >> 31;
+                countingMask &= matchMask;
+                count -= countingMask;
+            }
+            return count;
+        }
+#endif
     }
 }
diff --git a/crypto/src/crypto/paddings/X923Padding.cs b/crypto/src/crypto/paddings/X923Padding.cs
index fc9668116..12338aa04 100644
--- a/crypto/src/crypto/paddings/X923Padding.cs
+++ b/crypto/src/crypto/paddings/X923Padding.cs
@@ -1,7 +1,7 @@
 using System;
 
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Paddings
 {
@@ -35,37 +35,45 @@ namespace Org.BouncyCastle.Crypto.Paddings
             get { return "X9.23"; }
         }
 
-		/**
-        * add the pad bytes to the passed in block, returning the
-        * number of bytes added.
-        */
-        public int AddPadding(
-            byte[]  input,
-            int     inOff)
+        public int AddPadding(byte[] input, int inOff)
         {
-            byte code = (byte)(input.Length - inOff);
-
-            while (inOff < input.Length - 1)
+            int count = input.Length - inOff;
+            if (count > 1)
             {
                 if (random == null)
                 {
-                    input[inOff] = 0;
+                    Arrays.Fill(input, inOff, input.Length - 1, 0x00);
                 }
                 else
                 {
-                    input[inOff] = (byte)random.NextInt();
+                    random.NextBytes(input, inOff, count - 1);
                 }
-                inOff++;
             }
+            input[input.Length - 1] = (byte)count;
+            return count;
+        }
 
-            input[inOff] = code;
-
-            return code;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int AddPadding(Span<byte> block, int position)
+        {
+            int count = block.Length - position;
+            if (count > 1)
+            {
+                var body = block[position..(block.Length - 1)];
+                if (random == null)
+                {
+                    body.Fill(0x00);
+                }
+                else
+                {
+                    random.NextBytes(body);
+                }
+            }
+            block[block.Length - 1] = (byte)count;
+            return count;
         }
+#endif
 
-        /**
-        * return the number of pad bytes present in the block.
-        */
         public int PadCount(byte[] input)
         {
             int count = input[input.Length - 1];
@@ -77,5 +85,19 @@ namespace Org.BouncyCastle.Crypto.Paddings
 
             return count;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int PadCount(ReadOnlySpan<byte> block)
+        {
+            int count = block[block.Length - 1];
+            int position = block.Length - count;
+
+            int failed = (position | (count - 1)) >> 31;
+            if (failed != 0)
+                throw new InvalidCipherTextException("pad block corrupted");
+
+            return count;
+        }
+#endif
     }
 }
diff --git a/crypto/src/crypto/paddings/ZeroBytePadding.cs b/crypto/src/crypto/paddings/ZeroBytePadding.cs
index ab5f4a1a3..910fe7154 100644
--- a/crypto/src/crypto/paddings/ZeroBytePadding.cs
+++ b/crypto/src/crypto/paddings/ZeroBytePadding.cs
@@ -1,5 +1,5 @@
 using System;
-using Org.BouncyCastle.Crypto;
+
 using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Paddings
@@ -28,25 +28,27 @@ namespace Org.BouncyCastle.Crypto.Paddings
             // nothing to do.
         }
 
-        /// <summary> add the pad bytes to the passed in block, returning the
-        /// number of bytes added.
-        /// </summary>
-        public int AddPadding(
-			byte[]	input,
-			int		inOff)
+        public int AddPadding(byte[] input, int inOff)
         {
-            int added = (input.Length - inOff);
+            int added = input.Length - inOff;
 
             while (inOff < input.Length)
             {
-                input[inOff] = (byte) 0;
-                inOff++;
+                input[inOff++] = 0x00;
             }
 
             return added;
         }
 
-        /// <summary> return the number of pad bytes present in the block.</summary>
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int AddPadding(Span<byte> block, int position)
+        {
+            int count = block.Length - position;
+            block[position..].Fill(0x00);
+            return count;
+        }
+#endif
+
         public int PadCount(byte[] input)
         {
             int count = 0, still00Mask = -1;
@@ -60,5 +62,21 @@ namespace Org.BouncyCastle.Crypto.Paddings
             }
             return count;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int PadCount(ReadOnlySpan<byte> block)
+        {
+            int count = 0, still00Mask = -1;
+            int i = block.Length;
+            while (--i >= 0)
+            {
+                int next = block[i];
+                int match00Mask = ((next ^ 0x00) - 1) >> 31;
+                still00Mask &= match00Mask;
+                count -= still00Mask;
+            }
+            return count;
+        }
+#endif
     }
 }
diff --git a/crypto/test/src/test/BlockCipherTest.cs b/crypto/test/src/test/BlockCipherTest.cs
index d0e5e20b3..e57a8ad09 100644
--- a/crypto/test/src/test/BlockCipherTest.cs
+++ b/crypto/test/src/test/BlockCipherTest.cs
@@ -79,11 +79,11 @@ namespace Org.BouncyCastle.Tests
             "DES/CBC/PKCS5Padding",
             "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122afdc70484fb9c0232",
             "DES/CBC/ISO10126Padding",
-            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a980639850a2cc3e8",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122aee404f971826fd3b",
             "DES/CBC/ISO7816-4Padding",
             "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a1f80b9b0f1be49ac",
             "DES/CBC/X9.23Padding",
-            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a980639850a2cc3e8",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122aee404f971826fd3b",
             "DESede/CBC/PKCS7Padding",
             "4d3d7931875cf25593dc402298add8b914761e4936c9585ae22b2c1441169231a41e40695f1cff84",
             "SKIPJACK/CBC/PKCS7Padding",
@@ -103,9 +103,9 @@ namespace Org.BouncyCastle.Tests
             "IDEA/CBC/PKCS7Padding",
             "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9e584751325ef7c32",
             "IDEA/CBC/ISO10126Padding",
-            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d978b3fd73135f033b",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d937be6ee9fe5e35f6",
             "IDEA/CBC/X9.23Padding",
-            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d978b3fd73135f033b",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d937be6ee9fe5e35f6",
             "AES/CBC/PKCS7Padding",
             "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08389a44c4a8cc1a47cbaee1128da55bbb7",
             "AES/CBC/ISO7816-4Padding",