diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2024-03-26 20:11:34 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2024-03-26 20:11:34 +0700 |
commit | c984b8bfd8544dfc55dba91a02cbbbb9c580c217 (patch) | |
tree | 5ebd9ad5c5572c50a124226e7066bfba518f06b4 | |
parent | Fix warning (diff) | |
download | BouncyCastle.NET-ed25519-c984b8bfd8544dfc55dba91a02cbbbb9c580c217.tar.xz |
Improve TLS RSA PreMasterSecret decryption
-rw-r--r-- | crypto/src/crypto/tls/TlsRsaKeyExchange.cs | 38 | ||||
-rw-r--r-- | crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs | 5 |
2 files changed, 23 insertions, 20 deletions
diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs index c214196a9..20c2360ea 100644 --- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs +++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs @@ -11,11 +11,13 @@ namespace Org.BouncyCastle.Crypto.Tls { public static class TlsRsaKeyExchange { - public static byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret, RsaKeyParameters privateKey, + public const int PreMasterSecretLength = 48; + + public static byte[] DecryptPreMasterSecret(byte[] buf, int off, int len, RsaKeyParameters privateKey, int protocolVersion, SecureRandom secureRandom) { - if (Arrays.IsNullOrEmpty(encryptedPreMasterSecret)) - throw new ArgumentException("cannot be null or empty", nameof(encryptedPreMasterSecret)); + 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", nameof(privateKey)); @@ -31,24 +33,24 @@ namespace Org.BouncyCastle.Crypto.Tls secureRandom = CryptoServicesRegistrar.GetSecureRandom(secureRandom); /* - * Generate 48 random bytes we can use as a Pre-Master-Secret if the decrypted value is invalid. + * Generate random bytes we can use as a Pre-Master-Secret if the decrypted value is invalid. */ - byte[] result = new byte[48]; + byte[] result = new byte[PreMasterSecretLength]; secureRandom.NextBytes(result); try { - BigInteger input = ConvertInput(modulus, encryptedPreMasterSecret); + BigInteger input = ConvertInput(modulus, buf, off, len); byte[] encoding = RsaBlinded(privateKey, input, secureRandom); int pkcs1Length = (bitLength - 1) / 8; - int plainTextOffset = encoding.Length - 48; + int plainTextOffset = encoding.Length - PreMasterSecretLength; - int badEncodingMask = CheckPkcs1Encoding2(encoding, pkcs1Length, 48); + int badEncodingMask = CheckPkcs1Encoding2(encoding, pkcs1Length, PreMasterSecretLength); int badVersionMask = -(Pack.BE_To_UInt16(encoding, plainTextOffset) ^ protocolVersion) >> 31; int fallbackMask = badEncodingMask | badVersionMask; - for (int i = 0; i < 48; ++i) + for (int i = 0; i < PreMasterSecretLength; ++i) { result[i] = (byte)((result[i] & fallbackMask) | (encoding[plainTextOffset + i] & ~fallbackMask)); } @@ -69,6 +71,11 @@ namespace Org.BouncyCastle.Crypto.Tls return result; } + public static int GetInputLimit(RsaKeyParameters privateKey) + { + return (privateKey.Modulus.BitLength + 7) / 8; + } + private static int CAddTo(int len, int cond, byte[] x, byte[] z) { Debug.Assert(cond == 0 || cond == -1); @@ -116,16 +123,11 @@ namespace Org.BouncyCastle.Crypto.Tls return errorSign >> 31; } - private static BigInteger ConvertInput(BigInteger modulus, byte[] input) + private static BigInteger ConvertInput(BigInteger modulus, byte[] buf, int off, int len) { - int inputLimit = (modulus.BitLength + 7) / 8; - - if (input.Length <= inputLimit) - { - BigInteger result = new BigInteger(1, input); - if (result.CompareTo(modulus) < 0) - return result; - } + BigInteger result = BigIntegers.FromUnsignedByteArray(buf, off, len); + if (result.CompareTo(modulus) < 0) + return result; throw new DataLengthException("input too large for RSA cipher."); } diff --git a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs index 5cfb2690e..31f339c92 100644 --- a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs +++ b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs @@ -45,7 +45,6 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC public virtual TlsSecret Decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) { - // TODO Keep only the decryption itself here - move error handling outside return SafeDecryptPreMasterSecret(cryptoParams, (RsaKeyParameters)m_privateKey, ciphertext); } @@ -53,13 +52,15 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so that users can * implement "generic" encryption credentials externally */ + // TODO[api] Just inline this into Decrypt protected virtual TlsSecret SafeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams, RsaKeyParameters rsaServerPrivateKey, byte[] encryptedPreMasterSecret) { ProtocolVersion expectedVersion = cryptoParams.RsaPreMasterSecretVersion; byte[] preMasterSecret = Org.BouncyCastle.Crypto.Tls.TlsRsaKeyExchange.DecryptPreMasterSecret( - encryptedPreMasterSecret, rsaServerPrivateKey, expectedVersion.FullVersion, m_crypto.SecureRandom); + encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length, rsaServerPrivateKey, + expectedVersion.FullVersion, m_crypto.SecureRandom); return m_crypto.CreateSecret(preMasterSecret); } |