From 5187c2eabdadc912ed98deca4d36fb134c185d91 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Fri, 26 Aug 2022 14:45:57 +0700 Subject: Span-based variants for IBlockCipherPadding --- crypto/src/crypto/paddings/BlockCipherPadding.cs | 54 +++++++++---------- crypto/src/crypto/paddings/ISO10126d2Padding.cs | 53 ++++++++++++------- crypto/src/crypto/paddings/ISO7816d4Padding.cs | 60 +++++++++++++-------- crypto/src/crypto/paddings/Pkcs7Padding.cs | 54 +++++++++++++------ crypto/src/crypto/paddings/TbcPadding.cs | 67 ++++++++++++++++-------- crypto/src/crypto/paddings/X923Padding.cs | 62 +++++++++++++++------- crypto/src/crypto/paddings/ZeroBytePadding.cs | 40 ++++++++++---- crypto/test/src/test/BlockCipherTest.cs | 8 +-- 8 files changed, 255 insertions(+), 143 deletions(-) (limited to 'crypto') 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 - */ + /// Block cipher padders are expected to conform to this interface. public interface IBlockCipherPadding { - /** - * Initialise the padder. - * - * @param param parameters, if any required. - */ + /// Initialise the padder. + /// A source of randomness, if any required. void Init(SecureRandom random); - //throws ArgumentException; - /** - * Return the name of the algorithm the cipher implements. - * - * @return the name of the algorithm the cipher implements. - */ + /// The name of the algorithm this padder implements. string PaddingName { get; } - /** - * add the pad bytes to the passed in block, returning the - * number of bytes added. - */ + /// Add padding to the passed in block. + /// the block to add padding to. + /// the offset into the block the padding is to start at. + /// the number of bytes of padding added. 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 + /// Add padding to the passed in block. + /// the block to add padding to. + /// the offset into the block the padding is to start at. + /// the number of bytes of padding added. + int AddPadding(Span block, int position); +#endif + + /// Determine the length of padding present in the passed in block. + /// the block to check padding for. + /// the number of bytes of padding present. int PadCount(byte[] input); - //throws InvalidCipherTextException; - } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// Determine the length of padding present in the passed in block. + /// the block to check padding for. + /// the number of bytes of padding present. + int PadCount(ReadOnlySpan 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 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 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 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 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 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 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. } - /// add the pad bytes to the passed in block, returning the - /// number of bytes added. - ///

- /// 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. - ///

- ///
+ /// add the pad bytes to the passed in block, returning the number of bytes added. + /// + /// This assumes that the last block of plain text is always passed to it inside . + /// i.e. if is zero, indicating the padding will fill the entire block,the value of + /// should be the same as the last block of plain text. + /// 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; } - /// return the number of pad bytes present in the block. +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// add the pad bytes to the passed in block, returning the number of bytes added. + /// + /// This assumes that the last block of plain text is always passed to it inside . + /// i.e. if is zero, indicating the padding will fill the entire block,the value of + /// should be the same as the last block of plain text. + /// + public virtual int AddPadding(Span 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 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 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 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. } - /// 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); + int added = input.Length - inOff; while (inOff < input.Length) { - input[inOff] = (byte) 0; - inOff++; + input[inOff++] = 0x00; } return added; } - /// return the number of pad bytes present in the block. +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int AddPadding(Span 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 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", -- cgit 1.4.1