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

OaepEncoding

using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Encodings { public class OaepEncoding : IAsymmetricBlockCipher { private readonly IAsymmetricBlockCipher engine; private readonly IDigest mgf1Hash; private readonly int mgf1NoMemoLimit; private readonly byte[] defHash; private SecureRandom random; private bool forEncryption; public string AlgorithmName => engine.AlgorithmName + "/OAEPPadding"; public IAsymmetricBlockCipher UnderlyingCipher => engine; private static int GetMgf1NoMemoLimit(IDigest d) { if (d is IMemoable) return d.GetByteLength() - 1; return 2147483647; } public OaepEncoding(IAsymmetricBlockCipher cipher) : this(cipher, new Sha1Digest(), null) { } public OaepEncoding(IAsymmetricBlockCipher cipher, IDigest hash) : this(cipher, hash, null) { } public OaepEncoding(IAsymmetricBlockCipher cipher, IDigest hash, byte[] encodingParams) : this(cipher, hash, hash, encodingParams) { } public OaepEncoding(IAsymmetricBlockCipher cipher, IDigest hash, IDigest mgf1Hash, byte[] encodingParams) { engine = cipher; this.mgf1Hash = mgf1Hash; mgf1NoMemoLimit = GetMgf1NoMemoLimit(mgf1Hash); defHash = new byte[hash.GetDigestSize()]; hash.Reset(); if (encodingParams != null) hash.BlockUpdate(encodingParams, 0, encodingParams.Length); hash.DoFinal(defHash, 0); } public void Init(bool forEncryption, ICipherParameters parameters) { SecureRandom secureRandom = null; ParametersWithRandom parametersWithRandom = parameters as ParametersWithRandom; if (parametersWithRandom != null) secureRandom = parametersWithRandom.Random; random = (forEncryption ? CryptoServicesRegistrar.GetSecureRandom(secureRandom) : null); this.forEncryption = forEncryption; engine.Init(forEncryption, parameters); } public int GetInputBlockSize() { int inputBlockSize = engine.GetInputBlockSize(); if (forEncryption) return inputBlockSize - 1 - 2 * defHash.Length; return inputBlockSize; } public int GetOutputBlockSize() { int outputBlockSize = engine.GetOutputBlockSize(); if (forEncryption) return outputBlockSize; return outputBlockSize - 1 - 2 * defHash.Length; } public byte[] ProcessBlock(byte[] inBytes, int inOff, int inLen) { if (!forEncryption) return DecodeBlock(inBytes, inOff, inLen); return EncodeBlock(inBytes, inOff, inLen); } private byte[] EncodeBlock(byte[] inBytes, int inOff, int inLen) { int inputBlockSize = GetInputBlockSize(); Check.DataLength(inLen > inputBlockSize, "input data too long"); byte[] array = new byte[inputBlockSize + 1 + 2 * defHash.Length]; Array.Copy(inBytes, inOff, array, array.Length - inLen, inLen); array[array.Length - inLen - 1] = 1; Array.Copy(defHash, 0, array, defHash.Length, defHash.Length); random.NextBytes(array, 0, defHash.Length); mgf1Hash.Reset(); MaskGeneratorFunction(array, 0, defHash.Length, array, defHash.Length, array.Length - defHash.Length); MaskGeneratorFunction(array, defHash.Length, array.Length - defHash.Length, array, 0, defHash.Length); return engine.ProcessBlock(array, 0, array.Length); } private byte[] DecodeBlock(byte[] inBytes, int inOff, int inLen) { int num = GetOutputBlockSize() >> 31; byte[] array = new byte[engine.GetOutputBlockSize()]; byte[] array2 = engine.ProcessBlock(inBytes, inOff, inLen); num |= array.Length - array2.Length >> 31; int num2 = System.Math.Min(array.Length, array2.Length); Array.Copy(array2, 0, array, array.Length - num2, num2); Array.Clear(array2, 0, array2.Length); mgf1Hash.Reset(); MaskGeneratorFunction(array, defHash.Length, array.Length - defHash.Length, array, 0, defHash.Length); MaskGeneratorFunction(array, 0, defHash.Length, array, defHash.Length, array.Length - defHash.Length); for (int i = 0; i != defHash.Length; i++) { num |= (defHash[i] ^ array[defHash.Length + i]); } int num3 = -1; for (int j = 2 * defHash.Length; j != array.Length; j++) { int num4 = (-array[j] & num3) >> 31; num3 += (j & num4); } num |= num3 >> 31; num3++; if ((num | (array[num3] ^ 1)) != 0) { Array.Clear(array, 0, array.Length); throw new InvalidCipherTextException("data wrong"); } num3++; byte[] array3 = new byte[array.Length - num3]; Array.Copy(array, num3, array3, 0, array3.Length); Array.Clear(array, 0, array.Length); return array3; } private void MaskGeneratorFunction(byte[] z, int zOff, int zLen, byte[] mask, int maskOff, int maskLen) { IXof xof = mgf1Hash as IXof; if (xof != null) { byte[] array = new byte[maskLen]; xof.BlockUpdate(z, zOff, zLen); xof.OutputFinal(array, 0, maskLen); Bytes.XorTo(maskLen, array, 0, mask, maskOff); } else MaskGeneratorFunction1(z, zOff, zLen, mask, maskOff, maskLen); } private void MaskGeneratorFunction1(byte[] z, int zOff, int zLen, byte[] mask, int maskOff, int maskLen) { int digestSize = mgf1Hash.GetDigestSize(); byte[] array = new byte[digestSize]; byte[] array2 = new byte[4]; int num = 0; int num2 = maskOff + maskLen; int num3 = num2 - digestSize; int i = maskOff; mgf1Hash.BlockUpdate(z, zOff, zLen); if (zLen <= mgf1NoMemoLimit) { for (; i < num3; i += digestSize) { Pack.UInt32_To_BE((uint)num++, array2); mgf1Hash.BlockUpdate(array2, 0, array2.Length); mgf1Hash.DoFinal(array, 0); mgf1Hash.BlockUpdate(z, zOff, zLen); Bytes.XorTo(digestSize, array, 0, mask, i); } } else { IMemoable memoable = (IMemoable)mgf1Hash; IMemoable other = memoable.Copy(); for (; i < num3; i += digestSize) { Pack.UInt32_To_BE((uint)num++, array2); mgf1Hash.BlockUpdate(array2, 0, array2.Length); mgf1Hash.DoFinal(array, 0); memoable.Reset(other); Bytes.XorTo(digestSize, array, 0, mask, i); } } Pack.UInt32_To_BE((uint)num, array2); mgf1Hash.BlockUpdate(array2, 0, array2.Length); mgf1Hash.DoFinal(array, 0); Bytes.XorTo(num2 - i, array, 0, mask, i); } } }