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

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; return GetReducedBlockSize(inputBlockSize); } public int GetOutputBlockSize() { int outputBlockSize = engine.GetOutputBlockSize(); if (!forEncryption) return GetReducedBlockSize(outputBlockSize); return outputBlockSize; } private int GetReducedBlockSize(int blockSize) { return blockSize - 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 = engine.GetInputBlockSize(); Check.DataLength(inLen > GetReducedBlockSize(inputBlockSize), "input data too long"); byte[] array = new byte[inputBlockSize]; 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 outputBlockSize = engine.GetOutputBlockSize(); int num = GetReducedBlockSize(outputBlockSize) >> 31; byte[] array = new byte[outputBlockSize]; 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 unsafe void MaskGeneratorFunction(byte[] z, int zOff, int zLen, byte[] mask, int maskOff, int maskLen) { IXof xof = mgf1Hash as IXof; if (xof != null) { Span<byte> span = (maskLen > 512) ? ((Span<byte>)new byte[maskLen]) : new Span<byte>(stackalloc byte[(int)(uint)maskLen], maskLen); Span<byte> span2 = span; xof.BlockUpdate(z, zOff, zLen); xof.OutputFinal(span2); Bytes.XorTo(maskLen, span2, mask.AsSpan(maskOff)); } else MaskGeneratorFunction1(z, zOff, zLen, mask, maskOff, maskLen); } private unsafe void MaskGeneratorFunction1(byte[] z, int zOff, int zLen, byte[] mask, int maskOff, int maskLen) { int digestSize = mgf1Hash.GetDigestSize(); Span<byte> span; if (digestSize <= 128) { int num = digestSize; span = new Span<byte>(stackalloc byte[(int)(uint)num], num); } else span = new byte[digestSize]; Span<byte> span2 = span; Span<byte> span3 = new Span<byte>(stackalloc byte[4], 4); int num2 = 0; int num3 = maskOff + maskLen; int num4 = num3 - digestSize; int i = maskOff; mgf1Hash.BlockUpdate(z, zOff, zLen); if (zLen <= mgf1NoMemoLimit) { for (; i < num4; i += digestSize) { Pack.UInt32_To_BE((uint)num2++, span3); mgf1Hash.BlockUpdate(span3); mgf1Hash.DoFinal(span2); mgf1Hash.BlockUpdate(z, zOff, zLen); Bytes.XorTo(digestSize, span2, mask.AsSpan(i)); } } else { IMemoable memoable = (IMemoable)mgf1Hash; IMemoable other = memoable.Copy(); for (; i < num4; i += digestSize) { Pack.UInt32_To_BE((uint)num2++, span3); mgf1Hash.BlockUpdate(span3); mgf1Hash.DoFinal(span2); memoable.Reset(other); Bytes.XorTo(digestSize, span2, mask.AsSpan(i)); } } Pack.UInt32_To_BE((uint)num2, span3); mgf1Hash.BlockUpdate(span3); mgf1Hash.DoFinal(span2); Bytes.XorTo(num3 - i, span2, mask.AsSpan(i)); } } }