mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 00:07:36 +00:00
LibCrypto: Parse and store all RSA private key components
This commit is contained in:
parent
dc1180d6b2
commit
15836cc865
5 changed files with 168 additions and 73 deletions
|
@ -4,8 +4,8 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <LibCrypto/ASN1/PEM.h>
|
||||||
#include <LibCrypto/Hash/SHA2.h>
|
#include <LibCrypto/Hash/SHA2.h>
|
||||||
#include <LibCrypto/PK/PK.h>
|
|
||||||
#include <LibCrypto/PK/RSA.h>
|
#include <LibCrypto/PK/RSA.h>
|
||||||
#include <LibTest/TestCase.h>
|
#include <LibTest/TestCase.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -108,6 +108,39 @@ l3vmuDEF3/Bo1C1HTg0xRV/l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE(test_RSA_keygen_enc)
|
||||||
|
{
|
||||||
|
auto keypem = R"(-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA5HMXMnY+RhEcYXsa
|
||||||
|
OyB/YkcrO1nxIeyDCMqwg5MDrSXO8vPXSEb9AZUNMF1jKiFWPoHxZ+foRxrLv4d9
|
||||||
|
sV/ETwIDAQABAkBpC37UJkjWQRHyxP83xuasExuO6/mT5sQN692kcppTJ9wHNWoD
|
||||||
|
9ZcREk4GGiklu4qx48/fYt8Cv6z6JuQ0ZQExAiEA9XRZVUnCJ2xOcCFCbyIF+d3F
|
||||||
|
9Kht5rR77F9KsRlgUbkCIQDuQ7YzLpQ8V8BJwKbDeXw1vQvcPEnyKnTOoALpF6bq
|
||||||
|
RwIhAIDSm8Ajgf7m3RQEoLVrCe/l8WtCqsuWliOsr6rbQq4hAiEAx8R16wvOtZlN
|
||||||
|
W4jvSU1+WwAaBZl21lfKf8OhLRXrmNkCIG9IRdcSiNR/Ut8QfD3N9Bb1HsUm+Bvz
|
||||||
|
c8yGzl89pYST
|
||||||
|
-----END PRIVATE KEY-----)"sv;
|
||||||
|
auto decoded = Crypto::decode_pem(keypem.bytes());
|
||||||
|
auto keypair = Crypto::PK::RSA::parse_rsa_key(decoded);
|
||||||
|
auto priv_der = MUST(keypair.private_key.export_as_der());
|
||||||
|
auto priv_pem = MUST(Crypto::encode_pem(priv_der, Crypto::PEMType::PrivateKey));
|
||||||
|
auto rsa_from_pair = Crypto::PK::RSA(keypair.public_key, keypair.private_key);
|
||||||
|
auto rsa_from_pem = Crypto::PK::RSA(priv_pem);
|
||||||
|
|
||||||
|
u8 enc_buffer[rsa_from_pair.output_size()];
|
||||||
|
u8 dec_buffer[rsa_from_pair.output_size()];
|
||||||
|
|
||||||
|
auto enc = Bytes { enc_buffer, rsa_from_pair.output_size() };
|
||||||
|
auto dec = Bytes { dec_buffer, rsa_from_pair.output_size() };
|
||||||
|
|
||||||
|
dec.overwrite(0, "WellHelloFriends", 16);
|
||||||
|
|
||||||
|
rsa_from_pair.encrypt(dec, enc);
|
||||||
|
rsa_from_pem.decrypt(enc, dec);
|
||||||
|
|
||||||
|
EXPECT_EQ(memcmp(dec.data(), "WellHelloFriends", 16), 0);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE(test_RSA_encrypt_decrypt)
|
TEST_CASE(test_RSA_encrypt_decrypt)
|
||||||
{
|
{
|
||||||
Crypto::PK::RSA rsa(
|
Crypto::PK::RSA rsa(
|
||||||
|
|
|
@ -10,6 +10,14 @@
|
||||||
|
|
||||||
namespace Crypto::NumberTheory {
|
namespace Crypto::NumberTheory {
|
||||||
|
|
||||||
|
UnsignedBigInteger Mod(UnsignedBigInteger const& a, UnsignedBigInteger const& b)
|
||||||
|
{
|
||||||
|
UnsignedBigInteger result;
|
||||||
|
result.set_to(a);
|
||||||
|
result.set_to(result.divided_by(b).remainder);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
UnsignedBigInteger ModularInverse(UnsignedBigInteger const& a_, UnsignedBigInteger const& b)
|
UnsignedBigInteger ModularInverse(UnsignedBigInteger const& a_, UnsignedBigInteger const& b)
|
||||||
{
|
{
|
||||||
if (b == 1)
|
if (b == 1)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
namespace Crypto::NumberTheory {
|
namespace Crypto::NumberTheory {
|
||||||
|
|
||||||
|
UnsignedBigInteger Mod(UnsignedBigInteger const& a, UnsignedBigInteger const& b);
|
||||||
UnsignedBigInteger ModularInverse(UnsignedBigInteger const& a_, UnsignedBigInteger const& b);
|
UnsignedBigInteger ModularInverse(UnsignedBigInteger const& a_, UnsignedBigInteger const& b);
|
||||||
UnsignedBigInteger ModularPower(UnsignedBigInteger const& b, UnsignedBigInteger const& e, UnsignedBigInteger const& m);
|
UnsignedBigInteger ModularPower(UnsignedBigInteger const& b, UnsignedBigInteger const& e, UnsignedBigInteger const& m);
|
||||||
|
|
||||||
|
|
|
@ -132,37 +132,43 @@ RSA::KeyPairType RSA::parse_rsa_key(ReadonlyBytes der)
|
||||||
if (first_integer == 0) {
|
if (first_integer == 0) {
|
||||||
// This is a private key, parse the rest.
|
// This is a private key, parse the rest.
|
||||||
auto modulus_result = decoder.read<UnsignedBigInteger>();
|
auto modulus_result = decoder.read<UnsignedBigInteger>();
|
||||||
if (modulus_result.is_error()) {
|
|
||||||
dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: {}", modulus_result.error());
|
|
||||||
return keypair;
|
|
||||||
}
|
|
||||||
auto modulus = modulus_result.release_value();
|
|
||||||
|
|
||||||
auto public_exponent_result = decoder.read<UnsignedBigInteger>();
|
auto public_exponent_result = decoder.read<UnsignedBigInteger>();
|
||||||
if (public_exponent_result.is_error()) {
|
|
||||||
dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: {}", public_exponent_result.error());
|
|
||||||
return keypair;
|
|
||||||
}
|
|
||||||
auto public_exponent = public_exponent_result.release_value();
|
|
||||||
|
|
||||||
auto private_exponent_result = decoder.read<UnsignedBigInteger>();
|
auto private_exponent_result = decoder.read<UnsignedBigInteger>();
|
||||||
if (private_exponent_result.is_error()) {
|
auto prime1_result = decoder.read<UnsignedBigInteger>();
|
||||||
dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: {}", private_exponent_result.error());
|
auto prime2_result = decoder.read<UnsignedBigInteger>();
|
||||||
|
auto exponent1_result = decoder.read<UnsignedBigInteger>();
|
||||||
|
auto exponent2_result = decoder.read<UnsignedBigInteger>();
|
||||||
|
auto coefficient_result = decoder.read<UnsignedBigInteger>();
|
||||||
|
|
||||||
|
Array results = { &modulus_result, &public_exponent_result, &private_exponent_result, &prime1_result, &prime2_result, &exponent1_result, &exponent2_result, &coefficient_result };
|
||||||
|
for (auto& result : results) {
|
||||||
|
if (result->is_error()) {
|
||||||
|
dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: {}", result->error());
|
||||||
return keypair;
|
return keypair;
|
||||||
}
|
}
|
||||||
auto private_exponent = private_exponent_result.release_value();
|
}
|
||||||
|
|
||||||
// Drop the rest of the fields on the floor, we don't use them.
|
keypair.private_key = {
|
||||||
// FIXME: Actually use them...
|
modulus_result.value(),
|
||||||
keypair.private_key = { modulus, move(private_exponent), public_exponent };
|
private_exponent_result.release_value(),
|
||||||
keypair.public_key = { move(modulus), move(public_exponent) };
|
public_exponent_result.value(),
|
||||||
|
prime1_result.release_value(),
|
||||||
|
prime2_result.release_value(),
|
||||||
|
exponent1_result.release_value(),
|
||||||
|
exponent2_result.release_value(),
|
||||||
|
coefficient_result.release_value(),
|
||||||
|
};
|
||||||
|
keypair.public_key = { modulus_result.release_value(), public_exponent_result.release_value() };
|
||||||
|
|
||||||
return keypair;
|
return keypair;
|
||||||
} else if (first_integer == 1) {
|
}
|
||||||
|
|
||||||
|
if (first_integer == 1) {
|
||||||
// This is a multi-prime key, we don't support that.
|
// This is a multi-prime key, we don't support that.
|
||||||
dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: Multi-prime key not supported");
|
dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: Multi-prime key not supported");
|
||||||
return keypair;
|
return keypair;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
auto&& modulus = move(first_integer);
|
auto&& modulus = move(first_integer);
|
||||||
|
|
||||||
// Try reading a public key, `first_integer` is the modulus.
|
// Try reading a public key, `first_integer` is the modulus.
|
||||||
|
@ -179,7 +185,6 @@ RSA::KeyPairType RSA::parse_rsa_key(ReadonlyBytes der)
|
||||||
return keypair;
|
return keypair;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// It wasn't a PKCS#1 key, let's try our luck with PKCS#8.
|
// It wasn't a PKCS#1 key, let's try our luck with PKCS#8.
|
||||||
if (!check_if_pkcs8_rsa_key())
|
if (!check_if_pkcs8_rsa_key())
|
||||||
return keypair;
|
return keypair;
|
||||||
|
@ -207,7 +212,6 @@ RSA::KeyPairType RSA::parse_rsa_key(ReadonlyBytes der)
|
||||||
|
|
||||||
return parse_rsa_key(padded_data.bytes());
|
return parse_rsa_key(padded_data.bytes());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RSA::encrypt(ReadonlyBytes in, Bytes& out)
|
void RSA::encrypt(ReadonlyBytes in, Bytes& out)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
|
#include <LibCrypto/ASN1/DER.h>
|
||||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||||
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
||||||
#include <LibCrypto/PK/Code/EMSA_PSS.h>
|
#include <LibCrypto/PK/Code/EMSA_PSS.h>
|
||||||
|
@ -36,6 +37,18 @@ public:
|
||||||
size_t length() const { return m_length; }
|
size_t length() const { return m_length; }
|
||||||
void set_length(size_t length) { m_length = length; }
|
void set_length(size_t length) { m_length = length; }
|
||||||
|
|
||||||
|
ErrorOr<ByteBuffer> export_as_der() const
|
||||||
|
{
|
||||||
|
ASN1::Encoder encoder;
|
||||||
|
TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr<void> {
|
||||||
|
TRY(encoder.write(m_modulus));
|
||||||
|
TRY(encoder.write(m_public_exponent));
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
|
return encoder.finish();
|
||||||
|
}
|
||||||
|
|
||||||
void set(Integer n, Integer e)
|
void set(Integer n, Integer e)
|
||||||
{
|
{
|
||||||
m_modulus = move(n);
|
m_modulus = move(n);
|
||||||
|
@ -52,10 +65,28 @@ private:
|
||||||
template<typename Integer = UnsignedBigInteger>
|
template<typename Integer = UnsignedBigInteger>
|
||||||
class RSAPrivateKey {
|
class RSAPrivateKey {
|
||||||
public:
|
public:
|
||||||
RSAPrivateKey(Integer n, Integer d, Integer e)
|
RSAPrivateKey(Integer n, Integer d, Integer e, Integer p, Integer q)
|
||||||
: m_modulus(move(n))
|
: m_modulus(move(n))
|
||||||
, m_private_exponent(move(d))
|
, m_private_exponent(move(d))
|
||||||
, m_public_exponent(move(e))
|
, m_public_exponent(move(e))
|
||||||
|
, m_prime_1(move(p))
|
||||||
|
, m_prime_2(move(q))
|
||||||
|
, m_exponent_1(NumberTheory::Mod(m_private_exponent, m_prime_1.minus(1)))
|
||||||
|
, m_exponent_2(NumberTheory::Mod(m_private_exponent, m_prime_2.minus(1)))
|
||||||
|
, m_coefficient(NumberTheory::ModularInverse(m_prime_2, m_prime_1))
|
||||||
|
, m_length(m_modulus.trimmed_length() * sizeof(u32))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RSAPrivateKey(Integer n, Integer d, Integer e, Integer p, Integer q, Integer dp, Integer dq, Integer qinv)
|
||||||
|
: m_modulus(move(n))
|
||||||
|
, m_private_exponent(move(d))
|
||||||
|
, m_public_exponent(move(e))
|
||||||
|
, m_prime_1(move(p))
|
||||||
|
, m_prime_2(move(q))
|
||||||
|
, m_exponent_1(move(dp))
|
||||||
|
, m_exponent_2(move(dq))
|
||||||
|
, m_coefficient(move(qinv))
|
||||||
, m_length(m_modulus.trimmed_length() * sizeof(u32))
|
, m_length(m_modulus.trimmed_length() * sizeof(u32))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -65,21 +96,41 @@ public:
|
||||||
Integer const& modulus() const { return m_modulus; }
|
Integer const& modulus() const { return m_modulus; }
|
||||||
Integer const& private_exponent() const { return m_private_exponent; }
|
Integer const& private_exponent() const { return m_private_exponent; }
|
||||||
Integer const& public_exponent() const { return m_public_exponent; }
|
Integer const& public_exponent() const { return m_public_exponent; }
|
||||||
|
Integer const& prime1() const { return m_prime_1; }
|
||||||
|
Integer const& prime2() const { return m_prime_2; }
|
||||||
|
Integer const& exponent1() const { return m_exponent_1; }
|
||||||
|
Integer const& exponent2() const { return m_exponent_2; }
|
||||||
|
Integer const& coefficient() const { return m_coefficient; }
|
||||||
size_t length() const { return m_length; }
|
size_t length() const { return m_length; }
|
||||||
void set_length(size_t length) { m_length = length; }
|
|
||||||
|
|
||||||
void set(Integer n, Integer d, Integer e)
|
ErrorOr<ByteBuffer> export_as_der() const
|
||||||
{
|
{
|
||||||
m_modulus = move(n);
|
ASN1::Encoder encoder;
|
||||||
m_private_exponent = move(d);
|
TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr<void> {
|
||||||
m_public_exponent = move(e);
|
TRY(encoder.write(0x00u)); // version
|
||||||
m_length = m_modulus.trimmed_length() * sizeof(u32);
|
TRY(encoder.write(m_modulus));
|
||||||
|
TRY(encoder.write(m_public_exponent));
|
||||||
|
TRY(encoder.write(m_private_exponent));
|
||||||
|
TRY(encoder.write(m_prime_1));
|
||||||
|
TRY(encoder.write(m_prime_2));
|
||||||
|
TRY(encoder.write(m_exponent_1));
|
||||||
|
TRY(encoder.write(m_exponent_2));
|
||||||
|
TRY(encoder.write(m_coefficient));
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
|
return encoder.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Integer m_modulus;
|
Integer m_modulus;
|
||||||
Integer m_private_exponent;
|
Integer m_private_exponent;
|
||||||
Integer m_public_exponent;
|
Integer m_public_exponent;
|
||||||
|
Integer m_prime_1;
|
||||||
|
Integer m_prime_2;
|
||||||
|
Integer m_exponent_1; // d mod (p-1)
|
||||||
|
Integer m_exponent_2; // d mod (q-1)
|
||||||
|
Integer m_coefficient; // q^-1 mod p
|
||||||
size_t m_length { 0 };
|
size_t m_length { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,20 +165,18 @@ public:
|
||||||
auto n = p.multiplied_by(q);
|
auto n = p.multiplied_by(q);
|
||||||
|
|
||||||
auto d = NumberTheory::ModularInverse(e, lambda);
|
auto d = NumberTheory::ModularInverse(e, lambda);
|
||||||
dbgln("Your keys are Pub(n={}, e={}) and Priv(n={}, d={})", n, e, n, d);
|
dbgln("Your keys are Pub(n={}, e={}) and Priv(n={}, d={}, p={}, q={})", n, e, n, d, p, q);
|
||||||
RSAKeyPair<PublicKeyType, PrivateKeyType> keys {
|
RSAKeyPair<PublicKeyType, PrivateKeyType> keys {
|
||||||
{ n, e },
|
{ n, e },
|
||||||
{ n, d, e }
|
{ n, d, e, p, q }
|
||||||
};
|
};
|
||||||
keys.public_key.set_length(bits / 2 / 8);
|
|
||||||
keys.private_key.set_length(bits / 2 / 8);
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
RSA(IntegerType n, IntegerType d, IntegerType e)
|
RSA(IntegerType n, IntegerType d, IntegerType e)
|
||||||
{
|
{
|
||||||
m_public_key.set(n, e);
|
m_public_key.set(n, e);
|
||||||
m_private_key.set(n, d, e);
|
m_private_key = { n, d, e, 0, 0, 0, 0, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
RSA(PublicKeyType& pubkey, PrivateKeyType& privkey)
|
RSA(PublicKeyType& pubkey, PrivateKeyType& privkey)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue