<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />

Pkcs1Encoding

using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; using System.Threading; namespace Org.BouncyCastle.Crypto.Encodings { public class Pkcs1Encoding : IAsymmetricBlockCipher { public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict"; private const int HeaderLength = 10; private static long m_strictLengthEnabled; private SecureRandom random; private IAsymmetricBlockCipher engine; private bool forEncryption; private bool forPrivateKey; private bool useStrictLength; private int pLen = -1; private byte[] fallback; private byte[] blockBuffer; public static bool StrictLengthEnabled { get { return Convert.ToBoolean(Interlocked.Read(ref m_strictLengthEnabled)); } set { Interlocked.Exchange(ref m_strictLengthEnabled, Convert.ToInt64(value)); } } public string AlgorithmName => engine.AlgorithmName + "/PKCS1Padding"; public IAsymmetricBlockCipher UnderlyingCipher => engine; static Pkcs1Encoding() { string environmentVariable = Platform.GetEnvironmentVariable("Org.BouncyCastle.Pkcs1.Strict"); m_strictLengthEnabled = Convert.ToInt64(environmentVariable == null || Platform.EqualsIgnoreCase("true", environmentVariable)); } public Pkcs1Encoding(IAsymmetricBlockCipher cipher) { engine = cipher; useStrictLength = StrictLengthEnabled; } public Pkcs1Encoding(IAsymmetricBlockCipher cipher, int pLen) { engine = cipher; useStrictLength = StrictLengthEnabled; this.pLen = pLen; } public Pkcs1Encoding(IAsymmetricBlockCipher cipher, byte[] fallback) { engine = cipher; useStrictLength = StrictLengthEnabled; this.fallback = fallback; pLen = fallback.Length; } public void Init(bool forEncryption, ICipherParameters parameters) { ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom; AsymmetricKeyParameter asymmetricKeyParameter; if (parametersWithRandom != null) { asymmetricKeyParameter = (AsymmetricKeyParameter)parametersWithRandom.Parameters; random = parametersWithRandom.Random; } else { asymmetricKeyParameter = (AsymmetricKeyParameter)parameters; random = ((forEncryption && !asymmetricKeyParameter.IsPrivate) ? CryptoServicesRegistrar.GetSecureRandom() : null); } engine.Init(forEncryption, parameters); forPrivateKey = asymmetricKeyParameter.IsPrivate; this.forEncryption = forEncryption; blockBuffer = new byte[engine.GetOutputBlockSize()]; } public int GetInputBlockSize() { int inputBlockSize = engine.GetInputBlockSize(); if (!forEncryption) return inputBlockSize; return inputBlockSize - 10; } public int GetOutputBlockSize() { int outputBlockSize = engine.GetOutputBlockSize(); if (!forEncryption) return outputBlockSize - 10; return outputBlockSize; } public byte[] ProcessBlock(byte[] input, int inOff, int length) { if (!forEncryption) return DecodeBlock(input, inOff, length); return EncodeBlock(input, inOff, length); } private byte[] EncodeBlock(byte[] input, int inOff, int inLen) { if (inLen > GetInputBlockSize()) throw new ArgumentException("input data too large", "inLen"); byte[] array = new byte[engine.GetInputBlockSize()]; int num = array.Length - 1 - inLen; if (forPrivateKey) { array[0] = 1; for (int i = 1; i < num; i++) { array[i] = byte.MaxValue; } } else { random.NextBytes(array); array[0] = 2; for (int j = 1; j < num; j++) { while (array[j] == 0) { array[j] = (byte)random.NextInt(); } } } array[num] = 0; Array.Copy(input, inOff, array, array.Length - inLen, inLen); return engine.ProcessBlock(array, 0, array.Length); } private static int CheckPkcs1Encoding1(byte[] buf) { int num = 0; int num2 = 0; int num3 = -(buf[0] ^ 1); for (int i = 1; i < buf.Length; i++) { byte num4 = buf[i]; int num5 = (num4 ^ 0) - 1 >> 31; int num6 = (num4 ^ 255) - 1 >> 31; num2 ^= (i & ~num & num5); num |= num5; num3 |= ~(num | num6); } num3 |= num2 - 9; return (buf.Length - 1 - num2) | (num3 >> 31); } private static int CheckPkcs1Encoding2(byte[] buf) { int num = 0; int num2 = 0; int num3 = -(buf[0] ^ 2); for (int i = 1; i < buf.Length; i++) { int num4 = (buf[i] ^ 0) - 1 >> 31; num2 ^= (i & ~num & num4); num |= num4; } num3 |= num2 - 9; return (buf.Length - 1 - num2) | (num3 >> 31); } private static int CheckPkcs1Encoding2(byte[] buf, int plaintextLength) { int num = -(buf[0] ^ 2); int num2 = buf.Length - 1 - plaintextLength; num |= num2 - 9; for (int i = 1; i < num2; i++) { num |= buf[i] - 1; } num |= -buf[num2]; return num >> 31; } private byte[] DecodeBlockOrRandom(byte[] input, int inOff, int inLen) { if (!forPrivateKey) throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing"); int num = pLen; byte[] nextBytes = fallback; if (fallback == null) nextBytes = SecureRandom.GetNextBytes(random, num); int num2 = 0; int outputBlockSize = engine.GetOutputBlockSize(); byte[] array = engine.ProcessBlock(input, inOff, inLen); byte[] array2 = array; if (array.Length != outputBlockSize && (useStrictLength || array.Length < outputBlockSize)) array2 = blockBuffer; num2 |= CheckPkcs1Encoding2(array2, num); int num3 = array2.Length - num; byte[] array3 = new byte[num]; for (int i = 0; i < num; i++) { array3[i] = (byte)((array2[num3 + i] & ~num2) | (nextBytes[i] & num2)); } Arrays.Fill(array, 0); Arrays.Fill(blockBuffer, 0, System.Math.Max(0, blockBuffer.Length - array.Length), 0); return array3; } private byte[] DecodeBlock(byte[] input, int inOff, int inLen) { if (!forPrivateKey || pLen == -1) { int outputBlockSize = engine.GetOutputBlockSize(); byte[] array = engine.ProcessBlock(input, inOff, inLen); bool flag = useStrictLength & (array.Length != outputBlockSize); byte[] array2 = array; if (array.Length < outputBlockSize) array2 = blockBuffer; int num = forPrivateKey ? CheckPkcs1Encoding2(array2) : CheckPkcs1Encoding1(array2); try { if (num < 0) throw new InvalidCipherTextException("block incorrect"); if (flag) throw new InvalidCipherTextException("block incorrect size"); byte[] array3 = new byte[num]; Array.Copy(array2, array2.Length - num, array3, 0, num); return array3; } finally { Arrays.Fill(array, 0); Arrays.Fill(blockBuffer, 0, System.Math.Max(0, blockBuffer.Length - array.Length), 0); } } return DecodeBlockOrRandom(input, inOff, inLen); } } }