123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- /*
- * Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/Debug.h>
- #include <AK/Random.h>
- #include <AK/ScopeGuard.h>
- #include <LibCrypto/ASN1/ASN1.h>
- #include <LibCrypto/ASN1/DER.h>
- #include <LibCrypto/ASN1/PEM.h>
- #include <LibCrypto/PK/RSA.h>
- namespace Crypto {
- namespace PK {
- static constexpr Array<int, 7> pkcs8_rsa_key_oid { 1, 2, 840, 113549, 1, 1, 1 };
- RSA::KeyPairType RSA::parse_rsa_key(ReadonlyBytes der)
- {
- // we are going to assign to at least one of these
- KeyPairType keypair;
- ASN1::Decoder decoder(der);
- // There are four possible (supported) formats:
- // PKCS#1 private key
- // PKCS#1 public key
- // PKCS#8 private key
- // PKCS#8 public key
- // They're all a single sequence, so let's check that first
- {
- auto result = decoder.peek();
- if (result.is_error()) {
- // Bad data.
- dbgln_if(RSA_PARSE_DEBUG, "RSA key parse failed: {}", result.error());
- return keypair;
- }
- auto tag = result.value();
- if (tag.kind != ASN1::Kind::Sequence) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA key parse failed: Expected a Sequence but got {}", ASN1::kind_name(tag.kind));
- return keypair;
- }
- }
- // Then enter the sequence
- {
- auto error = decoder.enter();
- if (error.is_error()) {
- // Something was weird with the input.
- dbgln_if(RSA_PARSE_DEBUG, "RSA key parse failed: {}", error.error());
- return keypair;
- }
- }
- bool has_read_error = false;
- auto const check_if_pkcs8_rsa_key = [&] {
- // see if it's a sequence:
- auto tag_result = decoder.peek();
- if (tag_result.is_error()) {
- // Decode error :shrug:
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 public key parse failed: {}", tag_result.error());
- return false;
- }
- auto tag = tag_result.value();
- if (tag.kind != ASN1::Kind::Sequence) {
- // We don't know what this is, but it sure isn't a PKCS#8 key.
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 public key parse failed: Expected a Sequence but got {}", ASN1::kind_name(tag.kind));
- return false;
- }
- // It's a sequence, now let's see if it's actually an RSA key.
- auto error = decoder.enter();
- if (error.is_error()) {
- // Shenanigans!
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 public key parse failed: {}", error.error());
- return false;
- }
- ScopeGuard leave { [&] {
- auto error = decoder.leave();
- if (error.is_error()) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA key parse failed: {}", error.error());
- has_read_error = true;
- }
- } };
- // Now let's read the OID.
- auto oid_result = decoder.read<Vector<int>>();
- if (oid_result.is_error()) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 public key parse failed: {}", oid_result.error());
- return false;
- }
- auto oid = oid_result.release_value();
- // Now let's check that the OID matches "RSA key"
- if (oid != pkcs8_rsa_key_oid) {
- // Oh well. not an RSA key at all.
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 public key parse failed: Not an RSA key");
- return false;
- }
- return true;
- };
- auto integer_result = decoder.read<UnsignedBigInteger>();
- if (!integer_result.is_error()) {
- auto first_integer = integer_result.release_value();
- // It's either a PKCS#1 key, or a PKCS#8 private key.
- // Check for the PKCS#8 private key right away.
- if (check_if_pkcs8_rsa_key()) {
- if (has_read_error)
- return keypair;
- // Now read the private key, which is actually an octet string containing the PKCS#1 encoded private key.
- auto data_result = decoder.read<StringView>();
- if (data_result.is_error()) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 private key parse failed: {}", data_result.error());
- return keypair;
- }
- return parse_rsa_key(data_result.value().bytes());
- }
- if (has_read_error)
- return keypair;
- // It's not a PKCS#8 key, so it's a PKCS#1 key (or something we don't support)
- // if the first integer is zero or one, it's a private key.
- if (first_integer == 0) {
- // This is a private key, parse the rest.
- 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>();
- 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>();
- if (private_exponent_result.is_error()) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 private key parse failed: {}", private_exponent_result.error());
- return keypair;
- }
- auto private_exponent = private_exponent_result.release_value();
- // Drop the rest of the fields on the floor, we don't use them.
- // FIXME: Actually use them...
- keypair.private_key = { modulus, move(private_exponent), public_exponent };
- keypair.public_key = { move(modulus), move(public_exponent) };
- return keypair;
- } else if (first_integer == 1) {
- // 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");
- return keypair;
- } else {
- auto&& modulus = move(first_integer);
- // Try reading a public key, `first_integer` is the modulus.
- auto public_exponent_result = decoder.read<UnsignedBigInteger>();
- if (public_exponent_result.is_error()) {
- // Bad public key.
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 public key parse failed: {}", public_exponent_result.error());
- return keypair;
- }
- auto public_exponent = public_exponent_result.release_value();
- keypair.public_key.set(move(modulus), move(public_exponent));
- return keypair;
- }
- } else {
- // It wasn't a PKCS#1 key, let's try our luck with PKCS#8.
- if (!check_if_pkcs8_rsa_key())
- return keypair;
- if (has_read_error)
- return keypair;
- // Now we have a bit string, which contains the PKCS#1 encoded public key.
- auto data_result = decoder.read<BitmapView>();
- if (data_result.is_error()) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#8 public key parse failed: {}", data_result.error());
- return keypair;
- }
- // Now just read it as a PKCS#1 DER.
- auto data = data_result.release_value();
- // FIXME: This is pretty awkward, maybe just generate a zero'd out ByteBuffer from the parser instead?
- auto padded_data_result = ByteBuffer::create_zeroed(data.size_in_bytes());
- if (padded_data_result.is_error()) {
- dbgln_if(RSA_PARSE_DEBUG, "RSA PKCS#1 key parse failed: Not enough memory");
- return keypair;
- }
- auto padded_data = padded_data_result.release_value();
- padded_data.overwrite(0, data.data(), data.size_in_bytes());
- return parse_rsa_key(padded_data.bytes());
- }
- }
- 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())) {
- dbgln("value too large for key");
- out = {};
- return;
- }
- 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();
- if (size != outsize) {
- dbgln("POSSIBLE RSA BUG!!! Size mismatch: {} requested but {} bytes generated", outsize, size);
- out = out.slice(outsize - size, size);
- }
- }
- void RSA::decrypt(ReadonlyBytes in, Bytes& out)
- {
- // FIXME: Actually use the private key properly
- auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
- auto exp = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus());
- auto size = exp.export_data(out);
- auto align = m_private_key.length();
- auto aligned_size = (size + align - 1) / align * align;
- 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);
- }
- void RSA::sign(ReadonlyBytes in, Bytes& out)
- {
- auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
- auto exp = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus());
- auto size = exp.export_data(out);
- out = out.slice(out.size() - size, size);
- }
- void RSA::verify(ReadonlyBytes in, Bytes& out)
- {
- auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
- auto exp = NumberTheory::ModularPower(in_integer, m_public_key.public_exponent(), m_public_key.modulus());
- auto size = exp.export_data(out);
- out = out.slice(out.size() - size, size);
- }
- void RSA::import_private_key(ReadonlyBytes bytes, bool pem)
- {
- ByteBuffer buffer;
- if (pem) {
- buffer = decode_pem(bytes);
- bytes = buffer;
- }
- auto key = parse_rsa_key(bytes);
- if (!key.private_key.length()) {
- dbgln("We expected to see a private key, but we found none");
- VERIFY_NOT_REACHED();
- }
- m_private_key = key.private_key;
- }
- void RSA::import_public_key(ReadonlyBytes bytes, bool pem)
- {
- ByteBuffer buffer;
- if (pem) {
- buffer = decode_pem(bytes);
- bytes = buffer;
- }
- auto key = parse_rsa_key(bytes);
- if (!key.public_key.length()) {
- dbgln("We expected to see a public key, but we found none");
- VERIFY_NOT_REACHED();
- }
- m_public_key = key.public_key;
- }
- template<typename HashFunction>
- void RSA_EMSA_PSS<HashFunction>::sign(ReadonlyBytes in, Bytes& out)
- {
- // -- encode via EMSA_PSS
- auto mod_bits = m_rsa.private_key().modulus().trimmed_length() * sizeof(u32) * 8;
- Vector<u8, 2048> EM;
- EM.resize(mod_bits);
- auto EM_buf = Bytes { EM };
- m_emsa_pss.encode(in, EM_buf, mod_bits - 1);
- // -- sign via RSA
- m_rsa.sign(EM_buf, out);
- }
- template<typename HashFunction>
- VerificationConsistency RSA_EMSA_PSS<HashFunction>::verify(ReadonlyBytes in)
- {
- auto mod_bytes = m_rsa.public_key().modulus().trimmed_length() * sizeof(u32);
- if (in.size() != mod_bytes)
- return VerificationConsistency::Inconsistent;
- Vector<u8, 256> EM;
- EM.resize(mod_bytes);
- auto EM_buf = Bytes { EM };
- // -- verify via RSA
- m_rsa.verify(in, EM_buf);
- // -- verify via EMSA_PSS
- return m_emsa_pss.verify(in, EM, mod_bytes * 8 - 1);
- }
- void RSA_PKCS1_EME::encrypt(ReadonlyBytes in, Bytes& out)
- {
- auto mod_len = (m_public_key.modulus().trimmed_length() * sizeof(u32) * 8 + 7) / 8;
- dbgln_if(CRYPTO_DEBUG, "key size: {}", mod_len);
- if (in.size() > mod_len - 11) {
- dbgln("message too long :(");
- out = out.trim(0);
- return;
- }
- if (out.size() < mod_len) {
- dbgln("output buffer too small");
- return;
- }
- auto ps_length = mod_len - in.size() - 3;
- Vector<u8, 8096> ps;
- ps.resize(ps_length);
- fill_with_random(ps.data(), ps_length);
- // since fill_with_random can create zeros (shocking!)
- // we have to go through and un-zero the zeros
- for (size_t i = 0; i < ps_length; ++i)
- while (!ps[i])
- fill_with_random(ps.span().offset(i), 1);
- u8 paddings[] { 0x00, 0x02 };
- out.overwrite(0, paddings, 2);
- out.overwrite(2, ps.data(), ps_length);
- out.overwrite(2 + ps_length, paddings, 1);
- out.overwrite(3 + ps_length, in.data(), in.size());
- out = out.trim(3 + ps_length + in.size()); // should be a single block
- dbgln_if(CRYPTO_DEBUG, "padded output size: {} buffer size: {}", 3 + ps_length + in.size(), out.size());
- RSA::encrypt(out, out);
- }
- void RSA_PKCS1_EME::decrypt(ReadonlyBytes in, Bytes& out)
- {
- auto mod_len = (m_public_key.modulus().trimmed_length() * sizeof(u32) * 8 + 7) / 8;
- if (in.size() != mod_len) {
- dbgln("decryption error: wrong amount of data: {}", in.size());
- out = out.trim(0);
- return;
- }
- RSA::decrypt(in, out);
- if (out.size() < RSA::output_size()) {
- dbgln("decryption error: not enough data after decryption: {}", out.size());
- out = out.trim(0);
- return;
- }
- if (out[0] != 0x00) {
- dbgln("invalid padding byte 0 : {}", out[0]);
- return;
- }
- if (out[1] != 0x02) {
- dbgln("invalid padding byte 1 : {}", out[1]);
- return;
- }
- size_t offset = 2;
- while (offset < out.size() && out[offset])
- ++offset;
- if (offset == out.size()) {
- dbgln("garbage data, no zero to split padding");
- return;
- }
- ++offset;
- if (offset - 3 < 8) {
- dbgln("PS too small");
- return;
- }
- out = out.slice(offset, out.size() - offset);
- }
- void RSA_PKCS1_EME::sign(ReadonlyBytes, Bytes&)
- {
- dbgln("FIXME: RSA_PKCS_EME::sign");
- }
- void RSA_PKCS1_EME::verify(ReadonlyBytes, Bytes&)
- {
- dbgln("FIXME: RSA_PKCS_EME::verify");
- }
- }
- }
|