From a84d3878c2ff917537b0ea487353bd83f03b2fea Mon Sep 17 00:00:00 2001 From: devgianlu Date: Mon, 23 Dec 2024 18:29:47 +0100 Subject: [PATCH] LibCrypto: Use OpenSSL for RSA encryption and decryption --- Libraries/LibCrypto/PK/RSA.cpp | 93 ++++++++++++++++++++++++---------- Libraries/LibCrypto/PK/RSA.h | 5 ++ 2 files changed, 71 insertions(+), 27 deletions(-) diff --git a/Libraries/LibCrypto/PK/RSA.cpp b/Libraries/LibCrypto/PK/RSA.cpp index ebeab461d2a2d..0f3ea342054cd 100644 --- a/Libraries/LibCrypto/PK/RSA.cpp +++ b/Libraries/LibCrypto/PK/RSA.cpp @@ -163,44 +163,83 @@ ErrorOr RSA::generate_key_pair(size_t bits, IntegerType e) #undef OPENSSL_GET_KEY_PARAM +#define OPENSSL_SET_KEY_PARAM_NOT_ZERO(param, openssl_name, value) \ + auto param##_bn = TRY(unsigned_big_integer_to_openssl_bignum(value)); \ + if (!value.is_zero()) { \ + OPENSSL_TRY(OSSL_PARAM_BLD_push_BN(params_bld, openssl_name, param##_bn.ptr())); \ + } + +ErrorOr RSA::public_key_to_openssl_pkey(PublicKeyType const& public_key) +{ + auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr))); + + OPENSSL_TRY(EVP_PKEY_fromdata_init(ctx.ptr())); + + auto* params_bld = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_new()); + ArmedScopeGuard const free_params_bld = [&] { OSSL_PARAM_BLD_free(params_bld); }; + + OPENSSL_SET_KEY_PARAM_NOT_ZERO(n, OSSL_PKEY_PARAM_RSA_N, public_key.modulus()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(e, OSSL_PKEY_PARAM_RSA_E, public_key.public_exponent()); + + auto key = TRY(OpenSSL_PKEY::create()); + auto* key_ptr = key.ptr(); + OPENSSL_TRY(EVP_PKEY_fromdata(ctx.ptr(), &key_ptr, EVP_PKEY_PUBLIC_KEY, OSSL_PARAM_BLD_to_param(params_bld))); + return key; +} + +ErrorOr RSA::private_key_to_openssl_pkey(PrivateKeyType const& private_key) +{ + auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr))); + + OPENSSL_TRY(EVP_PKEY_fromdata_init(ctx.ptr())); + + auto* params_bld = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_new()); + ArmedScopeGuard const free_params_bld = [&] { OSSL_PARAM_BLD_free(params_bld); }; + + OPENSSL_SET_KEY_PARAM_NOT_ZERO(n, OSSL_PKEY_PARAM_RSA_N, private_key.modulus()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(e, OSSL_PKEY_PARAM_RSA_E, private_key.public_exponent()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(d, OSSL_PKEY_PARAM_RSA_D, private_key.private_exponent()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(p, OSSL_PKEY_PARAM_RSA_FACTOR1, private_key.prime1()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(q, OSSL_PKEY_PARAM_RSA_FACTOR2, private_key.prime2()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(dp, OSSL_PKEY_PARAM_RSA_EXPONENT1, private_key.exponent1()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(dq, OSSL_PKEY_PARAM_RSA_EXPONENT2, private_key.exponent2()); + OPENSSL_SET_KEY_PARAM_NOT_ZERO(qinv, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, private_key.coefficient()); + + auto key = TRY(OpenSSL_PKEY::create()); + auto* key_ptr = key.ptr(); + OPENSSL_TRY(EVP_PKEY_fromdata(ctx.ptr(), &key_ptr, EVP_PKEY_KEYPAIR, OSSL_PARAM_BLD_to_param(params_bld))); + return key; +} + +#undef OPENSSL_SET_KEY_PARAM_NOT_ZERO + ErrorOr RSA::encrypt(ReadonlyBytes in, Bytes& out) { - dbgln_if(CRYPTO_DEBUG, "in size: {}", in.size()); - auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size()); - if (in_integer >= m_public_key.modulus()) - return Error::from_string_literal("Data too large for key"); + auto key = TRY(public_key_to_openssl_pkey(m_public_key)); - auto exp = NumberTheory::ModularPower(in_integer, m_public_key.public_exponent(), m_public_key.modulus()); - auto size = exp.export_data(out); - auto outsize = out.size(); - VERIFY(size == outsize); + auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_pkey(nullptr, key.ptr(), nullptr))); + + OPENSSL_TRY(EVP_PKEY_encrypt_init(ctx.ptr())); + OPENSSL_TRY(EVP_PKEY_CTX_set_rsa_padding(ctx.ptr(), RSA_NO_PADDING)); + + size_t out_size = out.size(); + OPENSSL_TRY(EVP_PKEY_encrypt(ctx.ptr(), out.data(), &out_size, in.data(), in.size())); + out = out.slice(0, out_size); return {}; } ErrorOr RSA::decrypt(ReadonlyBytes in, Bytes& out) { - auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size()); - - UnsignedBigInteger m; - if (m_private_key.prime1().is_zero() || m_private_key.prime2().is_zero()) { - m = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus()); - } else { - auto m1 = NumberTheory::ModularPower(in_integer, m_private_key.exponent1(), m_private_key.prime1()); - auto m2 = NumberTheory::ModularPower(in_integer, m_private_key.exponent2(), m_private_key.prime2()); - while (m1 < m2) - m1 = m1.plus(m_private_key.prime1()); + auto key = TRY(private_key_to_openssl_pkey(m_private_key)); - auto h = NumberTheory::Mod(m1.minus(m2).multiplied_by(m_private_key.coefficient()), m_private_key.prime1()); - m = m2.plus(h.multiplied_by(m_private_key.prime2())); - } + auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_pkey(nullptr, key.ptr(), nullptr))); - auto size = m.export_data(out); - auto align = m_private_key.length(); - auto aligned_size = (size + align - 1) / align * align; + OPENSSL_TRY(EVP_PKEY_decrypt_init(ctx.ptr())); + OPENSSL_TRY(EVP_PKEY_CTX_set_rsa_padding(ctx.ptr(), RSA_NO_PADDING)); - for (auto i = size; i < aligned_size; ++i) - out[out.size() - i - 1] = 0; // zero the non-aligned values - out = out.slice(out.size() - aligned_size, aligned_size); + size_t out_size = out.size(); + OPENSSL_TRY(EVP_PKEY_decrypt(ctx.ptr(), out.data(), &out_size, in.data(), in.size())); + out = out.slice(0, out_size); return {}; } diff --git a/Libraries/LibCrypto/PK/RSA.h b/Libraries/LibCrypto/PK/RSA.h index 4706ce5772b16..e12aa46928a02 100644 --- a/Libraries/LibCrypto/PK/RSA.h +++ b/Libraries/LibCrypto/PK/RSA.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace Crypto::PK { @@ -219,6 +220,10 @@ class RSA : public PKSystem, RSAPublicKey public_key_to_openssl_pkey(PublicKeyType const& public_key); + static ErrorOr private_key_to_openssl_pkey(PrivateKeyType const& private_key); }; class RSA_PKCS1_EME : public RSA {