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

TlsRsaKeyExchange

public static class TlsRsaKeyExchange
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using System; namespace Org.BouncyCastle.Crypto.Tls { public static class TlsRsaKeyExchange { public const int PreMasterSecretLength = 48; public static byte[] DecryptPreMasterSecret(byte[] buf, int off, int len, RsaKeyParameters privateKey, int protocolVersion, SecureRandom secureRandom) { if (buf == null || len < 1 || len > GetInputLimit(privateKey) || off < 0 || off > buf.Length - len) throw new ArgumentException("input not a valid EncryptedPreMasterSecret"); if (!privateKey.IsPrivate) throw new ArgumentException("must be an RSA private key", "privateKey"); BigInteger modulus = privateKey.Modulus; int bitLength = modulus.BitLength; if (bitLength < 512) throw new ArgumentException("must be at least 512 bits", "privateKey"); if ((protocolVersion & 65535) == protocolVersion) { secureRandom = CryptoServicesRegistrar.GetSecureRandom(secureRandom); byte[] array = new byte[48]; secureRandom.NextBytes(array); try { BigInteger input = ConvertInput(modulus, buf, off, len); byte[] array2 = RsaBlinded(privateKey, input, secureRandom); int pkcs1Length = (bitLength - 1) / 8; int num = array2.Length - 48; int num2 = CheckPkcs1Encoding2(array2, pkcs1Length, 48); int num3 = -(Pack.BE_To_UInt16(array2, num) ^ protocolVersion) >> 31; int num4 = num2 | num3; for (int i = 0; i < 48; i++) { array[i] = (byte)((array[i] & num4) | (array2[num + i] & ~num4)); } Arrays.Fill(array2, 0); return array; } catch (Exception) { return array; } } throw new ArgumentException("must be a 16 bit value", "protocolVersion"); } public static int GetInputLimit(RsaKeyParameters privateKey) { return (privateKey.Modulus.BitLength + 7) / 8; } private static int CAddTo(int len, int cond, byte[] x, byte[] z) { int num = 0; for (int num2 = len - 1; num2 >= 0; num2--) { num += z[num2] + (x[num2] & cond); z[num2] = (byte)num; num >>= 8; } return num; } private static int CheckPkcs1Encoding2(byte[] buf, int pkcs1Length, int plaintextLength) { int num = pkcs1Length - plaintextLength - 10; int num2 = buf.Length - pkcs1Length; int num3 = buf.Length - 1 - plaintextLength; for (int i = 0; i < num2; i++) { num |= -buf[i]; } num |= -(buf[num2] ^ 2); for (int j = num2 + 1; j < num3; j++) { num |= buf[j] - 1; } num |= -buf[num3]; return num >> 31; } private static BigInteger ConvertInput(BigInteger modulus, byte[] buf, int off, int len) { BigInteger bigInteger = BigIntegers.FromUnsignedByteArray(buf, off, len); if (bigInteger.CompareTo(modulus) < 0) return bigInteger; throw new DataLengthException("input too large for RSA cipher."); } private static BigInteger Rsa(RsaKeyParameters privateKey, BigInteger input) { return input.ModPow(privateKey.Exponent, privateKey.Modulus); } private static byte[] RsaBlinded(RsaKeyParameters privateKey, BigInteger input, SecureRandom secureRandom) { BigInteger modulus = privateKey.Modulus; int num = (modulus.BitLength + 7) / 8; RsaPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = privateKey as RsaPrivateCrtKeyParameters; if (rsaPrivateCrtKeyParameters == null) return BigIntegers.AsUnsignedByteArray(num, Rsa(privateKey, input)); BigInteger publicExponent = rsaPrivateCrtKeyParameters.PublicExponent; BigInteger bigInteger = BigIntegers.CreateRandomInRange(BigInteger.One, modulus.Subtract(BigInteger.One), secureRandom); BigInteger bigInteger2 = bigInteger.ModPow(publicExponent, modulus); BigInteger bigInteger3 = BigIntegers.ModOddInverse(modulus, bigInteger); BigInteger input2 = bigInteger2.ModMultiply(input, modulus); BigInteger bigInteger4 = RsaCrt(rsaPrivateCrtKeyParameters, input2); BigInteger n = bigInteger3.Add(BigInteger.One).ModMultiply(bigInteger4, modulus); byte[] x = BigIntegers.AsUnsignedByteArray(num, bigInteger4); byte[] x2 = BigIntegers.AsUnsignedByteArray(num, modulus); byte[] array = BigIntegers.AsUnsignedByteArray(num, n); int cond = SubFrom(num, x, array); CAddTo(num, cond, x2, array); return array; } private static BigInteger RsaCrt(RsaPrivateCrtKeyParameters crtKey, BigInteger input) { BigInteger publicExponent = crtKey.PublicExponent; BigInteger p = crtKey.P; BigInteger q = crtKey.Q; BigInteger dP = crtKey.DP; BigInteger dQ = crtKey.DQ; BigInteger qInv = crtKey.QInv; BigInteger bigInteger = input.Remainder(p).ModPow(dP, p); BigInteger bigInteger2 = input.Remainder(q).ModPow(dQ, q); BigInteger bigInteger3 = bigInteger.Subtract(bigInteger2).ModMultiply(qInv, p).Multiply(q) .Add(bigInteger2); if (!bigInteger3.ModPow(publicExponent, crtKey.Modulus).Equals(input)) throw new InvalidOperationException("RSA engine faulty decryption/signing detected"); return bigInteger3; } private static int SubFrom(int len, byte[] x, byte[] z) { int num = 0; for (int num2 = len - 1; num2 >= 0; num2--) { num += z[num2] - x[num2]; z[num2] = (byte)num; num >>= 8; } return num; } } }