/* * Copyright (c) 2020, Ali Mohammad Pur * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace Crypto { namespace PK { template class RSAPublicKey { public: RSAPublicKey(Integer n, Integer e) : m_modulus(move(n)) , m_public_exponent(move(e)) , m_length(m_modulus.trimmed_length() * sizeof(u32)) { } RSAPublicKey() : m_modulus(0) , m_public_exponent(0) { } Integer const& modulus() const { return m_modulus; } Integer const& public_exponent() const { return m_public_exponent; } size_t length() const { return m_length; } void set_length(size_t length) { m_length = length; } void set(Integer n, Integer e) { m_modulus = move(n); m_public_exponent = move(e); m_length = (m_modulus.trimmed_length() * sizeof(u32)); } private: Integer m_modulus; Integer m_public_exponent; size_t m_length { 0 }; }; template class RSAPrivateKey { public: RSAPrivateKey(Integer n, Integer d, Integer e) : m_modulus(move(n)) , m_private_exponent(move(d)) , m_public_exponent(move(e)) , m_length(m_modulus.trimmed_length() * sizeof(u32)) { } RSAPrivateKey() = default; Integer const& modulus() const { return m_modulus; } Integer const& private_exponent() const { return m_private_exponent; } Integer const& public_exponent() const { return m_public_exponent; } size_t length() const { return m_length; } void set_length(size_t length) { m_length = length; } void set(Integer n, Integer d, Integer e) { m_modulus = move(n); m_private_exponent = move(d); m_public_exponent = move(e); m_length = m_modulus.trimmed_length() * sizeof(u32); } private: Integer m_modulus; Integer m_private_exponent; Integer m_public_exponent; size_t m_length { 0 }; }; template struct RSAKeyPair { PubKey public_key; PrivKey private_key; }; using IntegerType = UnsignedBigInteger; class RSA : public PKSystem, RSAPublicKey> { template friend class RSA_EMSA_PSS; public: using KeyPairType = RSAKeyPair; static KeyPairType parse_rsa_key(ReadonlyBytes der); static KeyPairType generate_key_pair(size_t bits = 256) { IntegerType e { 65537 }; // :P IntegerType p, q; IntegerType lambda; do { p = NumberTheory::random_big_prime(bits / 2); q = NumberTheory::random_big_prime(bits / 2); lambda = NumberTheory::LCM(p.minus(1), q.minus(1)); dbgln("checking combination p={}, q={}, lambda={}", p, q, lambda.length()); } while (!(NumberTheory::GCD(e, lambda) == 1)); auto n = p.multiplied_by(q); auto d = NumberTheory::ModularInverse(e, lambda); dbgln("Your keys are Pub(n={}, e={}) and Priv(n={}, d={})", n, e, n, d); RSAKeyPair keys { { n, e }, { n, d, e } }; keys.public_key.set_length(bits / 2 / 8); keys.private_key.set_length(bits / 2 / 8); return keys; } RSA(IntegerType n, IntegerType d, IntegerType e) { m_public_key.set(n, e); m_private_key.set(n, d, e); } RSA(PublicKeyType& pubkey, PrivateKeyType& privkey) : PKSystem, RSAPublicKey>(pubkey, privkey) { } RSA(ByteBuffer const& publicKeyPEM, ByteBuffer const& privateKeyPEM) { import_public_key(publicKeyPEM); import_private_key(privateKeyPEM); } RSA(StringView privKeyPEM) { import_private_key(privKeyPEM.bytes()); m_public_key.set(m_private_key.modulus(), m_private_key.public_exponent()); } // create our own keys RSA() { auto pair = generate_key_pair(); m_public_key = pair.public_key; m_private_key = pair.private_key; } virtual void encrypt(ReadonlyBytes in, Bytes& out) override; virtual void decrypt(ReadonlyBytes in, Bytes& out) override; virtual void sign(ReadonlyBytes in, Bytes& out) override; virtual void verify(ReadonlyBytes in, Bytes& out) override; #ifndef KERNEL virtual DeprecatedString class_name() const override { return "RSA"; } #endif virtual size_t output_size() const override { return m_public_key.length(); } void import_public_key(ReadonlyBytes, bool pem = true); void import_private_key(ReadonlyBytes, bool pem = true); PrivateKeyType const& private_key() const { return m_private_key; } PublicKeyType const& public_key() const { return m_public_key; } }; template class RSA_EMSA_PSS { public: RSA_EMSA_PSS(RSA& rsa) : m_rsa(rsa) { } void sign(ReadonlyBytes in, Bytes& out); VerificationConsistency verify(ReadonlyBytes in); private: EMSA_PSS m_emsa_pss; RSA m_rsa; }; class RSA_PKCS1_EME : public RSA { public: // forward all constructions to RSA template RSA_PKCS1_EME(Args... args) : RSA(args...) { } ~RSA_PKCS1_EME() = default; virtual void encrypt(ReadonlyBytes in, Bytes& out) override; virtual void decrypt(ReadonlyBytes in, Bytes& out) override; virtual void sign(ReadonlyBytes, Bytes&) override; virtual void verify(ReadonlyBytes, Bytes&) override; #ifndef KERNEL virtual DeprecatedString class_name() const override { return "RSA_PKCS1-EME"; } #endif virtual size_t output_size() const override { return m_public_key.length(); } }; } }