From 3b1788beb8fd1db8a569a970d51416d57be79b17 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Tue, 16 Jul 2024 13:57:55 +0300 Subject: [PATCH 1/8] Add pgp::KeyMaterial classes. --- src/lib/CMakeLists.txt | 1 + src/lib/key_material.cpp | 1925 ++++++++++++++++++++++++++++++++++++++ src/lib/key_material.hpp | 508 ++++++++++ 3 files changed, 2434 insertions(+) create mode 100644 src/lib/key_material.cpp create mode 100644 src/lib/key_material.hpp diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 34da153128..5d77df7eac 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -370,6 +370,7 @@ add_library(librnp-obj OBJECT json-utils.cpp utils.cpp pass-provider.cpp + key_material.cpp pgp-key.cpp rnp.cpp ) diff --git a/src/lib/key_material.cpp b/src/lib/key_material.cpp new file mode 100644 index 0000000000..b660434bcb --- /dev/null +++ b/src/lib/key_material.cpp @@ -0,0 +1,1925 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "key_material.hpp" +#include "librepgp/stream-packet.h" +#include "logging.h" +#include "utils.h" +#include "config.h" +#include + +namespace { +void +grip_hash_mpi(rnp::Hash &hash, const pgp::mpi &val, const char name, bool lzero = true) +{ + size_t len = val.bytes(); + size_t idx = 0; + for (idx = 0; (idx < len) && !val.mpi[idx]; idx++) + ; + + if (name) { + size_t hlen = idx >= len ? 0 : len - idx; + if ((len > idx) && lzero && (val.mpi[idx] & 0x80)) { + hlen++; + } + + char buf[26] = {0}; + snprintf(buf, sizeof(buf), "(1:%c%zu:", name, hlen); + hash.add(buf, strlen(buf)); + } + + if (idx < len) { + /* gcrypt prepends mpis with zero if higher bit is set */ + if (lzero && (val.mpi[idx] & 0x80)) { + uint8_t zero = 0; + hash.add(&zero, 1); + } + hash.add(val.mpi + idx, len - idx); + } + if (name) { + hash.add(")", 1); + } +} + +void +grip_hash_ecc_hex(rnp::Hash &hash, const char *hex, char name) +{ + pgp::mpi mpi = {}; + mpi.len = rnp::hex_decode(hex, mpi.mpi, sizeof(mpi.mpi)); + if (!mpi.len) { + RNP_LOG("wrong hex mpi"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + /* libgcrypt doesn't add leading zero when hashes ecc mpis */ + return grip_hash_mpi(hash, mpi, name, false); +} + +void +grip_hash_ec(rnp::Hash &hash, const pgp_ec_key_t &key) +{ + const ec_curve_desc_t *desc = get_curve_desc(key.curve); + if (!desc) { + RNP_LOG("unknown curve %d", (int) key.curve); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + /* build uncompressed point from gx and gy */ + pgp::mpi g = {}; + g.mpi[0] = 0x04; + g.len = 1; + size_t len = rnp::hex_decode(desc->gx, g.mpi + g.len, sizeof(g.mpi) - g.len); + if (!len) { + RNP_LOG("wrong x mpi"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + g.len += len; + len = rnp::hex_decode(desc->gy, g.mpi + g.len, sizeof(g.mpi) - g.len); + if (!len) { + RNP_LOG("wrong y mpi"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + g.len += len; + + /* p, a, b, g, n, q */ + grip_hash_ecc_hex(hash, desc->p, 'p'); + grip_hash_ecc_hex(hash, desc->a, 'a'); + grip_hash_ecc_hex(hash, desc->b, 'b'); + grip_hash_mpi(hash, g, 'g', false); + grip_hash_ecc_hex(hash, desc->n, 'n'); + + if ((key.curve == PGP_CURVE_ED25519) || (key.curve == PGP_CURVE_25519)) { + if (g.len < 1) { + RNP_LOG("wrong 25519 p"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + g.len = key.p.len - 1; + memcpy(g.mpi, key.p.mpi + 1, g.len); + grip_hash_mpi(hash, g, 'q', false); + } else { + grip_hash_mpi(hash, key.p, 'q', false); + } +} +} // namespace + +namespace pgp { + +KeyMaterial::~KeyMaterial() +{ +} + +pgp_pubkey_alg_t +KeyMaterial::alg() const noexcept +{ + return alg_; +} + +bool +KeyMaterial::secret() const noexcept +{ + return secret_; +} + +bool +KeyMaterial::valid() const +{ + return validity_.validated && validity_.valid; +} + +bool +KeyMaterial::equals(const KeyMaterial &value) noexcept +{ + return alg_ == value.alg_; +} + +void +KeyMaterial::validate(rnp::SecurityContext &ctx, bool reset) +{ + if (!reset && validity_.validated) { + return; + } + validity_.reset(); +#ifdef FUZZERS_ENABLED + /* do not timeout on large keys during fuzzing */ + validity_.valid = true; +#else + validity_.valid = validate_material(ctx, reset); +#endif + validity_.validated = true; +} + +const pgp_validity_t & +KeyMaterial::validity() const noexcept +{ + return validity_; +} + +void +KeyMaterial::set_validity(const pgp_validity_t &val) +{ + validity_ = val; +} + +void +KeyMaterial::reset_validity() +{ + validity_.reset(); +} + +void +KeyMaterial::clear_secret() +{ + secret_ = false; +} + +bool +KeyMaterial::finish_generate() +{ + validity_.mark_valid(); + secret_ = true; + return true; +} + +bool +KeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + RNP_LOG("key generation not implemented for PK alg: %d", alg_); + return false; +} + +rnp_result_t +KeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ + return RNP_ERROR_NOT_SUPPORTED; +} + +rnp_result_t +KeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ + return RNP_ERROR_NOT_SUPPORTED; +} + +rnp_result_t +KeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + return RNP_ERROR_NOT_SUPPORTED; +} + +rnp_result_t +KeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return RNP_ERROR_NOT_SUPPORTED; +} + +pgp_hash_alg_t +KeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +{ + return hash; +} + +bool +KeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const +{ + return true; +} + +pgp_curve_t +KeyMaterial::curve() const noexcept +{ + return PGP_CURVE_UNKNOWN; +} + +pgp_key_grip_t +KeyMaterial::grip() const +{ + auto hash = rnp::Hash::create(PGP_HASH_SHA1); + grip_update(*hash); + pgp_key_grip_t res; + hash->finish(res.data()); + return res; +} + +std::unique_ptr +KeyMaterial::create(pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + case PGP_PKA_RSA_SIGN_ONLY: + return std::unique_ptr(new RSAKeyMaterial(alg)); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return std::unique_ptr(new EGKeyMaterial(alg)); + case PGP_PKA_DSA: + return std::unique_ptr(new DSAKeyMaterial()); + case PGP_PKA_ECDH: + return std::unique_ptr(new ECDHKeyMaterial()); + case PGP_PKA_ECDSA: + return std::unique_ptr(new ECDSAKeyMaterial()); + case PGP_PKA_EDDSA: + return std::unique_ptr(new EDDSAKeyMaterial()); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return std::unique_ptr(new Ed25519KeyMaterial()); + case PGP_PKA_X25519: + return std::unique_ptr(new X25519KeyMaterial()); +#endif + case PGP_PKA_SM2: + return std::unique_ptr(new SM2KeyMaterial()); +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER768_P256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER1024_P384: + FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER768_BP256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_KYBER1024_BP384: + return std::unique_ptr(new KyberKeyMaterial(alg)); + case PGP_PKA_DILITHIUM3_ED25519: + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM3_P256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM5_P384: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM3_BP256: + FALLTHROUGH_STATEMENT; + case PGP_PKA_DILITHIUM5_BP384: + return std::unique_ptr(new DilithiumKeyMaterial(alg)); + case PGP_PKA_SPHINCSPLUS_SHA2: + FALLTHROUGH_STATEMENT; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return std::unique_ptr(new SphincsPlusKeyMaterial(alg)); +#endif + default: + return nullptr; + } +} + +std::unique_ptr +KeyMaterial::create(pgp_pubkey_alg_t alg, const pgp_rsa_key_t &key) +{ + return std::unique_ptr(new pgp::RSAKeyMaterial(alg, key)); +} + +std::unique_ptr +KeyMaterial::create(const pgp_dsa_key_t &key) +{ + return std::unique_ptr(new pgp::DSAKeyMaterial(key)); +} + +std::unique_ptr +KeyMaterial::create(pgp_pubkey_alg_t alg, const pgp_eg_key_t &key) +{ + return std::unique_ptr(new pgp::EGKeyMaterial(alg, key)); +} + +std::unique_ptr +KeyMaterial::create(pgp_pubkey_alg_t alg, const pgp_ec_key_t &key) +{ + switch (alg) { + case PGP_PKA_ECDSA: + return std::unique_ptr(new pgp::ECDSAKeyMaterial(key)); + case PGP_PKA_ECDH: + return std::unique_ptr(new pgp::ECDHKeyMaterial(key)); + case PGP_PKA_EDDSA: + return std::unique_ptr(new pgp::EDDSAKeyMaterial(key)); + case PGP_PKA_SM2: + return std::unique_ptr(new pgp::SM2KeyMaterial(key)); + default: + throw std::invalid_argument("Invalid EC algorithm."); + } +} + +std::unique_ptr +RSAKeyMaterial::clone() +{ + return std::unique_ptr(new RSAKeyMaterial(*this)); +} + +void +RSAKeyMaterial::grip_update(rnp::Hash &hash) const +{ + /* keygrip is subjectKeyHash from pkcs#15 for RSA. */ + grip_hash_mpi(hash, key_.n, '\0'); +} + +bool +RSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !rsa_validate_key(&ctx.rng, &key_, secret_); +} + +bool +RSAKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return (key->key_.n == key_.n) && (key->key_.e == key_.e); +} + +void +RSAKeyMaterial::clear_secret() +{ + key_.clear_secret(); + KeyMaterial::clear_secret(); +} + +bool +RSAKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + return pkt.get(key_.n) && pkt.get(key_.e); +} + +bool +RSAKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + if (!pkt.get(key_.d) || !pkt.get(key_.p) || !pkt.get(key_.q) || !pkt.get(key_.u)) { + RNP_LOG("failed to parse rsa secret key data"); + return false; + } + secret_ = true; + return true; +} + +void +RSAKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.n); + pkt.add(key_.e); +} + +void +RSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.d); + pkt.add(key_.p); + pkt.add(key_.q); + pkt.add(key_.u); +} + +bool +RSAKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + /* We do not generate PGP_PKA_RSA_ENCRYPT_ONLY or PGP_PKA_RSA_SIGN_ONLY keys */ + if (alg_ != PGP_PKA_RSA) { + RNP_LOG("Unsupported algorithm for key generation: %d", alg_); + return false; + } + if (rsa_generate(¶ms.ctx->rng, &key_, params.rsa.modulus_bit_len)) { + RNP_LOG("failed to generate RSA key"); + return false; + } + return finish_generate(); +} + +rnp_result_t +RSAKeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ + return rsa_encrypt_pkcs1(&ctx.rng, &out.rsa, data, len, &key_); +} + +rnp_result_t +RSAKeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ + if ((alg() != PGP_PKA_RSA) && (alg() != PGP_PKA_RSA_ENCRYPT_ONLY)) { + RNP_LOG("Non-encrypting RSA algorithm: %d\n", alg()); + return RNP_ERROR_BAD_PARAMETERS; + } + return rsa_decrypt_pkcs1(&ctx.rng, out, &out_len, &in.rsa, &key_); +} + +rnp_result_t +RSAKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + if (alg() == PGP_PKA_RSA_ENCRYPT_ONLY) { + RNP_LOG("RSA encrypt-only signature considered as invalid."); + return RNP_ERROR_SIGNATURE_INVALID; + } + return rsa_verify_pkcs1(&sig.rsa, sig.halg, hash.data(), hash.size(), &key_); +} + +rnp_result_t +RSAKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return rsa_sign_pkcs1(&ctx.rng, &sig.rsa, sig.halg, hash.data(), hash.size(), &key_); +} + +void +RSAKeyMaterial::set_secret(const mpi &d, const mpi &p, const mpi &q, const mpi &u) +{ + key_.d = d; + key_.p = p; + key_.q = q; + key_.u = u; + secret_ = true; +} + +size_t +RSAKeyMaterial::bits() const noexcept +{ + return 8 * key_.n.bytes(); +} + +const mpi & +RSAKeyMaterial::n() const noexcept +{ + return key_.n; +} + +const mpi & +RSAKeyMaterial::e() const noexcept +{ + return key_.e; +} + +const mpi & +RSAKeyMaterial::d() const noexcept +{ + return key_.d; +} + +const mpi & +RSAKeyMaterial::p() const noexcept +{ + return key_.p; +} + +const mpi & +RSAKeyMaterial::q() const noexcept +{ + return key_.q; +} + +const mpi & +RSAKeyMaterial::u() const noexcept +{ + return key_.u; +} + +std::unique_ptr +DSAKeyMaterial::clone() +{ + return std::unique_ptr(new DSAKeyMaterial(*this)); +} + +void +DSAKeyMaterial::grip_update(rnp::Hash &hash) const +{ + grip_hash_mpi(hash, key_.p, 'p'); + grip_hash_mpi(hash, key_.q, 'q'); + grip_hash_mpi(hash, key_.g, 'g'); + grip_hash_mpi(hash, key_.y, 'y'); +} + +bool +DSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !dsa_validate_key(&ctx.rng, &key_, secret_); +} + +bool +DSAKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return (key->key_.p == key_.p) && (key->key_.q == key_.q) && (key->key_.g == key_.g) && + (key->key_.y == key_.y); +} + +void +DSAKeyMaterial::clear_secret() +{ + key_.clear_secret(); + KeyMaterial::clear_secret(); +} + +bool +DSAKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + return pkt.get(key_.p) && pkt.get(key_.q) && pkt.get(key_.g) && pkt.get(key_.y); +} + +bool +DSAKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + if (!pkt.get(key_.x)) { + RNP_LOG("failed to parse dsa secret key data"); + return false; + } + secret_ = true; + return true; +} + +void +DSAKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.p); + pkt.add(key_.q); + pkt.add(key_.g); + pkt.add(key_.y); +} + +void +DSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.x); +} + +bool +DSAKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (dsa_generate(¶ms.ctx->rng, &key_, params.dsa.p_bitlen, params.dsa.q_bitlen)) { + RNP_LOG("failed to generate DSA key"); + return false; + } + return finish_generate(); +} + +rnp_result_t +DSAKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + return dsa_verify(&sig.dsa, hash.data(), hash.size(), &key_); +} + +rnp_result_t +DSAKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return dsa_sign(&ctx.rng, &sig.dsa, hash.data(), hash.size(), &key_); +} + +pgp_hash_alg_t +DSAKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +{ + pgp_hash_alg_t hash_min = dsa_get_min_hash(key_.q.bits()); + if (rnp::Hash::size(hash) < rnp::Hash::size(hash_min)) { + return hash_min; + } + return hash; +} + +void +DSAKeyMaterial::set_secret(const mpi &x) +{ + key_.x = x; + secret_ = true; +} + +size_t +DSAKeyMaterial::bits() const noexcept +{ + return 8 * key_.p.bytes(); +} + +size_t +DSAKeyMaterial::qbits() const noexcept +{ + return 8 * key_.q.bytes(); +} + +const mpi & +DSAKeyMaterial::p() const noexcept +{ + return key_.p; +} + +const mpi & +DSAKeyMaterial::q() const noexcept +{ + return key_.q; +} + +const mpi & +DSAKeyMaterial::g() const noexcept +{ + return key_.g; +} + +const mpi & +DSAKeyMaterial::y() const noexcept +{ + return key_.y; +} + +const mpi & +DSAKeyMaterial::x() const noexcept +{ + return key_.x; +} + +std::unique_ptr +EGKeyMaterial::clone() +{ + return std::unique_ptr(new EGKeyMaterial(*this)); +} + +void +EGKeyMaterial::grip_update(rnp::Hash &hash) const +{ + grip_hash_mpi(hash, key_.p, 'p'); + grip_hash_mpi(hash, key_.g, 'g'); + grip_hash_mpi(hash, key_.y, 'y'); +} + +bool +EGKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return elgamal_validate_key(&key_, secret_); +} + +bool +EGKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return (key->key_.p == key_.p) && (key->key_.g == key_.g) && (key->key_.y == key_.y); +} + +void +EGKeyMaterial::clear_secret() +{ + key_.clear_secret(); + KeyMaterial::clear_secret(); +} + +bool +EGKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + return pkt.get(key_.p) && pkt.get(key_.g) && pkt.get(key_.y); +} + +bool +EGKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + if (!pkt.get(key_.x)) { + RNP_LOG("failed to parse eg secret key data"); + return false; + } + secret_ = true; + return true; +} + +void +EGKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.p); + pkt.add(key_.g); + pkt.add(key_.y); +} + +void +EGKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.x); +} + +bool +EGKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + /* We do not generate PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN keys */ + if (alg_ != PGP_PKA_ELGAMAL) { + RNP_LOG("Unsupported algorithm for key generation: %d", alg_); + return false; + } + if (elgamal_generate(¶ms.ctx->rng, &key_, params.elgamal.key_bitlen)) { + RNP_LOG("failed to generate ElGamal key"); + return false; + } + return finish_generate(); +} + +rnp_result_t +EGKeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ + return elgamal_encrypt_pkcs1(&ctx.rng, &out.eg, data, len, &key_); +} + +rnp_result_t +EGKeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ + return elgamal_decrypt_pkcs1(&ctx.rng, out, &out_len, &in.eg, &key_); +} + +rnp_result_t +EGKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + RNP_LOG("ElGamal signatures are considered as invalid."); + return RNP_ERROR_SIGNATURE_INVALID; +} + +void +EGKeyMaterial::set_secret(const mpi &x) +{ + key_.x = x; + secret_ = true; +} + +size_t +EGKeyMaterial::bits() const noexcept +{ + return 8 * key_.y.bytes(); +} + +const mpi & +EGKeyMaterial::p() const noexcept +{ + return key_.p; +} + +const mpi & +EGKeyMaterial::g() const noexcept +{ + return key_.g; +} + +const mpi & +EGKeyMaterial::y() const noexcept +{ + return key_.y; +} + +const mpi & +EGKeyMaterial::x() const noexcept +{ + return key_.x; +} + +void +ECKeyMaterial::grip_update(rnp::Hash &hash) const +{ + grip_hash_ec(hash, key_); +} + +bool +ECKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return (key->key_.curve == key_.curve) && (key->key_.p == key_.p); +} + +void +ECKeyMaterial::clear_secret() +{ + key_.clear_secret(); + KeyMaterial::clear_secret(); +} + +rnp_result_t +ECKeyMaterial::check_curve(size_t hash_len) +{ + const ec_curve_desc_t *curve = get_curve_desc(key_.curve); + if (!curve) { + RNP_LOG("Unknown curve"); + return RNP_ERROR_BAD_PARAMETERS; + } + if (!curve_supported(key_.curve)) { + RNP_LOG("EC sign: curve %s is not supported.", curve->pgp_name); + return RNP_ERROR_NOT_SUPPORTED; + } + /* "-2" because ECDSA on P-521 must work with SHA-512 digest */ + if (BITS_TO_BYTES(curve->bitlen) - 2 > hash_len) { + RNP_LOG("Message hash too small"); + return RNP_ERROR_BAD_PARAMETERS; + } + return RNP_SUCCESS; +} + +bool +ECKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + if (!pkt.get(key_.curve) || !pkt.get(key_.p)) { + return false; + } + return true; +} + +bool +ECKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + if (!pkt.get(key_.x)) { + RNP_LOG("failed to parse ecc secret key data"); + return false; + } + secret_ = true; + return true; +} + +void +ECKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.curve); + pkt.add(key_.p); +} + +void +ECKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.x); +} + +bool +ECKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (!curve_supported(params.ecc.curve)) { + RNP_LOG("EC generate: curve %d is not supported.", params.ecc.curve); + return false; + } + if (ec_generate(¶ms.ctx->rng, &key_, alg_, params.ecc.curve)) { + RNP_LOG("failed to generate EC key"); + return false; + } + key_.curve = params.ecc.curve; + return finish_generate(); +} + +void +ECKeyMaterial::set_secret(const mpi &x) +{ + key_.x = x; + secret_ = true; +} + +size_t +ECKeyMaterial::bits() const noexcept +{ + auto curve_desc = get_curve_desc(key_.curve); + return curve_desc ? curve_desc->bitlen : 0; +} + +pgp_curve_t +ECKeyMaterial::curve() const noexcept +{ + return key_.curve; +} + +const mpi & +ECKeyMaterial::p() const noexcept +{ + return key_.p; +} + +const mpi & +ECKeyMaterial::x() const noexcept +{ + return key_.x; +} + +bool +ECDSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + if (!curve_supported(key_.curve)) { + /* allow to import key if curve is not supported */ + RNP_LOG("ECDSA validate: curve %d is not supported.", key_.curve); + return true; + } + return !ecdsa_validate_key(&ctx.rng, &key_, secret_); +} + +std::unique_ptr +ECDSAKeyMaterial::clone() +{ + return std::unique_ptr(new ECDSAKeyMaterial(*this)); +} + +rnp_result_t +ECDSAKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + if (!curve_supported(key_.curve)) { + RNP_LOG("Curve %d is not supported.", key_.curve); + return RNP_ERROR_NOT_SUPPORTED; + } + return ecdsa_verify(&sig.ecc, sig.halg, hash.data(), hash.size(), &key_); +} + +rnp_result_t +ECDSAKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + auto ret = check_curve(hash.size()); + if (ret) { + return ret; + } + return ecdsa_sign(&ctx.rng, &sig.ecc, sig.halg, hash.data(), hash.size(), &key_); +} + +pgp_hash_alg_t +ECDSAKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +{ + pgp_hash_alg_t hash_min = ecdsa_get_min_hash(key_.curve); + if (rnp::Hash::size(hash) < rnp::Hash::size(hash_min)) { + return hash_min; + } + return hash; +} + +bool +ECDHKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + if (!curve_supported(key_.curve)) { + /* allow to import key if curve is not supported */ + RNP_LOG("ECDH validate: curve %d is not supported.", key_.curve); + return true; + } + return !ecdh_validate_key(&ctx.rng, &key_, secret_); +} + +std::unique_ptr +ECDHKeyMaterial::clone() +{ + return std::unique_ptr(new ECDHKeyMaterial(*this)); +} + +bool +ECDHKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + if (!ECKeyMaterial::parse(pkt)) { + return false; + } + /* Additional ECDH fields */ + /* Read KDF parameters. At the moment should be 0x03 0x01 halg ealg */ + uint8_t len = 0, halg = 0, walg = 0; + if (!pkt.get(len) || (len != 3)) { + return false; + } + if (!pkt.get(len) || (len != 1)) { + return false; + } + if (!pkt.get(halg) || !pkt.get(walg)) { + return false; + } + key_.kdf_hash_alg = (pgp_hash_alg_t) halg; + key_.key_wrap_alg = (pgp_symm_alg_t) walg; + return true; +} + +void +ECDHKeyMaterial::write(pgp_packet_body_t &pkt) +{ + ECKeyMaterial::write(pkt); + pkt.add_byte(3); + pkt.add_byte(1); + pkt.add_byte(key_.kdf_hash_alg); + pkt.add_byte(key_.key_wrap_alg); +} + +bool +ECDHKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (!ecdh_set_params(&key_, params.ecc.curve)) { + RNP_LOG("Unsupported curve [ID=%d]", params.ecc.curve); + return false; + } + /* Special case for x25519*/ + if (params.ecc.curve == PGP_CURVE_25519) { + if (x25519_generate(¶ms.ctx->rng, &key_)) { + RNP_LOG("failed to generate x25519 key"); + return false; + } + key_.curve = params.ecc.curve; + return finish_generate(); + ; + } + /* Fallback to default EC generation for other cases */ + return ECKeyMaterial::generate(params); +} + +rnp_result_t +ECDHKeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ + if (!curve_supported(key_.curve)) { + RNP_LOG("ECDH encrypt: curve %d is not supported.", key_.curve); + return RNP_ERROR_NOT_SUPPORTED; + } + assert(out.ecdh.fp); + return ecdh_encrypt_pkcs5(&ctx.rng, &out.ecdh, data, len, &key_, *out.ecdh.fp); +} + +rnp_result_t +ECDHKeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ + if (!curve_supported(key_.curve)) { + RNP_LOG("ECDH decrypt: curve %d is not supported.", key_.curve); + return RNP_ERROR_BAD_PARAMETERS; + } + if ((key_.curve == PGP_CURVE_25519) && !x25519_bits_tweaked()) { + RNP_LOG("Warning: bits of 25519 secret key are not tweaked."); + } + return ecdh_decrypt_pkcs5(out, &out_len, &in.ecdh, &key_, *in.ecdh.fp); +} + +pgp_hash_alg_t +ECDHKeyMaterial::kdf_hash_alg() const noexcept +{ + return key_.kdf_hash_alg; +} + +pgp_symm_alg_t +ECDHKeyMaterial::key_wrap_alg() const noexcept +{ + return key_.key_wrap_alg; +} + +bool +ECDHKeyMaterial::x25519_bits_tweaked() const noexcept +{ + return (key_.curve == PGP_CURVE_25519) && ::x25519_bits_tweaked(key_); +} + +bool +ECDHKeyMaterial::x25519_tweak_bits() noexcept +{ + return (key_.curve == PGP_CURVE_25519) && ::x25519_tweak_bits(key_); +} + +bool +EDDSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !eddsa_validate_key(&ctx.rng, &key_, secret_); +} + +std::unique_ptr +EDDSAKeyMaterial::clone() +{ + return std::unique_ptr(new EDDSAKeyMaterial(*this)); +} + +bool +EDDSAKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (eddsa_generate(¶ms.ctx->rng, &key_)) { + RNP_LOG("failed to generate EDDSA key"); + return false; + } + return finish_generate(); +} + +rnp_result_t +EDDSAKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + return eddsa_verify(&sig.ecc, hash.data(), hash.size(), &key_); +} + +rnp_result_t +EDDSAKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return eddsa_sign(&ctx.rng, &sig.ecc, hash.data(), hash.size(), &key_); +} + +bool +SM2KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ +#if defined(ENABLE_SM2) + return !sm2_validate_key(&ctx.rng, &key_, secret_); +#else + RNP_LOG("SM2 key validation is not available."); + return false; +#endif +} + +std::unique_ptr +SM2KeyMaterial::clone() +{ + return std::unique_ptr(new SM2KeyMaterial(*this)); +} + +rnp_result_t +SM2KeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ +#if defined(ENABLE_SM2) + return sm2_encrypt(&ctx.rng, &out.sm2, data, len, PGP_HASH_SM3, &key_); +#else + RNP_LOG("sm2_encrypt is not available"); + return RNP_ERROR_NOT_IMPLEMENTED; +#endif +} + +rnp_result_t +SM2KeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ +#if defined(ENABLE_SM2) + return sm2_decrypt(out, &out_len, &in.sm2, &key_); +#else + RNP_LOG("SM2 decryption is not available."); + return RNP_ERROR_NOT_IMPLEMENTED; +#endif +} + +rnp_result_t +SM2KeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ +#if defined(ENABLE_SM2) + return sm2_verify(&sig.ecc, sig.halg, hash.data(), hash.size(), &key_); +#else + RNP_LOG("SM2 verification is not available."); + return RNP_ERROR_NOT_IMPLEMENTED; +#endif +} + +rnp_result_t +SM2KeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ +#if defined(ENABLE_SM2) + auto ret = check_curve(hash.size()); + if (ret) { + return ret; + } + return sm2_sign(&ctx.rng, &sig.ecc, sig.halg, hash.data(), hash.size(), &key_); +#else + RNP_LOG("SM2 signing is not available."); + return RNP_ERROR_NOT_IMPLEMENTED; +#endif +} + +void +SM2KeyMaterial::compute_za(rnp::Hash &hash) const +{ +#if defined(ENABLE_SM2) + auto res = sm2_compute_za(key_, hash); + if (res) { + RNP_LOG("failed to compute SM2 ZA field"); + throw rnp::rnp_exception(res); + } +#else + RNP_LOG("SM2 ZA computation not available"); + throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED); +#endif +} + +#if defined(ENABLE_CRYPTO_REFRESH) +std::unique_ptr +Ed25519KeyMaterial::clone() +{ + return std::unique_ptr(new Ed25519KeyMaterial(*this)); +} + +void +Ed25519KeyMaterial::grip_update(rnp::Hash &hash) const +{ + // TODO: if GnuPG would ever support v6, check whether this works correctly. + hash.add(pub()); +} + +bool +Ed25519KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !ed25519_validate_key_native(&ctx.rng, &key_, secret_); +} + +bool +Ed25519KeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return key->key_.pub == key_.pub; +} + +void +Ed25519KeyMaterial::clear_secret() +{ + key_.clear_secret(); + KeyMaterial::clear_secret(); +} + +bool +Ed25519KeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + auto ec_desc = get_curve_desc(PGP_CURVE_ED25519); + std::vector buf(BITS_TO_BYTES(ec_desc->bitlen)); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse Ed25519 public key data"); + return false; + } + key_.pub = buf; + return true; +} + +bool +Ed25519KeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + auto ec_desc = get_curve_desc(PGP_CURVE_ED25519); + std::vector buf(BITS_TO_BYTES(ec_desc->bitlen)); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse Ed25519 secret key data"); + return false; + } + key_.priv = buf; + secret_ = true; + return true; +} + +void +Ed25519KeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.pub); +} + +void +Ed25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.priv); +} + +bool +Ed25519KeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (generate_ed25519_native(¶ms.ctx->rng, key_.priv, key_.pub)) { + RNP_LOG("failed to generate ED25519 key"); + return false; + } + return finish_generate(); +} + +rnp_result_t +Ed25519KeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + return ed25519_verify_native(sig.ed25519.sig, key_.pub, hash.data(), hash.size()); +} + +rnp_result_t +Ed25519KeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return ed25519_sign_native(&ctx.rng, sig.ed25519.sig, key_.priv, hash.data(), hash.size()); +} + +size_t +Ed25519KeyMaterial::bits() const noexcept +{ + return 255; +} + +pgp_curve_t +Ed25519KeyMaterial::curve() const noexcept +{ + return PGP_CURVE_ED25519; +} + +const std::vector & +Ed25519KeyMaterial::pub() const noexcept +{ + return key_.pub; +} + +const std::vector & +Ed25519KeyMaterial::priv() const noexcept +{ + return key_.priv; +} + +std::unique_ptr +X25519KeyMaterial::clone() +{ + return std::unique_ptr(new X25519KeyMaterial(*this)); +} + +void +X25519KeyMaterial::grip_update(rnp::Hash &hash) const +{ + // TODO: if GnuPG would ever support v6, check whether this works correctly. + hash.add(pub()); +} + +bool +X25519KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !x25519_validate_key_native(&ctx.rng, &key_, secret_); +} + +bool +X25519KeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return key->key_.pub == key_.pub; +} + +void +X25519KeyMaterial::clear_secret() +{ + key_.clear_secret(); + KeyMaterial::clear_secret(); +} + +bool +X25519KeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + auto ec_desc = get_curve_desc(PGP_CURVE_25519); + std::vector buf(BITS_TO_BYTES(ec_desc->bitlen)); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse X25519 public key data"); + return false; + } + key_.pub = buf; + return true; +} + +bool +X25519KeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + auto ec_desc = get_curve_desc(PGP_CURVE_25519); + std::vector buf(BITS_TO_BYTES(ec_desc->bitlen)); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse X25519 secret key data"); + return false; + } + key_.priv = buf; + secret_ = true; + return true; +} + +void +X25519KeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.pub); +} + +void +X25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.priv); +} + +bool +X25519KeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (generate_x25519_native(¶ms.ctx->rng, key_.priv, key_.pub)) { + RNP_LOG("failed to generate X25519 key"); + return false; + } + return finish_generate(); +} + +rnp_result_t +X25519KeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ + return x25519_native_encrypt(&ctx.rng, key_.pub, data, len, &out.x25519); +} + +rnp_result_t +X25519KeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ + return x25519_native_decrypt(&ctx.rng, key_, &in.x25519, out, &out_len); +} + +size_t +X25519KeyMaterial::bits() const noexcept +{ + return 255; +} + +pgp_curve_t +X25519KeyMaterial::curve() const noexcept +{ + return PGP_CURVE_25519; +} + +const std::vector & +X25519KeyMaterial::pub() const noexcept +{ + return key_.pub; +} + +const std::vector & +X25519KeyMaterial::priv() const noexcept +{ + return key_.priv; +} +#endif + +#if defined(ENABLE_PQC) +std::unique_ptr +KyberKeyMaterial::clone() +{ + return std::unique_ptr(new KyberKeyMaterial(*this)); +} + +void +KyberKeyMaterial::grip_update(rnp::Hash &hash) const +{ + hash.add(pub().get_encoded()); +} + +bool +KyberKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !kyber_ecdh_validate_key(&ctx.rng, &key_, secret_); +} + +bool +KyberKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return key->key_.pub == key_.pub; +} + +void +KyberKeyMaterial::clear_secret() +{ + key_.priv.secure_clear(); + KeyMaterial::clear_secret(); +} + +bool +KyberKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + std::vector buf(pgp_kyber_ecdh_composite_public_key_t::encoded_size(alg())); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse mlkem-ecdh public key data"); + return false; + } + key_.pub = pgp_kyber_ecdh_composite_public_key_t(buf, alg()); + return true; +} + +bool +KyberKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + std::vector buf(pgp_kyber_ecdh_composite_private_key_t::encoded_size(alg())); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse mkem-ecdh secret key data"); + return false; + } + key_.priv = pgp_kyber_ecdh_composite_private_key_t(buf.data(), buf.size(), alg()); + secret_ = true; + return true; +} + +void +KyberKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.pub.get_encoded()); +} + +void +KyberKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.priv.get_encoded()); +} + +bool +KyberKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (pgp_kyber_ecdh_composite_key_t::gen_keypair(¶ms.ctx->rng, &key_, alg_)) { + RNP_LOG("failed to generate MLKEM-ECDH-composite key for PK alg %d", alg_); + return false; + } + return finish_generate(); +} + +rnp_result_t +KyberKeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) +{ + return key_.pub.encrypt(&ctx.rng, &out.kyber_ecdh, data, len); +} + +rnp_result_t +KyberKeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) +{ + return key_.priv.decrypt(&ctx.rng, out, &out_len, &in.kyber_ecdh); +} + +size_t +KyberKeyMaterial::bits() const noexcept +{ + return 8 * pub().get_encoded().size(); /* public key length */ +} + +const pgp_kyber_ecdh_composite_public_key_t & +KyberKeyMaterial::pub() const noexcept +{ + return key_.pub; +} + +const pgp_kyber_ecdh_composite_private_key_t & +KyberKeyMaterial::priv() const noexcept +{ + return key_.priv; +} + +std::unique_ptr +DilithiumKeyMaterial::clone() +{ + return std::unique_ptr(new DilithiumKeyMaterial(*this)); +} + +void +DilithiumKeyMaterial::grip_update(rnp::Hash &hash) const +{ + hash.add(pub().get_encoded()); +} + +bool +DilithiumKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !dilithium_exdsa_validate_key(&ctx.rng, &key_, secret_); +} + +bool +DilithiumKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return key->key_.pub == key_.pub; +} + +void +DilithiumKeyMaterial::clear_secret() +{ + key_.priv.secure_clear(); + KeyMaterial::clear_secret(); +} + +bool +DilithiumKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + std::vector buf(pgp_dilithium_exdsa_composite_public_key_t::encoded_size(alg())); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse mldsa-ecdsa/eddsa public key data"); + return false; + } + key_.pub = pgp_dilithium_exdsa_composite_public_key_t(buf, alg()); + return true; +} + +bool +DilithiumKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + std::vector buf(pgp_dilithium_exdsa_composite_private_key_t::encoded_size(alg())); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse mldsa-ecdsa/eddsa secret key data"); + return false; + } + key_.priv = pgp_dilithium_exdsa_composite_private_key_t(buf.data(), buf.size(), alg()); + secret_ = true; + return true; +} + +void +DilithiumKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add(key_.pub.get_encoded()); +} + +void +DilithiumKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add(key_.priv.get_encoded()); +} + +bool +DilithiumKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (pgp_dilithium_exdsa_composite_key_t::gen_keypair(¶ms.ctx->rng, &key_, alg_)) { + RNP_LOG("failed to generate mldsa-ecdsa/eddsa-composite key for PK alg %d", alg_); + return false; + } + return finish_generate(); +} + +rnp_result_t +DilithiumKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + return key_.pub.verify(&sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); +} + +rnp_result_t +DilithiumKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return key_.priv.sign(&ctx.rng, &sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); +} + +pgp_hash_alg_t +DilithiumKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +{ + return dilithium_default_hash_alg(); +} + +size_t +DilithiumKeyMaterial::bits() const noexcept +{ + return 8 * pub().get_encoded().size(); /* public key length*/ +} + +const pgp_dilithium_exdsa_composite_public_key_t & +DilithiumKeyMaterial::pub() const noexcept +{ + return key_.pub; +} + +const pgp_dilithium_exdsa_composite_private_key_t & +DilithiumKeyMaterial::priv() const noexcept +{ + return key_.priv; +} + +std::unique_ptr +SphincsPlusKeyMaterial::clone() +{ + return std::unique_ptr(new SphincsPlusKeyMaterial(*this)); +} + +void +SphincsPlusKeyMaterial::grip_update(rnp::Hash &hash) const +{ + hash.add(pub().get_encoded()); +} + +bool +SphincsPlusKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +{ + return !sphincsplus_validate_key(&ctx.rng, &key_, secret_); +} + +bool +SphincsPlusKeyMaterial::equals(const KeyMaterial &value) noexcept +{ + auto key = dynamic_cast(&value); + if (!key || !KeyMaterial::equals(value)) { + return false; + } + return key->key_.pub == key_.pub; +} + +void +SphincsPlusKeyMaterial::clear_secret() +{ + key_.priv.secure_clear(); + KeyMaterial::clear_secret(); +} + +bool +SphincsPlusKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + secret_ = false; + uint8_t bt = 0; + if (!pkt.get(bt)) { + RNP_LOG("failed to parse SLH-DSA public key data"); + return false; + } + sphincsplus_parameter_t param = (sphincsplus_parameter_t) bt; + std::vector buf(sphincsplus_pubkey_size(param)); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse SLH-DSA public key data"); + return false; + } + key_.pub = pgp_sphincsplus_public_key_t(buf, param, alg()); + return true; +} + +bool +SphincsPlusKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +{ + uint8_t bt = 0; + if (!pkt.get(bt)) { + RNP_LOG("failed to parse SLH-DSA secret key data"); + return false; + } + sphincsplus_parameter_t param = (sphincsplus_parameter_t) bt; + std::vector buf(sphincsplus_privkey_size(param)); + if (!pkt.get(buf.data(), buf.size())) { + RNP_LOG("failed to parse SLH-DSA secret key data"); + return false; + } + key_.priv = pgp_sphincsplus_private_key_t(buf, param, alg()); + secret_ = true; + return true; +} + +void +SphincsPlusKeyMaterial::write(pgp_packet_body_t &pkt) +{ + pkt.add_byte((uint8_t) key_.pub.param()); + pkt.add(key_.pub.get_encoded()); +} + +void +SphincsPlusKeyMaterial::write_secret(pgp_packet_body_t &pkt) +{ + pkt.add_byte((uint8_t) key_.priv.param()); + pkt.add(key_.priv.get_encoded()); +} + +bool +SphincsPlusKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +{ + if (pgp_sphincsplus_generate(¶ms.ctx->rng, &key_, params.sphincsplus.param, alg_)) { + RNP_LOG("failed to generate SLH-DSA key for PK alg %d", alg_); + return false; + } + return finish_generate(); +} + +rnp_result_t +SphincsPlusKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const +{ + return key_.pub.verify(&sig.sphincsplus, hash.data(), hash.size()); +} + +rnp_result_t +SphincsPlusKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) +{ + return key_.priv.sign(&ctx.rng, &sig.sphincsplus, hash.data(), hash.size()); +} + +pgp_hash_alg_t +SphincsPlusKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +{ + return sphincsplus_default_hash_alg(alg_, key_.pub.param()); +} + +bool +SphincsPlusKeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const +{ + return key_.pub.validate_signature_hash_requirements(hash); +} + +size_t +SphincsPlusKeyMaterial::bits() const noexcept +{ + return 8 * pub().get_encoded().size(); /* public key length */ +} + +const pgp_sphincsplus_public_key_t & +SphincsPlusKeyMaterial::pub() const noexcept +{ + return key_.pub; +} + +const pgp_sphincsplus_private_key_t & +SphincsPlusKeyMaterial::priv() const noexcept +{ + return key_.priv; +} +#endif + +} // namespace pgp diff --git a/src/lib/key_material.hpp b/src/lib/key_material.hpp new file mode 100644 index 0000000000..62049d65f7 --- /dev/null +++ b/src/lib/key_material.hpp @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_KEY_MATERIAL_HPP_ +#define RNP_KEY_MATERIAL_HPP_ + +#include "types.h" + +typedef struct pgp_packet_body_t pgp_packet_body_t; +typedef struct rnp_keygen_crypto_params_t rnp_keygen_crypto_params_t; +typedef struct pgp_encrypted_material_t pgp_encrypted_material_t; +typedef struct pgp_signature_material_t pgp_signature_material_t; + +namespace pgp { +class KeyMaterial { + pgp_validity_t validity_; /* key material validation status */ + protected: + pgp_pubkey_alg_t alg_; /* algorithm of the key */ + bool secret_; /* secret part of the key material is populated */ + + virtual void grip_update(rnp::Hash &hash) const = 0; + virtual bool validate_material(rnp::SecurityContext &ctx, bool reset = true) = 0; + bool finish_generate(); + + public: + KeyMaterial(pgp_pubkey_alg_t kalg = PGP_PKA_NOTHING, bool secret = false) + : validity_({}), alg_(kalg), secret_(secret){}; + virtual ~KeyMaterial(); + virtual std::unique_ptr clone() = 0; + + pgp_pubkey_alg_t alg() const noexcept; + bool secret() const noexcept; + void validate(rnp::SecurityContext &ctx, bool reset = true); + const pgp_validity_t &validity() const noexcept; + void set_validity(const pgp_validity_t &val); + void reset_validity(); + bool valid() const; + virtual bool equals(const KeyMaterial &value) noexcept; + virtual void clear_secret(); + virtual bool parse(pgp_packet_body_t &pkt) noexcept = 0; + virtual bool parse_secret(pgp_packet_body_t &pkt) noexcept = 0; + virtual void write(pgp_packet_body_t &pkt) = 0; + virtual void write_secret(pgp_packet_body_t &pkt) = 0; + virtual bool generate(const rnp_keygen_crypto_params_t ¶ms); + virtual rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len); + virtual rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in); + virtual rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const; + virtual rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash); + + /* Pick up hash algorithm, used for signing, to be compatible with key material. */ + virtual pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const; + virtual bool sig_hash_allowed(pgp_hash_alg_t hash) const; + virtual size_t bits() const noexcept = 0; + virtual pgp_curve_t curve() const noexcept; + pgp_key_grip_t grip() const; + + static std::unique_ptr create(pgp_pubkey_alg_t alg); + static std::unique_ptr create(pgp_pubkey_alg_t alg, const pgp_rsa_key_t &key); + static std::unique_ptr create(const pgp_dsa_key_t &key); + static std::unique_ptr create(pgp_pubkey_alg_t alg, const pgp_eg_key_t &key); + static std::unique_ptr create(pgp_pubkey_alg_t alg, const pgp_ec_key_t &key); +}; + +class RSAKeyMaterial : public KeyMaterial { + protected: + pgp_rsa_key_t key_; + + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + RSAKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + RSAKeyMaterial(pgp_pubkey_alg_t kalg, const pgp_rsa_key_t &key, bool secret = false) + : KeyMaterial(kalg, secret), key_(key){}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) override; + rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + + void set_secret(const mpi &d, const mpi &p, const mpi &q, const mpi &u); + size_t bits() const noexcept override; + + const mpi &n() const noexcept; + const mpi &e() const noexcept; + const mpi &d() const noexcept; + const mpi &p() const noexcept; + const mpi &q() const noexcept; + const mpi &u() const noexcept; +}; + +class DSAKeyMaterial : public KeyMaterial { + protected: + pgp_dsa_key_t key_; + + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + DSAKeyMaterial() : KeyMaterial(PGP_PKA_DSA), key_{} {}; + DSAKeyMaterial(const pgp_dsa_key_t &key, bool secret = false) + : KeyMaterial(PGP_PKA_DSA, secret), key_(key){}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; + void set_secret(const mpi &x); + size_t bits() const noexcept override; + size_t qbits() const noexcept; + + const mpi &p() const noexcept; + const mpi &q() const noexcept; + const mpi &g() const noexcept; + const mpi &y() const noexcept; + const mpi &x() const noexcept; +}; + +class EGKeyMaterial : public KeyMaterial { + protected: + pgp_eg_key_t key_; + + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + EGKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + EGKeyMaterial(pgp_pubkey_alg_t kalg, const pgp_eg_key_t &key, bool secret = false) + : KeyMaterial(kalg, secret), key_(key){}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) override; + rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + + void set_secret(const mpi &x); + size_t bits() const noexcept override; + + const mpi &p() const noexcept; + const mpi &g() const noexcept; + const mpi &y() const noexcept; + const mpi &x() const noexcept; +}; + +class ECKeyMaterial : public KeyMaterial { + protected: + pgp_ec_key_t key_; + + void grip_update(rnp::Hash &hash) const override; + rnp_result_t check_curve(size_t hash_len); + + public: + ECKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + ECKeyMaterial(pgp_pubkey_alg_t kalg, const pgp_ec_key_t &key, bool secret = false) + : KeyMaterial(kalg, secret), key_(key){}; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + void set_secret(const mpi &x); + size_t bits() const noexcept override; + pgp_curve_t curve() const noexcept override; + + const mpi &p() const noexcept; + const mpi &x() const noexcept; +}; + +class ECDSAKeyMaterial : public ECKeyMaterial { + protected: + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + ECDSAKeyMaterial() : ECKeyMaterial(PGP_PKA_ECDSA){}; + ECDSAKeyMaterial(const pgp_ec_key_t &key, bool secret = false) + : ECKeyMaterial(PGP_PKA_ECDSA, key, secret){}; + std::unique_ptr clone() override; + + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; +}; + +class ECDHKeyMaterial : public ECKeyMaterial { + protected: + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + ECDHKeyMaterial() : ECKeyMaterial(PGP_PKA_ECDH){}; + ECDHKeyMaterial(const pgp_ec_key_t &key, bool secret = false) + : ECKeyMaterial(PGP_PKA_ECDH, key, secret){}; + std::unique_ptr clone() override; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) override; + rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) override; + + pgp_hash_alg_t kdf_hash_alg() const noexcept; + pgp_symm_alg_t key_wrap_alg() const noexcept; + bool x25519_bits_tweaked() const noexcept; + bool x25519_tweak_bits() noexcept; +}; + +class EDDSAKeyMaterial : public ECKeyMaterial { + protected: + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + EDDSAKeyMaterial() : ECKeyMaterial(PGP_PKA_EDDSA){}; + EDDSAKeyMaterial(const pgp_ec_key_t &key, bool secret = false) + : ECKeyMaterial(PGP_PKA_EDDSA, key, secret){}; + std::unique_ptr clone() override; + + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; +}; + +class SM2KeyMaterial : public ECKeyMaterial { + protected: + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + SM2KeyMaterial() : ECKeyMaterial(PGP_PKA_SM2){}; + SM2KeyMaterial(const pgp_ec_key_t &key, bool secret = false) + : ECKeyMaterial(PGP_PKA_SM2, key, secret){}; + std::unique_ptr clone() override; + + rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) override; + rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + void compute_za(rnp::Hash &hash) const; +}; + +#if defined(ENABLE_CRYPTO_REFRESH) +class Ed25519KeyMaterial : public KeyMaterial { + pgp_ed25519_key_t key_; + + protected: + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + Ed25519KeyMaterial() : KeyMaterial(PGP_PKA_ED25519), key_{} {}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + size_t bits() const noexcept override; + pgp_curve_t curve() const noexcept override; + + const std::vector &pub() const noexcept; + const std::vector &priv() const noexcept; +}; + +class X25519KeyMaterial : public KeyMaterial { + pgp_x25519_key_t key_; + + protected: + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + X25519KeyMaterial() : KeyMaterial(PGP_PKA_X25519), key_{} {}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) override; + rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) override; + size_t bits() const noexcept override; + pgp_curve_t curve() const noexcept override; + + const std::vector &pub() const noexcept; + const std::vector &priv() const noexcept; +}; +#endif + +#if defined(ENABLE_PQC) +class KyberKeyMaterial : public KeyMaterial { + pgp_kyber_ecdh_key_t key_; + + protected: + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + KyberKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) override; + rnp_result_t decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) override; + size_t bits() const noexcept override; + + const pgp_kyber_ecdh_composite_public_key_t & pub() const noexcept; + const pgp_kyber_ecdh_composite_private_key_t &priv() const noexcept; +}; + +class DilithiumKeyMaterial : public KeyMaterial { + pgp_dilithium_exdsa_key_t key_; + + protected: + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + DilithiumKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + std::unique_ptr clone() override; + + /** @brief Check two key material for equality. Only public part is checked, so this may be + * called on public/secret key material */ + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; + size_t bits() const noexcept override; + + const pgp_dilithium_exdsa_composite_public_key_t & pub() const noexcept; + const pgp_dilithium_exdsa_composite_private_key_t &priv() const noexcept; +}; + +class SphincsPlusKeyMaterial : public KeyMaterial { + pgp_sphincsplus_key_t key_; + + protected: + void grip_update(rnp::Hash &hash) const override; + bool validate_material(rnp::SecurityContext &ctx, bool reset) override; + + public: + SphincsPlusKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + std::unique_ptr clone() override; + + bool equals(const KeyMaterial &value) noexcept override; + void clear_secret() override; + bool parse(pgp_packet_body_t &pkt) noexcept override; + bool parse_secret(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) override; + void write_secret(pgp_packet_body_t &pkt) override; + bool generate(const rnp_keygen_crypto_params_t ¶ms) override; + rnp_result_t verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) override; + pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; + bool sig_hash_allowed(pgp_hash_alg_t hash) const override; + size_t bits() const noexcept override; + + const pgp_sphincsplus_public_key_t & pub() const noexcept; + const pgp_sphincsplus_private_key_t &priv() const noexcept; +}; +#endif +} // namespace pgp + +#endif // RNP_KEY_MATERIAL_HPP_ \ No newline at end of file From f222110af1c5b82314de88e90ef6534083486c75 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Wed, 1 May 2024 11:45:05 +0300 Subject: [PATCH 2/8] Use pgp::KeyMaterial instead of pgp_key_material_t. --- src/lib/crypto.cpp | 278 +------- src/lib/crypto.h | 12 - src/lib/crypto/dsa.h | 11 + src/lib/crypto/ec.h | 36 + src/lib/crypto/ecdh.cpp | 2 +- src/lib/crypto/ecdh.h | 7 +- src/lib/crypto/elgamal.h | 11 + src/lib/crypto/rsa.h | 14 + src/lib/crypto/signatures.cpp | 265 +------ src/lib/crypto/signatures.h | 5 +- src/lib/fingerprint.cpp | 12 +- src/lib/key_material.cpp | 4 +- src/lib/pgp-key.cpp | 403 +---------- src/lib/pgp-key.h | 23 +- src/lib/rnp.cpp | 120 ++-- src/lib/types.h | 35 +- src/librekey/g23_sexp.hpp | 2 +- src/librekey/key_store_g10.cpp | 262 ++++--- src/librepgp/stream-dump.cpp | 379 +++++----- src/librepgp/stream-key.cpp | 501 +------------- src/librepgp/stream-key.h | 9 +- src/librepgp/stream-parse.cpp | 95 +-- src/librepgp/stream-write.cpp | 111 +-- src/tests/cipher.cpp | 655 ++++++++++-------- src/tests/cli_tests.py | 2 +- .../data/test_key_validity/case5/generate.cpp | 2 +- src/tests/key-protect.cpp | 82 ++- src/tests/key-unlock.cpp | 13 +- src/tests/load-pgp.cpp | 6 +- 29 files changed, 1061 insertions(+), 2296 deletions(-) diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index a6f4a0ff40..a9a33b6968 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -95,135 +95,18 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, #endif seckey.creation_time = crypto.ctx->time(); seckey.alg = crypto.key_alg; - seckey.material.alg = crypto.key_alg; + seckey.material = pgp::KeyMaterial::create(crypto.key_alg); + if (!seckey.material) { + RNP_LOG("Unsupported key algorithm: %d", crypto.key_alg); + return false; + } seckey.tag = primary ? PGP_PKT_SECRET_KEY : PGP_PKT_SECRET_SUBKEY; - switch (seckey.alg) { - case PGP_PKA_RSA: - if (rsa_generate(&crypto.ctx->rng, &seckey.material.rsa, crypto.rsa.modulus_bit_len)) { - RNP_LOG("failed to generate RSA key"); - return false; - } - break; - case PGP_PKA_DSA: - if (dsa_generate(&crypto.ctx->rng, - &seckey.material.dsa, - crypto.dsa.p_bitlen, - crypto.dsa.q_bitlen)) { - RNP_LOG("failed to generate DSA key"); - return false; - } - break; - case PGP_PKA_EDDSA: - if (eddsa_generate(&crypto.ctx->rng, &seckey.material.ec)) { - RNP_LOG("failed to generate EDDSA key"); - return false; - } - break; - case PGP_PKA_ECDH: - if (!ecdh_set_params(&seckey.material.ec, crypto.ecc.curve)) { - RNP_LOG("Unsupported curve [ID=%d]", crypto.ecc.curve); - return false; - } - if (crypto.ecc.curve == PGP_CURVE_25519) { - if (x25519_generate(&crypto.ctx->rng, &seckey.material.ec)) { - RNP_LOG("failed to generate x25519 key"); - return false; - } - seckey.material.ec.curve = crypto.ecc.curve; - break; - } - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - if (!curve_supported(crypto.ecc.curve)) { - RNP_LOG("EC generate: curve %d is not supported.", (int) crypto.ecc.curve); - return false; - } - if (ec_generate(&crypto.ctx->rng, &seckey.material.ec, seckey.alg, crypto.ecc.curve)) { - RNP_LOG("failed to generate EC key"); - return false; - } - seckey.material.ec.curve = crypto.ecc.curve; - break; - case PGP_PKA_ELGAMAL: - if (elgamal_generate( - &crypto.ctx->rng, &seckey.material.eg, crypto.elgamal.key_bitlen)) { - RNP_LOG("failed to generate ElGamal key"); - return false; - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - if (generate_ed25519_native(&crypto.ctx->rng, - seckey.material.ed25519.priv, - seckey.material.ed25519.pub) != RNP_SUCCESS) { - RNP_LOG("failed to generate ED25519 key"); - return false; - } - break; - case PGP_PKA_X25519: - if (generate_x25519_native(&crypto.ctx->rng, - seckey.material.x25519.priv, - seckey.material.x25519.pub) != RNP_SUCCESS) { - RNP_LOG("failed to generate X25519 key"); - return false; - } - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - if (pgp_kyber_ecdh_composite_key_t::gen_keypair( - &crypto.ctx->rng, &seckey.material.kyber_ecdh, seckey.alg)) { - RNP_LOG("failed to generate MLKEM-ECDH-composite key for PK alg %d", seckey.alg); - return false; - } - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - if (pgp_dilithium_exdsa_composite_key_t::gen_keypair( - &crypto.ctx->rng, &seckey.material.dilithium_exdsa, seckey.alg)) { - RNP_LOG("failed to generate mldsa-ecdsa/eddsa-composite key for PK alg %d", - seckey.alg); - return false; - } - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - if (pgp_sphincsplus_generate(&crypto.ctx->rng, - &seckey.material.sphincsplus, - crypto.sphincsplus.param, - seckey.alg)) { - RNP_LOG("failed to generate SLH-DSA key for PK alg %d", seckey.alg); - return false; - } - break; -#endif - default: - RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); + if (!seckey.material->generate(crypto)) { return false; } + seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; - seckey.material.secret = true; - seckey.material.validity.mark_valid(); /* fill the sec_data/sec_len */ if (encrypt_secret_key(&seckey, NULL, crypto.ctx->rng)) { RNP_LOG("failed to fill sec_data"); @@ -231,150 +114,3 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, } return true; } - -bool -key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2) -{ - if (key1->alg != key2->alg) { - return false; - } - - switch (key1->alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return (key1->rsa.n == key2->rsa.n) && (key1->rsa.e == key2->rsa.e); - case PGP_PKA_DSA: - return (key1->dsa.p == key2->dsa.p) && (key1->dsa.q == key2->dsa.q) && - (key1->dsa.g == key2->dsa.g) && (key1->dsa.y == key2->dsa.y); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return (key1->eg.p == key2->eg.p) && (key1->eg.g == key2->eg.g) && - (key1->eg.y == key2->eg.y); - case PGP_PKA_EDDSA: - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - return (key1->ec.curve == key2->ec.curve) && (key1->ec.p == key2->ec.p); -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return (key1->ed25519.pub == key2->ed25519.pub); - case PGP_PKA_X25519: - return (key1->x25519.pub == key2->x25519.pub); -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return (key1->kyber_ecdh.pub == key2->kyber_ecdh.pub); - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return (key1->dilithium_exdsa.pub == key2->dilithium_exdsa.pub); - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return (key1->sphincsplus.pub == key2->sphincsplus.pub); -#endif - default: - RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); - return false; - } -} - -rnp_result_t -validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) -{ -#ifdef FUZZERS_ENABLED - /* do not timeout on large keys during fuzzing */ - return RNP_SUCCESS; -#else - switch (material->alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return rsa_validate_key(rng, &material->rsa, material->secret); - case PGP_PKA_DSA: - return dsa_validate_key(rng, &material->dsa, material->secret); - case PGP_PKA_EDDSA: - return eddsa_validate_key(rng, &material->ec, material->secret); - case PGP_PKA_ECDH: - if (!curve_supported(material->ec.curve)) { - /* allow to import key if curve is not supported */ - RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve); - return RNP_SUCCESS; - } - return ecdh_validate_key(rng, &material->ec, material->secret); - case PGP_PKA_ECDSA: - if (!curve_supported(material->ec.curve)) { - /* allow to import key if curve is not supported */ - RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve); - return RNP_SUCCESS; - } - return ecdsa_validate_key(rng, &material->ec, material->secret); - case PGP_PKA_SM2: -#if defined(ENABLE_SM2) - return sm2_validate_key(rng, &material->ec, material->secret); -#else - RNP_LOG("SM2 key validation is not available."); - return RNP_ERROR_NOT_IMPLEMENTED; -#endif - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return elgamal_validate_key(&material->eg, material->secret) ? RNP_SUCCESS : - RNP_ERROR_GENERIC; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return ed25519_validate_key_native(rng, &material->ed25519, material->secret); - case PGP_PKA_X25519: - return x25519_validate_key_native(rng, &material->x25519, material->secret); -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return kyber_ecdh_validate_key(rng, &material->kyber_ecdh, material->secret); - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return dilithium_exdsa_validate_key(rng, &material->dilithium_exdsa, material->secret); - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return sphincsplus_validate_key(rng, &material->sphincsplus, material->secret); -#endif - default: - RNP_LOG("unknown public key algorithm: %d", (int) material->alg); - } - - return RNP_ERROR_BAD_PARAMETERS; -#endif -} diff --git a/src/lib/crypto.h b/src/lib/crypto.h index 4fd1f81d89..47346f0f06 100644 --- a/src/lib/crypto.h +++ b/src/lib/crypto.h @@ -104,16 +104,4 @@ bool pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, const pgp_password_provider_t &password_provider, pgp_key_store_format_t secformat); -/** - * @brief Check two key material for equality. Only public part is checked, so this can be - * called on public/secret key material - * - * @param key1 first key material - * @param key2 second key material - * @return true if both key materials are equal or false otherwise - */ -bool key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2); - -rnp_result_t validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng); - #endif /* CRYPTO_H_ */ diff --git a/src/lib/crypto/dsa.h b/src/lib/crypto/dsa.h index 52eaae3bb7..fe6d795cac 100644 --- a/src/lib/crypto/dsa.h +++ b/src/lib/crypto/dsa.h @@ -43,6 +43,17 @@ typedef struct pgp_dsa_key_t { pgp::mpi y; /* secret mpi */ pgp::mpi x; + + void + clear_secret() + { + x.forget(); + } + + ~pgp_dsa_key_t() + { + clear_secret(); + } } pgp_dsa_key_t; typedef struct pgp_dsa_signature_t { diff --git a/src/lib/crypto/ec.h b/src/lib/crypto/ec.h index 2b85844007..d96508dc87 100644 --- a/src/lib/crypto/ec.h +++ b/src/lib/crypto/ec.h @@ -35,6 +35,7 @@ #include #include "crypto/rng.h" #include "crypto/mpi.h" +#include "crypto/mem.h" #include #define MAX_CURVE_BIT_SIZE 521 // secp521r1 @@ -83,6 +84,17 @@ typedef struct pgp_ec_key_t { /* ecdh params */ pgp_hash_alg_t kdf_hash_alg; /* Hash used by kdf */ pgp_symm_alg_t key_wrap_alg; /* Symmetric algorithm used to wrap KEK*/ + + void + clear_secret() + { + x.forget(); + } + + ~pgp_ec_key_t() + { + clear_secret(); + } } pgp_ec_key_t; typedef struct pgp_ec_signature_t { @@ -94,6 +106,18 @@ typedef struct pgp_ec_signature_t { typedef struct pgp_ed25519_key_t { std::vector pub; // \ native encoding std::vector priv; // / + + void + clear_secret() + { + secure_clear(priv.data(), priv.size()); + priv.resize(0); + } + + ~pgp_ed25519_key_t() + { + clear_secret(); + } } pgp_ed25519_key_t; typedef struct pgp_ed25519_signature_t { @@ -103,6 +127,18 @@ typedef struct pgp_ed25519_signature_t { typedef struct pgp_x25519_key_t { std::vector pub; // \ native encoding std::vector priv; // / + + void + clear_secret() + { + secure_clear(priv.data(), priv.size()); + priv.resize(0); + } + + ~pgp_x25519_key_t() + { + clear_secret(); + } } pgp_x25519_key_t; typedef struct pgp_x25519_encrypted_t { diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index 024a759e0d..206e352a97 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -302,7 +302,7 @@ ecdh_decrypt_pkcs5(uint8_t * out, const pgp_ec_key_t * key, const pgp_fingerprint_t & fingerprint) { - if (!out_len || !in || !key || !key->x.bytes()) { + if (!out || !out_len || !in || !key || !key->x.bytes()) { return RNP_ERROR_BAD_PARAMETERS; } diff --git a/src/lib/crypto/ecdh.h b/src/lib/crypto/ecdh.h index 1ac35ccf79..ef9a00d7f4 100644 --- a/src/lib/crypto/ecdh.h +++ b/src/lib/crypto/ecdh.h @@ -41,9 +41,10 @@ typedef struct pgp_fingerprint_t pgp_fingerprint_t; typedef struct pgp_ecdh_encrypted_t { - pgp::mpi p; - uint8_t m[ECDH_WRAPPED_KEY_SIZE]; - size_t mlen; + pgp::mpi p; + uint8_t m[ECDH_WRAPPED_KEY_SIZE]; + size_t mlen; + const pgp_fingerprint_t *fp; } pgp_ecdh_encrypted_t; rnp_result_t ecdh_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret); diff --git a/src/lib/crypto/elgamal.h b/src/lib/crypto/elgamal.h index ce35a958a4..369022fc26 100644 --- a/src/lib/crypto/elgamal.h +++ b/src/lib/crypto/elgamal.h @@ -37,6 +37,17 @@ typedef struct pgp_eg_key_t { pgp::mpi y; /* secret mpi */ pgp::mpi x; + + void + clear_secret() + { + x.forget(); + } + + ~pgp_eg_key_t() + { + clear_secret(); + } } pgp_eg_key_t; typedef struct pgp_eg_signature_t { diff --git a/src/lib/crypto/rsa.h b/src/lib/crypto/rsa.h index 998742812e..9f8583cee1 100644 --- a/src/lib/crypto/rsa.h +++ b/src/lib/crypto/rsa.h @@ -44,6 +44,20 @@ typedef struct pgp_rsa_key_t { pgp::mpi p; pgp::mpi q; pgp::mpi u; + + void + clear_secret() + { + d.forget(); + p.forget(); + q.forget(); + u.forget(); + } + + ~pgp_rsa_key_t() + { + clear_secret(); + } } pgp_rsa_key_t; typedef struct pgp_rsa_signature_t { diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 1735c59572..71b623d089 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -42,11 +42,9 @@ * @param hdr literal packet header for attached signatures or NULL otherwise. * @return RNP_SUCCESS on success or some error otherwise */ -static void +static rnp::secure_vector signature_hash_finish(const pgp_signature_t & sig, rnp::Hash & hash, - uint8_t * hbuf, - size_t & hlen, const pgp_literal_hdr_t *hdr) { hash.add(sig.hashed_data, sig.hashed_len); @@ -86,7 +84,9 @@ signature_hash_finish(const pgp_signature_t & sig, default: break; } - hlen = hash.finish(hbuf); + rnp::secure_vector res(hash.size()); + hash.finish(res.data()); + return res; } std::unique_ptr @@ -100,46 +100,27 @@ signature_init(const pgp_key_pkt_t &key, const pgp_signature_t &sig) } #endif - if (key.material.alg == PGP_PKA_SM2) { -#if defined(ENABLE_SM2) - rnp_result_t r = sm2_compute_za(key.material.ec, *hash); - if (r != RNP_SUCCESS) { - RNP_LOG("failed to compute SM2 ZA field"); - throw rnp::rnp_exception(r); - } -#else - RNP_LOG("SM2 ZA computation not available"); - throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED); -#endif + if (key.material->alg() == PGP_PKA_SM2) { + auto &sm2 = dynamic_cast(*key.material); + sm2.compute_za(*hash); } return hash; } void signature_calculate(pgp_signature_t & sig, - pgp_key_material_t & seckey, + pgp::KeyMaterial & seckey, rnp::Hash & hash, rnp::SecurityContext & ctx, const pgp_literal_hdr_t *hdr) { - uint8_t hval[PGP_MAX_HASH_SIZE]; - size_t hlen = 0; - rnp_result_t ret = RNP_ERROR_GENERIC; - const pgp_hash_alg_t hash_alg = hash.alg(); - /* Finalize hash first, since function is required to do this */ - try { - signature_hash_finish(sig, hash, hval, hlen, hdr); - } catch (const std::exception &e) { - RNP_LOG("Failed to finalize hash: %s", e.what()); - throw; - } - - if (!seckey.secret) { + auto hval = signature_hash_finish(sig, hash, hdr); + if (!seckey.secret()) { RNP_LOG("Secret key is required."); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - if (sig.palg != seckey.alg) { + if (sig.palg != seckey.alg()) { RNP_LOG("Signature and secret key do not agree on algorithm type."); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } @@ -150,131 +131,31 @@ signature_calculate(pgp_signature_t & sig, throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - /* copy left 16 bits to signature */ - memcpy(sig.lbits, hval, 2); + /* Copy left 16 bits to signature */ + memcpy(sig.lbits, hval.data(), 2); - /* sign */ pgp_signature_material_t material = {}; - switch (sig.palg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - ret = rsa_sign_pkcs1(&ctx.rng, &material.rsa, sig.halg, hval, hlen, &seckey.rsa); - if (ret) { - RNP_LOG("rsa signing failed"); - } - break; - case PGP_PKA_EDDSA: - ret = eddsa_sign(&ctx.rng, &material.ecc, hval, hlen, &seckey.ec); - if (ret) { - RNP_LOG("eddsa signing failed"); - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - ret = - ed25519_sign_native(&ctx.rng, material.ed25519.sig, seckey.ed25519.priv, hval, hlen); - if (ret) { - RNP_LOG("ed25519 signing failed"); - } - break; -#endif - case PGP_PKA_DSA: - ret = dsa_sign(&ctx.rng, &material.dsa, hval, hlen, &seckey.dsa); - if (ret != RNP_SUCCESS) { - RNP_LOG("DSA signing failed"); - } - break; - /* - * ECDH is signed with ECDSA. This must be changed when ECDH will support - * X25519, but I need to check how it should be done exactly. - */ - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: { - const ec_curve_desc_t *curve = get_curve_desc(seckey.ec.curve); - if (!curve) { - RNP_LOG("Unknown curve"); - ret = RNP_ERROR_BAD_PARAMETERS; - break; - } - if (!curve_supported(seckey.ec.curve)) { - RNP_LOG("EC sign: curve %s is not supported.", curve->pgp_name); - ret = RNP_ERROR_NOT_SUPPORTED; - break; - } - /* "-2" because ECDSA on P-521 must work with SHA-512 digest */ - if (BITS_TO_BYTES(curve->bitlen) - 2 > hlen) { - RNP_LOG("Message hash too small"); - ret = RNP_ERROR_BAD_PARAMETERS; - break; - } - - if (sig.palg == PGP_PKA_SM2) { -#if defined(ENABLE_SM2) - ret = sm2_sign(&ctx.rng, &material.ecc, hash_alg, hval, hlen, &seckey.ec); - if (ret) { - RNP_LOG("SM2 signing failed"); - } -#else - RNP_LOG("SM2 signing is not available."); - ret = RNP_ERROR_NOT_IMPLEMENTED; -#endif - break; - } + /* Some algos require used hash algorithm for signing */ + material.halg = sig.halg; + /* Sign */ + auto ret = seckey.sign(ctx, material, hval); - ret = ecdsa_sign(&ctx.rng, &material.ecc, hash_alg, hval, hlen, &seckey.ec); - if (ret) { - RNP_LOG("ECDSA signing failed"); - } - break; - } -#if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - ret = seckey.dilithium_exdsa.priv.sign( - &ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - ret = seckey.sphincsplus.priv.sign(&ctx.rng, &material.sphincsplus, hval, hlen); - break; -#endif - default: - RNP_LOG("Unsupported algorithm %d", sig.palg); - break; - } if (ret) { throw rnp::rnp_exception(ret); } - try { - sig.write_material(material); - } catch (const std::exception &e) { - RNP_LOG("%s", e.what()); - throw; - } + sig.write_material(material); } rnp_result_t signature_validate(const pgp_signature_t & sig, - const pgp_key_material_t & key, + const pgp::KeyMaterial & key, rnp::Hash & hash, const rnp::SecurityContext &ctx, const pgp_literal_hdr_t * hdr) { - if (sig.palg != key.alg) { - RNP_LOG("Signature and key do not agree on algorithm type: %d vs %d", - (int) sig.palg, - (int) key.alg); + if (sig.palg != key.alg()) { + RNP_LOG( + "Signature and key do not agree on algorithm type: %d vs %d", sig.palg, key.alg()); return RNP_ERROR_BAD_PARAMETERS; } @@ -289,18 +170,7 @@ signature_validate(const pgp_signature_t & sig, #if defined(ENABLE_PQC) /* check that hash matches key requirements */ - bool hash_alg_valid = false; - switch (key.alg) { - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - hash_alg_valid = key.sphincsplus.pub.validate_signature_hash_requirements(hash.alg()); - break; - default: - hash_alg_valid = true; - break; - } - if (!hash_alg_valid) { + if (!key.sig_hash_allowed(hash.alg())) { RNP_LOG("Signature invalid since hash algorithm requirements are not met for the " "given key."); return RNP_ERROR_SIGNATURE_INVALID; @@ -308,94 +178,19 @@ signature_validate(const pgp_signature_t & sig, #endif /* Finalize hash */ - uint8_t hval[PGP_MAX_HASH_SIZE]; - size_t hlen = 0; - try { - signature_hash_finish(sig, hash, hval, hlen, hdr); - } catch (const std::exception &e) { - RNP_LOG("Failed to finalize signature hash."); - return RNP_ERROR_GENERIC; - } + auto hval = signature_hash_finish(sig, hash, hdr); /* compare lbits */ - if (memcmp(hval, sig.lbits, 2)) { + if (memcmp(hval.data(), sig.lbits, 2)) { RNP_LOG("wrong lbits"); return RNP_ERROR_SIGNATURE_INVALID; } /* validate signature */ pgp_signature_material_t material = {}; - try { - sig.parse_material(material); - } catch (const std::exception &e) { - RNP_LOG("%s", e.what()); - return RNP_ERROR_OUT_OF_MEMORY; - } - rnp_result_t ret = RNP_ERROR_GENERIC; - switch (sig.palg) { - case PGP_PKA_DSA: - ret = dsa_verify(&material.dsa, hval, hlen, &key.dsa); - break; - case PGP_PKA_EDDSA: - ret = eddsa_verify(&material.ecc, hval, hlen, &key.ec); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - ret = ed25519_verify_native(material.ed25519.sig, key.ed25519.pub, hval, hlen); - break; -#endif - case PGP_PKA_SM2: -#if defined(ENABLE_SM2) - ret = sm2_verify(&material.ecc, hash.alg(), hval, hlen, &key.ec); -#else - RNP_LOG("SM2 verification is not available."); - ret = RNP_ERROR_NOT_IMPLEMENTED; -#endif - break; - case PGP_PKA_RSA: - case PGP_PKA_RSA_SIGN_ONLY: - ret = rsa_verify_pkcs1(&material.rsa, sig.halg, hval, hlen, &key.rsa); - break; - case PGP_PKA_RSA_ENCRYPT_ONLY: - RNP_LOG("RSA encrypt-only signature considered as invalid."); - ret = RNP_ERROR_SIGNATURE_INVALID; - break; - case PGP_PKA_ECDSA: - if (!curve_supported(key.ec.curve)) { - RNP_LOG("ECDSA verify: curve %d is not supported.", (int) key.ec.curve); - ret = RNP_ERROR_NOT_SUPPORTED; - break; - } - ret = ecdsa_verify(&material.ecc, hash.alg(), hval, hlen, &key.ec); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - RNP_LOG("ElGamal are considered as invalid."); - ret = RNP_ERROR_SIGNATURE_INVALID; - break; -#if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - ret = - key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - ret = key.sphincsplus.pub.verify(&material.sphincsplus, hval, hlen); - break; -#endif - default: - RNP_LOG("Unknown algorithm"); - ret = RNP_ERROR_BAD_PARAMETERS; - } - return ret; + /* We check whether material could be parsed during the signature parsing */ + sig.parse_material(material); + material.halg = sig.halg; + + return key.verify(ctx, material, hval); } diff --git a/src/lib/crypto/signatures.h b/src/lib/crypto/signatures.h index 3cba7cc4ff..58c1735f2d 100644 --- a/src/lib/crypto/signatures.h +++ b/src/lib/crypto/signatures.h @@ -28,6 +28,7 @@ #define RNP_SIGNATURES_H_ #include "crypto/hash.hpp" +#include "key_material.hpp" /** * @brief Initialize a signature computation. @@ -48,7 +49,7 @@ std::unique_ptr signature_init(const pgp_key_pkt_t & key, * @param hdr literal packet header for attached document signatures or NULL otherwise. */ void signature_calculate(pgp_signature_t & sig, - pgp_key_material_t & seckey, + pgp::KeyMaterial & seckey, rnp::Hash & hash, rnp::SecurityContext & ctx, const pgp_literal_hdr_t *hdr = NULL); @@ -66,7 +67,7 @@ void signature_calculate(pgp_signature_t & sig, * @return RNP_SUCCESS if signature was successfully validated or error code otherwise. */ rnp_result_t signature_validate(const pgp_signature_t & sig, - const pgp_key_material_t & key, + const pgp::KeyMaterial & key, rnp::Hash & hash, const rnp::SecurityContext &ctx, const pgp_literal_hdr_t * hdr = NULL); diff --git a/src/lib/fingerprint.cpp b/src/lib/fingerprint.cpp index b503a13563..1b77416e2d 100644 --- a/src/lib/fingerprint.cpp +++ b/src/lib/fingerprint.cpp @@ -48,9 +48,10 @@ try { RNP_LOG("bad algorithm"); return RNP_ERROR_NOT_SUPPORTED; } - auto hash = rnp::Hash::create(PGP_HASH_MD5); - hash->add(key.material.rsa.n); - hash->add(key.material.rsa.e); + auto &rsa = dynamic_cast(*key.material); + auto hash = rnp::Hash::create(PGP_HASH_MD5); + hash->add(rsa.n()); + hash->add(rsa.e()); fp.length = hash->finish(fp.fingerprint); return RNP_SUCCESS; } @@ -92,8 +93,9 @@ pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key) RNP_LOG("bad algorithm"); return RNP_ERROR_NOT_SUPPORTED; } - size_t n = key.material.rsa.n.bytes(); - (void) memcpy(keyid.data(), key.material.rsa.n.mpi + n - keyid.size(), keyid.size()); + auto & rsa = dynamic_cast(*key.material); + size_t n = rsa.n().bytes(); + (void) memcpy(keyid.data(), rsa.n().mpi + n - keyid.size(), keyid.size()); return RNP_SUCCESS; } case PGP_V4: diff --git a/src/lib/key_material.cpp b/src/lib/key_material.cpp index b660434bcb..ba921bcd94 100644 --- a/src/lib/key_material.cpp +++ b/src/lib/key_material.cpp @@ -302,7 +302,7 @@ KeyMaterial::create(pgp_pubkey_alg_t alg) #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448 case PGP_PKA_KYBER768_P256: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: @@ -313,7 +313,7 @@ KeyMaterial::create(pgp_pubkey_alg_t alg) return std::unique_ptr(new KyberKeyMaterial(alg)); case PGP_PKA_DILITHIUM3_ED25519: FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448 case PGP_PKA_DILITHIUM3_P256: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 83f792ece9..ab8f1ad61e 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -478,48 +478,6 @@ find_suitable_key(pgp_op_t op, pgp_key_t *key, rnp::KeyProvider *key_provider, b return subkey; } -pgp_hash_alg_t -pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey) -{ -#if defined(ENABLE_PQC) - switch (pubkey->alg) { - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return sphincsplus_default_hash_alg(pubkey->alg, - pubkey->material.sphincsplus.pub.param()); - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return dilithium_default_hash_alg(); - default: - break; - } -#endif - - if ((pubkey->alg != PGP_PKA_DSA) && (pubkey->alg != PGP_PKA_ECDSA)) { - return hash; - } - - pgp_hash_alg_t hash_min; - if (pubkey->alg == PGP_PKA_ECDSA) { - hash_min = ecdsa_get_min_hash(pubkey->material.ec.curve); - } else { - hash_min = dsa_get_min_hash(pubkey->material.dsa.q.bits()); - } - - if (rnp::Hash::size(hash) < rnp::Hash::size(hash_min)) { - return hash_min; - } - return hash; -} - static void bytevec_append_uniq(std::vector &vec, uint8_t val) { @@ -790,13 +748,13 @@ pgp_revoke_t::pgp_revoke_t(pgp_subsig_t &sig) pgp_key_t::pgp_key_t(const pgp_key_pkt_t &keypkt) : pkt_(keypkt) { - if (!is_key_pkt(pkt_.tag) || !pkt_.material.alg) { + if (!is_key_pkt(pkt_.tag) || !pkt_.material->alg()) { throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - if (pgp_keyid(keyid_, pkt_) || pgp_fingerprint(fingerprint_, pkt_) || - !pkt_.material.get_grip(grip_)) { + if (pgp_keyid(keyid_, pkt_) || pgp_fingerprint(fingerprint_, pkt_)) { throw rnp::rnp_exception(RNP_ERROR_GENERIC); } + grip_ = pkt_.material->grip(); /* parse secret key if not encrypted */ if (is_secret_key_pkt(pkt_.tag)) { @@ -806,7 +764,7 @@ pgp_key_t::pgp_key_t(const pgp_key_pkt_t &keypkt) : pkt_(keypkt) throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } /* decryption resets validity */ - pkt_.material.validity = keypkt.material.validity; + pkt_.material->set_validity(keypkt.material->validity()); } /* add rawpacket */ rawpkt_ = pgp_rawpacket_t(pkt_); @@ -1234,10 +1192,22 @@ pgp_key_t::set_pkt(const pgp_key_pkt_t &pkt) pkt_ = pkt; } -pgp_key_material_t & +const pgp::KeyMaterial & +pgp_key_t::material() const +{ + if (!pkt_.material) { + throw rnp::rnp_exception(RNP_ERROR_NULL_POINTER); + } + return *pkt_.material; +} + +pgp::KeyMaterial & pgp_key_t::material() { - return pkt_.material; + if (!pkt_.material) { + throw rnp::rnp_exception(RNP_ERROR_NULL_POINTER); + } + return *pkt_.material; } pgp_pubkey_alg_t @@ -1249,21 +1219,7 @@ pgp_key_t::alg() const pgp_curve_t pgp_key_t::curve() const { - switch (alg()) { - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return pkt_.material.ec.curve; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return PGP_CURVE_ED25519; - case PGP_PKA_X25519: - return PGP_CURVE_25519; -#endif - default: - return PGP_CURVE_UNKNOWN; - } + return material().curve(); } pgp_version_t @@ -1281,7 +1237,7 @@ pgp_key_t::type() const bool pgp_key_t::encrypted() const { - return is_secret() && !pkt().material.secret; + return is_secret() && !material().secret(); } uint8_t @@ -1609,11 +1565,8 @@ pgp_key_t::unlock(const pgp_password_provider_t &provider, pgp_op_t op) return false; } - // this shouldn't really be necessary, but just in case - forget_secret_key_fields(&pkt_.material); - // copy the decrypted mpis into the pgp_key_t - pkt_.material = decrypted_seckey->material; - pkt_.material.secret = true; + // move the decrypted mpis into the pgp_key_t + pkt_.material = std::move(decrypted_seckey->material); delete decrypted_seckey; return true; } @@ -1632,7 +1585,7 @@ pgp_key_t::lock() return true; } - forget_secret_key_fields(&pkt_.material); + material().clear_secret(); return true; } @@ -1662,7 +1615,7 @@ pgp_key_t::protect(pgp_key_pkt_t & decrypted, return false; } bool ownpkt = &decrypted == &pkt_; - if (!decrypted.material.secret) { + if (!decrypted.material->secret()) { RNP_LOG("Decrypted secret key must be provided"); return false; } @@ -1723,7 +1676,7 @@ pgp_key_t::unprotect(const pgp_password_provider_t &password_provider, } pkt_ = std::move(*decrypted_seckey); /* current logic is that unprotected key should be additionally unlocked */ - forget_secret_key_fields(&pkt_.material); + material().clear_secret(); delete decrypted_seckey; return true; } @@ -2079,7 +2032,7 @@ pgp_key_t::validate_sig(pgp_signature_info_t & sinfo, /* Validate signature itself */ if (sinfo.signer_valid || valid_at(sinfo.sig->creation())) { - sinfo.valid = !signature_validate(*sinfo.sig, pkt_.material, hash, ctx, hdr); + sinfo.valid = !signature_validate(*sinfo.sig, *pkt_.material, hash, ctx, hdr); } else { sinfo.valid = false; RNP_LOG("invalid or untrusted key"); @@ -2453,7 +2406,7 @@ pgp_key_t::sign_init(rnp::RNG & rng, pgp_version_t version) const { sig.version = version; - sig.halg = pgp_hash_adjust_alg_to_key(hash, &pkt_); + sig.halg = pkt_.material->adjust_hash(hash); sig.palg = alg(); sig.set_keyfp(fp()); sig.set_creation(creation); @@ -2477,7 +2430,7 @@ pgp_key_t::sign_cert(const pgp_key_pkt_t & key, { sig.fill_hashed_data(); auto hash = signature_hash_certification(sig, key, uid); - signature_calculate(sig, pkt_.material, *hash, ctx); + signature_calculate(sig, *pkt_.material, *hash, ctx); } void @@ -2487,7 +2440,7 @@ pgp_key_t::sign_direct(const pgp_key_pkt_t & key, { sig.fill_hashed_data(); auto hash = signature_hash_direct(sig, key); - signature_calculate(sig, pkt_.material, *hash, ctx); + signature_calculate(sig, *pkt_.material, *hash, ctx); } void @@ -2498,7 +2451,7 @@ pgp_key_t::sign_binding(const pgp_key_pkt_t & key, sig.fill_hashed_data(); auto hash = is_primary() ? signature_hash_binding(sig, pkt(), key) : signature_hash_binding(sig, key, pkt()); - signature_calculate(sig, pkt_.material, *hash, ctx); + signature_calculate(sig, *pkt_.material, *hash, ctx); } void @@ -2882,9 +2835,9 @@ pgp_key_t::merge(const pgp_key_t &src) if (is_secret() && !is_locked()) { /* we may do thing below only because key material is opaque structure without * pointers! */ - tmpkey.pkt().material = pkt().material; + tmpkey.pkt().material = pkt().material->clone(); } else if (src.is_secret() && !src.is_locked()) { - tmpkey.pkt().material = src.pkt().material; + tmpkey.pkt().material = src.pkt().material->clone(); } /* copy validity status */ tmpkey.validity_ = validity_; @@ -2938,9 +2891,9 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) if (is_secret() && !is_locked()) { /* we may do thing below only because key material is opaque structure without * pointers! */ - tmpkey.pkt().material = pkt().material; + tmpkey.pkt().material = pkt().material->clone(); } else if (src.is_secret() && !src.is_locked()) { - tmpkey.pkt().material = src.pkt().material; + tmpkey.pkt().material = src.pkt().material->clone(); } /* copy validity status */ tmpkey.validity_ = validity_; @@ -2949,291 +2902,3 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) *this = std::move(tmpkey); return true; } - -pgp_curve_t -pgp_key_material_t::curve() const -{ - switch (alg) { - case PGP_PKA_ECDH: - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - FALLTHROUGH_STATEMENT; - case PGP_PKA_EDDSA: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SM2: - return ec.curve; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return PGP_CURVE_ED25519; - case PGP_PKA_X25519: - return PGP_CURVE_25519; -#endif - default: - return PGP_CURVE_UNKNOWN; - } -} - -size_t -pgp_key_material_t::bits() const -{ - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return 8 * rsa.n.bytes(); - case PGP_PKA_DSA: - return 8 * dsa.p.bytes(); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return 8 * eg.y.bytes(); - case PGP_PKA_ECDH: - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - FALLTHROUGH_STATEMENT; - case PGP_PKA_EDDSA: - FALLTHROUGH_STATEMENT; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - FALLTHROUGH_STATEMENT; - case PGP_PKA_X25519: - FALLTHROUGH_STATEMENT; -#endif - case PGP_PKA_SM2: { - /* handle ecc cases */ - const ec_curve_desc_t *curve_desc = get_curve_desc(curve()); - return curve_desc ? curve_desc->bitlen : 0; - } -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return 8 * kyber_ecdh.pub.get_encoded().size(); /* public key length */ - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return 8 * dilithium_exdsa.pub.get_encoded().size(); /* public key length*/ - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return 8 * sphincsplus.pub.get_encoded().size(); /* public key length */ -#endif - default: - RNP_LOG("Unknown public key alg: %d", (int) alg); - return 0; - } -} - -size_t -pgp_key_material_t::qbits() const -{ - if (alg != PGP_PKA_DSA) { - return 0; - } - return 8 * dsa.q.bytes(); -} - -void -pgp_key_material_t::validate(rnp::SecurityContext &ctx, bool reset) -{ - if (!reset && validity.validated) { - return; - } - validity.reset(); - validity.valid = !validate_pgp_key_material(this, &ctx.rng); - validity.validated = true; -} - -bool -pgp_key_material_t::valid() const -{ - return validity.validated && validity.valid; -} - -namespace { -void -grip_hash_mpi(rnp::Hash &hash, const pgp::mpi &val, const char name, bool lzero = true) -{ - size_t len = val.bytes(); - size_t idx = 0; - for (idx = 0; (idx < len) && !val.mpi[idx]; idx++) - ; - - if (name) { - size_t hlen = idx >= len ? 0 : len - idx; - if ((len > idx) && lzero && (val.mpi[idx] & 0x80)) { - hlen++; - } - - char buf[26] = {0}; - snprintf(buf, sizeof(buf), "(1:%c%zu:", name, hlen); - hash.add(buf, strlen(buf)); - } - - if (idx < len) { - /* gcrypt prepends mpis with zero if higher bit is set */ - if (lzero && (val.mpi[idx] & 0x80)) { - uint8_t zero = 0; - hash.add(&zero, 1); - } - hash.add(val.mpi + idx, len - idx); - } - if (name) { - hash.add(")", 1); - } -} - -void -grip_hash_ecc_hex(rnp::Hash &hash, const char *hex, char name) -{ - pgp::mpi mpi = {}; - mpi.len = rnp::hex_decode(hex, mpi.mpi, sizeof(mpi.mpi)); - if (!mpi.len) { - RNP_LOG("wrong hex mpi"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - - /* libgcrypt doesn't add leading zero when hashes ecc mpis */ - return grip_hash_mpi(hash, mpi, name, false); -} - -void -grip_hash_ec(rnp::Hash &hash, const pgp_ec_key_t &key) -{ - const ec_curve_desc_t *desc = get_curve_desc(key.curve); - if (!desc) { - RNP_LOG("unknown curve %d", (int) key.curve); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - - /* build uncompressed point from gx and gy */ - pgp::mpi g = {}; - g.mpi[0] = 0x04; - g.len = 1; - size_t len = rnp::hex_decode(desc->gx, g.mpi + g.len, sizeof(g.mpi) - g.len); - if (!len) { - RNP_LOG("wrong x mpi"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - g.len += len; - len = rnp::hex_decode(desc->gy, g.mpi + g.len, sizeof(g.mpi) - g.len); - if (!len) { - RNP_LOG("wrong y mpi"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - g.len += len; - - /* p, a, b, g, n, q */ - grip_hash_ecc_hex(hash, desc->p, 'p'); - grip_hash_ecc_hex(hash, desc->a, 'a'); - grip_hash_ecc_hex(hash, desc->b, 'b'); - grip_hash_mpi(hash, g, 'g', false); - grip_hash_ecc_hex(hash, desc->n, 'n'); - - if ((key.curve == PGP_CURVE_ED25519) || (key.curve == PGP_CURVE_25519)) { - if (g.len < 1) { - RNP_LOG("wrong 25519 p"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - g.len = key.p.len - 1; - memcpy(g.mpi, key.p.mpi + 1, g.len); - grip_hash_mpi(hash, g, 'q', false); - } else { - grip_hash_mpi(hash, key.p, 'q', false); - } -} -} // namespace - -/* keygrip is subjectKeyHash from pkcs#15 for RSA. */ -bool -pgp_key_material_t::get_grip(pgp_key_grip_t &grip) const -{ - try { - auto hash = rnp::Hash::create(PGP_HASH_SHA1); - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_SIGN_ONLY: - case PGP_PKA_RSA_ENCRYPT_ONLY: - grip_hash_mpi(*hash, rsa.n, '\0'); - break; - case PGP_PKA_DSA: - grip_hash_mpi(*hash, dsa.p, 'p'); - grip_hash_mpi(*hash, dsa.q, 'q'); - grip_hash_mpi(*hash, dsa.g, 'g'); - grip_hash_mpi(*hash, dsa.y, 'y'); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - grip_hash_mpi(*hash, eg.p, 'p'); - grip_hash_mpi(*hash, eg.g, 'g'); - grip_hash_mpi(*hash, eg.y, 'y'); - break; - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - grip_hash_ec(*hash, ec); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - // TODO: if GnuPG would ever support v6, check whether this works correctly. - case PGP_PKA_ED25519: - hash->add(ed25519.pub); - break; - case PGP_PKA_X25519: - hash->add(x25519.pub); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - hash->add(kyber_ecdh.pub.get_encoded()); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - hash->add(dilithium_exdsa.pub.get_encoded()); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - hash->add(sphincsplus.pub.get_encoded()); - break; -#endif - default: - RNP_LOG("unsupported public-key algorithm %d", (int) alg); - return false; - } - return hash->finish(grip.data()) == grip.size(); - } catch (const std::exception &e) { - RNP_LOG("Grip calculation failed: %s", e.what()); - return false; - } -} diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 62e94e113d..51ed91d8c5 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -211,11 +211,11 @@ struct pgp_key_t { size_t revoker_count() const; const pgp_fingerprint_t &get_revoker(size_t idx) const; - const pgp_key_pkt_t &pkt() const; - pgp_key_pkt_t & pkt(); - void set_pkt(const pgp_key_pkt_t &pkt); - - pgp_key_material_t &material(); + const pgp_key_pkt_t & pkt() const; + pgp_key_pkt_t & pkt(); + void set_pkt(const pgp_key_pkt_t &pkt); + const pgp::KeyMaterial &material() const; + pgp::KeyMaterial & material(); pgp_pubkey_alg_t alg() const; pgp_curve_t curve() const; @@ -689,17 +689,4 @@ pgp_key_t *find_suitable_key(pgp_op_t op, rnp::KeyProvider *key_provider, bool no_primary = false); -/* - * Picks up hash algorithm according to domain parameters set - * in `pubkey' and user provided hash. That's mostly because DSA - * and ECDSA needs special treatment. - * - * @param hash set by the caller - * @param pubkey initialized public key - * - * @returns hash algorithm that must be use for operation (mostly - signing with secure key which corresponds to 'pubkey') - */ -pgp_hash_alg_t pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey); - #endif // RNP_PACKET_KEY_H diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 7b7b96183b..ae20cdae4e 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -4160,7 +4160,8 @@ try { (seckey->curve() != PGP_CURVE_25519)) { return RNP_ERROR_BAD_PARAMETERS; } - *result = x25519_bits_tweaked(seckey->material().ec); + auto &material = dynamic_cast(seckey->material()); + *result = material.x25519_bits_tweaked(); return RNP_SUCCESS; } FFI_GUARD @@ -4176,7 +4177,8 @@ try { (seckey->curve() != PGP_CURVE_25519)) { return RNP_ERROR_BAD_PARAMETERS; } - if (!x25519_tweak_bits(seckey->pkt().material.ec)) { + auto &material = dynamic_cast(seckey->material()); + if (!material.x25519_tweak_bits()) { FFI_LOG(key->ffi, "Failed to tweak 25519 key bits."); return RNP_ERROR_BAD_STATE; } @@ -6846,8 +6848,8 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - return get_map_value( - sphincsplus_params_map, key->material().sphincsplus.pub.param(), param); + auto &material = dynamic_cast(key->material()); + return get_map_value(sphincsplus_params_map, material.pub().param(), param); } FFI_GUARD #endif @@ -6875,11 +6877,11 @@ try { return RNP_ERROR_NULL_POINTER; } pgp_key_t *key = get_key_prefer_public(handle); - size_t _qbits = key->material().qbits(); - if (!_qbits) { + auto material = dynamic_cast(&key->material()); + if (!material) { return RNP_ERROR_BAD_PARAMETERS; } - *qbits = _qbits; + *qbits = material->qbits(); return RNP_SUCCESS; } FFI_GUARD @@ -7692,25 +7694,46 @@ add_json_mpis(json_object *jso, ...) } static rnp_result_t -add_json_public_mpis(json_object *jso, pgp_key_t *key) +add_json_mpis(json_object *jso, pgp_key_t *key, bool secret = false) { - const pgp_key_material_t &km = key->material(); - switch (km.alg) { + auto &km = key->material(); + switch (km.alg()) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return add_json_mpis(jso, "n", &km.rsa.n, "e", &km.rsa.e, NULL); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return add_json_mpis(jso, "p", &km.eg.p, "g", &km.eg.g, "y", &km.eg.y, NULL); - case PGP_PKA_DSA: + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(km); + if (!secret) { + return add_json_mpis(jso, "n", &rsa.n(), "e", &rsa.e(), NULL); + } return add_json_mpis( - jso, "p", &km.dsa.p, "q", &km.dsa.q, "g", &km.dsa.g, "y", &km.dsa.y, NULL); + jso, "d", &rsa.d(), "p", &rsa.p(), "q", &rsa.q(), "u", &rsa.u(), NULL); + } + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(km); + if (!secret) { + return add_json_mpis(jso, "p", &eg.p(), "g", &eg.g(), "y", &eg.y(), NULL); + } + return add_json_mpis(jso, "x", &eg.x(), NULL); + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(km); + if (!secret) { + return add_json_mpis( + jso, "p", &dsa.p(), "q", &dsa.q(), "g", &dsa.g(), "y", &dsa.y(), NULL); + } + return add_json_mpis(jso, "x", &dsa.x(), NULL); + } case PGP_PKA_ECDH: case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return add_json_mpis(jso, "point", &km.ec.p, NULL); + case PGP_PKA_SM2: { + auto &ec = dynamic_cast(km); + if (!secret) { + return add_json_mpis(jso, "point", &ec.p(), NULL); + } + return add_json_mpis(jso, "x", &ec.x(), NULL); + } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: case PGP_PKA_X25519: @@ -7750,50 +7773,6 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) return RNP_SUCCESS; } -static rnp_result_t -add_json_secret_mpis(json_object *jso, pgp_key_t *key) -{ - const pgp_key_material_t &km = key->material(); - switch (key->alg()) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return add_json_mpis( - jso, "d", &km.rsa.d, "p", &km.rsa.p, "q", &km.rsa.q, "u", &km.rsa.u, NULL); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return add_json_mpis(jso, "x", &km.eg.x, NULL); - case PGP_PKA_DSA: - return add_json_mpis(jso, "x", &km.dsa.x, NULL); - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return add_json_mpis(jso, "x", &km.ec.x, NULL); -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - case PGP_PKA_X25519: - return RNP_SUCCESS; /* TODO */ -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return RNP_SUCCESS; /* TODO */ -#endif - default: - return RNP_ERROR_NOT_SUPPORTED; - } - return RNP_SUCCESS; -} - static rnp_result_t add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) { @@ -8029,13 +8008,16 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) // curve / alg-specific items switch (key->alg()) { case PGP_PKA_ECDH: { - const char *hash_name = - id_str_pair::lookup(hash_alg_map, key->material().ec.kdf_hash_alg, NULL); + auto ecdh = dynamic_cast(&key->material()); + if (!ecdh) { + return RNP_ERROR_BAD_PARAMETERS; + } + const char *hash_name = id_str_pair::lookup(hash_alg_map, ecdh->kdf_hash_alg(), NULL); if (!hash_name) { return RNP_ERROR_BAD_PARAMETERS; } const char *cipher_name = - id_str_pair::lookup(symm_alg_map, key->material().ec.key_wrap_alg, NULL); + id_str_pair::lookup(symm_alg_map, ecdh->key_wrap_alg(), NULL); if (!cipher_name) { return RNP_ERROR_BAD_PARAMETERS; } @@ -8049,7 +8031,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) case PGP_PKA_EDDSA: case PGP_PKA_SM2: { const char *curve_name = NULL; - if (!curve_type_to_str(key->material().ec.curve, &curve_name)) { + if (!curve_type_to_str(key->material().curve(), &curve_name)) { return RNP_ERROR_BAD_PARAMETERS; } if (!json_add(jso, "curve", curve_name)) { @@ -8182,7 +8164,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } rnp_result_t tmpret; - if ((tmpret = add_json_public_mpis(jsompis, key))) { + if ((tmpret = add_json_mpis(jsompis, key))) { return tmpret; } } @@ -8203,7 +8185,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } rnp_result_t tmpret; - if ((tmpret = add_json_secret_mpis(jsompis, handle->sec))) { + if ((tmpret = add_json_mpis(jsompis, handle->sec, true))) { return tmpret; } } diff --git a/src/lib/types.h b/src/lib/types.h index a7eac3a121..dc38aab0af 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -164,40 +164,6 @@ typedef struct pgp_validity_t { void reset(); } pgp_validity_t; -/** - * Type to keep public/secret key mpis without any openpgp-dependent data. - */ -typedef struct pgp_key_material_t { - pgp_pubkey_alg_t alg; /* algorithm of the key */ - bool secret; /* secret part of the key material is populated */ - pgp_validity_t validity; /* key material validation status */ - - union { - pgp_rsa_key_t rsa; - pgp_dsa_key_t dsa; - pgp_eg_key_t eg; - pgp_ec_key_t ec; - }; -#if defined(ENABLE_CRYPTO_REFRESH) - pgp_ed25519_key_t ed25519; /* non-trivial type, cannot be in a union */ - pgp_x25519_key_t x25519; /* non-trivial type, cannot be in a union */ -#endif -#if defined(ENABLE_PQC) - pgp_kyber_ecdh_key_t kyber_ecdh; /* non-trivial type, cannot be in a union */ - pgp_dilithium_exdsa_key_t dilithium_exdsa; /* non-trivial type, cannot be in a union */ - pgp_sphincsplus_key_t sphincsplus; /* non-trivial type, cannot be in a union */ -#endif - - pgp_curve_t curve() - const; /* return curve for EC algorithms, PGP_CURVE_UNKNOWN otherwise */ - size_t bits() const; - size_t qbits() const; - void validate(rnp::SecurityContext &ctx, bool reset = true); - bool valid() const; - - bool get_grip(pgp_key_grip_t &grip) const; -} pgp_key_material_t; - /** * Type to keep signature without any openpgp-dependent data. */ @@ -216,6 +182,7 @@ typedef struct pgp_signature_material_t { dilithium_exdsa; // non-trivial type cannot be member in union pgp_sphincsplus_signature_t sphincsplus; // non-trivial type cannot be member in union #endif + pgp_hash_alg_t halg; } pgp_signature_material_t; /** diff --git a/src/librekey/g23_sexp.hpp b/src/librekey/g23_sexp.hpp index 0fb5c5144a..f7b0222260 100644 --- a/src/librekey/g23_sexp.hpp +++ b/src/librekey/g23_sexp.hpp @@ -53,7 +53,7 @@ class gnupg_sexp_t : public sexp::sexp_list_t { void add(unsigned u); p_gnupg_sexp add_sub(); void add_mpi(const std::string &name, const pgp::mpi &val); - void add_curve(const std::string &name, const pgp_ec_key_t &key); + void add_curve(const std::string &name, pgp_curve_t curve); void add_pubkey(const pgp_key_pkt_t &key); void add_seckey(const pgp_key_pkt_t &key); void add_protected_seckey(pgp_key_pkt_t & seckey, diff --git a/src/librekey/key_store_g10.cpp b/src/librekey/key_store_g10.cpp index aa0292e2ff..51e695d391 100644 --- a/src/librekey/key_store_g10.cpp +++ b/src/librekey/key_store_g10.cpp @@ -347,9 +347,9 @@ gnupg_sexp_t::add_mpi(const std::string &name, const pgp::mpi &mpi) } void -gnupg_sexp_t::add_curve(const std::string &name, const pgp_ec_key_t &key) +gnupg_sexp_t::add_curve(const std::string &name, pgp_curve_t kcurve) { - const char *curve = id_str_pair::lookup(g10_curve_names, key.curve, NULL); + const char *curve = id_str_pair::lookup(g10_curve_names, kcurve, NULL); if (!curve) { RNP_LOG("unknown curve"); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); @@ -359,13 +359,13 @@ gnupg_sexp_t::add_curve(const std::string &name, const pgp_ec_key_t &key) psub_s_exp->add(name); psub_s_exp->add(curve); - if ((key.curve != PGP_CURVE_ED25519) && (key.curve != PGP_CURVE_25519)) { + if ((kcurve != PGP_CURVE_ED25519) && (kcurve != PGP_CURVE_25519)) { return; } psub_s_exp = add_sub(); psub_s_exp->add("flags"); - psub_s_exp->add((key.curve == PGP_CURVE_ED25519) ? "eddsa" : "djb-tweak"); + psub_s_exp->add((kcurve == PGP_CURVE_ED25519) ? "eddsa" : "djb-tweak"); } static bool @@ -373,47 +373,50 @@ parse_pubkey(pgp_key_pkt_t &pubkey, const sexp_list_t *s_exp, pgp_pubkey_alg_t a { pubkey.version = PGP_V4; pubkey.alg = alg; - pubkey.material.alg = alg; switch (alg) { - case PGP_PKA_DSA: - if (!read_mpi(s_exp, "p", pubkey.material.dsa.p) || - !read_mpi(s_exp, "q", pubkey.material.dsa.q) || - !read_mpi(s_exp, "g", pubkey.material.dsa.g) || - !read_mpi(s_exp, "y", pubkey.material.dsa.y)) { + case PGP_PKA_DSA: { + pgp_dsa_key_t dsa{}; + if (!read_mpi(s_exp, "p", dsa.p) || !read_mpi(s_exp, "q", dsa.q) || + !read_mpi(s_exp, "g", dsa.g) || !read_mpi(s_exp, "y", dsa.y)) { return false; } + pubkey.material = pgp::KeyMaterial::create(dsa); break; - + } case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!read_mpi(s_exp, "n", pubkey.material.rsa.n) || - !read_mpi(s_exp, "e", pubkey.material.rsa.e)) { + case PGP_PKA_RSA_SIGN_ONLY: { + pgp_rsa_key_t rsa{}; + if (!read_mpi(s_exp, "n", rsa.n) || !read_mpi(s_exp, "e", rsa.e)) { return false; } + pubkey.material = pgp::KeyMaterial::create(alg, rsa); break; - + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!read_mpi(s_exp, "p", pubkey.material.eg.p) || - !read_mpi(s_exp, "g", pubkey.material.eg.g) || - !read_mpi(s_exp, "y", pubkey.material.eg.y)) { + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + pgp_eg_key_t eg{}; + if (!read_mpi(s_exp, "p", eg.p) || !read_mpi(s_exp, "g", eg.g) || + !read_mpi(s_exp, "y", eg.y)) { return false; } + pubkey.material = pgp::KeyMaterial::create(alg, eg); break; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: - if (!read_curve(s_exp, "curve", pubkey.material.ec) || - !read_mpi(s_exp, "q", pubkey.material.ec.p)) { + case PGP_PKA_EDDSA: { + pgp_ec_key_t ec{}; + if (!read_curve(s_exp, "curve", ec) || !read_mpi(s_exp, "q", ec.p)) { return false; } - if (pubkey.material.ec.curve == PGP_CURVE_ED25519) { + if (ec.curve == PGP_CURVE_ED25519) { /* need to adjust it here since 'ecc' key type defaults to ECDSA */ pubkey.alg = PGP_PKA_EDDSA; - pubkey.material.alg = PGP_PKA_EDDSA; } + pubkey.material = pgp::KeyMaterial::create(pubkey.alg, ec); break; + } default: RNP_LOG("Unsupported public key algorithm: %d", (int) alg); return false; @@ -423,44 +426,62 @@ parse_pubkey(pgp_key_pkt_t &pubkey, const sexp_list_t *s_exp, pgp_pubkey_alg_t a } static bool -parse_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *s_exp, pgp_pubkey_alg_t alg) +parse_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *s_exp) { - switch (alg) { - case PGP_PKA_DSA: - if (!read_mpi(s_exp, "x", seckey.material.dsa.x)) { + switch (seckey.alg) { + case PGP_PKA_DSA: { + pgp::mpi x; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "x", x)) { return false; } - break; + key->set_secret(x); + x.forget(); + return true; + } case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!read_mpi(s_exp, "d", seckey.material.rsa.d) || - !read_mpi(s_exp, "p", seckey.material.rsa.p) || - !read_mpi(s_exp, "q", seckey.material.rsa.q) || - !read_mpi(s_exp, "u", seckey.material.rsa.u)) { + case PGP_PKA_RSA_SIGN_ONLY: { + pgp::mpi d, p, q, u; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "d", d) || !read_mpi(s_exp, "p", p) || + !read_mpi(s_exp, "q", q) || !read_mpi(s_exp, "u", u)) { return false; } - break; + key->set_secret(d, p, q, u); + d.forget(); + p.forget(); + q.forget(); + u.forget(); + return true; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!read_mpi(s_exp, "x", seckey.material.eg.x)) { + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + pgp::mpi x; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "x", x)) { return false; } - break; + key->set_secret(x); + x.forget(); + return true; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: - if (!read_mpi(s_exp, "d", seckey.material.ec.x)) { + case PGP_PKA_EDDSA: { + pgp::mpi x; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "d", x)) { return false; } - break; + key->set_secret(x); + x.forget(); + return true; + } default: - RNP_LOG("Unsupported public key algorithm: %d", (int) alg); + RNP_LOG("Unsupported public key algorithm: %d", (int) seckey.alg); return false; } - - seckey.material.secret = true; - return true; } static bool @@ -654,7 +675,7 @@ parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const cha // we're all done if no password was provided (decryption not requested) if (!password) { - seckey.material.secret = false; + seckey.material->clear_secret(); return true; } @@ -705,7 +726,7 @@ parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const cha protected_at_data->get_string().size()); } // parse MPIs - if (!parse_seckey(seckey, decrypted_s_exp.sexp_list_at(0), seckey.alg)) { + if (!parse_seckey(seckey, decrypted_s_exp.sexp_list_at(0))) { RNP_LOG("failed to parse seckey"); return false; } @@ -744,15 +765,15 @@ parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const cha return false; } } - seckey.material.secret = true; return true; } static bool -g23_parse_seckey(pgp_key_pkt_t &seckey, - const uint8_t *data, - size_t data_len, - const char * password) +g23_parse_seckey(pgp_key_pkt_t & seckey, + const uint8_t * data, + size_t data_len, + const char * password, + pgp_pubkey_alg_t pubalg = PGP_PKA_NOTHING) { gnupg_extended_private_key_t g23_extended_key; @@ -805,19 +826,22 @@ g23_parse_seckey(pgp_key_pkt_t &seckey, return false; } - auto & alg_bt = alg_s_exp->sexp_string_at(0)->get_string(); - pgp_pubkey_alg_t alg = static_cast( - id_str_pair::lookup(g10_alg_aliases, (const char *) alg_bt.data(), PGP_PKA_NOTHING)); - if (alg == PGP_PKA_NOTHING) { - RNP_LOG( - "Unsupported algorithm: '%.*s'", (int) alg_bt.size(), (const char *) alg_bt.data()); - return false; - } - bool ret = false; - if (!parse_pubkey(seckey, alg_s_exp, alg)) { - RNP_LOG("failed to parse pubkey"); - goto done; + auto alg = pubalg; + if (alg == PGP_PKA_NOTHING) { + auto &alg_bt = alg_s_exp->sexp_string_at(0)->get_string(); + auto alg_st = (const char *) alg_bt.data(); + alg = static_cast( + id_str_pair::lookup(g10_alg_aliases, alg_st, PGP_PKA_NOTHING)); + if (alg == PGP_PKA_NOTHING) { + RNP_LOG("Unsupported algorithm: '%.*s'", (int) alg_bt.size(), alg_st); + return false; + } + /* Parse pubkey only if it was not parsed before */ + if (!parse_pubkey(seckey, alg_s_exp, alg)) { + RNP_LOG("failed to parse pubkey"); + goto done; + } } if (is_protected) { @@ -828,7 +852,7 @@ g23_parse_seckey(pgp_key_pkt_t &seckey, seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; seckey.sec_protection.symm_alg = PGP_SA_PLAINTEXT; seckey.sec_protection.s2k.hash_alg = PGP_HASH_UNKNOWN; - if (!parse_seckey(seckey, alg_s_exp, alg)) { + if (!parse_seckey(seckey, alg_s_exp)) { RNP_LOG("failed to parse seckey"); goto done; } @@ -850,13 +874,9 @@ g10_decrypt_seckey(const pgp_rawpacket_t &raw, return NULL; } auto seckey = std::unique_ptr(new pgp_key_pkt_t(pubkey, false)); - if (!g23_parse_seckey(*seckey, raw.raw.data(), raw.raw.size(), password)) { - return NULL; + if (!g23_parse_seckey(*seckey, raw.raw.data(), raw.raw.size(), password, pubkey.alg)) { + return nullptr; } - /* g10 has the same 'ecc' algo for ECDSA/ECDH/EDDSA. Probably should be better place to fix - * this. */ - seckey->alg = pubkey.alg; - seckey->material.alg = pubkey.material.alg; return seckey.release(); } @@ -865,31 +885,43 @@ copy_secret_fields(pgp_key_pkt_t &dst, const pgp_key_pkt_t &src) { switch (src.alg) { case PGP_PKA_DSA: - dst.material.dsa.x = src.material.dsa.x; + if (src.material->secret()) { + auto &dsasrc = dynamic_cast(*src.material); + auto &dsadst = dynamic_cast(*dst.material); + dsadst.set_secret(dsasrc.x()); + } break; case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: case PGP_PKA_RSA_SIGN_ONLY: - dst.material.rsa.d = src.material.rsa.d; - dst.material.rsa.p = src.material.rsa.p; - dst.material.rsa.q = src.material.rsa.q; - dst.material.rsa.u = src.material.rsa.u; + if (src.material->secret()) { + auto &rsasrc = dynamic_cast(*src.material); + auto &rsadst = dynamic_cast(*dst.material); + rsadst.set_secret(rsasrc.d(), rsasrc.p(), rsasrc.q(), rsasrc.u()); + } break; case PGP_PKA_ELGAMAL: case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - dst.material.eg.x = src.material.eg.x; + if (src.material->secret()) { + auto &egsrc = dynamic_cast(*src.material); + auto &egdst = dynamic_cast(*dst.material); + egdst.set_secret(egsrc.x()); + } break; case PGP_PKA_ECDSA: case PGP_PKA_ECDH: case PGP_PKA_EDDSA: - dst.material.ec.x = src.material.ec.x; + if (src.material->secret()) { + auto &ecsrc = dynamic_cast(*src.material); + auto &ecdst = dynamic_cast(*dst.material); + ecdst.set_secret(ecsrc.x()); + } break; default: RNP_LOG("Unsupported public key algorithm: %d", (int) src.alg); return false; } - dst.material.secret = src.material.secret; dst.sec_protection = src.sec_protection; dst.tag = is_subkey_pkt(dst.tag) ? PGP_PKT_SECRET_SUBKEY : PGP_PKT_SECRET_KEY; return true; @@ -910,11 +942,8 @@ KeyStore::load_g10(pgp_source_t &src, const KeyProvider *key_provider) /* copy public key fields if any */ pgp_key_t key; if (key_provider) { - pgp_key_grip_t grip{}; - if (!seckey.material.get_grip(grip)) { - return false; - } - auto pubkey = + pgp_key_grip_t grip = seckey.material->grip(); + auto pubkey = key_provider->request_key(*rnp::KeySearch::create(grip), PGP_OP_MERGE_INFO); if (!pubkey) { return false; @@ -973,33 +1002,41 @@ void gnupg_sexp_t::add_pubkey(const pgp_key_pkt_t &key) { switch (key.alg) { - case PGP_PKA_DSA: + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*key.material); add("dsa"); - add_mpi("p", key.material.dsa.p); - add_mpi("q", key.material.dsa.q); - add_mpi("g", key.material.dsa.g); - add_mpi("y", key.material.dsa.y); + add_mpi("p", dsa.p()); + add_mpi("q", dsa.q()); + add_mpi("g", dsa.g()); + add_mpi("y", dsa.y()); break; + } case PGP_PKA_RSA_SIGN_ONLY: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA: + case PGP_PKA_RSA: { + auto &rsa = dynamic_cast(*key.material); add("rsa"); - add_mpi("n", key.material.rsa.n); - add_mpi("e", key.material.rsa.e); + add_mpi("n", rsa.n()); + add_mpi("e", rsa.e()); break; - case PGP_PKA_ELGAMAL: + } + case PGP_PKA_ELGAMAL: { + auto &eg = dynamic_cast(*key.material); add("elg"); - add_mpi("p", key.material.eg.p); - add_mpi("g", key.material.eg.g); - add_mpi("y", key.material.eg.y); + add_mpi("p", eg.p()); + add_mpi("g", eg.g()); + add_mpi("y", eg.y()); break; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: + case PGP_PKA_EDDSA: { + auto &ec = dynamic_cast(*key.material); add("ecc"); - add_curve("curve", key.material.ec); - add_mpi("q", key.material.ec.p); + add_curve("curve", ec.curve()); + add_mpi("q", ec.p()); break; + } default: RNP_LOG("Unsupported public key algorithm: %d", (int) key.alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); @@ -1010,24 +1047,31 @@ void gnupg_sexp_t::add_seckey(const pgp_key_pkt_t &key) { switch (key.alg) { - case PGP_PKA_DSA: - add_mpi("x", key.material.dsa.x); + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*key.material); + add_mpi("x", dsa.x()); break; + } case PGP_PKA_RSA_SIGN_ONLY: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA: - add_mpi("d", key.material.rsa.d); - add_mpi("p", key.material.rsa.p); - add_mpi("q", key.material.rsa.q); - add_mpi("u", key.material.rsa.u); + case PGP_PKA_RSA: { + auto &rsa = dynamic_cast(*key.material); + add_mpi("d", rsa.d()); + add_mpi("p", rsa.p()); + add_mpi("q", rsa.q()); + add_mpi("u", rsa.u()); break; - case PGP_PKA_ELGAMAL: - add_mpi("x", key.material.eg.x); + } + case PGP_PKA_ELGAMAL: { + auto &eg = dynamic_cast(*key.material); + add_mpi("x", eg.x()); break; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: case PGP_PKA_EDDSA: { - add_mpi("d", key.material.ec.x); + auto &ec = dynamic_cast(*key.material); + add_mpi("d", ec.x()); break; } default: diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index ad9157d254..7b075ac9f8 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -880,82 +880,70 @@ stream_dump_signature(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) return ret; } -static rnp_result_t -stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +static void +stream_dump_key_material(rnp_dump_ctx_t & ctx, + const pgp::KeyMaterial *material, + pgp_dest_t * dst) { - pgp_key_pkt_t key; - rnp_result_t ret; - pgp_fingerprint_t keyfp = {}; - - try { - ret = key.parse(*src); - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); - ret = RNP_ERROR_GENERIC; - /* LCOV_EXCL_END */ - } - if (ret) { - return ret; - } - - dst_printf(dst, "%s packet\n", id_str_pair::lookup(key_type_map, key.tag, "Unknown")); - indent_dest_increase(dst); - - dst_printf(dst, "version: %d\n", (int) key.version); - dst_print_time(dst, "creation time", key.creation_time); - if (key.version < PGP_V4) { - dst_printf(dst, "v3 validity days: %d\n", (int) key.v3_days); - } - dst_print_palg(dst, NULL, key.alg); - if (key.version == PGP_V5) { - dst_printf(dst, "v5 public key material length: %" PRIu32 "\n", key.v5_pub_len); + if (!material) { + return; } - dst_printf(dst, "public key material:\n"); - indent_dest_increase(dst); - - switch (key.alg) { + switch (material->alg()) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - dst_print_mpi(dst, "rsa n", key.material.rsa.n, ctx->dump_mpi); - dst_print_mpi(dst, "rsa e", key.material.rsa.e, ctx->dump_mpi); - break; - case PGP_PKA_DSA: - dst_print_mpi(dst, "dsa p", key.material.dsa.p, ctx->dump_mpi); - dst_print_mpi(dst, "dsa q", key.material.dsa.q, ctx->dump_mpi); - dst_print_mpi(dst, "dsa g", key.material.dsa.g, ctx->dump_mpi); - dst_print_mpi(dst, "dsa y", key.material.dsa.y, ctx->dump_mpi); - break; + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material); + dst_print_mpi(dst, "rsa n", rsa.n(), ctx.dump_mpi); + dst_print_mpi(dst, "rsa e", rsa.e(), ctx.dump_mpi); + return; + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*material); + dst_print_mpi(dst, "dsa p", dsa.p(), ctx.dump_mpi); + dst_print_mpi(dst, "dsa q", dsa.q(), ctx.dump_mpi); + dst_print_mpi(dst, "dsa g", dsa.g(), ctx.dump_mpi); + dst_print_mpi(dst, "dsa y", dsa.y(), ctx.dump_mpi); + return; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - dst_print_mpi(dst, "eg p", key.material.eg.p, ctx->dump_mpi); - dst_print_mpi(dst, "eg g", key.material.eg.g, ctx->dump_mpi); - dst_print_mpi(dst, "eg y", key.material.eg.y, ctx->dump_mpi); - break; + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material); + dst_print_mpi(dst, "eg p", eg.p(), ctx.dump_mpi); + dst_print_mpi(dst, "eg g", eg.g(), ctx.dump_mpi); + dst_print_mpi(dst, "eg y", eg.y(), ctx.dump_mpi); + return; + } case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: case PGP_PKA_SM2: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - dst_print_mpi(dst, "ecc p", key.material.ec.p, ctx->dump_mpi); + auto &ec = dynamic_cast(*material); + auto cdesc = get_curve_desc(ec.curve()); + dst_print_mpi(dst, "ecc p", ec.p(), ctx.dump_mpi); dst_printf(dst, "ecc curve: %s\n", cdesc ? cdesc->pgp_name : "unknown"); - break; + return; } case PGP_PKA_ECDH: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - dst_print_mpi(dst, "ecdh p", key.material.ec.p, ctx->dump_mpi); + auto &ec = dynamic_cast(*material); + auto cdesc = get_curve_desc(ec.curve()); + /* Common EC fields */ + dst_print_mpi(dst, "ecdh p", ec.p(), ctx.dump_mpi); dst_printf(dst, "ecdh curve: %s\n", cdesc ? cdesc->pgp_name : "unknown"); - dst_print_halg(dst, "ecdh hash algorithm", key.material.ec.kdf_hash_alg); - dst_printf(dst, "ecdh key wrap algorithm: %d\n", (int) key.material.ec.key_wrap_alg); - break; + /* ECDH-only fields */ + dst_print_halg(dst, "ecdh hash algorithm", ec.kdf_hash_alg()); + dst_printf(dst, "ecdh key wrap algorithm: %d\n", (int) ec.key_wrap_alg()); + return; } #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - dst_print_vec(dst, "ed25519", key.material.ed25519.pub, ctx->dump_mpi); - break; - case PGP_PKA_X25519: - dst_print_vec(dst, "x25519", key.material.x25519.pub, ctx->dump_mpi); - break; + case PGP_PKA_ED25519: { + auto &ed25519 = dynamic_cast(*material); + dst_print_vec(dst, "ed25519", ed25519.pub(), ctx.dump_mpi); + return; + } + case PGP_PKA_X25519: { + auto &x25519 = dynamic_cast(*material); + dst_print_vec(dst, "x25519", x25519.pub(), ctx.dump_mpi); + return; + } #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: @@ -967,12 +955,12 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - dst_print_vec(dst, - "mlkem-ecdh encoded pubkey", - key.material.kyber_ecdh.pub.get_encoded(), - ctx->dump_mpi); - break; + case PGP_PKA_KYBER1024_BP384: { + auto &kyber = dynamic_cast(*material); + dst_print_vec( + dst, "mlkem-ecdh encoded pubkey", kyber.pub().get_encoded(), ctx.dump_mpi); + return; + } case PGP_PKA_DILITHIUM3_ED25519: FALLTHROUGH_STATEMENT; // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; @@ -982,24 +970,61 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: + case PGP_PKA_DILITHIUM5_BP384: { + auto &dilithium = dynamic_cast(*material); dst_print_vec(dst, "mldsa-ecdsa/eddsa encodced pubkey", - key.material.dilithium_exdsa.pub.get_encoded(), - ctx->dump_mpi); - break; + dilithium.pub().get_encoded(), + ctx.dump_mpi); + return; + } case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - dst_print_vec(dst, - "slhdsa encoded pubkey", - key.material.sphincsplus.pub.get_encoded(), - ctx->dump_mpi); - break; + case PGP_PKA_SPHINCSPLUS_SHAKE: { + auto &sphincs = dynamic_cast(*material); + dst_print_vec(dst, "slhdsa encoded pubkey", sphincs.pub().get_encoded(), ctx.dump_mpi); + return; + } #endif default: dst_printf(dst, "unknown public key algorithm\n"); } +} + +static rnp_result_t +stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_key_pkt_t key; + rnp_result_t ret; + pgp_fingerprint_t keyfp = {}; + + try { + ret = key.parse(*src); + } catch (const std::exception &e) { + /* LCOV_EXCL_START */ + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + /* LCOV_EXCL_END */ + } + if (ret) { + return ret; + } + + dst_printf(dst, "%s packet\n", id_str_pair::lookup(key_type_map, key.tag, "Unknown")); + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) key.version); + dst_print_time(dst, "creation time", key.creation_time); + if (key.version < PGP_V4) { + dst_printf(dst, "v3 validity days: %d\n", (int) key.v3_days); + } + dst_print_palg(dst, NULL, key.alg); + if (key.version == PGP_V5) { + dst_printf(dst, "v5 public key material length: %" PRIu32 "\n", key.v5_pub_len); + } + dst_printf(dst, "public key material:\n"); + indent_dest_increase(dst); + stream_dump_key_material(*ctx, key.material.get(), dst); indent_dest_decrease(dst); if (is_secret_key_pkt(key.tag)) { @@ -1051,8 +1076,8 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) } if (ctx->dump_grips) { - pgp_key_grip_t grip; - if (key.material.get_grip(grip)) { + if (key.material) { + pgp_key_grip_t grip = key.material->grip(); dst_print_hex(dst, "grip", grip.data(), grip.size(), false); } else { dst_printf(dst, "grip: failed to calculate\n"); @@ -2047,107 +2072,77 @@ stream_dump_signature_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object * return stream_dump_signature_pkt_json(ctx, &sig, pkt); } -static rnp_result_t -stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +static bool +stream_dump_key_material_json(rnp_dump_ctx_t & ctx, + const pgp::KeyMaterial *material, + json_object * jso) { - pgp_key_pkt_t key; - rnp_result_t ret; - json_object * material = NULL; - - try { - ret = key.parse(*src); - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); - ret = RNP_ERROR_GENERIC; - /* LCOV_EXCL_END */ - } - if (ret) { - return ret; - } - - if (!json_add(pkt, "version", (int) key.version)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if (!json_add(pkt, "creation time", (uint64_t) key.creation_time)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if ((key.version < PGP_V4) && !json_add(pkt, "v3 days", (int) key.v3_days)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if (!obj_add_intstr_json(pkt, "algorithm", key.alg, pubkey_alg_map)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if ((key.version == PGP_V5) && - !json_add(pkt, "v5 public key material length", (int) key.v5_pub_len)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - - material = json_object_new_object(); - if (!material || !json_add(pkt, "material", material)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (!material) { + return false; // LCOV_EXCL_LINE } - - switch (key.alg) { + switch (material->alg()) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!obj_add_mpi_json(material, "n", key.material.rsa.n, ctx->dump_mpi) || - !obj_add_mpi_json(material, "e", key.material.rsa.e, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material); + if (!obj_add_mpi_json(jso, "n", rsa.n(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "e", rsa.e(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - break; - case PGP_PKA_DSA: - if (!obj_add_mpi_json(material, "p", key.material.dsa.p, ctx->dump_mpi) || - !obj_add_mpi_json(material, "q", key.material.dsa.q, ctx->dump_mpi) || - !obj_add_mpi_json(material, "g", key.material.dsa.g, ctx->dump_mpi) || - !obj_add_mpi_json(material, "y", key.material.dsa.y, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + return true; + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*material); + if (!obj_add_mpi_json(jso, "p", dsa.p(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "q", dsa.q(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "g", dsa.g(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "y", dsa.y(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - break; + return true; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!obj_add_mpi_json(material, "p", key.material.eg.p, ctx->dump_mpi) || - !obj_add_mpi_json(material, "g", key.material.eg.g, ctx->dump_mpi) || - !obj_add_mpi_json(material, "y", key.material.eg.y, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material); + if (!obj_add_mpi_json(jso, "p", eg.p(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "g", eg.g(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "y", eg.y(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - break; + return true; + } case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: - case PGP_PKA_SM2: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - if (!obj_add_mpi_json(material, "p", key.material.ec.p, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if (!json_add(material, "curve", cdesc ? cdesc->pgp_name : "unknown")) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - break; - } + case PGP_PKA_SM2: case PGP_PKA_ECDH: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - if (!obj_add_mpi_json(material, "p", key.material.ec.p, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + auto &ec = dynamic_cast(*material); + auto cdesc = get_curve_desc(ec.curve()); + /* Common EC fields */ + if (!obj_add_mpi_json(jso, "p", ec.p(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - if (!json_add(material, "curve", cdesc ? cdesc->pgp_name : "unknown")) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (!json_add(jso, "curve", cdesc ? cdesc->pgp_name : "unknown")) { + return false; // LCOV_EXCL_LINE } - if (!obj_add_intstr_json( - material, "hash algorithm", key.material.ec.kdf_hash_alg, hash_alg_map)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (material->alg() != PGP_PKA_ECDH) { + return true; + } + /* ECDH-only fields */ + auto &ecdh = dynamic_cast(*material); + if (!obj_add_intstr_json(jso, "hash algorithm", ecdh.kdf_hash_alg(), hash_alg_map)) { + return false; // LCOV_EXCL_LINE } if (!obj_add_intstr_json( - material, "key wrap algorithm", key.material.ec.key_wrap_alg, symm_alg_map)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + jso, "key wrap algorithm", ecdh.key_wrap_alg(), symm_alg_map)) { + return false; // LCOV_EXCL_LINE } - break; + return true; } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: case PGP_PKA_X25519: /* TODO */ - break; + return true; #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: @@ -2161,7 +2156,7 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: // TODO - break; + return true; case PGP_PKA_DILITHIUM3_ED25519: FALLTHROUGH_STATEMENT; // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; @@ -2173,15 +2168,60 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: /* TODO */ - break; + return true; case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: /* TODO */ - break; + return true; #endif default: - break; + return false; + } +} + +static rnp_result_t +stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +{ + pgp_key_pkt_t key; + rnp_result_t ret; + json_object * material = NULL; + + try { + ret = key.parse(*src); + } catch (const std::exception &e) { + /* LCOV_EXCL_START */ + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + /* LCOV_EXCL_END */ + } + if (ret) { + return ret; + } + + if (!json_add(pkt, "version", (int) key.version)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if (!json_add(pkt, "creation time", (uint64_t) key.creation_time)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if ((key.version < PGP_V4) && !json_add(pkt, "v3 days", (int) key.v3_days)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if (!obj_add_intstr_json(pkt, "algorithm", key.alg, pubkey_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if ((key.version == PGP_V5) && + !json_add(pkt, "v5 public key material length", (int) key.v5_pub_len)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + + material = json_object_new_object(); + if (!material || !json_add(pkt, "material", material)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if (!stream_dump_key_material_json(*ctx, key.material.get(), material)) { + return RNP_ERROR_OUT_OF_MEMORY; } if (is_secret_key_pkt(key.tag)) { @@ -2217,10 +2257,13 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - pgp_key_grip_t grip; - if (!key.material.get_grip(grip) || - !json_add_hex(pkt, "grip", grip.data(), grip.size())) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (key.material) { + pgp_key_grip_t grip = key.material->grip(); + if (!json_add_hex(pkt, "grip", grip.data(), grip.size())) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + } else { + return RNP_ERROR_BAD_PARAMETERS; // LCOV_EXCL_LINE } } return RNP_SUCCESS; diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index ae31cf9ca6..5e9a9b6d87 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -597,129 +597,18 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) /* parse mpis depending on algorithm */ pgp_packet_body_t body(mpis, len); -#if defined(ENABLE_CRYPTO_REFRESH) || defined(ENABLE_PQC) - std::vector tmpbuf; -#endif - - switch (key.alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!body.get(key.material.rsa.d) || !body.get(key.material.rsa.p) || - !body.get(key.material.rsa.q) || !body.get(key.material.rsa.u)) { - RNP_LOG("failed to parse rsa secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_DSA: - if (!body.get(key.material.dsa.x)) { - RNP_LOG("failed to parse dsa secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_EDDSA: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - if (!body.get(key.material.ec.x)) { - RNP_LOG("failed to parse ecc secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!body.get(key.material.eg.x)) { - RNP_LOG("failed to parse eg secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_ED25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse Ed25519 secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.ed25519.priv = tmpbuf; - break; - } - case PGP_PKA_X25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse X25519 secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.x25519.priv = tmpbuf; - break; - } -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - tmpbuf.resize(pgp_kyber_ecdh_composite_private_key_t::encoded_size(key.alg)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mkem-ecdh secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.kyber_ecdh.priv = - pgp_kyber_ecdh_composite_private_key_t(tmpbuf.data(), tmpbuf.size(), key.alg); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - tmpbuf.resize(pgp_dilithium_exdsa_composite_private_key_t::encoded_size(key.alg)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mldsa-ecdsa/eddsa secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.dilithium_exdsa.priv = pgp_dilithium_exdsa_composite_private_key_t( - tmpbuf.data(), tmpbuf.size(), key.alg); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: { - uint8_t param; - if (!body.get(param)) { - RNP_LOG("failed to parse SLH-DSA secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - tmpbuf.resize(sphincsplus_privkey_size((sphincsplus_parameter_t) param)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse SLH-DSA secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.sphincsplus.priv = - pgp_sphincsplus_private_key_t(tmpbuf, (sphincsplus_parameter_t) param, key.alg); - break; - } -#endif - default: + if (!key.material) { RNP_LOG("unknown pk alg : %d", (int) key.alg); return RNP_ERROR_BAD_PARAMETERS; } + if (!key.material->parse_secret(body)) { + return RNP_ERROR_BAD_FORMAT; + } if (body.left()) { RNP_LOG("extra data in sec key"); return RNP_ERROR_BAD_FORMAT; } - key.material.secret = true; return RNP_SUCCESS; } catch (const std::exception &e) { RNP_LOG("%s", e.what()); @@ -737,7 +626,7 @@ decrypt_secret_key(pgp_key_pkt_t *key, const char *password) return RNP_ERROR_BAD_PARAMETERS; } /* mark material as not validated as it may be valid for public part */ - key->material.validity.reset(); + key->material->reset_validity(); /* check whether data is not encrypted */ if (!key->sec_protection.s2k.usage) { @@ -816,72 +705,7 @@ static void write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) { /* add mpis */ - switch (key.alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - body.add(key.material.rsa.d); - body.add(key.material.rsa.p); - body.add(key.material.rsa.q); - body.add(key.material.rsa.u); - break; - case PGP_PKA_DSA: - body.add(key.material.dsa.x); - break; - case PGP_PKA_EDDSA: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - body.add(key.material.ec.x); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - body.add(key.material.eg.x); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - body.add(key.material.ed25519.priv); - break; - case PGP_PKA_X25519: - body.add(key.material.x25519.priv); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - body.add(key.material.kyber_ecdh.priv.get_encoded()); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - body.add(key.material.dilithium_exdsa.priv.get_encoded()); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - body.add_byte((uint8_t) key.material.sphincsplus.priv.param()); - body.add(key.material.sphincsplus.priv.get_encoded()); - break; -#endif - default: - RNP_LOG("unknown pk alg : %d", (int) key.alg); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } + key.material->write_secret(body); #if defined(ENABLE_CRYPTO_REFRESH) if (key.version == PGP_V6 && key.sec_protection.s2k.usage == PGP_S2KU_NONE) { @@ -914,7 +738,7 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) rnp_result_t encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) { - if (!is_secret_key_pkt(key->tag) || !key->material.secret) { + if (!is_secret_key_pkt(key->tag) || !key->material->secret()) { return RNP_ERROR_BAD_PARAMETERS; } if (key->sec_protection.s2k.usage && @@ -984,7 +808,7 @@ encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) memcpy(key->sec_data, body.data(), body.size()); key->sec_len = body.size(); /* cleanup cleartext fields */ - forget_secret_key_fields(&key->material); + key->material->clear_secret(); return RNP_SUCCESS; } catch (const std::exception &e) { RNP_LOG("%s", e.what()); @@ -992,83 +816,6 @@ encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) } } -void -forget_secret_key_fields(pgp_key_material_t *key) -{ - if (!key || !key->secret) { - return; - } - - switch (key->alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - key->rsa.d.forget(); - key->rsa.p.forget(); - key->rsa.q.forget(); - key->rsa.u.forget(); - break; - case PGP_PKA_DSA: - key->dsa.x.forget(); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - key->eg.x.forget(); - break; - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - key->ec.x.forget(); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - secure_clear(key->ed25519.priv.data(), key->ed25519.priv.size()); - key->ed25519.priv.clear(); - break; - case PGP_PKA_X25519: - secure_clear(key->x25519.priv.data(), key->x25519.priv.size()); - key->x25519.priv.clear(); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - key->kyber_ecdh.priv.secure_clear(); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - key->dilithium_exdsa.priv.secure_clear(); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - key->sphincsplus.priv.secure_clear(); - break; -#endif - default: - RNP_LOG("unknown key algorithm: %d", (int) key->alg); - } - - key->secret = false; -} - pgp_userid_pkt_t::pgp_userid_pkt_t(const pgp_userid_pkt_t &src) { tag = src.tag; @@ -1211,9 +958,11 @@ pgp_key_pkt_t::pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly) } memcpy(hashed_data, src.hashed_data, hashed_len); } - material = src.material; + material = src.material ? src.material->clone() : nullptr; if (pubonly) { - forget_secret_key_fields(&material); + if (material) { + material->clear_secret(); + } sec_len = 0; v5_s2k_len = 0; v5_sec_len = 0; @@ -1245,8 +994,7 @@ pgp_key_pkt_t::pgp_key_pkt_t(pgp_key_pkt_t &&src) hashed_len = src.hashed_len; hashed_data = src.hashed_data; src.hashed_data = NULL; - material = src.material; - forget_secret_key_fields(&src.material); + material = std::move(src.material); sec_len = src.sec_len; v5_s2k_len = src.v5_s2k_len; v5_sec_len = src.v5_sec_len; @@ -1270,8 +1018,7 @@ pgp_key_pkt_t::operator=(pgp_key_pkt_t &&src) free(hashed_data); hashed_data = src.hashed_data; src.hashed_data = NULL; - material = src.material; - forget_secret_key_fields(&src.material); + material = std::move(src.material); secure_clear(sec_data, sec_len); free(sec_data); sec_len = src.sec_len; @@ -1303,7 +1050,7 @@ pgp_key_pkt_t::operator=(const pgp_key_pkt_t &src) } memcpy(hashed_data, src.hashed_data, hashed_len); } - material = src.material; + material = src.material ? src.material->clone() : nullptr; secure_clear(sec_data, sec_len); free(sec_data); sec_data = NULL; @@ -1323,7 +1070,6 @@ pgp_key_pkt_t::operator=(const pgp_key_pkt_t &src) pgp_key_pkt_t::~pgp_key_pkt_t() { - forget_secret_key_fields(&material); free(hashed_data); secure_clear(sec_data, sec_len); free(sec_data); @@ -1488,7 +1234,11 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_ERROR_BAD_FORMAT; } alg = (pgp_pubkey_alg_t) analg; - material.alg = (pgp_pubkey_alg_t) analg; + material = pgp::KeyMaterial::create(alg); + if (!material) { + RNP_LOG("unknown key algorithm: %d", (int) alg); + return RNP_ERROR_BAD_FORMAT; + } switch (version) { case PGP_V2: case PGP_V3: @@ -1516,131 +1266,10 @@ pgp_key_pkt_t::parse(pgp_source_t &src) } /* algorithm specific fields */ - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!pkt.get(material.rsa.n) || !pkt.get(material.rsa.e)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_DSA: - if (!pkt.get(material.dsa.p) || !pkt.get(material.dsa.q) || !pkt.get(material.dsa.g) || - !pkt.get(material.dsa.y)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!pkt.get(material.eg.p) || !pkt.get(material.eg.g) || !pkt.get(material.eg.y)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - if (!pkt.get(material.ec.curve) || !pkt.get(material.ec.p)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ECDH: { - if (!pkt.get(material.ec.curve) || !pkt.get(material.ec.p)) { - return RNP_ERROR_BAD_FORMAT; - } - /* read KDF parameters. At the moment should be 0x03 0x01 halg ealg */ - uint8_t len = 0, halg = 0, walg = 0; - if (!pkt.get(len) || (len != 3)) { - return RNP_ERROR_BAD_FORMAT; - } - if (!pkt.get(len) || (len != 1)) { - return RNP_ERROR_BAD_FORMAT; - } - if (!pkt.get(halg) || !pkt.get(walg)) { - return RNP_ERROR_BAD_FORMAT; - } - material.ec.kdf_hash_alg = (pgp_hash_alg_t) halg; - material.ec.key_wrap_alg = (pgp_symm_alg_t) walg; - break; - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_ED25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse Ed25519 public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.ed25519.pub = tmpbuf; - break; - } - case PGP_PKA_X25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse X25519 public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.x25519.pub = tmpbuf; - break; - } -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - tmpbuf.resize(pgp_kyber_ecdh_composite_public_key_t::encoded_size(alg)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mlkem-ecdh public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.kyber_ecdh.pub = pgp_kyber_ecdh_composite_public_key_t(tmpbuf, alg); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - tmpbuf.resize(pgp_dilithium_exdsa_composite_public_key_t::encoded_size(alg)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mldsa-ecdsa/eddsa public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.dilithium_exdsa.pub = pgp_dilithium_exdsa_composite_public_key_t(tmpbuf, alg); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: { - uint8_t param; - if (!pkt.get(param)) { - RNP_LOG("failed to parse SLH-DSA public key data"); - return RNP_ERROR_BAD_FORMAT; - } - tmpbuf.resize(sphincsplus_pubkey_size((sphincsplus_parameter_t) param)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse SLH-DSA public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.sphincsplus.pub = - pgp_sphincsplus_public_key_t(tmpbuf, (sphincsplus_parameter_t) param, alg); - break; - } -#endif - default: - RNP_LOG("unknown key algorithm: %d", (int) alg); + if (!material->parse(pkt)) { return RNP_ERROR_BAD_FORMAT; } + /* fill hashed data used for signatures */ if (!(hashed_data = (uint8_t *) malloc(pkt.size() - pkt.left()))) { RNP_LOG("allocation failed"); @@ -1763,88 +1392,6 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_SUCCESS; } -void -pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody) -{ - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - hbody.add(material.rsa.n); - hbody.add(material.rsa.e); - break; - case PGP_PKA_DSA: - hbody.add(material.dsa.p); - hbody.add(material.dsa.q); - hbody.add(material.dsa.g); - hbody.add(material.dsa.y); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - hbody.add(material.eg.p); - hbody.add(material.eg.g); - hbody.add(material.eg.y); - break; - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - hbody.add(material.ec.curve); - hbody.add(material.ec.p); - break; - case PGP_PKA_ECDH: - hbody.add(material.ec.curve); - hbody.add(material.ec.p); - hbody.add_byte(3); - hbody.add_byte(1); - hbody.add_byte(material.ec.kdf_hash_alg); - hbody.add_byte(material.ec.key_wrap_alg); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - hbody.add(material.ed25519.pub); - break; - case PGP_PKA_X25519: - hbody.add(material.x25519.pub); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - hbody.add(material.kyber_ecdh.pub.get_encoded()); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - hbody.add(material.dilithium_exdsa.pub.get_encoded()); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - hbody.add_byte((uint8_t) material.sphincsplus.pub.param()); - hbody.add(material.sphincsplus.pub.get_encoded()); - break; -#endif - default: - RNP_LOG("unknown key algorithm: %d", (int) alg); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } -} - void pgp_key_pkt_t::fill_hashed_data() { @@ -1868,7 +1415,7 @@ pgp_key_pkt_t::fill_hashed_data() /* Algorithm specific fields */ pgp_packet_body_t alg_spec_fields(PGP_PKT_RESERVED); - make_alg_spec_fields_for_public_key(alg_spec_fields); + material->write(alg_spec_fields); #if defined(ENABLE_CRYPTO_REFRESH) if (version == PGP_V6) { hbody.add_uint32(alg_spec_fields.size()); @@ -1904,7 +1451,7 @@ pgp_key_pkt_t::equals(const pgp_key_pkt_t &key, bool pubonly) const noexcept return false; } /* check key material */ - return key_material_equal(&material, &key.material); + return material->equals(*key.material); } pgp_transferable_subkey_t::pgp_transferable_subkey_t(const pgp_transferable_subkey_t &src, diff --git a/src/librepgp/stream-key.h b/src/librepgp/stream-key.h index 708c196705..24f5ff1f76 100644 --- a/src/librepgp/stream-key.h +++ b/src/librepgp/stream-key.h @@ -34,6 +34,7 @@ #include "stream-common.h" #include "stream-sig.h" #include "stream-packet.h" +#include "key_material.hpp" /** Struct to hold a key packet. May contain public or private key/subkey */ typedef struct pgp_key_pkt_t { @@ -47,7 +48,7 @@ typedef struct pgp_key_pkt_t { uint8_t *hashed_data; /* key's hashed data used for signature calculation */ size_t hashed_len; - pgp_key_material_t material; + std::unique_ptr material; /* secret key data, if available. sec_len == 0, sec_data == NULL for public key/subkey */ pgp_key_protection_t sec_protection; @@ -58,7 +59,7 @@ typedef struct pgp_key_pkt_t { pgp_key_pkt_t() : tag(PGP_PKT_RESERVED), version(PGP_VUNKNOWN), creation_time(0), alg(PGP_PKA_NOTHING), - v3_days(0), v5_pub_len(0), hashed_data(NULL), hashed_len(0), material({}), + v3_days(0), v5_pub_len(0), hashed_data(NULL), hashed_len(0), material(nullptr), sec_protection({}), sec_data(NULL), sec_len(0), v5_s2k_len(0), v5_sec_len(0){}; pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly = false); pgp_key_pkt_t(pgp_key_pkt_t &&src); @@ -74,8 +75,6 @@ typedef struct pgp_key_pkt_t { bool equals(const pgp_key_pkt_t &key, bool pubonly = false) const noexcept; private: - /* create the contents of the algorithm specific public key fields in a separate packet */ - void make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody); void make_s2k_params(pgp_packet_body_t &hbody); uint8_t s2k_specifier_len(pgp_s2k_specifier_t specifier); } pgp_key_pkt_t; @@ -147,6 +146,4 @@ rnp_result_t decrypt_secret_key(pgp_key_pkt_t *key, const char *password); rnp_result_t encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng); -void forget_secret_key_fields(pgp_key_material_t *key); - #endif diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index b597624d48..74ee59a45b 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1619,95 +1619,14 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, rnp::secure_array decbuf; /* Decrypting session key value */ - rnp_result_t err; - bool res = false; - auto & keymaterial = seckey.material(); - size_t declen = 0; - switch (sesskey.alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - err = rsa_decrypt_pkcs1( - &ctx.rng, decbuf.data(), &declen, &encmaterial.rsa, &keymaterial.rsa); - if (err) { - RNP_LOG("RSA decryption failure"); - return false; - } - break; - case PGP_PKA_SM2: -#if defined(ENABLE_SM2) - declen = decbuf.size(); - err = sm2_decrypt(decbuf.data(), &declen, &encmaterial.sm2, &keymaterial.ec); - if (err != RNP_SUCCESS) { - RNP_LOG("SM2 decryption failure, error %x", (int) err); - return false; - } - break; -#else - RNP_LOG("SM2 decryption is not available."); - return false; -#endif - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { - const rnp_result_t ret = elgamal_decrypt_pkcs1( - &ctx.rng, decbuf.data(), &declen, &encmaterial.eg, &keymaterial.eg); - if (ret) { - RNP_LOG("ElGamal decryption failure [%X]", ret); - return false; - } - break; - } - case PGP_PKA_ECDH: { - if (!curve_supported(keymaterial.ec.curve)) { - RNP_LOG("ECDH decrypt: curve %d is not supported.", (int) keymaterial.ec.curve); - return false; - } - if ((keymaterial.ec.curve == PGP_CURVE_25519) && - !x25519_bits_tweaked(keymaterial.ec)) { - RNP_LOG("Warning: bits of 25519 secret key are not tweaked."); - } - declen = decbuf.size(); - err = ecdh_decrypt_pkcs5( - decbuf.data(), &declen, &encmaterial.ecdh, &keymaterial.ec, seckey.fp()); - if (err) { - RNP_LOG("ECDH decryption error %u", err); - return false; - } - break; - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: - declen = decbuf.size(); - err = x25519_native_decrypt( - &ctx.rng, keymaterial.x25519, &encmaterial.x25519, decbuf.data(), &declen); - if (err) { - RNP_LOG("X25519 decryption error %u", err); - return false; - } - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: { - declen = decbuf.size(); - err = keymaterial.kyber_ecdh.priv.decrypt( - &ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh); - if (err) { - RNP_LOG("ML-KEM + ECC decryption failure"); - return false; - } - break; + bool res = false; + size_t declen = decbuf.size(); + + if (sesskey.alg == PGP_PKA_ECDH) { + encmaterial.ecdh.fp = &seckey.fp(); } -#endif - default: - RNP_LOG("unsupported public key algorithm %d\n", seckey.alg()); + auto err = seckey.pkt().material->decrypt(ctx, decbuf.data(), declen, encmaterial); + if (err) { return false; } diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 90048770ce..46039a8da9 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -675,102 +675,12 @@ encrypted_add_recipient(pgp_write_handler_t *handler, pgp_encrypted_material_t material; - switch (userkey->alg()) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: { - ret = rsa_encrypt_pkcs1(&handler->ctx->ctx->rng, - &material.rsa, - enckey.data(), - enckey_len, - &userkey->material().rsa); - if (ret) { - RNP_LOG("rsa_encrypt_pkcs1 failed"); - return ret; - } - break; - } - case PGP_PKA_SM2: { -#if defined(ENABLE_SM2) - ret = sm2_encrypt(&handler->ctx->ctx->rng, - &material.sm2, - enckey.data(), - enckey_len, - PGP_HASH_SM3, - &userkey->material().ec); - if (ret) { - RNP_LOG("sm2_encrypt failed"); - return ret; - } - break; -#else - RNP_LOG("sm2_encrypt is not available"); - return RNP_ERROR_NOT_IMPLEMENTED; -#endif + if (userkey->alg() == PGP_PKA_ECDH) { + material.ecdh.fp = &userkey->fp(); } - case PGP_PKA_ECDH: { - if (!curve_supported(userkey->material().ec.curve)) { - RNP_LOG("ECDH encrypt: curve %d is not supported.", - (int) userkey->material().ec.curve); - return RNP_ERROR_NOT_SUPPORTED; - } - ret = ecdh_encrypt_pkcs5(&handler->ctx->ctx->rng, - &material.ecdh, - enckey.data(), - enckey_len, - &userkey->material().ec, - userkey->fp()); - if (ret) { - RNP_LOG("ECDH encryption failed %d", ret); - return ret; - } - break; - } - case PGP_PKA_ELGAMAL: { - ret = elgamal_encrypt_pkcs1(&handler->ctx->ctx->rng, - &material.eg, - enckey.data(), - enckey_len, - &userkey->material().eg); - if (ret) { - RNP_LOG("pgp_elgamal_public_encrypt failed"); - return ret; - } - break; - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: - ret = x25519_native_encrypt(&handler->ctx->ctx->rng, - userkey->material().x25519.pub, - enckey.data(), - enckey_len, - &material.x25519); - if (ret) { - RNP_LOG("x25519 encryption failed"); - return ret; - } - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - ret = userkey->material().kyber_ecdh.pub.encrypt( - &handler->ctx->ctx->rng, &material.kyber_ecdh, enckey.data(), enckey_len); - if (ret) { - RNP_LOG("ML-KEM + ECC Encrypt failed"); - return ret; - } - break; -#endif - default: - RNP_LOG("unsupported alg: %d", (int) userkey->alg()); + ret = userkey->pkt().material->encrypt( + *handler->ctx->ctx, material, enckey.data(), enckey_len); + if (ret) { return ret; } @@ -1364,7 +1274,8 @@ signed_fill_signature(pgp_dest_signed_param_t ¶m, } /* calculate the signature */ auto hdr = param.has_lhdr ? ¶m.lhdr : NULL; - signature_calculate(sig, signer.key->material(), *listh->clone(), *param.ctx->ctx, hdr); + signature_calculate( + sig, *signer.key->pkt().material, *listh->clone(), *param.ctx->ctx, hdr); } static rnp_result_t @@ -1498,13 +1409,13 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo { pgp_dest_signer_info_t sinfo = {}; - if (!signer->key->is_secret()) { + if (!signer->key->pkt().material || !signer->key->is_secret()) { RNP_LOG("secret key required for signing"); return RNP_ERROR_BAD_PARAMETERS; } /* validate signing key material if didn't before */ - signer->key->pkt().material.validate(*param->ctx->ctx, false); - if (!signer->key->pkt().material.valid()) { + signer->key->pkt().material->validate(*param->ctx->ctx, false); + if (!signer->key->pkt().material->valid()) { RNP_LOG("attempt to sign to the key with invalid material"); return RNP_ERROR_NO_SUITABLE_KEY; } @@ -1515,7 +1426,7 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo sinfo.sigexpire = signer->sigexpire; /* Add hash to the list */ - sinfo.halg = pgp_hash_adjust_alg_to_key(signer->halg, &signer->key->pkt()); + sinfo.halg = signer->key->material().adjust_hash(signer->halg); try { param->hashes.add_alg(sinfo.halg); } catch (const std::exception &e) { diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 616133da13..c12b8f33ca 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -115,10 +115,8 @@ TEST_F(rnp_tests, cipher_test_success) TEST_F(rnp_tests, pkcs1_rsa_test_success) { - uint8_t ptext[1024 / 8] = {'a', 'b', 'c', 0}; - uint8_t dec[1024 / 8]; - pgp_rsa_encrypted_t enc; - size_t dec_size; + uint8_t ptext[1024 / 8] = {'a', 'b', 'c', 0}; + uint8_t dec[1024 / 8]; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_RSA; @@ -127,92 +125,91 @@ TEST_F(rnp_tests, pkcs1_rsa_test_success) key_desc.ctx = &global_ctx; pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); - const pgp_rsa_key_t *key_rsa = &seckey.material.rsa; - assert_rnp_success(rsa_encrypt_pkcs1(&global_ctx.rng, &enc, ptext, 3, key_rsa)); - assert_int_equal(enc.m.len, 1024 / 8); + pgp_encrypted_material_t enc; + assert_rnp_success(seckey.material->encrypt(global_ctx, enc, ptext, 3)); + assert_int_equal(enc.rsa.m.len, 1024 / 8); memset(dec, 0, sizeof(dec)); - dec_size = 0; - assert_rnp_success(rsa_decrypt_pkcs1(&global_ctx.rng, dec, &dec_size, &enc, key_rsa)); + size_t dec_size = 0; + assert_rnp_success(seckey.material->decrypt(global_ctx, dec, dec_size, enc)); assert_true(bin_eq_hex(dec, 3, "616263")); assert_int_equal(dec_size, 3); } TEST_F(rnp_tests, rnp_test_eddsa) { - rnp::SecurityContext ctx; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_EDDSA; key_desc.hash_alg = PGP_HASH_SHA256; - key_desc.ctx = &ctx; + key_desc.ctx = &global_ctx; pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); - const uint8_t hash[32] = {0}; - pgp_ec_signature_t sig = {{{0}}}; - - assert_rnp_success( - eddsa_sign(&global_ctx.rng, &sig, hash, sizeof(hash), &seckey.material.ec)); + rnp::secure_vector hash(32); + pgp_signature_material_t sig = {}; - assert_rnp_success(eddsa_verify(&sig, hash, sizeof(hash), &seckey.material.ec)); + assert_rnp_success(seckey.material->sign(global_ctx, sig, hash)); + assert_rnp_success(seckey.material->verify(global_ctx, sig, hash)); // cut one byte off hash -> invalid sig - assert_rnp_failure(eddsa_verify(&sig, hash, sizeof(hash) - 1, &seckey.material.ec)); + rnp::secure_vector hash_cut(31); + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash_cut)); // swap r/s -> invalid sig - pgp::mpi tmp = sig.r; - sig.r = sig.s; - sig.s = tmp; - assert_rnp_failure(eddsa_verify(&sig, hash, sizeof(hash), &seckey.material.ec)); + pgp::mpi tmp = sig.ecc.r; + sig.ecc.r = sig.ecc.s; + sig.ecc.s = tmp; + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash)); } TEST_F(rnp_tests, rnp_test_x25519) { rnp_keygen_crypto_params_t key_desc = {}; - pgp_key_pkt_t seckey; - pgp_ecdh_encrypted_t enc = {}; - uint8_t in[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - uint8_t out[16] = {}; - size_t outlen = 0; - pgp_fingerprint_t fp = {}; - key_desc.key_alg = PGP_PKA_ECDH; key_desc.hash_alg = PGP_HASH_SHA256; key_desc.ctx = &global_ctx; key_desc.ecc.curve = PGP_CURVE_25519; + pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); /* check for length and correctly tweaked bits */ - assert_int_equal(seckey.material.ec.x.len, 32); - assert_int_equal(seckey.material.ec.x.mpi[31] & 7, 0); - assert_int_equal(seckey.material.ec.x.mpi[0] & 128, 0); - assert_int_equal(seckey.material.ec.x.mpi[0] & 64, 64); + auto &ec = dynamic_cast(*seckey.material); + assert_int_equal(ec.x().len, 32); + assert_int_equal(ec.x().mpi[31] & 7, 0); + assert_int_equal(ec.x().mpi[0] & 128, 0); + assert_int_equal(ec.x().mpi[0] & 64, 64); + /* encrypt */ + pgp_fingerprint_t fp = {}; assert_rnp_success(pgp_fingerprint(fp, seckey)); - assert_rnp_success( - ecdh_encrypt_pkcs5(&global_ctx.rng, &enc, in, sizeof(in), &seckey.material.ec, fp)); - assert_true(enc.mlen > 16); - assert_true((enc.p.mpi[0] == 0x40) && (enc.p.len == 33)); - outlen = sizeof(out); - assert_rnp_success(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); - assert_true(outlen == 16); - assert_true(memcmp(in, out, 16) == 0); - + uint8_t in[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + pgp_encrypted_material_t enc = {}; + enc.ecdh.fp = &fp; + assert_rnp_success(seckey.material->encrypt(global_ctx, enc, in, sizeof(in))); + assert_true(enc.ecdh.mlen > 16); + assert_int_equal(enc.ecdh.p.mpi[0], 0x40); + assert_int_equal(enc.ecdh.p.len, 33); + /* decrypt */ + uint8_t out[16] = {}; + size_t outlen = sizeof(out); + assert_rnp_success(seckey.material->decrypt(global_ctx, out, outlen, enc)); + assert_int_equal(outlen, 16); + assert_int_equal(memcmp(in, out, 16), 0); /* negative cases */ - enc.p.mpi[16] ^= 0xff; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.p.mpi[16] ^= 0xff; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); - enc.p.mpi[16] ^= 0xff; - enc.p.mpi[0] = 0x04; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.p.mpi[16] ^= 0xff; + enc.ecdh.p.mpi[0] = 0x04; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); - enc.p.mpi[0] = 0x40; - enc.mlen--; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.p.mpi[0] = 0x40; + enc.ecdh.mlen--; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); - enc.mlen += 2; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.mlen += 2; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); } static void @@ -239,7 +236,6 @@ TEST_F(rnp_tests, raw_elgamal_random_key_test_success) TEST_F(rnp_tests, ecdsa_signverify_success) { - uint8_t message[64]; const pgp_hash_alg_t hash_alg = PGP_HASH_SHA512; struct curve { @@ -250,9 +246,9 @@ TEST_F(rnp_tests, ecdsa_signverify_success) for (size_t i = 0; i < ARRAY_SIZE(curves); i++) { // Generate test data. Mainly to make valgrind not to complain about uninitialized data - global_ctx.rng.get(message, sizeof(message)); + rnp::secure_vector hash(rnp::Hash::size(hash_alg)); + global_ctx.rng.get(hash.data(), hash.size()); - pgp_ec_signature_t sig = {{{0}}}; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_ECDSA; key_desc.hash_alg = hash_alg; @@ -265,20 +261,17 @@ TEST_F(rnp_tests, ecdsa_signverify_success) assert_true(pgp_generate_seckey(key_desc, seckey1, true)); assert_true(pgp_generate_seckey(key_desc, seckey2, true)); - const pgp_ec_key_t *key1 = &seckey1.material.ec; - const pgp_ec_key_t *key2 = &seckey2.material.ec; - - assert_rnp_success( - ecdsa_sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message), key1)); - - assert_rnp_success(ecdsa_verify(&sig, hash_alg, message, sizeof(message), key1)); + pgp_signature_material_t sig = {}; + sig.halg = hash_alg; + assert_rnp_success(seckey1.material->sign(global_ctx, sig, hash)); + assert_rnp_success(seckey1.material->verify(global_ctx, sig, hash)); // Fails because of different key used - assert_rnp_failure(ecdsa_verify(&sig, hash_alg, message, sizeof(message), key2)); + assert_rnp_failure(seckey2.material->verify(global_ctx, sig, hash)); // Fails because message won't verify - message[0] = ~message[0]; - assert_rnp_failure(ecdsa_verify(&sig, hash_alg, message, sizeof(message), key1)); + hash[0] = ~hash[0]; + assert_rnp_failure(seckey1.material->verify(global_ctx, sig, hash)); } } @@ -290,47 +283,62 @@ TEST_F(rnp_tests, ecdh_roundtrip) } curves[] = { {PGP_CURVE_NIST_P_256, 32}, {PGP_CURVE_NIST_P_384, 48}, {PGP_CURVE_NIST_P_521, 66}}; - pgp_ecdh_encrypted_t enc; - uint8_t plaintext[32] = {0}; - size_t plaintext_len = sizeof(plaintext); - uint8_t result[32] = {0}; - size_t result_len = sizeof(result); + uint8_t in[32] = {1, 2, 3}; + size_t in_len = sizeof(in); for (size_t i = 0; i < ARRAY_SIZE(curves); i++) { - rnp_keygen_crypto_params_t key_desc; + rnp_keygen_crypto_params_t key_desc{}; key_desc.key_alg = PGP_PKA_ECDH; key_desc.hash_alg = PGP_HASH_SHA512; key_desc.ecc.curve = curves[i].id; key_desc.ctx = &global_ctx; - pgp_key_pkt_t ecdh_key1; + pgp_key_pkt_t ecdh_key1{}; assert_true(pgp_generate_seckey(key_desc, ecdh_key1, true)); - pgp_fingerprint_t ecdh_key1_fpr = {}; + pgp_fingerprint_t ecdh_key1_fpr{}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); - assert_rnp_success(ecdh_encrypt_pkcs5(&global_ctx.rng, - &enc, - plaintext, - plaintext_len, - &ecdh_key1.material.ec, - ecdh_key1_fpr)); + pgp_encrypted_material_t enc{}; + enc.ecdh.fp = &ecdh_key1_fpr; + assert_rnp_success(ecdh_key1.material->encrypt(global_ctx, enc, in, in_len)); - assert_rnp_success(ecdh_decrypt_pkcs5( - result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr)); + uint8_t res[40] = {0}; + size_t res_len = sizeof(res); + assert_rnp_success(ecdh_key1.material->decrypt(global_ctx, res, res_len, enc)); - assert_int_equal(plaintext_len, result_len); - assert_int_equal(memcmp(plaintext, result, result_len), 0); + assert_int_equal(in_len, res_len); + assert_int_equal(memcmp(in, res, res_len), 0); } } +namespace pgp { +class ECDHTestKeyMaterial : public ECDHKeyMaterial { + public: + ECDHTestKeyMaterial(const ECDHKeyMaterial &src) : ECDHKeyMaterial(src) + { + } + + void + set_key_wrap_alg(pgp_symm_alg_t alg) + { + key_.key_wrap_alg = alg; + } + + pgp_ec_key_t & + ec() + { + return key_; + } +}; +} // namespace pgp + TEST_F(rnp_tests, ecdh_decryptionNegativeCases) { - uint8_t plaintext[32] = {0}; - size_t plaintext_len = sizeof(plaintext); - uint8_t result[32] = {0}; - size_t result_len = sizeof(result); - pgp_ecdh_encrypted_t enc; + uint8_t in[32] = {1, 2, 3, 4}; + size_t in_len = sizeof(in); + uint8_t res[36] = {0}; + size_t res_len = sizeof(res); rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_ECDH; @@ -344,74 +352,58 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases) pgp_fingerprint_t ecdh_key1_fpr = {}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); - assert_rnp_success(ecdh_encrypt_pkcs5( - &global_ctx.rng, &enc, plaintext, plaintext_len, &ecdh_key1.material.ec, ecdh_key1_fpr)); + pgp_encrypted_material_t enc; + enc.ecdh.fp = &ecdh_key1_fpr; + assert_rnp_success(ecdh_key1.material->encrypt(global_ctx, enc, in, in_len)); - assert_int_equal(ecdh_decrypt_pkcs5(NULL, 0, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), + assert_int_equal(ecdh_key1.material->decrypt(global_ctx, nullptr, res_len, enc), RNP_ERROR_BAD_PARAMETERS); - assert_int_equal(ecdh_decrypt_pkcs5(result, &result_len, &enc, NULL, ecdh_key1_fpr), - RNP_ERROR_BAD_PARAMETERS); - - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, NULL, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_BAD_PARAMETERS); - - size_t mlen = enc.mlen; - enc.mlen = 0; - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_GENERIC); + size_t mlen = enc.ecdh.mlen; + enc.ecdh.mlen = 0; + assert_int_equal(ecdh_key1.material->decrypt(global_ctx, res, res_len, enc), + RNP_ERROR_GENERIC); - enc.mlen = mlen - 1; - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_GENERIC); + enc.ecdh.mlen = mlen - 1; + assert_int_equal(ecdh_key1.material->decrypt(global_ctx, res, res_len, enc), + RNP_ERROR_GENERIC); - int key_wrapping_alg = ecdh_key1.material.ec.key_wrap_alg; - ecdh_key1.material.ec.key_wrap_alg = PGP_SA_IDEA; - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_NOT_SUPPORTED); - ecdh_key1.material.ec.key_wrap_alg = (pgp_symm_alg_t) key_wrapping_alg; + pgp::ECDHTestKeyMaterial key1_mod( + dynamic_cast(*ecdh_key1.material)); + key1_mod.set_key_wrap_alg(PGP_SA_IDEA); + assert_int_equal(key1_mod.decrypt(global_ctx, res, res_len, enc), RNP_ERROR_NOT_SUPPORTED); } #if defined(ENABLE_SM2) TEST_F(rnp_tests, sm2_roundtrip) { - uint8_t key[27] = {0}; - uint8_t decrypted[27]; - size_t decrypted_size; - rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_SM2; key_desc.hash_alg = PGP_HASH_SM3; key_desc.ecc.curve = PGP_CURVE_SM2_P_256; key_desc.ctx = &global_ctx; + uint8_t key[27] = {0}; global_ctx.rng.get(key, sizeof(key)); pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); - const pgp_ec_key_t *eckey = &seckey.material.ec; + auto &eckey = *seckey.material; - pgp_hash_alg_t hashes[] = {PGP_HASH_SM3, PGP_HASH_SHA256, PGP_HASH_SHA512}; - pgp_sm2_encrypted_t enc; - rnp_result_t ret; + pgp_hash_alg_t hashes[] = {PGP_HASH_SM3, PGP_HASH_SHA256, PGP_HASH_SHA512}; + pgp_encrypted_material_t enc; for (size_t i = 0; i < ARRAY_SIZE(hashes); ++i) { - ret = sm2_encrypt(&global_ctx.rng, &enc, key, sizeof(key), hashes[i], eckey); + auto ret = eckey.encrypt(global_ctx, enc, key, sizeof(key)); assert_int_equal(ret, RNP_SUCCESS); - memset(decrypted, 0, sizeof(decrypted)); - decrypted_size = sizeof(decrypted); - ret = sm2_decrypt(decrypted, &decrypted_size, &enc, eckey); + uint8_t dec[32] = {0}; + size_t dec_size = sizeof(dec); + ret = eckey.decrypt(global_ctx, dec, dec_size, enc); assert_int_equal(ret, RNP_SUCCESS); - assert_int_equal(decrypted_size, sizeof(key)); - for (size_t i = 0; i < decrypted_size; ++i) { - assert_int_equal(key[i], decrypted[i]); - } + assert_int_equal(dec_size, sizeof(key)); + assert_int_equal(memcmp(key, dec, dec_size), 0); } } #endif @@ -507,10 +499,6 @@ TEST_F(rnp_tests, sm2_sha256_signature_test) TEST_F(rnp_tests, test_dsa_roundtrip) { - uint8_t message[PGP_MAX_HASH_SIZE]; - pgp_key_pkt_t seckey; - pgp_dsa_signature_t sig; - struct key_params { size_t p; size_t q; @@ -531,10 +519,10 @@ TEST_F(rnp_tests, test_dsa_roundtrip) {1024, 256, PGP_HASH_SHA256}, }; + uint8_t message[PGP_MAX_HASH_SIZE]; global_ctx.rng.get(message, sizeof(message)); for (size_t i = 0; i < ARRAY_SIZE(keys); i++) { - sig = {}; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_DSA; key_desc.hash_alg = keys[i].h; @@ -542,6 +530,7 @@ TEST_F(rnp_tests, test_dsa_roundtrip) key_desc.dsa.q_bitlen = keys[i].q; key_desc.ctx = &global_ctx; + pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); // try to prevent timeouts in travis-ci printf("p: %zu q: %zu h: %s\n", @@ -550,20 +539,21 @@ TEST_F(rnp_tests, test_dsa_roundtrip) rnp::Hash::name(key_desc.hash_alg)); fflush(stdout); - pgp_dsa_key_t *key1 = &seckey.material.dsa; + auto &key = *seckey.material; - size_t h_size = rnp::Hash::size(keys[i].h); - assert_int_equal(dsa_sign(&global_ctx.rng, &sig, message, h_size, key1), RNP_SUCCESS); - assert_int_equal(dsa_verify(&sig, message, h_size, key1), RNP_SUCCESS); + size_t h_size = rnp::Hash::size(keys[i].h); + rnp::secure_vector hash(message, message + h_size); + pgp_signature_material_t sig = {}; + assert_rnp_success(key.sign(global_ctx, sig, hash)); + assert_rnp_success(key.verify(global_ctx, sig, hash)); } } TEST_F(rnp_tests, test_dsa_verify_negative) { - uint8_t message[PGP_MAX_HASH_SIZE]; - pgp_key_pkt_t sec_key1; - pgp_key_pkt_t sec_key2; - pgp_dsa_signature_t sig = {}; + uint8_t message[PGP_MAX_HASH_SIZE]; + pgp_key_pkt_t sec_key1; + pgp_key_pkt_t sec_key2; struct key_params { size_t p; @@ -588,16 +578,18 @@ TEST_F(rnp_tests, test_dsa_verify_negative) rnp::Hash::name(key_desc.hash_alg)); assert_true(pgp_generate_seckey(key_desc, sec_key2, true)); - pgp_dsa_key_t *key1 = &sec_key1.material.dsa; - pgp_dsa_key_t *key2 = &sec_key2.material.dsa; + auto &key1 = *sec_key1.material; + auto &key2 = *sec_key2.material; - size_t h_size = rnp::Hash::size(key.h); - assert_int_equal(dsa_sign(&global_ctx.rng, &sig, message, h_size, key1), RNP_SUCCESS); + size_t h_size = rnp::Hash::size(key.h); + rnp::secure_vector hash(message, message + h_size); + pgp_signature_material_t sig = {}; + assert_rnp_success(key1.sign(global_ctx, sig, hash)); // wrong key used - assert_int_equal(dsa_verify(&sig, message, h_size, key2), RNP_ERROR_SIGNATURE_INVALID); + assert_int_equal(key2.verify(global_ctx, sig, hash), RNP_ERROR_SIGNATURE_INVALID); // different message - message[0] = ~message[0]; - assert_int_equal(dsa_verify(&sig, message, h_size, key1), RNP_ERROR_SIGNATURE_INVALID); + hash[0] = ~hash[0]; + assert_int_equal(key1.verify(global_ctx, sig, hash), RNP_ERROR_SIGNATURE_INVALID); } #if defined(ENABLE_PQC) @@ -609,14 +601,13 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) PGP_PKA_KYBER768_BP256, PGP_PKA_KYBER1024_BP384}; - pgp_kyber_ecdh_encrypted_t enc; - uint8_t plaintext[32] = {0}; - size_t plaintext_len = sizeof(plaintext); - uint8_t result[32] = {0}; - size_t result_len = sizeof(result); + uint8_t in[32] = {0}; + size_t in_len = sizeof(in); + uint8_t res[36] = {0}; + size_t res_len = sizeof(res); - for (size_t i = 0; i < plaintext_len; i++) { - plaintext[i] = i; // assures that we do not have a special case with all-zeroes + for (size_t i = 0; i < in_len; i++) { + in[i] = i; // assures that we do not have a special case with all-zeroes } for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { @@ -628,17 +619,12 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) pgp_key_pkt_t key_pkt; assert_true(pgp_generate_seckey(key_desc, key_pkt, true)); - pgp_fingerprint_t key_fpr = {}; - assert_rnp_success(pgp_fingerprint(key_fpr, key_pkt)); + pgp_encrypted_material_t enc; + assert_rnp_success(key_pkt.material->encrypt(global_ctx, enc, in, in_len)); + assert_rnp_success(key_pkt.material->decrypt(global_ctx, res, res_len, enc)); - pgp_key_t key(key_pkt); - assert_rnp_success(key_pkt.material.kyber_ecdh.pub.encrypt( - &global_ctx.rng, &enc, plaintext, plaintext_len)); - assert_rnp_success(key_pkt.material.kyber_ecdh.priv.decrypt( - &global_ctx.rng, result, &result_len, &enc)); - - assert_int_equal(plaintext_len, result_len); - assert_int_equal(memcmp(plaintext, result, result_len), 0); + assert_int_equal(in_len, res_len); + assert_int_equal(memcmp(in, res, res_len), 0); } } @@ -657,8 +643,7 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) // Generate test data. Mainly to make valgrind not to complain about uninitialized data global_ctx.rng.get(message, sizeof(message)); - pgp_dilithium_exdsa_signature_t sig; - rnp_keygen_crypto_params_t key_desc; + rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = algs[i]; key_desc.hash_alg = hash_alg; key_desc.ctx = &global_ctx; @@ -669,16 +654,17 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) assert_true(pgp_generate_seckey(key_desc, seckey1, true)); assert_true(pgp_generate_seckey(key_desc, seckey2, true)); - const pgp_dilithium_exdsa_key_t *key1 = &seckey1.material.dilithium_exdsa; - const pgp_dilithium_exdsa_key_t *key2 = &seckey2.material.dilithium_exdsa; + auto &key1 = *seckey1.material; + auto &key2 = *seckey2.material; - assert_rnp_success( - key1->priv.sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message))); - - assert_rnp_success(key1->pub.verify(&sig, hash_alg, message, sizeof(message))); + pgp_signature_material_t sig; + sig.halg = hash_alg; + rnp::secure_vector hash(message, message + sizeof(message)); + assert_rnp_success(key1.sign(global_ctx, sig, hash)); + assert_rnp_success(key1.verify(global_ctx, sig, hash)); // Fails because of different key used - assert_rnp_failure(key2->pub.verify(&sig, hash_alg, message, sizeof(message))); + assert_rnp_failure(key2.verify(global_ctx, sig, hash)); } } @@ -699,8 +685,7 @@ TEST_F(rnp_tests, sphincsplus_signverify_success) // data global_ctx.rng.get(message, sizeof(message)); - pgp_sphincsplus_signature_t sig; - rnp_keygen_crypto_params_t key_desc; + rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = algs[i]; key_desc.sphincsplus.param = params[j]; key_desc.ctx = &global_ctx; @@ -711,16 +696,15 @@ TEST_F(rnp_tests, sphincsplus_signverify_success) assert_true(pgp_generate_seckey(key_desc, seckey1, true)); assert_true(pgp_generate_seckey(key_desc, seckey2, true)); - const pgp_sphincsplus_key_t *key1 = &seckey1.material.sphincsplus; - const pgp_sphincsplus_key_t *key2 = &seckey2.material.sphincsplus; - - assert_rnp_success( - key1->priv.sign(&global_ctx.rng, &sig, message, sizeof(message))); - - assert_rnp_success(key1->pub.verify(&sig, message, sizeof(message))); + auto & key1 = *seckey1.material; + auto & key2 = *seckey2.material; + rnp::secure_vector hash(message, message + sizeof(message)); + pgp_signature_material_t sig; + assert_rnp_success(key1.sign(global_ctx, sig, hash)); + assert_rnp_success(key1.verify(global_ctx, sig, hash)); // Fails because of different key used - assert_rnp_failure(key2->pub.verify(&sig, message, sizeof(message))); + assert_rnp_failure(key2.verify(global_ctx, sig, hash)); } } } @@ -796,155 +780,274 @@ read_key_pkt(pgp_key_pkt_t *key, const char *path) return res; } +namespace pgp { +class RSATestKeyMaterial : public RSAKeyMaterial { + public: + RSATestKeyMaterial(const RSAKeyMaterial &src) : RSAKeyMaterial(src) + { + } + + pgp_rsa_key_t & + rsa() + { + return key_; + } +}; + +class DSATestKeyMaterial : public DSAKeyMaterial { + public: + DSATestKeyMaterial(const DSAKeyMaterial &src) : DSAKeyMaterial(src) + { + } + + pgp_dsa_key_t & + dsa() + { + return key_; + } +}; + +class EGTestKeyMaterial : public EGKeyMaterial { + public: + EGTestKeyMaterial(const EGKeyMaterial &src) : EGKeyMaterial(src) + { + } + + pgp_eg_key_t & + eg() + { + return key_; + } +}; + +class ECDSATestKeyMaterial : public ECDSAKeyMaterial { + public: + ECDSATestKeyMaterial(const ECDSAKeyMaterial &src) : ECDSAKeyMaterial(src) + { + } + + pgp_ec_key_t & + ec() + { + return key_; + } +}; + +class EDDSATestKeyMaterial : public EDDSAKeyMaterial { + public: + EDDSATestKeyMaterial(const EDDSAKeyMaterial &src) : EDDSAKeyMaterial(src) + { + } + + pgp_ec_key_t & + ec() + { + return key_; + } +}; + +} // namespace pgp + #define KEYS "data/test_validate_key_material/" TEST_F(rnp_tests, test_validate_key_material) { pgp_key_pkt_t key; - rnp::RNG & rng = global_ctx.rng; /* RSA key and subkey */ assert_true(read_key_pkt(&key, KEYS "rsa-pub.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] |= 1; - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::RSATestKeyMaterial rkey(dynamic_cast(*key.material)); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] |= 1; + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "rsa-sub.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] |= 1; - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + rkey = pgp::RSATestKeyMaterial(dynamic_cast(*key.material)); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] |= 1; + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "rsa-sec.pgp")); - key.material.validate(global_ctx); - assert_true(key.material.validity.valid); - assert_true(key.material.validity.validated); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + assert_true(key.material->validity().valid); + assert_true(key.material->validity().validated); assert_rnp_success(decrypt_secret_key(&key, NULL)); /* make sure validity is reset after decryption */ - assert_false(key.material.validity.valid); - assert_false(key.material.validity.validated); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] += 1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] -= 1; - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] -= 2; - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] -= 2; - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); + assert_false(key.material->validity().valid); + assert_false(key.material->validity().validated); + assert_true(key.material->secret()); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + rkey = pgp::RSATestKeyMaterial(dynamic_cast(*key.material)); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] += 1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] -= 1; + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] -= 2; + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] -= 2; + rkey.validate(global_ctx); + assert_true(rkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "rsa-ssb.pgp")); assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] += 1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] -= 1; - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] -= 2; - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] -= 2; - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); + assert_true(key.material->secret()); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + rkey = pgp::RSATestKeyMaterial(dynamic_cast(*key.material)); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] += 1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] -= 1; + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] -= 2; + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] -= 2; + rkey.validate(global_ctx); + assert_true(rkey.valid()); key = pgp_key_pkt_t(); /* DSA-ElGamal key */ assert_true(read_key_pkt(&key, KEYS "dsa-sec.pgp")); - key.material.dsa.q.mpi[key.material.dsa.q.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.q.mpi[key.material.dsa.q.len - 1] -= 2; + pgp::DSATestKeyMaterial dkey(dynamic_cast(*key.material)); + dkey.dsa().q.mpi[dkey.dsa().q.len - 1] += 2; + dkey.validate(global_ctx); + assert_false(dkey.valid()); + dkey.dsa().q.mpi[dkey.dsa().q.len - 1] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.y.mpi[key.material.dsa.y.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.y.mpi[key.material.dsa.y.len - 1] -= 2; - key.material.dsa.p.mpi[key.material.dsa.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.p.mpi[key.material.dsa.p.len - 1] -= 2; + assert_true(key.material->secret()); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + dkey = pgp::DSATestKeyMaterial(dynamic_cast(*key.material)); + dkey.dsa().y.mpi[dkey.dsa().y.len - 1] += 2; + dkey.validate(global_ctx); + assert_false(dkey.valid()); + dkey.dsa().y.mpi[dkey.dsa().y.len - 1] -= 2; + dkey.dsa().p.mpi[dkey.dsa().p.len - 1] += 2; + dkey.validate(global_ctx); + assert_false(dkey.valid()); + dkey.dsa().p.mpi[dkey.dsa().p.len - 1] -= 2; /* since Botan calculates y from x on key load we do not check x vs y */ - key.material.dsa.x = key.material.dsa.q; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + dkey.dsa().x = dkey.dsa().q; + dkey.validate(global_ctx); + assert_false(dkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "eg-sec.pgp")); - key.material.eg.p.mpi[key.material.eg.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.eg.p.mpi[key.material.eg.p.len - 1] -= 2; + pgp::EGTestKeyMaterial gkey(dynamic_cast(*key.material)); + gkey.eg().p.mpi[gkey.eg().p.len - 1] += 2; + gkey.validate(global_ctx); + assert_false(gkey.valid()); + gkey.eg().p.mpi[gkey.eg().p.len - 1] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.eg.p.mpi[key.material.eg.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.eg.p.mpi[key.material.eg.p.len - 1] -= 2; + assert_true(key.material->secret()); + gkey = pgp::EGTestKeyMaterial(dynamic_cast(*key.material)); + gkey.validate(global_ctx); + assert_true(gkey.valid()); + gkey.eg().p.mpi[gkey.eg().p.len - 1] += 2; + gkey.validate(global_ctx); + assert_false(gkey.valid()); + gkey.eg().p.mpi[gkey.eg().p.len - 1] -= 2; /* since Botan calculates y from x on key load we do not check x vs y */ - key.material.eg.x = key.material.eg.p; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + gkey.eg().x = gkey.eg().p; + gkey.validate(global_ctx); + assert_false(gkey.valid()); key = pgp_key_pkt_t(); /* ElGamal key with small subgroup */ assert_true(read_key_pkt(&key, KEYS "eg-sec-small-group.pgp")); - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_false(key.material->valid()); assert_rnp_success(decrypt_secret_key(&key, NULL)); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "eg-sec-small-group-enc.pgp")); - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_false(key.material->valid()); assert_rnp_success(decrypt_secret_key(&key, "password")); key = pgp_key_pkt_t(); /* ECDSA key */ assert_true(read_key_pkt(&key, KEYS "ecdsa-p256-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; - key.material.ec.p.mpi[10] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[10] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::ECDSATestKeyMaterial ekey(dynamic_cast(*key.material)); + ekey.validate(global_ctx); + assert_true(ekey.valid()); + ekey.ec().p.mpi[0] += 2; + ekey.validate(global_ctx); + assert_false(ekey.valid()); + ekey.ec().p.mpi[0] -= 2; + ekey.ec().p.mpi[10] += 2; + ekey.validate(global_ctx); + assert_false(ekey.valid()); + ekey.ec().p.mpi[10] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); + assert_true(key.material->secret()); key = pgp_key_pkt_t(); /* ECDH key */ assert_true(read_key_pkt(&key, KEYS "ecdh-p256-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; - key.material.ec.p.mpi[10] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[10] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::ECDHTestKeyMaterial ehkey(dynamic_cast(*key.material)); + ehkey.ec().p.mpi[0] += 2; + ehkey.validate(global_ctx); + assert_false(ehkey.valid()); + ehkey.ec().p.mpi[0] -= 2; + ehkey.ec().p.mpi[10] += 2; + ehkey.validate(global_ctx); + assert_false(ehkey.valid()); + ehkey.ec().p.mpi[10] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); + assert_true(key.material->secret()); key = pgp_key_pkt_t(); /* EDDSA key, just test for header since any value can be secret key */ assert_true(read_key_pkt(&key, KEYS "ed25519-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::EDDSATestKeyMaterial edkey(dynamic_cast(*key.material)); + edkey.ec().p.mpi[0] += 2; + edkey.validate(global_ctx); + assert_false(edkey.valid()); + edkey.ec().p.mpi[0] -= 2; key = pgp_key_pkt_t(); /* x25519 key, same as the previous - botan calculates pub key from the secret one */ assert_true(read_key_pkt(&key, KEYS "x25519-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + ehkey = pgp::ECDHTestKeyMaterial(dynamic_cast(*key.material)); + ehkey.ec().p.mpi[0] += 2; + ehkey.validate(global_ctx); + assert_false(ehkey.valid()); + ehkey.ec().p.mpi[0] -= 2; key = pgp_key_pkt_t(); } diff --git a/src/tests/cli_tests.py b/src/tests/cli_tests.py index ebea4a7517..f3f2a22408 100755 --- a/src/tests/cli_tests.py +++ b/src/tests/cli_tests.py @@ -2490,7 +2490,7 @@ def test_rnp_autocrypt_key_import(self): def test_rnp_list_packets(self): KEY_P256 = data_path('test_list_packets/ecc-p256-pub.asc') - # List packets in humand-readable format + # List packets in human-readable format params = ['--list-packets', KEY_P256] ret, out, _ = run_proc(RNP, params) self.assertEqual(ret, 0, PKT_LIST_FAILED) diff --git a/src/tests/data/test_key_validity/case5/generate.cpp b/src/tests/data/test_key_validity/case5/generate.cpp index 6ec92cd470..3b185aec7a 100644 --- a/src/tests/data/test_key_validity/case5/generate.cpp +++ b/src/tests/data/test_key_validity/case5/generate.cpp @@ -94,7 +94,7 @@ main(int argc, char **argv) pgp_keyid(keyid, sizeof(keyid), tskey.key); pgp_fingerprint(&keyfp, tskey.key); - binding->halg = pgp_hash_adjust_alg_to_key(binding->halg, &tskey.key); + binding->halg = tskey.key.material->adjust_hash(binding->halg); binding->palg = tskey.key.alg; binding->set_keyfp(keyfp); diff --git a/src/tests/key-protect.cpp b/src/tests/key-protect.cpp index d22960d838..30e4c67c0d 100644 --- a/src/tests/key-protect.cpp +++ b/src/tests/key-protect.cpp @@ -30,6 +30,22 @@ #include "support.h" #include "crypto.h" +bool +rsa_sec_empty(const pgp::KeyMaterial &key) +{ + auto &rsa = dynamic_cast(key); + return mpi_empty(rsa.d()) && mpi_empty(rsa.p()) && mpi_empty(rsa.q()) && + mpi_empty(rsa.u()); +} + +bool +rsa_sec_filled(const pgp::KeyMaterial &key) +{ + auto &rsa = dynamic_cast(key); + return !mpi_empty(rsa.d()) && !mpi_empty(rsa.p()) && !mpi_empty(rsa.q()) && + !mpi_empty(rsa.u()); +} + /* This test loads a .gpg keyring and tests protect/unprotect functionality. * There is also some lock/unlock testing in here, since the two are * somewhat related. @@ -77,10 +93,7 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_int_equal(key->alg(), PGP_PKA_RSA); // confirm key material is currently all NULL (in other words, the key is locked) - assert_true(mpi_empty(key->material().rsa.d)); - assert_true(mpi_empty(key->material().rsa.p)); - assert_true(mpi_empty(key->material().rsa.q)); - assert_true(mpi_empty(key->material().rsa.u)); + assert_true(rsa_sec_empty(key->material())); // try to unprotect with a failing password provider pgp_password_provider_t pprov(failing_password_callback); @@ -99,10 +112,7 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_true(key->is_locked()); // confirm secret key material is still NULL - assert_true(mpi_empty(key->material().rsa.d)); - assert_true(mpi_empty(key->material().rsa.p)); - assert_true(mpi_empty(key->material().rsa.q)); - assert_true(mpi_empty(key->material().rsa.u)); + assert_true(rsa_sec_empty(key->material())); // unlock (no password required since the key is not protected) pprov = {asserting_password_callback}; @@ -110,16 +120,14 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_false(key->is_locked()); // secret key material should be available - assert_false(mpi_empty(key->material().rsa.d)); - assert_false(mpi_empty(key->material().rsa.p)); - assert_false(mpi_empty(key->material().rsa.q)); - assert_false(mpi_empty(key->material().rsa.u)); + assert_true(rsa_sec_filled(key->material())); // save the secret MPIs for some later comparisons - pgp::mpi d = key->material().rsa.d; - pgp::mpi p = key->material().rsa.p; - pgp::mpi q = key->material().rsa.q; - pgp::mpi u = key->material().rsa.u; + auto &rsa = dynamic_cast(key->material()); + auto d = rsa.d(); + auto p = rsa.p(); + auto q = rsa.q(); + auto u = rsa.u(); // confirm that packets[0] is no longer encrypted { @@ -140,36 +148,35 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_false(reloaded_key->is_locked()); assert_false(reloaded_key->is_protected()); // secret key material should not be NULL - assert_false(mpi_empty(reloaded_key->material().rsa.d)); - assert_false(mpi_empty(reloaded_key->material().rsa.p)); - assert_false(mpi_empty(reloaded_key->material().rsa.q)); - assert_false(mpi_empty(reloaded_key->material().rsa.u)); + auto &rsar = dynamic_cast(reloaded_key->material()); + assert_false(mpi_empty(rsar.d())); + assert_false(mpi_empty(rsar.p())); + assert_false(mpi_empty(rsar.q())); + assert_false(mpi_empty(rsar.u())); // compare MPIs of the reloaded key, with the unlocked key from earlier - assert_true(key->material().rsa.d == reloaded_key->material().rsa.d); - assert_true(key->material().rsa.p == reloaded_key->material().rsa.p); - assert_true(key->material().rsa.q == reloaded_key->material().rsa.q); - assert_true(key->material().rsa.u == reloaded_key->material().rsa.u); + assert_true(rsa.d() == rsar.d()); + assert_true(rsa.p() == rsar.p()); + assert_true(rsa.q() == rsar.q()); + assert_true(rsa.u() == rsar.u()); // negative test to try to ensure the above is a valid test - assert_false(key->material().rsa.d == reloaded_key->material().rsa.p); + assert_false(rsa.d() == rsar.p()); // lock it assert_true(reloaded_key->lock()); assert_true(reloaded_key->is_locked()); // confirm that secret MPIs are NULL again - assert_true(mpi_empty(reloaded_key->material().rsa.d)); - assert_true(mpi_empty(reloaded_key->material().rsa.p)); - assert_true(mpi_empty(reloaded_key->material().rsa.q)); - assert_true(mpi_empty(reloaded_key->material().rsa.u)); + assert_true(rsa_sec_empty(reloaded_key->material())); // unlock it (no password, since it's not protected) pgp_password_provider_t pprov(asserting_password_callback); assert_true(reloaded_key->unlock(pprov)); assert_false(reloaded_key->is_locked()); // compare MPIs of the reloaded key, with the unlocked key from earlier - assert_true(key->material().rsa.d == reloaded_key->material().rsa.d); - assert_true(key->material().rsa.p == reloaded_key->material().rsa.p); - assert_true(key->material().rsa.q == reloaded_key->material().rsa.q); - assert_true(key->material().rsa.u == reloaded_key->material().rsa.u); + auto &rsar2 = dynamic_cast(reloaded_key->material()); + assert_true(rsa.d() == rsar2.d()); + assert_true(rsa.p() == rsar2.p()); + assert_true(rsa.q() == rsar2.q()); + assert_true(rsa.u() == rsar2.u()); delete ks; } @@ -212,10 +219,11 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_false(key->is_locked()); // compare secret MPIs with those from earlier - assert_true(key->material().rsa.d == d); - assert_true(key->material().rsa.p == p); - assert_true(key->material().rsa.q == q); - assert_true(key->material().rsa.u == u); + auto &rsa2 = dynamic_cast(key->material()); + assert_true(rsa2.d() == d); + assert_true(rsa2.p() == p); + assert_true(rsa2.q() == q); + assert_true(rsa2.u() == u); // cleanup delete key; diff --git a/src/tests/key-unlock.cpp b/src/tests/key-unlock.cpp index 53ccb94687..fc58fd9eb9 100644 --- a/src/tests/key-unlock.cpp +++ b/src/tests/key-unlock.cpp @@ -31,6 +31,9 @@ #include "support.h" #include +bool rsa_sec_empty(const pgp::KeyMaterial &key); +bool rsa_sec_filled(const pgp::KeyMaterial &key); + TEST_F(rnp_tests, test_key_unlock_pgp) { cli_rnp_t rnp = {}; @@ -86,10 +89,7 @@ TEST_F(rnp_tests, test_key_unlock_pgp) rnp_buffer_destroy(alg); // confirm the secret MPIs are NULL - assert_true(mpi_empty(key->sec->material().rsa.d)); - assert_true(mpi_empty(key->sec->material().rsa.p)); - assert_true(mpi_empty(key->sec->material().rsa.q)); - assert_true(mpi_empty(key->sec->material().rsa.u)); + assert_true(rsa_sec_empty(key->sec->material())); // try to unlock with a failing password provider provider.callback = failing_password_callback; @@ -114,10 +114,7 @@ TEST_F(rnp_tests, test_key_unlock_pgp) assert_false(locked); // confirm the secret MPIs are now filled in - assert_false(mpi_empty(key->sec->material().rsa.d)); - assert_false(mpi_empty(key->sec->material().rsa.p)); - assert_false(mpi_empty(key->sec->material().rsa.q)); - assert_false(mpi_empty(key->sec->material().rsa.u)); + assert_true(rsa_sec_filled(key->sec->material())); // now the signing key is unlocked, confirm that no password is required for signing assert_rnp_success( diff --git a/src/tests/load-pgp.cpp b/src/tests/load-pgp.cpp index 07292ae746..888ddbcc28 100644 --- a/src/tests/load-pgp.cpp +++ b/src/tests/load-pgp.cpp @@ -705,7 +705,7 @@ TEST_F(rnp_tests, test_load_public_from_secret) assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_KEY); assert_null(keycp.pkt().sec_data); assert_int_equal(keycp.pkt().sec_len, 0); - assert_false(keycp.pkt().material.secret); + assert_false(keycp.pkt().material->secret()); pubstore->add_key(keycp); /* subkey 1 */ keycp = pgp_key_t(*skey1, true); @@ -717,7 +717,7 @@ TEST_F(rnp_tests, test_load_public_from_secret) assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY); assert_null(keycp.pkt().sec_data); assert_int_equal(keycp.pkt().sec_len, 0); - assert_false(keycp.pkt().material.secret); + assert_false(keycp.pkt().material->secret()); pubstore->add_key(keycp); /* subkey 2 */ keycp = pgp_key_t(*skey2, true); @@ -729,7 +729,7 @@ TEST_F(rnp_tests, test_load_public_from_secret) assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY); assert_null(keycp.pkt().sec_data); assert_int_equal(keycp.pkt().sec_len, 0); - assert_false(keycp.pkt().material.secret); + assert_false(keycp.pkt().material->secret()); pubstore->add_key(keycp); /* save pubring */ assert_true(pubstore->write()); From 36f34d2a104e3c4f52237de25fe1417efe43ea96 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Tue, 23 Jul 2024 18:22:25 +0300 Subject: [PATCH 3/8] Fix bunch of compiler warnings. --- src/librepgp/stream-common.cpp | 5 ++++- src/librepgp/stream-parse.cpp | 4 +++- src/librepgp/stream-write.cpp | 6 ++---- src/rnp/fficli.cpp | 2 +- src/tests/key-unlock.cpp | 3 --- src/tests/support.h | 4 ++++ 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/librepgp/stream-common.cpp b/src/librepgp/stream-common.cpp index 18b4b59101..c7ba9326dc 100644 --- a/src/librepgp/stream-common.cpp +++ b/src/librepgp/stream-common.cpp @@ -251,7 +251,10 @@ pgp_source_t::skip(size_t len) rnp_result_t pgp_source_t::finish() { - return raw_finish ? raw_finish(this) : RNP_SUCCESS; + if (raw_finish) { + return raw_finish(this); + } + return RNP_SUCCESS; } bool diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 74ee59a45b..7a15a275bb 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1132,7 +1132,9 @@ signed_read_signatures(pgp_source_t *src) /* we have more onepasses then signatures */ if (ret == RNP_ERROR_READ) { RNP_LOG("Warning: premature end of signatures"); - return param->siginfos.size() ? RNP_SUCCESS : ret; + if (!param->siginfos.empty()) { + return RNP_SUCCESS; + } } if (ret) { return ret; diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 46039a8da9..220c3cfa5e 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -2129,13 +2129,11 @@ rnp_compress_src(pgp_source_t &src, pgp_dest_t &dst, pgp_compression_type_t zalg rnp_result_t rnp_wrap_src(pgp_source_t &src, pgp_dest_t &dst, const std::string &filename, uint32_t modtime) { - pgp_write_handler_t handler = {}; - rnp_ctx_t ctx; + rnp_ctx_t ctx{}; ctx.filename = filename; ctx.filemtime = modtime; - handler.ctx = &ctx; - pgp_dest_t literal = {}; + pgp_dest_t literal{}; pgp_literal_hdr_t hdr{}; build_literal_hdr(ctx, hdr); diff --git a/src/rnp/fficli.cpp b/src/rnp/fficli.cpp index fe5bd99014..5a65c699a3 100644 --- a/src/rnp/fficli.cpp +++ b/src/rnp/fficli.cpp @@ -549,7 +549,7 @@ ffi_key_callback(rnp_ffi_t ffi, } #ifdef _WIN32 -void +static void rnpffiInvalidParameterHandler(const wchar_t *expression, const wchar_t *function, const wchar_t *file, diff --git a/src/tests/key-unlock.cpp b/src/tests/key-unlock.cpp index fc58fd9eb9..8ab7efe5d0 100644 --- a/src/tests/key-unlock.cpp +++ b/src/tests/key-unlock.cpp @@ -31,9 +31,6 @@ #include "support.h" #include -bool rsa_sec_empty(const pgp::KeyMaterial &key); -bool rsa_sec_filled(const pgp::KeyMaterial &key); - TEST_F(rnp_tests, test_key_unlock_pgp) { cli_rnp_t rnp = {}; diff --git a/src/tests/support.h b/src/tests/support.h index 62a04422db..0468598048 100644 --- a/src/tests/support.h +++ b/src/tests/support.h @@ -133,6 +133,10 @@ void test_ffi_init(rnp_ffi_t *ffi); bool mpi_empty(const pgp::mpi &val); +bool rsa_sec_empty(const pgp::KeyMaterial &key); + +bool rsa_sec_filled(const pgp::KeyMaterial &key); + bool write_pass_to_pipe(int fd, size_t count); /* Setup readable pipe with default password inside */ bool setupPasswordfd(int *pipefd); From fc355ba65ca995a671fe4cc7bba66e593387d77a Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Thu, 25 Jul 2024 13:46:37 +0300 Subject: [PATCH 4/8] Update g10 fuzzer with linking to Botan library. --- src/fuzzing/CMakeLists.txt | 6 +++++- src/lib/CMakeLists.txt | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/fuzzing/CMakeLists.txt b/src/fuzzing/CMakeLists.txt index c177035e1d..5b3a74c8ee 100644 --- a/src/fuzzing/CMakeLists.txt +++ b/src/fuzzing/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Ribose Inc. +# Copyright (c) 2020, 2024 Ribose Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -22,6 +22,7 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +find_package(Botan 2.14.0 REQUIRED) if(NOT DEFINED ENV{LIB_FUZZING_ENGINE}) add_compile_options(-fsanitize=fuzzer-no-link) @@ -127,6 +128,8 @@ target_link_libraries(fuzz_keyring_kbx add_executable(fuzz_keyring_g10 keyring_g10.cpp) +set_target_properties(fuzz_keyring_g10 PROPERTIES CXX_STANDARD 20) + target_include_directories(fuzz_keyring_g10 PRIVATE "${PROJECT_SOURCE_DIR}/src" @@ -136,6 +139,7 @@ target_include_directories(fuzz_keyring_g10 target_link_libraries(fuzz_keyring_g10 PRIVATE librnp-static + Botan::Botan ) if (ENABLE_SANITIZERS) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 5d77df7eac..1e4443c757 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -58,9 +58,9 @@ if(ENABLE_PQC) endif() # check that AEAD is enabled and not turned off for ENABLE_CRYPTO_REFRESH - if(ENABLE_CRYPTO_REFRESH AND (NOT ENABLE_AEAD)) - message(FATAL_ERROR "ENABLE_CRYPTO_REFRESH requires ENABLE_AEAD, but it's either Off or Auto and got turned off") - endif() +if(ENABLE_CRYPTO_REFRESH AND (NOT ENABLE_AEAD)) + message(FATAL_ERROR "ENABLE_CRYPTO_REFRESH requires ENABLE_AEAD, but it's either Off or Auto and got turned off") +endif() # generate a config.h include(CheckIncludeFileCXX) From 40d3b49851fb9ec0971b9b5d37adc0692d4ed93c Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Tue, 23 Jul 2024 18:22:50 +0300 Subject: [PATCH 5/8] Enable RNP logging to be able to troubleshoot Windows CI runner. --- .github/workflows/windows-msys2.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/windows-msys2.yml b/.github/workflows/windows-msys2.yml index 2c45ca04c5..9377ee0f92 100644 --- a/.github/workflows/windows-msys2.yml +++ b/.github/workflows/windows-msys2.yml @@ -130,6 +130,7 @@ jobs: mkdir -p "build/Testing/Temporary" cp "cmake/CTestCostData.txt" "build/Testing/Temporary" export PATH="$PWD/build/src/lib:$PATH" + export RNP_LOG_CONSOLE=1 ctest --parallel ${{ env.CORES }} --test-dir build -C Debug --output-on-failure - name: Install From 962e9dbea168148ab6dc19959ef97613b18bc347 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Thu, 25 Jul 2024 12:33:06 +0300 Subject: [PATCH 6/8] Remove code which may cause segfault from the tests. --- src/tests/key-protect.cpp | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/tests/key-protect.cpp b/src/tests/key-protect.cpp index 30e4c67c0d..cead598546 100644 --- a/src/tests/key-protect.cpp +++ b/src/tests/key-protect.cpp @@ -261,36 +261,6 @@ TEST_F(rnp_tests, test_key_protect_sec_data) memcpy(raw_ssub, ssub.pkt().sec_data, 32); pgp_key_pkt_t *skeypkt; pgp_key_pkt_t *ssubpkt; -#if defined(__has_feature) -#if !__has_feature(address_sanitizer) - /* copy keys and delete, making sure secret data is wiped*/ - pgp_key_t *skeycp = new pgp_key_t(skey); - pgp_key_t *ssubcp = new pgp_key_t(ssub); - uint8_t * raw_skey_ptr = skeycp->pkt().sec_data; - uint8_t * raw_ssub_ptr = ssubcp->pkt().sec_data; - assert_int_equal(memcmp(raw_skey, raw_skey_ptr, 32), 0); - assert_int_equal(memcmp(raw_ssub, raw_ssub_ptr, 32), 0); - delete skeycp; - delete ssubcp; - assert_int_not_equal(memcmp(raw_skey, raw_skey_ptr, 32), 0); - assert_int_not_equal(memcmp(raw_ssub, raw_ssub_ptr, 32), 0); - /* do the same with key packet */ - skeypkt = new pgp_key_pkt_t(skey.pkt()); - ssubpkt = new pgp_key_pkt_t(ssub.pkt()); - raw_skey_ptr = skeypkt->sec_data; - raw_ssub_ptr = ssubpkt->sec_data; - assert_int_equal(memcmp(raw_skey, raw_skey_ptr, 32), 0); - assert_int_equal(memcmp(raw_ssub, raw_ssub_ptr, 32), 0); - delete skeypkt; - delete ssubpkt; - assert_int_not_equal(memcmp(raw_skey, raw_skey_ptr, 32), 0); - assert_int_not_equal(memcmp(raw_ssub, raw_ssub_ptr, 32), 0); - /* save original pointers */ - raw_skey_ptr = skey.pkt().sec_data; - raw_ssub_ptr = ssub.pkt().sec_data; -#endif -#endif - /* protect key and subkey */ pgp_password_provider_t pprov(string_copy_password_callback, (void *) "password"); rnp_key_protection_params_t prot = {}; @@ -298,12 +268,6 @@ TEST_F(rnp_tests, test_key_protect_sec_data) assert_true(ssub.protect(prot, pprov, global_ctx)); assert_int_not_equal(memcmp(raw_skey, skey.pkt().sec_data, 32), 0); assert_int_not_equal(memcmp(raw_ssub, ssub.pkt().sec_data, 32), 0); -#if defined(__has_feature) -#if !__has_feature(address_sanitizer) - assert_int_not_equal(memcmp(raw_skey, raw_skey_ptr, 32), 0); - assert_int_not_equal(memcmp(raw_ssub, raw_ssub_ptr, 32), 0); -#endif -#endif /* make sure rawpkt is also protected */ skeypkt = new pgp_key_pkt_t(); pgp_source_t memsrc = {}; From 48f94da8b8d806d967ee60d1610d7dfecfe9c39f Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Mon, 29 Jul 2024 15:23:42 +0300 Subject: [PATCH 7/8] Update constness where applicable. --- src/lib/crypto/exdsa_ecdhkem.cpp | 2 +- src/lib/crypto/exdsa_ecdhkem.h | 2 +- src/lib/crypto/kyber.cpp | 2 +- src/lib/crypto/kyber.h | 2 +- src/lib/crypto/kyber_ecdh_composite.cpp | 4 +- src/lib/crypto/kyber_ecdh_composite.h | 4 +- src/lib/key_material.cpp | 106 +++++++++++------------ src/lib/key_material.hpp | 110 ++++++++++++------------ 8 files changed, 116 insertions(+), 116 deletions(-) diff --git a/src/lib/crypto/exdsa_ecdhkem.cpp b/src/lib/crypto/exdsa_ecdhkem.cpp index 2d664d8598..4d8d47287c 100644 --- a/src/lib/crypto/exdsa_ecdhkem.cpp +++ b/src/lib/crypto/exdsa_ecdhkem.cpp @@ -116,7 +116,7 @@ ecdh_kem_private_key_t::get_pubkey_encoded(rnp::RNG *rng) const rnp_result_t ecdh_kem_public_key_t::encapsulate(rnp::RNG * rng, std::vector &ciphertext, - std::vector &symmetric_key) + std::vector &symmetric_key) const { if (curve_ == PGP_CURVE_25519) { Botan::Curve25519_PrivateKey eph_prv_key(*(rng->obj())); diff --git a/src/lib/crypto/exdsa_ecdhkem.h b/src/lib/crypto/exdsa_ecdhkem.h index 03fe025d6a..6fe2ab0283 100644 --- a/src/lib/crypto/exdsa_ecdhkem.h +++ b/src/lib/crypto/exdsa_ecdhkem.h @@ -88,7 +88,7 @@ class ecdh_kem_public_key_t : public ec_key_t { rnp_result_t encapsulate(rnp::RNG * rng, std::vector &ciphertext, - std::vector &symmetric_key); + std::vector &symmetric_key) const; private: Botan::ECDH_PublicKey botan_key_ecdh(rnp::RNG *rng) const; diff --git a/src/lib/crypto/kyber.cpp b/src/lib/crypto/kyber.cpp index f7e353c949..eaf78e2c64 100644 --- a/src/lib/crypto/kyber.cpp +++ b/src/lib/crypto/kyber.cpp @@ -89,7 +89,7 @@ pgp_kyber_private_key_t::botan_key() const } kyber_encap_result_t -pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) +pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) const { assert(is_initialized_); auto decoded_kyber_pub = botan_key(); diff --git a/src/lib/crypto/kyber.h b/src/lib/crypto/kyber.h index 24122ce8d0..7254f28d60 100644 --- a/src/lib/crypto/kyber.h +++ b/src/lib/crypto/kyber.h @@ -82,7 +82,7 @@ class pgp_kyber_public_key_t { kyber_parameter_e mode); pgp_kyber_public_key_t(std::vector const &key_encoded, kyber_parameter_e mode); pgp_kyber_public_key_t() = default; - kyber_encap_result_t encapsulate(rnp::RNG *rng); + kyber_encap_result_t encapsulate(rnp::RNG *rng) const; bool operator==(const pgp_kyber_public_key_t &rhs) const diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp index b343103f24..647f862252 100644 --- a/src/lib/crypto/kyber_ecdh_composite.cpp +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -339,7 +339,7 @@ rnp_result_t pgp_kyber_ecdh_composite_private_key_t::decrypt(rnp::RNG * rng, uint8_t * out, size_t * out_len, - const pgp_kyber_ecdh_encrypted_t *enc) + const pgp_kyber_ecdh_encrypted_t *enc) const { initialized_or_throw(); rnp_result_t res; @@ -495,7 +495,7 @@ rnp_result_t pgp_kyber_ecdh_composite_public_key_t::encrypt(rnp::RNG * rng, pgp_kyber_ecdh_encrypted_t *out, const uint8_t * session_key, - size_t session_key_len) + size_t session_key_len) const { initialized_or_throw(); diff --git a/src/lib/crypto/kyber_ecdh_composite.h b/src/lib/crypto/kyber_ecdh_composite.h index 3450d90f89..a798dd13a3 100644 --- a/src/lib/crypto/kyber_ecdh_composite.h +++ b/src/lib/crypto/kyber_ecdh_composite.h @@ -99,7 +99,7 @@ class pgp_kyber_ecdh_composite_private_key_t : public pgp_kyber_ecdh_composite_k rnp_result_t decrypt(rnp::RNG * rng, uint8_t * out, size_t * out_len, - const pgp_kyber_ecdh_encrypted_t *enc); + const pgp_kyber_ecdh_encrypted_t *enc) const; bool is_valid(rnp::RNG *rng) const; std::vector get_encoded() const; @@ -148,7 +148,7 @@ class pgp_kyber_ecdh_composite_public_key_t : public pgp_kyber_ecdh_composite_ke rnp_result_t encrypt(rnp::RNG * rng, pgp_kyber_ecdh_encrypted_t *out, const uint8_t * in, - size_t in_len); + size_t in_len) const; bool is_valid(rnp::RNG *rng) const; std::vector get_encoded() const; diff --git a/src/lib/key_material.cpp b/src/lib/key_material.cpp index ba921bcd94..3a1d5058df 100644 --- a/src/lib/key_material.cpp +++ b/src/lib/key_material.cpp @@ -150,7 +150,7 @@ KeyMaterial::valid() const } bool -KeyMaterial::equals(const KeyMaterial &value) noexcept +KeyMaterial::equals(const KeyMaterial &value) const noexcept { return alg_ == value.alg_; } @@ -214,7 +214,7 @@ rnp_result_t KeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { return RNP_ERROR_NOT_SUPPORTED; } @@ -223,7 +223,7 @@ rnp_result_t KeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { return RNP_ERROR_NOT_SUPPORTED; } @@ -239,7 +239,7 @@ KeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t KeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return RNP_ERROR_NOT_SUPPORTED; } @@ -387,7 +387,7 @@ RSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -RSAKeyMaterial::equals(const KeyMaterial &value) noexcept +RSAKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -422,14 +422,14 @@ RSAKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -RSAKeyMaterial::write(pgp_packet_body_t &pkt) +RSAKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.n); pkt.add(key_.e); } void -RSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) +RSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.d); pkt.add(key_.p); @@ -456,7 +456,7 @@ rnp_result_t RSAKeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { return rsa_encrypt_pkcs1(&ctx.rng, &out.rsa, data, len, &key_); } @@ -465,7 +465,7 @@ rnp_result_t RSAKeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { if ((alg() != PGP_PKA_RSA) && (alg() != PGP_PKA_RSA_ENCRYPT_ONLY)) { RNP_LOG("Non-encrypting RSA algorithm: %d\n", alg()); @@ -489,7 +489,7 @@ RSAKeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t RSAKeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return rsa_sign_pkcs1(&ctx.rng, &sig.rsa, sig.halg, hash.data(), hash.size(), &key_); } @@ -568,7 +568,7 @@ DSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -DSAKeyMaterial::equals(const KeyMaterial &value) noexcept +DSAKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -604,7 +604,7 @@ DSAKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -DSAKeyMaterial::write(pgp_packet_body_t &pkt) +DSAKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.p); pkt.add(key_.q); @@ -613,7 +613,7 @@ DSAKeyMaterial::write(pgp_packet_body_t &pkt) } void -DSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) +DSAKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.x); } @@ -639,7 +639,7 @@ DSAKeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t DSAKeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return dsa_sign(&ctx.rng, &sig.dsa, hash.data(), hash.size(), &key_); } @@ -724,7 +724,7 @@ EGKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -EGKeyMaterial::equals(const KeyMaterial &value) noexcept +EGKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -759,7 +759,7 @@ EGKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -EGKeyMaterial::write(pgp_packet_body_t &pkt) +EGKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.p); pkt.add(key_.g); @@ -767,7 +767,7 @@ EGKeyMaterial::write(pgp_packet_body_t &pkt) } void -EGKeyMaterial::write_secret(pgp_packet_body_t &pkt) +EGKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.x); } @@ -791,7 +791,7 @@ rnp_result_t EGKeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { return elgamal_encrypt_pkcs1(&ctx.rng, &out.eg, data, len, &key_); } @@ -800,7 +800,7 @@ rnp_result_t EGKeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { return elgamal_decrypt_pkcs1(&ctx.rng, out, &out_len, &in.eg, &key_); } @@ -858,7 +858,7 @@ ECKeyMaterial::grip_update(rnp::Hash &hash) const } bool -ECKeyMaterial::equals(const KeyMaterial &value) noexcept +ECKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -875,7 +875,7 @@ ECKeyMaterial::clear_secret() } rnp_result_t -ECKeyMaterial::check_curve(size_t hash_len) +ECKeyMaterial::check_curve(size_t hash_len) const { const ec_curve_desc_t *curve = get_curve_desc(key_.curve); if (!curve) { @@ -916,14 +916,14 @@ ECKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -ECKeyMaterial::write(pgp_packet_body_t &pkt) +ECKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.curve); pkt.add(key_.p); } void -ECKeyMaterial::write_secret(pgp_packet_body_t &pkt) +ECKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.x); } @@ -1007,7 +1007,7 @@ ECDSAKeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t ECDSAKeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { auto ret = check_curve(hash.size()); if (ret) { @@ -1067,7 +1067,7 @@ ECDHKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept } void -ECDHKeyMaterial::write(pgp_packet_body_t &pkt) +ECDHKeyMaterial::write(pgp_packet_body_t &pkt) const { ECKeyMaterial::write(pkt); pkt.add_byte(3); @@ -1101,7 +1101,7 @@ rnp_result_t ECDHKeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { if (!curve_supported(key_.curve)) { RNP_LOG("ECDH encrypt: curve %d is not supported.", key_.curve); @@ -1115,7 +1115,7 @@ rnp_result_t ECDHKeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { if (!curve_supported(key_.curve)) { RNP_LOG("ECDH decrypt: curve %d is not supported.", key_.curve); @@ -1184,7 +1184,7 @@ EDDSAKeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t EDDSAKeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return eddsa_sign(&ctx.rng, &sig.ecc, hash.data(), hash.size(), &key_); } @@ -1210,7 +1210,7 @@ rnp_result_t SM2KeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { #if defined(ENABLE_SM2) return sm2_encrypt(&ctx.rng, &out.sm2, data, len, PGP_HASH_SM3, &key_); @@ -1224,7 +1224,7 @@ rnp_result_t SM2KeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { #if defined(ENABLE_SM2) return sm2_decrypt(out, &out_len, &in.sm2, &key_); @@ -1250,7 +1250,7 @@ SM2KeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t SM2KeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { #if defined(ENABLE_SM2) auto ret = check_curve(hash.size()); @@ -1300,7 +1300,7 @@ Ed25519KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -Ed25519KeyMaterial::equals(const KeyMaterial &value) noexcept +Ed25519KeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -1345,13 +1345,13 @@ Ed25519KeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -Ed25519KeyMaterial::write(pgp_packet_body_t &pkt) +Ed25519KeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.pub); } void -Ed25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) +Ed25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.priv); } @@ -1377,7 +1377,7 @@ Ed25519KeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t Ed25519KeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return ed25519_sign_native(&ctx.rng, sig.ed25519.sig, key_.priv, hash.data(), hash.size()); } @@ -1426,7 +1426,7 @@ X25519KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -X25519KeyMaterial::equals(const KeyMaterial &value) noexcept +X25519KeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -1471,13 +1471,13 @@ X25519KeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -X25519KeyMaterial::write(pgp_packet_body_t &pkt) +X25519KeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.pub); } void -X25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) +X25519KeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.priv); } @@ -1496,7 +1496,7 @@ rnp_result_t X25519KeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { return x25519_native_encrypt(&ctx.rng, key_.pub, data, len, &out.x25519); } @@ -1505,7 +1505,7 @@ rnp_result_t X25519KeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { return x25519_native_decrypt(&ctx.rng, key_, &in.x25519, out, &out_len); } @@ -1555,7 +1555,7 @@ KyberKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -KyberKeyMaterial::equals(const KeyMaterial &value) noexcept +KyberKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -1598,13 +1598,13 @@ KyberKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -KyberKeyMaterial::write(pgp_packet_body_t &pkt) +KyberKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.pub.get_encoded()); } void -KyberKeyMaterial::write_secret(pgp_packet_body_t &pkt) +KyberKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.priv.get_encoded()); } @@ -1623,7 +1623,7 @@ rnp_result_t KyberKeyMaterial::encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) + size_t len) const { return key_.pub.encrypt(&ctx.rng, &out.kyber_ecdh, data, len); } @@ -1632,7 +1632,7 @@ rnp_result_t KyberKeyMaterial::decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) + const pgp_encrypted_material_t &in) const { return key_.priv.decrypt(&ctx.rng, out, &out_len, &in.kyber_ecdh); } @@ -1674,7 +1674,7 @@ DilithiumKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -DilithiumKeyMaterial::equals(const KeyMaterial &value) noexcept +DilithiumKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -1717,13 +1717,13 @@ DilithiumKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -DilithiumKeyMaterial::write(pgp_packet_body_t &pkt) +DilithiumKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.pub.get_encoded()); } void -DilithiumKeyMaterial::write_secret(pgp_packet_body_t &pkt) +DilithiumKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.priv.get_encoded()); } @@ -1749,7 +1749,7 @@ DilithiumKeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t DilithiumKeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return key_.priv.sign(&ctx.rng, &sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); } @@ -1797,7 +1797,7 @@ SphincsPlusKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) } bool -SphincsPlusKeyMaterial::equals(const KeyMaterial &value) noexcept +SphincsPlusKeyMaterial::equals(const KeyMaterial &value) const noexcept { auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { @@ -1852,14 +1852,14 @@ SphincsPlusKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -SphincsPlusKeyMaterial::write(pgp_packet_body_t &pkt) +SphincsPlusKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add_byte((uint8_t) key_.pub.param()); pkt.add(key_.pub.get_encoded()); } void -SphincsPlusKeyMaterial::write_secret(pgp_packet_body_t &pkt) +SphincsPlusKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add_byte((uint8_t) key_.priv.param()); pkt.add(key_.priv.get_encoded()); @@ -1886,7 +1886,7 @@ SphincsPlusKeyMaterial::verify(const rnp::SecurityContext & ctx, rnp_result_t SphincsPlusKeyMaterial::sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) + const rnp::secure_vector &hash) const { return key_.priv.sign(&ctx.rng, &sig.sphincsplus, hash.data(), hash.size()); } diff --git a/src/lib/key_material.hpp b/src/lib/key_material.hpp index 62049d65f7..058dff8aff 100644 --- a/src/lib/key_material.hpp +++ b/src/lib/key_material.hpp @@ -58,27 +58,27 @@ class KeyMaterial { void set_validity(const pgp_validity_t &val); void reset_validity(); bool valid() const; - virtual bool equals(const KeyMaterial &value) noexcept; + virtual bool equals(const KeyMaterial &value) const noexcept; virtual void clear_secret(); virtual bool parse(pgp_packet_body_t &pkt) noexcept = 0; virtual bool parse_secret(pgp_packet_body_t &pkt) noexcept = 0; - virtual void write(pgp_packet_body_t &pkt) = 0; - virtual void write_secret(pgp_packet_body_t &pkt) = 0; + virtual void write(pgp_packet_body_t &pkt) const = 0; + virtual void write_secret(pgp_packet_body_t &pkt) const = 0; virtual bool generate(const rnp_keygen_crypto_params_t ¶ms); virtual rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len); + size_t len) const; virtual rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in); + const pgp_encrypted_material_t &in) const; virtual rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const; virtual rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash); + const rnp::secure_vector &hash) const; /* Pick up hash algorithm, used for signing, to be compatible with key material. */ virtual pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const; @@ -107,27 +107,27 @@ class RSAKeyMaterial : public KeyMaterial { : KeyMaterial(kalg, secret), key_(key){}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) override; + size_t len) const override; rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) override; + const pgp_encrypted_material_t &in) const override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; void set_secret(const mpi &d, const mpi &p, const mpi &q, const mpi &u); size_t bits() const noexcept override; @@ -153,19 +153,19 @@ class DSAKeyMaterial : public KeyMaterial { : KeyMaterial(PGP_PKA_DSA, secret), key_(key){}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; void set_secret(const mpi &x); size_t bits() const noexcept override; @@ -191,21 +191,21 @@ class EGKeyMaterial : public KeyMaterial { : KeyMaterial(kalg, secret), key_(key){}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) override; + size_t len) const override; rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) override; + const pgp_encrypted_material_t &in) const override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; @@ -224,19 +224,19 @@ class ECKeyMaterial : public KeyMaterial { pgp_ec_key_t key_; void grip_update(rnp::Hash &hash) const override; - rnp_result_t check_curve(size_t hash_len); + rnp_result_t check_curve(size_t hash_len) const; public: ECKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; ECKeyMaterial(pgp_pubkey_alg_t kalg, const pgp_ec_key_t &key, bool secret = false) : KeyMaterial(kalg, secret), key_(key){}; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; void set_secret(const mpi &x); size_t bits() const noexcept override; @@ -261,7 +261,7 @@ class ECDSAKeyMaterial : public ECKeyMaterial { const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; }; @@ -276,16 +276,16 @@ class ECDHKeyMaterial : public ECKeyMaterial { std::unique_ptr clone() override; bool parse(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) override; + size_t len) const override; rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) override; + const pgp_encrypted_material_t &in) const override; pgp_hash_alg_t kdf_hash_alg() const noexcept; pgp_symm_alg_t key_wrap_alg() const noexcept; @@ -309,7 +309,7 @@ class EDDSAKeyMaterial : public ECKeyMaterial { const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; }; class SM2KeyMaterial : public ECKeyMaterial { @@ -325,17 +325,17 @@ class SM2KeyMaterial : public ECKeyMaterial { rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) override; + size_t len) const override; rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) override; + const pgp_encrypted_material_t &in) const override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; void compute_za(rnp::Hash &hash) const; }; @@ -351,19 +351,19 @@ class Ed25519KeyMaterial : public KeyMaterial { Ed25519KeyMaterial() : KeyMaterial(PGP_PKA_ED25519), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; size_t bits() const noexcept override; pgp_curve_t curve() const noexcept override; @@ -382,21 +382,21 @@ class X25519KeyMaterial : public KeyMaterial { X25519KeyMaterial() : KeyMaterial(PGP_PKA_X25519), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) override; + size_t len) const override; rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) override; + const pgp_encrypted_material_t &in) const override; size_t bits() const noexcept override; pgp_curve_t curve() const noexcept override; @@ -417,21 +417,21 @@ class KyberKeyMaterial : public KeyMaterial { KyberKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t encrypt(rnp::SecurityContext & ctx, pgp_encrypted_material_t &out, const uint8_t * data, - size_t len) override; + size_t len) const override; rnp_result_t decrypt(rnp::SecurityContext & ctx, uint8_t * out, size_t & out_len, - const pgp_encrypted_material_t &in) override; + const pgp_encrypted_material_t &in) const override; size_t bits() const noexcept override; const pgp_kyber_ecdh_composite_public_key_t & pub() const noexcept; @@ -451,19 +451,19 @@ class DilithiumKeyMaterial : public KeyMaterial { /** @brief Check two key material for equality. Only public part is checked, so this may be * called on public/secret key material */ - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; size_t bits() const noexcept override; @@ -482,19 +482,19 @@ class SphincsPlusKeyMaterial : public KeyMaterial { SphincsPlusKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) noexcept override; + bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; - void write(pgp_packet_body_t &pkt) override; - void write_secret(pgp_packet_body_t &pkt) override; + void write(pgp_packet_body_t &pkt) const override; + void write_secret(pgp_packet_body_t &pkt) const override; bool generate(const rnp_keygen_crypto_params_t ¶ms) override; rnp_result_t verify(const rnp::SecurityContext & ctx, const pgp_signature_material_t & sig, const rnp::secure_vector &hash) const override; rnp_result_t sign(rnp::SecurityContext & ctx, pgp_signature_material_t & sig, - const rnp::secure_vector &hash) override; + const rnp::secure_vector &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; bool sig_hash_allowed(pgp_hash_alg_t hash) const override; size_t bits() const noexcept override; From 878e89b43c77c8682da48c80cf830b645e144ce5 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Tue, 30 Jul 2024 12:28:06 +0300 Subject: [PATCH 8/8] Rename PQC classes. --- src/lib/key_material.cpp | 142 +++++++++++++++++------------------ src/lib/key_material.hpp | 12 +-- src/lib/rnp.cpp | 2 +- src/librepgp/stream-dump.cpp | 6 +- 4 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/lib/key_material.cpp b/src/lib/key_material.cpp index 3a1d5058df..d6209bd07a 100644 --- a/src/lib/key_material.cpp +++ b/src/lib/key_material.cpp @@ -310,7 +310,7 @@ KeyMaterial::create(pgp_pubkey_alg_t alg) case PGP_PKA_KYBER768_BP256: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: - return std::unique_ptr(new KyberKeyMaterial(alg)); + return std::unique_ptr(new MlkemEcdhKeyMaterial(alg)); case PGP_PKA_DILITHIUM3_ED25519: FALLTHROUGH_STATEMENT; // TODO: add case PGP_PKA_DILITHIUM5_ED448 @@ -321,11 +321,11 @@ KeyMaterial::create(pgp_pubkey_alg_t alg) case PGP_PKA_DILITHIUM3_BP256: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: - return std::unique_ptr(new DilithiumKeyMaterial(alg)); + return std::unique_ptr(new DilithiumEccKeyMaterial(alg)); case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: - return std::unique_ptr(new SphincsPlusKeyMaterial(alg)); + return std::unique_ptr(new SlhdsaKeyMaterial(alg)); #endif default: return nullptr; @@ -1537,27 +1537,27 @@ X25519KeyMaterial::priv() const noexcept #if defined(ENABLE_PQC) std::unique_ptr -KyberKeyMaterial::clone() +MlkemEcdhKeyMaterial::clone() { - return std::unique_ptr(new KyberKeyMaterial(*this)); + return std::unique_ptr(new MlkemEcdhKeyMaterial(*this)); } void -KyberKeyMaterial::grip_update(rnp::Hash &hash) const +MlkemEcdhKeyMaterial::grip_update(rnp::Hash &hash) const { hash.add(pub().get_encoded()); } bool -KyberKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +MlkemEcdhKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) { return !kyber_ecdh_validate_key(&ctx.rng, &key_, secret_); } bool -KyberKeyMaterial::equals(const KeyMaterial &value) const noexcept +MlkemEcdhKeyMaterial::equals(const KeyMaterial &value) const noexcept { - auto key = dynamic_cast(&value); + auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { return false; } @@ -1565,14 +1565,14 @@ KyberKeyMaterial::equals(const KeyMaterial &value) const noexcept } void -KyberKeyMaterial::clear_secret() +MlkemEcdhKeyMaterial::clear_secret() { key_.priv.secure_clear(); KeyMaterial::clear_secret(); } bool -KyberKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +MlkemEcdhKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept { secret_ = false; std::vector buf(pgp_kyber_ecdh_composite_public_key_t::encoded_size(alg())); @@ -1585,7 +1585,7 @@ KyberKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept } bool -KyberKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +MlkemEcdhKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept { std::vector buf(pgp_kyber_ecdh_composite_private_key_t::encoded_size(alg())); if (!pkt.get(buf.data(), buf.size())) { @@ -1598,19 +1598,19 @@ KyberKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -KyberKeyMaterial::write(pgp_packet_body_t &pkt) const +MlkemEcdhKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.pub.get_encoded()); } void -KyberKeyMaterial::write_secret(pgp_packet_body_t &pkt) const +MlkemEcdhKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.priv.get_encoded()); } bool -KyberKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +MlkemEcdhKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) { if (pgp_kyber_ecdh_composite_key_t::gen_keypair(¶ms.ctx->rng, &key_, alg_)) { RNP_LOG("failed to generate MLKEM-ECDH-composite key for PK alg %d", alg_); @@ -1620,63 +1620,63 @@ KyberKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) } rnp_result_t -KyberKeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const uint8_t * data, - size_t len) const +MlkemEcdhKeyMaterial::encrypt(rnp::SecurityContext & ctx, + pgp_encrypted_material_t &out, + const uint8_t * data, + size_t len) const { return key_.pub.encrypt(&ctx.rng, &out.kyber_ecdh, data, len); } rnp_result_t -KyberKeyMaterial::decrypt(rnp::SecurityContext & ctx, - uint8_t * out, - size_t & out_len, - const pgp_encrypted_material_t &in) const +MlkemEcdhKeyMaterial::decrypt(rnp::SecurityContext & ctx, + uint8_t * out, + size_t & out_len, + const pgp_encrypted_material_t &in) const { return key_.priv.decrypt(&ctx.rng, out, &out_len, &in.kyber_ecdh); } size_t -KyberKeyMaterial::bits() const noexcept +MlkemEcdhKeyMaterial::bits() const noexcept { return 8 * pub().get_encoded().size(); /* public key length */ } const pgp_kyber_ecdh_composite_public_key_t & -KyberKeyMaterial::pub() const noexcept +MlkemEcdhKeyMaterial::pub() const noexcept { return key_.pub; } const pgp_kyber_ecdh_composite_private_key_t & -KyberKeyMaterial::priv() const noexcept +MlkemEcdhKeyMaterial::priv() const noexcept { return key_.priv; } std::unique_ptr -DilithiumKeyMaterial::clone() +DilithiumEccKeyMaterial::clone() { - return std::unique_ptr(new DilithiumKeyMaterial(*this)); + return std::unique_ptr(new DilithiumEccKeyMaterial(*this)); } void -DilithiumKeyMaterial::grip_update(rnp::Hash &hash) const +DilithiumEccKeyMaterial::grip_update(rnp::Hash &hash) const { hash.add(pub().get_encoded()); } bool -DilithiumKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +DilithiumEccKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) { return !dilithium_exdsa_validate_key(&ctx.rng, &key_, secret_); } bool -DilithiumKeyMaterial::equals(const KeyMaterial &value) const noexcept +DilithiumEccKeyMaterial::equals(const KeyMaterial &value) const noexcept { - auto key = dynamic_cast(&value); + auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { return false; } @@ -1684,14 +1684,14 @@ DilithiumKeyMaterial::equals(const KeyMaterial &value) const noexcept } void -DilithiumKeyMaterial::clear_secret() +DilithiumEccKeyMaterial::clear_secret() { key_.priv.secure_clear(); KeyMaterial::clear_secret(); } bool -DilithiumKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +DilithiumEccKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept { secret_ = false; std::vector buf(pgp_dilithium_exdsa_composite_public_key_t::encoded_size(alg())); @@ -1704,7 +1704,7 @@ DilithiumKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept } bool -DilithiumKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +DilithiumEccKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept { std::vector buf(pgp_dilithium_exdsa_composite_private_key_t::encoded_size(alg())); if (!pkt.get(buf.data(), buf.size())) { @@ -1717,19 +1717,19 @@ DilithiumKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -DilithiumKeyMaterial::write(pgp_packet_body_t &pkt) const +DilithiumEccKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add(key_.pub.get_encoded()); } void -DilithiumKeyMaterial::write_secret(pgp_packet_body_t &pkt) const +DilithiumEccKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add(key_.priv.get_encoded()); } bool -DilithiumKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +DilithiumEccKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) { if (pgp_dilithium_exdsa_composite_key_t::gen_keypair(¶ms.ctx->rng, &key_, alg_)) { RNP_LOG("failed to generate mldsa-ecdsa/eddsa-composite key for PK alg %d", alg_); @@ -1739,67 +1739,67 @@ DilithiumKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) } rnp_result_t -DilithiumKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t & sig, - const rnp::secure_vector &hash) const +DilithiumEccKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const { return key_.pub.verify(&sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); } rnp_result_t -DilithiumKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t & sig, - const rnp::secure_vector &hash) const +DilithiumEccKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const { return key_.priv.sign(&ctx.rng, &sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); } pgp_hash_alg_t -DilithiumKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +DilithiumEccKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const { return dilithium_default_hash_alg(); } size_t -DilithiumKeyMaterial::bits() const noexcept +DilithiumEccKeyMaterial::bits() const noexcept { return 8 * pub().get_encoded().size(); /* public key length*/ } const pgp_dilithium_exdsa_composite_public_key_t & -DilithiumKeyMaterial::pub() const noexcept +DilithiumEccKeyMaterial::pub() const noexcept { return key_.pub; } const pgp_dilithium_exdsa_composite_private_key_t & -DilithiumKeyMaterial::priv() const noexcept +DilithiumEccKeyMaterial::priv() const noexcept { return key_.priv; } std::unique_ptr -SphincsPlusKeyMaterial::clone() +SlhdsaKeyMaterial::clone() { - return std::unique_ptr(new SphincsPlusKeyMaterial(*this)); + return std::unique_ptr(new SlhdsaKeyMaterial(*this)); } void -SphincsPlusKeyMaterial::grip_update(rnp::Hash &hash) const +SlhdsaKeyMaterial::grip_update(rnp::Hash &hash) const { hash.add(pub().get_encoded()); } bool -SphincsPlusKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) +SlhdsaKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) { return !sphincsplus_validate_key(&ctx.rng, &key_, secret_); } bool -SphincsPlusKeyMaterial::equals(const KeyMaterial &value) const noexcept +SlhdsaKeyMaterial::equals(const KeyMaterial &value) const noexcept { - auto key = dynamic_cast(&value); + auto key = dynamic_cast(&value); if (!key || !KeyMaterial::equals(value)) { return false; } @@ -1807,14 +1807,14 @@ SphincsPlusKeyMaterial::equals(const KeyMaterial &value) const noexcept } void -SphincsPlusKeyMaterial::clear_secret() +SlhdsaKeyMaterial::clear_secret() { key_.priv.secure_clear(); KeyMaterial::clear_secret(); } bool -SphincsPlusKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept +SlhdsaKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept { secret_ = false; uint8_t bt = 0; @@ -1833,7 +1833,7 @@ SphincsPlusKeyMaterial::parse(pgp_packet_body_t &pkt) noexcept } bool -SphincsPlusKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept +SlhdsaKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept { uint8_t bt = 0; if (!pkt.get(bt)) { @@ -1852,21 +1852,21 @@ SphincsPlusKeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept } void -SphincsPlusKeyMaterial::write(pgp_packet_body_t &pkt) const +SlhdsaKeyMaterial::write(pgp_packet_body_t &pkt) const { pkt.add_byte((uint8_t) key_.pub.param()); pkt.add(key_.pub.get_encoded()); } void -SphincsPlusKeyMaterial::write_secret(pgp_packet_body_t &pkt) const +SlhdsaKeyMaterial::write_secret(pgp_packet_body_t &pkt) const { pkt.add_byte((uint8_t) key_.priv.param()); pkt.add(key_.priv.get_encoded()); } bool -SphincsPlusKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) +SlhdsaKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) { if (pgp_sphincsplus_generate(¶ms.ctx->rng, &key_, params.sphincsplus.param, alg_)) { RNP_LOG("failed to generate SLH-DSA key for PK alg %d", alg_); @@ -1876,47 +1876,47 @@ SphincsPlusKeyMaterial::generate(const rnp_keygen_crypto_params_t ¶ms) } rnp_result_t -SphincsPlusKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t & sig, - const rnp::secure_vector &hash) const +SlhdsaKeyMaterial::verify(const rnp::SecurityContext & ctx, + const pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const { return key_.pub.verify(&sig.sphincsplus, hash.data(), hash.size()); } rnp_result_t -SphincsPlusKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t & sig, - const rnp::secure_vector &hash) const +SlhdsaKeyMaterial::sign(rnp::SecurityContext & ctx, + pgp_signature_material_t & sig, + const rnp::secure_vector &hash) const { return key_.priv.sign(&ctx.rng, &sig.sphincsplus, hash.data(), hash.size()); } pgp_hash_alg_t -SphincsPlusKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const +SlhdsaKeyMaterial::adjust_hash(pgp_hash_alg_t hash) const { return sphincsplus_default_hash_alg(alg_, key_.pub.param()); } bool -SphincsPlusKeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const +SlhdsaKeyMaterial::sig_hash_allowed(pgp_hash_alg_t hash) const { return key_.pub.validate_signature_hash_requirements(hash); } size_t -SphincsPlusKeyMaterial::bits() const noexcept +SlhdsaKeyMaterial::bits() const noexcept { return 8 * pub().get_encoded().size(); /* public key length */ } const pgp_sphincsplus_public_key_t & -SphincsPlusKeyMaterial::pub() const noexcept +SlhdsaKeyMaterial::pub() const noexcept { return key_.pub; } const pgp_sphincsplus_private_key_t & -SphincsPlusKeyMaterial::priv() const noexcept +SlhdsaKeyMaterial::priv() const noexcept { return key_.priv; } diff --git a/src/lib/key_material.hpp b/src/lib/key_material.hpp index 058dff8aff..68d02e8e14 100644 --- a/src/lib/key_material.hpp +++ b/src/lib/key_material.hpp @@ -406,7 +406,7 @@ class X25519KeyMaterial : public KeyMaterial { #endif #if defined(ENABLE_PQC) -class KyberKeyMaterial : public KeyMaterial { +class MlkemEcdhKeyMaterial : public KeyMaterial { pgp_kyber_ecdh_key_t key_; protected: @@ -414,7 +414,7 @@ class KyberKeyMaterial : public KeyMaterial { bool validate_material(rnp::SecurityContext &ctx, bool reset) override; public: - KyberKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + MlkemEcdhKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; bool equals(const KeyMaterial &value) const noexcept override; @@ -438,7 +438,7 @@ class KyberKeyMaterial : public KeyMaterial { const pgp_kyber_ecdh_composite_private_key_t &priv() const noexcept; }; -class DilithiumKeyMaterial : public KeyMaterial { +class DilithiumEccKeyMaterial : public KeyMaterial { pgp_dilithium_exdsa_key_t key_; protected: @@ -446,7 +446,7 @@ class DilithiumKeyMaterial : public KeyMaterial { bool validate_material(rnp::SecurityContext &ctx, bool reset) override; public: - DilithiumKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + DilithiumEccKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; /** @brief Check two key material for equality. Only public part is checked, so this may be @@ -471,7 +471,7 @@ class DilithiumKeyMaterial : public KeyMaterial { const pgp_dilithium_exdsa_composite_private_key_t &priv() const noexcept; }; -class SphincsPlusKeyMaterial : public KeyMaterial { +class SlhdsaKeyMaterial : public KeyMaterial { pgp_sphincsplus_key_t key_; protected: @@ -479,7 +479,7 @@ class SphincsPlusKeyMaterial : public KeyMaterial { bool validate_material(rnp::SecurityContext &ctx, bool reset) override; public: - SphincsPlusKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; + SlhdsaKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; bool equals(const KeyMaterial &value) const noexcept override; diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index ae20cdae4e..539e32ee8c 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -6848,7 +6848,7 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - auto &material = dynamic_cast(key->material()); + auto &material = dynamic_cast(key->material()); return get_map_value(sphincsplus_params_map, material.pub().param(), param); } FFI_GUARD diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 7b075ac9f8..31f3d980e1 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -956,7 +956,7 @@ stream_dump_key_material(rnp_dump_ctx_t & ctx, case PGP_PKA_KYBER768_BP256: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: { - auto &kyber = dynamic_cast(*material); + auto &kyber = dynamic_cast(*material); dst_print_vec( dst, "mlkem-ecdh encoded pubkey", kyber.pub().get_encoded(), ctx.dump_mpi); return; @@ -971,7 +971,7 @@ stream_dump_key_material(rnp_dump_ctx_t & ctx, case PGP_PKA_DILITHIUM3_BP256: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: { - auto &dilithium = dynamic_cast(*material); + auto &dilithium = dynamic_cast(*material); dst_print_vec(dst, "mldsa-ecdsa/eddsa encodced pubkey", dilithium.pub().get_encoded(), @@ -981,7 +981,7 @@ stream_dump_key_material(rnp_dump_ctx_t & ctx, case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: { - auto &sphincs = dynamic_cast(*material); + auto &sphincs = dynamic_cast(*material); dst_print_vec(dst, "slhdsa encoded pubkey", sphincs.pub().get_encoded(), ctx.dump_mpi); return; }