Skip to content

Commit

Permalink
LibCrypto: Use OpenSSL for RSA encryption and decryption
Browse files Browse the repository at this point in the history
  • Loading branch information
devgianlu committed Dec 24, 2024
1 parent b5aec2a commit 255d991
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 27 deletions.
93 changes: 66 additions & 27 deletions Libraries/LibCrypto/PK/RSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,44 +163,83 @@ ErrorOr<RSA::KeyPairType> 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) \
if (!value.is_zero()) { \
auto param##_bn = TRY(unsigned_big_integer_to_openssl_bignum(value)); \
OPENSSL_TRY(OSSL_PARAM_BLD_push_BN(params_bld, openssl_name, param##_bn.ptr())); \
}

ErrorOr<OpenSSL_PKEY> 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<OpenSSL_PKEY> 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<void> 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<void> 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 {};
}

Expand Down
5 changes: 5 additions & 0 deletions Libraries/LibCrypto/PK/RSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <LibCrypto/ASN1/DER.h>
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
#include <LibCrypto/NumberTheory/ModularFunctions.h>
#include <LibCrypto/OpenSSL.h>
#include <LibCrypto/PK/PK.h>

namespace Crypto::PK {
Expand Down Expand Up @@ -219,6 +220,10 @@ class RSA : public PKSystem<RSAPrivateKey<IntegerType>, RSAPublicKey<IntegerType

void set_public_key(PublicKeyType const& key) { m_public_key = key; }
void set_private_key(PrivateKeyType const& key) { m_private_key = key; }

protected:
static ErrorOr<OpenSSL_PKEY> public_key_to_openssl_pkey(PublicKeyType const& public_key);
static ErrorOr<OpenSSL_PKEY> private_key_to_openssl_pkey(PrivateKeyType const& private_key);
};

class RSA_PKCS1_EME : public RSA {
Expand Down

0 comments on commit 255d991

Please sign in to comment.