From 433d304ab0766f2e5b88d7cea39050a07f2b9fcd Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Wed, 7 Jun 2023 13:43:33 +0200 Subject: [PATCH 01/20] add support for v6 keys, v6 signatures and add new c++ rng object correction of key and signature related code based on rnp feedback address some more points of PR reiew address some more points of PR reiew rename parse_v3 and update comments correction of key version handling according to rnp feedback changes to v6 key & sig remove redundant ifdef fix conditional compilation of Botan C++ RNG --- CMakeLists.txt | 3 + include/repgp/repgp_def.h | 35 ++++- include/rnp/rnp.h | 30 ++++ src/lib/config.h.in | 1 + src/lib/crypto.cpp | 7 +- src/lib/crypto.h | 3 +- src/lib/crypto/rng.cpp | 16 +++ src/lib/crypto/rng.h | 17 +++ src/lib/crypto/signatures.cpp | 24 +++- src/lib/crypto/signatures.h | 4 +- src/lib/ffi-priv-types.h | 3 +- src/lib/fingerprint.cpp | 32 ++++- src/lib/generate-key.cpp | 2 +- src/lib/pgp-key.cpp | 34 +++-- src/lib/pgp-key.h | 4 +- src/lib/rnp.cpp | 40 +++++- src/lib/types.h | 9 +- src/librekey/kbx_blob.hpp | 2 +- src/librekey/key_store_kbx.cpp | 5 +- src/librekey/rnp_key_store.cpp | 2 +- src/librepgp/stream-dump.cpp | 34 ++++- src/librepgp/stream-key.cpp | 119 ++++++++++++--- src/librepgp/stream-key.h | 4 + src/librepgp/stream-packet.cpp | 21 ++- src/librepgp/stream-packet.h | 2 + src/librepgp/stream-sig.cpp | 254 +++++++++++++++++++++++++++------ src/librepgp/stream-sig.h | 12 +- src/librepgp/stream-write.cpp | 7 +- src/rnp/fficli.cpp | 25 +++- src/rnp/fficli.h | 6 +- src/rnp/rnp.cpp | 4 + src/rnp/rnpcfg.h | 1 + src/rnpkeys/tui.cpp | 11 +- src/tests/ffi-enc.cpp | 113 +++++++++++++++ src/tests/generatekey.cpp | 3 + src/tests/key-store-search.cpp | 4 +- src/tests/support.cpp | 4 +- 37 files changed, 782 insertions(+), 115 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ecf2191bb..4dcde416a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,9 @@ tristate_feature_auto(ENABLE_BLOWFISH "Enable Blowfish cipher support.") tristate_feature_auto(ENABLE_CAST5 "Enable CAST5 cipher support.") tristate_feature_auto(ENABLE_RIPEMD160 "Enable RIPEMD-160 hash support.") +option(ENABLE_CRYPTO_REFRESH "Enable crypto-refresh support (v6)") + + set(ENABLE_DOC Auto CACHE STRING "Enable building documentation.") set_property(CACHE ENABLE_DOC PROPERTY STRINGS ${TRISTATE_VALUES}) diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index 218736c37..2a7fff4d9 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -32,6 +32,7 @@ #define REPGP_DEF_H_ #include +#include "config.h" /************************************/ /* Packet Tags - RFC4880, 4.2 */ @@ -94,8 +95,17 @@ #define PGP_KEY_ID_SIZE 8 /* Size of the fingerprint */ -#define PGP_FINGERPRINT_SIZE 20 -#define PGP_FINGERPRINT_HEX_SIZE (PGP_FINGERPRINT_SIZE * 2) + 1 +#define PGP_FINGERPRINT_V4_SIZE 20 +#if defined(ENABLE_CRYPTO_REFRESH) + #define PGP_FINGERPRINT_V6_SIZE 32 + #define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V6_SIZE +#else + #define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V4_SIZE +#endif +#define PGP_MAX_FINGERPRINT_HEX_SIZE (PGP_MAX_FINGERPRINT_SIZE * 2) + 1 + +/* SEIPDv2 salt length */ +#define PGP_SEIPDV2_SALT_LEN 32 /* Size of the key grip */ #define PGP_KEY_GRIP_SIZE 20 @@ -104,6 +114,11 @@ #define PGP_MARKER_CONTENTS "PGP" #define PGP_MARKER_LEN 3 +/* V6 Signature Salt */ +#if defined(ENABLE_CRYPTO_REFRESH) + #define PGP_MAX_SALT_SIZE_V6_SIG 32 +#endif + /** Old Packet Format Lengths. * Defines the meanings of the 2 bits for length type in the * old packet format. @@ -388,6 +403,10 @@ typedef enum { PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE = 32, /* embedded signature */ PGP_SIG_SUBPKT_ISSUER_FPR = 33, /* issuer fingerprint */ PGP_SIG_SUBPKT_PREFERRED_AEAD = 34, /* preferred AEAD algorithms */ +#if defined(ENABLE_CRYPTO_REFRESH) + /* PGP_SIG_SUBPKT_INTENDED_RECIPIENT_FINGERPRINT = 35, */ + PGP_SIG_SUBPKT_PREFERRED_AEAD_CIPHERSUITES = 39, +#endif PGP_SIG_SUBPKT_PRIVATE_100 = 100, /* private/experimental subpackets */ PGP_SIG_SUBPKT_PRIVATE_101 = 101, PGP_SIG_SUBPKT_PRIVATE_102 = 102, @@ -423,7 +442,10 @@ typedef enum { typedef enum { PGP_KEY_FEATURE_MDC = 0x01, PGP_KEY_FEATURE_AEAD = 0x02, - PGP_KEY_FEATURE_V5 = 0x04 + PGP_KEY_FEATURE_V5 = 0x04, +#if defined(ENABLE_CRYPTO_REFRESH) + PGP_KEY_FEATURE_SEIPDV2 = 0x08 +#endif } pgp_key_feature_t; /** Types of Compression */ @@ -439,6 +461,8 @@ enum { PGP_SE_IP_DATA_VERSION = 1, PGP_PKSK_V3 = 3, PGP_SKSK_V4 = 4, PGP_SKSK_V5 /** Version. * OpenPGP has two different protocol versions: version 3 and version 4. + * Also there is a draft that defines version 5, see + * https://datatracker.ietf.org/doc/draft-ietf-openpgp-crypto-refresh/ * * \see RFC4880 5.2 */ @@ -446,7 +470,10 @@ typedef enum { PGP_VUNKNOWN = 0, PGP_V2 = 2, /* Version 2 (essentially the same as v3) */ PGP_V3 = 3, /* Version 3 */ - PGP_V4 = 4 /* Version 4 */ + PGP_V4 = 4, /* Version 4 */ +#if defined(ENABLE_CRYPTO_REFRESH) + PGP_V6 = 6 /* Version 6 (crypto refresh) */ +#endif } pgp_version_t; typedef enum pgp_op_t { diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 8e7971ab2..e972c9464 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -1176,6 +1176,16 @@ RNP_API rnp_result_t rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op); RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, const char * keyserver); +#if defined(ENABLE_CRYPTO_REFRESH) +/** Set the generated key version to v6. + * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any time. + * + * @param op pointer to opaque key generation context. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_v6_key(rnp_op_generate_t op); +#endif + /** Execute the prepared key or subkey generation operation. * Note: if you set protection algorithm, then you need to specify ffi password provider to * be able to request password for key encryption. @@ -1716,6 +1726,14 @@ RNP_API rnp_result_t rnp_uid_remove(rnp_key_handle_t key, rnp_uid_handle_t uid); */ RNP_API rnp_result_t rnp_uid_handle_destroy(rnp_uid_handle_t uid); +/** + * @brief Get key's version as integer. + * + * @param key key handle, should not be NULL + * @return RNP_SUCCESS or error code on failure. + */ +RNP_API rnp_result_t rnp_key_get_version(rnp_key_handle_t handle, uint32_t *version); + /** Get number of the key's subkeys. * * @param key key handle. @@ -2972,6 +2990,18 @@ RNP_API rnp_result_t rnp_op_encrypt_create(rnp_op_encrypt_t *op, */ RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_handle_t key); +#if defined(ENABLE_CRYPTO_REFRESH) +/** + * @brief Enables the creation of PKESK v6 (instead of v3) which results in the use of SEIPDv2. + * The actually created version depends on the capabilities of the list of recipients. + * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any time. + * + * @param op opaque encrypting context. Must be allocated and initialized. + * @return RNP_SUCCESS or errorcode if failed. + */ +RNP_API rnp_result_t rnp_op_encrypt_enable_pkesk_v6(rnp_op_encrypt_t op); +#endif + /** * @brief Add signature to encrypting context, so data will be encrypted and signed. * diff --git a/src/lib/config.h.in b/src/lib/config.h.in index 3b31ec99e..5086c41ce 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -60,6 +60,7 @@ #cmakedefine ENABLE_TWOFISH #cmakedefine ENABLE_BRAINPOOL #cmakedefine ENABLE_IDEA +#cmakedefine ENABLE_CRYPTO_REFRESH #cmakedefine ENABLE_BLOWFISH #cmakedefine ENABLE_CAST5 #cmakedefine ENABLE_RIPEMD160 diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index da3cba1c4..7535eb5c9 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -83,11 +83,16 @@ __RCSID("$NetBSD: crypto.c,v 1.36 2014/02/17 07:39:19 agc Exp $"); bool pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, pgp_key_pkt_t & seckey, - bool primary) + bool primary, + pgp_version_t pgp_version) { /* populate pgp key structure */ seckey = {}; +#if defined(ENABLE_CRYPTO_REFRESH) + seckey.version = pgp_version; +#else seckey.version = PGP_V4; +#endif seckey.creation_time = crypto.ctx->time(); seckey.alg = crypto.key_alg; seckey.material.alg = crypto.key_alg; diff --git a/src/lib/crypto.h b/src/lib/crypto.h index 320daf8d4..4fd1f81d8 100644 --- a/src/lib/crypto.h +++ b/src/lib/crypto.h @@ -62,7 +62,8 @@ /* raw key generation */ bool pgp_generate_seckey(const rnp_keygen_crypto_params_t ¶ms, pgp_key_pkt_t & seckey, - bool primary); + bool primary, + pgp_version_t pgp_version = PGP_V4); /** generate a new primary key * diff --git a/src/lib/crypto/rng.cpp b/src/lib/crypto/rng.cpp index bf5bfadc8..8acd69e56 100644 --- a/src/lib/crypto/rng.cpp +++ b/src/lib/crypto/rng.cpp @@ -35,6 +35,14 @@ RNG::RNG(Type type) if (botan_rng_init(&botan_rng, type == Type::DRBG ? "user" : NULL)) { throw rnp::rnp_exception(RNP_ERROR_RNG); } +#if defined(ENABLE_CRYPTO_REFRESH) + if (type == Type::DRBG) { + botan_rng_obj.reset(new Botan::AutoSeeded_RNG); + } + else { + botan_rng_obj.reset(new Botan::System_RNG); + } +#endif } RNG::~RNG() @@ -56,4 +64,12 @@ RNG::handle() { return botan_rng; } + +#if defined(ENABLE_CRYPTO_REFRESH) +Botan::RandomNumberGenerator * +RNG::obj() const +{ + return botan_rng_obj.get(); +} +#endif } // namespace rnp diff --git a/src/lib/crypto/rng.h b/src/lib/crypto/rng.h index f452bd9ed..6ac9f58b9 100644 --- a/src/lib/crypto/rng.h +++ b/src/lib/crypto/rng.h @@ -34,6 +34,11 @@ #ifdef CRYPTO_BACKEND_BOTAN typedef struct botan_rng_struct *botan_rng_t; + +#if defined(ENABLE_CRYPTO_REFRESH) +#include +#include +#endif #endif namespace rnp { @@ -41,6 +46,9 @@ class RNG { private: #ifdef CRYPTO_BACKEND_BOTAN struct botan_rng_struct *botan_rng; +#if defined(ENABLE_CRYPTO_REFRESH) + std::unique_ptr botan_rng_obj; +#endif #endif public: enum Type { DRBG, System }; @@ -71,6 +79,15 @@ class RNG { * internal error NULL is returned */ struct botan_rng_struct *handle(); + +#if defined(ENABLE_CRYPTO_REFRESH) + /** + * @brief Returns the Botan RNG C++ object + * Note: It is planned to move away from the FFI handle. + * For the transition phase, both approaches are implemented. + */ + Botan::RandomNumberGenerator* obj() const; +#endif #endif }; } // namespace rnp diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 8531360dd..8fa45b61d 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -28,6 +28,7 @@ #include "crypto/signatures.h" #include "librepgp/stream-packet.h" #include "librepgp/stream-sig.h" +#include "librepgp/stream-key.h" #include "utils.h" #include "sec_profile.hpp" @@ -44,21 +45,32 @@ static void signature_hash_finish(const pgp_signature_t &sig, rnp::Hash &hash, uint8_t *hbuf, size_t &hlen) { hash.add(sig.hashed_data, sig.hashed_len); - if (sig.version > PGP_V3) { - uint8_t trailer[6] = {0x04, 0xff, 0x00, 0x00, 0x00, 0x00}; + if(sig.version >= PGP_V4) + { + uint8_t trailer[6] = {0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; + trailer[0] = sig.version; write_uint32(&trailer[2], sig.hashed_len); + hash.add(trailer, 6); } hlen = hash.finish(hbuf); } std::unique_ptr -signature_init(const pgp_key_material_t &key, pgp_hash_alg_t hash_alg) +signature_init(const pgp_key_pkt_t &key, const pgp_signature_t &sig) { - auto hash = rnp::Hash::create(hash_alg); - if (key.alg == PGP_PKA_SM2) { + auto hash = rnp::Hash::create(sig.halg); + +#if defined(ENABLE_CRYPTO_REFRESH) + if (key.version == PGP_V6) + { + hash->add(sig.salt, sig.salt_size); + } +#endif + + if (key.material.alg == PGP_PKA_SM2) { #if defined(ENABLE_SM2) - rnp_result_t r = sm2_compute_za(key.ec, *hash); + 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); diff --git a/src/lib/crypto/signatures.h b/src/lib/crypto/signatures.h index 6ba64ce1f..8dfa2b270 100644 --- a/src/lib/crypto/signatures.h +++ b/src/lib/crypto/signatures.h @@ -35,8 +35,8 @@ * @param hash_alg the digest algo to be used * @param hash digest object that will be initialized */ -std::unique_ptr signature_init(const pgp_key_material_t &key, - pgp_hash_alg_t hash_alg); +std::unique_ptr signature_init(const pgp_key_pkt_t &key, + const pgp_signature_t &sig); /** * @brief Calculate signature with pre-populated hash diff --git a/src/lib/ffi-priv-types.h b/src/lib/ffi-priv-types.h index beb624c9b..924343d74 100644 --- a/src/lib/ffi-priv-types.h +++ b/src/lib/ffi-priv-types.h @@ -129,6 +129,7 @@ struct rnp_op_generate_st { rnp_key_protection_params_t protection{}; rnp_selfsig_cert_info_t cert{}; rnp_selfsig_binding_info_t binding{}; + pgp_version_t pgp_version = PGP_V4; }; struct rnp_op_sign_signature_st { @@ -196,7 +197,7 @@ struct rnp_op_encrypt_st { }; #define RNP_LOCATOR_MAX_SIZE (MAX_ID_LENGTH + 1) -static_assert(RNP_LOCATOR_MAX_SIZE > PGP_FINGERPRINT_SIZE * 2, "Locator size mismatch."); +static_assert(RNP_LOCATOR_MAX_SIZE > PGP_MAX_FINGERPRINT_SIZE * 2, "Locator size mismatch."); static_assert(RNP_LOCATOR_MAX_SIZE > PGP_KEY_ID_SIZE * 2, "Locator size mismatch."); static_assert(RNP_LOCATOR_MAX_SIZE > PGP_KEY_GRIP_SIZE * 2, "Locator size mismatch."); static_assert(RNP_LOCATOR_MAX_SIZE > MAX_ID_LENGTH, "Locator size mismatch."); diff --git a/src/lib/fingerprint.cpp b/src/lib/fingerprint.cpp index c937c7491..2ba304d73 100644 --- a/src/lib/fingerprint.cpp +++ b/src/lib/fingerprint.cpp @@ -57,13 +57,27 @@ pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key) } } - if (key.version != PGP_V4) { + switch (key.version) { +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: [[fallthrough]]; +#endif + case PGP_V4: + break; + default: RNP_LOG("unsupported key version"); return RNP_ERROR_NOT_SUPPORTED; } + std::unique_ptr hash; + if (key.version == PGP_V4) { + hash = rnp::Hash::create(PGP_HASH_SHA1); + } +#if defined(ENABLE_CRYPTO_REFRESH) + else if (key.version == PGP_V6) { + hash = rnp::Hash::create(PGP_HASH_SHA256); + } +#endif try { - auto hash = rnp::Hash::create(PGP_HASH_SHA1); signature_hash_key(key, *hash); fp.length = hash->finish(fp.fingerprint); return RNP_SUCCESS; @@ -100,7 +114,19 @@ pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key) if ((ret = pgp_fingerprint(fp, key))) { return ret; } - (void) memcpy(keyid.data(), fp.fingerprint + fp.length - keyid.size(), keyid.size()); + + switch (key.version) { + case PGP_V4: + (void) memcpy(keyid.data(), fp.fingerprint + fp.length - keyid.size(), keyid.size()); + break; +#ifdef ENABLE_CRYPTO_REFRESH + case PGP_V6: + (void) memcpy(keyid.data(), fp.fingerprint, keyid.size()); + break; +#endif + default: + return RNP_ERROR_BAD_STATE; + } return RNP_SUCCESS; } diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index dfd5556dd..e4acedebd 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -324,7 +324,7 @@ pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, // generate the raw key and fill tag/secret fields pgp_key_pkt_t secpkt; - if (!pgp_generate_seckey(desc.crypto, secpkt, true)) { + if (!pgp_generate_seckey(desc.crypto, secpkt, true, desc.pgp_version)) { return false; } diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 430033158..5f162e407 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -1667,7 +1667,7 @@ pgp_key_t::write_xfer(pgp_dest_t &dst, const rnp_key_store_t *keyring) const for (auto &fp : subkey_fps_) { const pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(keyring, fp); if (!subkey) { - char fphex[PGP_FINGERPRINT_SIZE * 2 + 1] = {0}; + char fphex[PGP_MAX_FINGERPRINT_SIZE * 2 + 1] = {0}; rnp::hex_encode( fp.fingerprint, fp.length, fphex, sizeof(fphex), rnp::HEX_LOWERCASE); RNP_LOG("Warning! Subkey %s not found.", fphex); @@ -1830,8 +1830,15 @@ pgp_key_t::is_signer(const pgp_subsig_t &sig) const return sig.sig.keyfp() == fp(); } if (!sig.sig.has_keyid()) { - return false; + return false || ( +#if defined(ENABLE_CRYPTO_REFRESH) + (version() == PGP_V6) // v6 packets MUST NOT include this subpacket, therefore return true for v6 +#else + false +#endif + ); } + return keyid() == sig.sig.keyid(); } @@ -2276,14 +2283,23 @@ pgp_key_t::mark_valid() } void -pgp_key_t::sign_init(pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation) const +pgp_key_t::sign_init(rnp::RNG &rng, pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation, pgp_version_t version) const { - sig.version = PGP_V4; + sig.version = version; sig.halg = pgp_hash_adjust_alg_to_key(hash, &pkt_); sig.palg = alg(); sig.set_keyfp(fp()); sig.set_creation(creation); - sig.set_keyid(keyid()); + if(version == PGP_V4) { + // for v6 issuing keys, this MUST NOT be included + sig.set_keyid(keyid()); + } +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6) { + sig.salt_size = rnp::Hash::size(sig.halg)/2; + rng.get(sig.salt, sig.salt_size); + } +#endif } void @@ -2325,7 +2341,7 @@ pgp_key_t::gen_revocation(const pgp_revoke_t & revoke, pgp_signature_t & sig, rnp::SecurityContext &ctx) { - sign_init(sig, hash, ctx.time()); + sign_init(ctx.rng, sig, hash, ctx.time(), key.version); sig.set_type(is_primary_key_pkt(key.tag) ? PGP_SIG_REV_KEY : PGP_SIG_REV_SUBKEY); sig.set_revocation_reason(revoke.code, revoke.reason); @@ -2349,7 +2365,7 @@ pgp_key_t::sign_subkey_binding(pgp_key_t & sub, /* add primary key binding subpacket if requested */ if (subsign) { pgp_signature_t embsig; - sub.sign_init(embsig, sig.halg, ctx.time()); + sub.sign_init(ctx.rng, embsig, sig.halg, ctx.time(), sub.version()); embsig.set_type(PGP_SIG_PRIMARY); sub.sign_binding(pkt(), embsig, ctx); sig.set_embedded_sig(embsig); @@ -2396,7 +2412,7 @@ pgp_key_t::add_uid_cert(rnp_selfsig_cert_info_t &cert, /* Fill the transferable userid */ pgp_userid_pkt_t uid; pgp_signature_t sig; - sign_init(sig, hash, ctx.time()); + sign_init(ctx.rng, sig, hash, ctx.time(), pkt().version); cert.populate(uid, sig); try { sign_cert(pkt_, uid, sig, ctx); @@ -2430,7 +2446,7 @@ pgp_key_t::add_sub_binding(pgp_key_t & subsec, /* populate signature */ pgp_signature_t sig; - sign_init(sig, hash, ctx.time()); + sign_init(ctx.rng, sig, hash, ctx.time(), version()); sig.set_type(PGP_SIG_SUBKEY); if (binding.key_expiration) { sig.set_key_expiration(binding.key_expiration); diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index aa088bb47..11f9b96ca 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -457,8 +457,10 @@ struct pgp_key_t { * @param hash hash algorithm to use (may be changed if it is not suitable for public key * algorithm). * @param creation signature's creation time. + * @param version signature version */ - void sign_init(pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation) const; + void sign_init(rnp::RNG &rng, pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation, pgp_version_t version) const; + /** * @brief Calculate a certification and fill signature material. * Note: secret key must be unlocked before calling this function. diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 2f08bc4a0..a47f1943a 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -3727,14 +3727,17 @@ str_to_locator(rnp_ffi_t ffi, } } break; case PGP_KEY_SEARCH_FINGERPRINT: { - // TODO: support v5 fingerprints - // Note: v2/v3 fingerprint are 16 bytes (32 chars) long. - if ((strlen(identifier) != (PGP_FINGERPRINT_SIZE * 2)) && (strlen(identifier) != 32)) { + // Note: v2/v3 fingerprint are 16 bytes (32 chars) long + if (strlen(identifier) != (PGP_FINGERPRINT_V4_SIZE * 2) && +#if defined(ENABLE_CRYPTO_REFRESH) + strlen(identifier) != (PGP_FINGERPRINT_V6_SIZE * 2) && +#endif + (strlen(identifier) != 32)) { FFI_LOG(ffi, "Invalid fingerprint: %s", identifier); return RNP_ERROR_BAD_PARAMETERS; } locator->by.fingerprint.length = rnp::hex_decode( - identifier, locator->by.fingerprint.fingerprint, PGP_FINGERPRINT_SIZE); + identifier, locator->by.fingerprint.fingerprint, PGP_MAX_FINGERPRINT_SIZE); if (!locator->by.fingerprint.length) { FFI_LOG(ffi, "Invalid fingerprint: %s", identifier); return RNP_ERROR_BAD_PARAMETERS; @@ -5586,6 +5589,19 @@ try { } FFI_GUARD +#if defined(ENABLE_CRYPTO_REFRESH) +rnp_result_t +rnp_op_generate_set_v6_key(rnp_op_generate_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + op->pgp_version = PGP_V6; + return RNP_SUCCESS; +} +FFI_GUARD +#endif + rnp_result_t rnp_op_generate_execute(rnp_op_generate_t op) try { @@ -5602,6 +5618,7 @@ try { rnp_keygen_primary_desc_t keygen = {}; keygen.crypto = op->crypto; keygen.cert = op->cert; + keygen.pgp_version = op->pgp_version; op->cert.prefs = {}; /* generate call will free prefs */ if (!pgp_generate_primary_key(keygen, true, sec, pub, op->ffi->secring->format)) { @@ -5612,6 +5629,7 @@ try { rnp_keygen_subkey_desc_t keygen = {}; keygen.crypto = op->crypto; keygen.binding = op->binding; + keygen.pgp_version = op->pgp_version; if (!pgp_generate_subkey(keygen, true, *op->primary_sec, @@ -6407,6 +6425,18 @@ try { } FFI_GUARD +rnp_result_t +rnp_key_get_version(rnp_key_handle_t handle, uint32_t *version) +try { + if (!handle || !version) { + return RNP_ERROR_NULL_POINTER; + } + + *version = get_key_prefer_public(handle)->version(); + return RNP_SUCCESS; +} +FFI_GUARD + rnp_result_t rnp_key_get_subkey_count(rnp_key_handle_t handle, size_t *count) try { @@ -7661,7 +7691,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } // fingerprint - char fpr[PGP_FINGERPRINT_SIZE * 2 + 1]; + char fpr[PGP_MAX_FINGERPRINT_SIZE * 2 + 1]; if (!rnp::hex_encode(key->fp().fingerprint, key->fp().length, fpr, sizeof(fpr))) { return RNP_ERROR_GENERIC; } diff --git a/src/lib/types.h b/src/lib/types.h index 5a67d4225..e311f09a3 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -102,7 +102,7 @@ class id_str_pair { /** pgp_fingerprint_t */ typedef struct pgp_fingerprint_t { - uint8_t fingerprint[PGP_FINGERPRINT_SIZE]; + uint8_t fingerprint[PGP_MAX_FINGERPRINT_SIZE]; unsigned length; bool operator==(const pgp_fingerprint_t &src) const; bool operator!=(const pgp_fingerprint_t &src) const; @@ -117,9 +117,10 @@ template <> struct hash { { /* since fingerprint value is hash itself, we may use its low bytes */ size_t res = 0; - static_assert(sizeof(fp.fingerprint) == PGP_FINGERPRINT_SIZE, + static_assert(sizeof(fp.fingerprint) == PGP_MAX_FINGERPRINT_SIZE, + "pgp_fingerprint_t size mismatch"); + static_assert(PGP_MAX_FINGERPRINT_SIZE >= sizeof(res), "pgp_fingerprint_t size mismatch"); - static_assert(PGP_FINGERPRINT_SIZE >= sizeof(res), "pgp_fingerprint_t size mismatch"); std::memcpy(&res, fp.fingerprint, sizeof(res)); return res; } @@ -465,11 +466,13 @@ typedef struct rnp_selfsig_binding_info_t { typedef struct rnp_keygen_primary_desc_t { rnp_keygen_crypto_params_t crypto{}; rnp_selfsig_cert_info_t cert{}; + pgp_version_t pgp_version = PGP_V4; } rnp_keygen_primary_desc_t; typedef struct rnp_keygen_subkey_desc_t { rnp_keygen_crypto_params_t crypto; rnp_selfsig_binding_info_t binding; + pgp_version_t pgp_version = PGP_V4; } rnp_keygen_subkey_desc_t; typedef struct rnp_key_protection_params_t { diff --git a/src/librekey/kbx_blob.hpp b/src/librekey/kbx_blob.hpp index 274413c6e..5c6b3ee73 100644 --- a/src/librekey/kbx_blob.hpp +++ b/src/librekey/kbx_blob.hpp @@ -90,7 +90,7 @@ class kbx_header_blob_t : public kbx_blob_t { }; typedef struct { - uint8_t fp[PGP_FINGERPRINT_SIZE]; + uint8_t fp[PGP_MAX_FINGERPRINT_SIZE]; uint32_t keyid_offset; uint16_t flags; } kbx_pgp_key_t; diff --git a/src/librekey/key_store_kbx.cpp b/src/librekey/key_store_kbx.cpp index 677567247..136e00fb0 100644 --- a/src/librekey/key_store_kbx.cpp +++ b/src/librekey/key_store_kbx.cpp @@ -525,7 +525,7 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest return false; } - if (!pbuf(&mem.dst(), key->fp().fingerprint, PGP_FINGERPRINT_SIZE) || + if (!pbuf(&mem.dst(), key->fp().fingerprint, key->fp().length) || !pu32(&mem.dst(), mem.writeb() - 8) || // offset to keyid (part of fpr for V4) !pu16(&mem.dst(), 0) || // flags, not used by GnuPG !pu16(&mem.dst(), 0)) { // RFU @@ -536,7 +536,8 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest std::vector subkey_sig_expirations; for (auto &sfp : key->subkey_fps()) { pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp); - if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, PGP_FINGERPRINT_SIZE) || + if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, key->fp().length) || + //if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, PGP_FINGERPRINT_SIZE) || // from upstream during merge 2023-03-20 !pu32(&mem.dst(), mem.writeb() - 8) || // offset to keyid (part of fpr for V4) !pu16(&mem.dst(), 0) || // flags, not used by GnuPG !pu16(&mem.dst(), 0)) { // RFU diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index 002a51e7c..a8873c6f7 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -154,7 +154,7 @@ rnp_key_store_write_to_path(rnp_key_store_t *key_store) } for (auto &key : key_store->keys) { - char grip[PGP_FINGERPRINT_HEX_SIZE] = {0}; + char grip[PGP_MAX_FINGERPRINT_HEX_SIZE] = {0}; rnp::hex_encode(key.grip().data(), key.grip().size(), grip, sizeof(grip)); snprintf(path, sizeof(path), "%s/%s.key", key_store->path.c_str(), grip); diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 4976e0d67..4b74584d5 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -320,6 +320,20 @@ dst_print_mpi(pgp_dest_t *dst, const char *name, pgp_mpi_t *mpi, bool dumpbin) } } +#if defined(ENABLE_CRYPTO_REFRESH) +static void +dst_print_vec(pgp_dest_t *dst, const char *name, std::vector const &data, bool dumpbin) +{ + std::vector hex(2 * data.size()); + if (!dumpbin) { + dst_printf(dst, "%s\n", name); + } else { + vsnprinthex(hex.data(), hex.size(), data.data(), data.size()); + dst_printf(dst, "%s, %s\n", name, hex.data()); + } +} +#endif + static void dst_print_palg(pgp_dest_t *dst, const char *name, pgp_pubkey_alg_t palg) { @@ -434,6 +448,18 @@ dst_print_keyid(pgp_dest_t *dst, const char *name, const pgp_key_id_t &keyid) dst_print_hex(dst, name, keyid.data(), keyid.size(), false); } +#if defined(ENABLE_CRYPTO_REFRESH) +static void +dst_print_fp(pgp_dest_t *dst, const char *name, const pgp_fingerprint_t &fp) +{ + if (!name) { + name = "fingerprint"; + } + dst_print_hex(dst, name, fp.fingerprint, fp.length, true); +} +#endif + + static void dst_print_s2k(pgp_dest_t *dst, pgp_s2k_t *s2k) { @@ -574,7 +600,7 @@ signature_dump_subpacket(rnp_dump_ctx_t *ctx, pgp_dest_t *dst, const pgp_sig_sub dst_printf(dst, "class: %d\n", (int) subpkt.fields.revocation_key.klass); dst_print_palg(dst, NULL, subpkt.fields.revocation_key.pkalg); dst_print_hex( - dst, "fingerprint", subpkt.fields.revocation_key.fp, PGP_FINGERPRINT_SIZE, true); + dst, "fingerprint", subpkt.fields.revocation_key.fp, PGP_FINGERPRINT_V4_SIZE, true); break; case PGP_SIG_SUBPKT_ISSUER_KEY_ID: dst_print_hex(dst, sname, subpkt.fields.issuer, PGP_KEY_ID_SIZE, false); @@ -655,6 +681,10 @@ signature_dump_subpacket(rnp_dump_ctx_t *ctx, pgp_dest_t *dst, const pgp_sig_sub dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_MDC ? "mdc " : ""); dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_AEAD ? "aead " : ""); dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_V5 ? "v5 keys " : ""); +#if defined(ENABLE_CRYPTO_REFRESH) + dst_printf( + dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_SEIPDV2 ? "SEIPD v2 " : ""); +#endif dst_printf(dst, ")\n"); break; case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE: @@ -1601,7 +1631,7 @@ signature_dump_subpacket_json(rnp_dump_ctx_t * ctx, return json_add(obj, "class", (int) subpkt.fields.revocation_key.klass) && json_add(obj, "algorithm", (int) subpkt.fields.revocation_key.pkalg) && json_add_hex( - obj, "fingerprint", subpkt.fields.revocation_key.fp, PGP_FINGERPRINT_SIZE); + obj, "fingerprint", subpkt.fields.revocation_key.fp, PGP_FINGERPRINT_V4_SIZE); case PGP_SIG_SUBPKT_ISSUER_KEY_ID: return json_add_hex(obj, "issuer keyid", subpkt.fields.issuer, PGP_KEY_ID_SIZE); case PGP_SIG_SUBPKT_KEYSERV_PREFS: diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index 8090ff7d5..9d4bf4544 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -540,6 +540,12 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) /* check the cleartext data */ switch (key.sec_protection.s2k.usage) { case PGP_S2KU_NONE: +#if defined(ENABLE_CRYPTO_REFRESH) + if(key.version == PGP_V6) { + break; /* checksum removed for v6 and usage byte zero */ + } + [[fallthrough]]; +#endif case PGP_S2KU_ENCRYPTED: { /* calculate and check sum16 of the cleartext */ if (len < 2) { @@ -591,6 +597,10 @@ 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) + std::vector tmpbuf; +#endif + switch (key.alg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: @@ -746,11 +756,17 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: body.add(key.material.eg.x); break; - default: +default: RNP_LOG("unknown pk alg : %d", (int) key.alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } +#if defined(ENABLE_CRYPTO_REFRESH) + if(key.version == PGP_V6 && key.sec_protection.s2k.usage == PGP_S2KU_NONE) { + return; /* checksum removed for v6 and usage byte zero */ + } +#endif + /* add sum16 if sha1 is not used */ if (key.sec_protection.s2k.usage != PGP_S2KU_ENCRYPTED_AND_HASHED) { uint16_t sum = 0; @@ -1211,6 +1227,10 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_ERROR_BAD_FORMAT; } +#if defined(ENABLE_CRYPTO_REFRESH) + std::vector tmpbuf; +#endif + pgp_packet_body_t pkt((pgp_pkt_type_t) atag); /* Read the packet into memory */ rnp_result_t res = pkt.read(src); @@ -1221,10 +1241,23 @@ pgp_key_pkt_t::parse(pgp_source_t &src) tag = (pgp_pkt_type_t) atag; /* version */ uint8_t ver = 0; - if (!pkt.get(ver) || (ver < PGP_V2) || (ver > PGP_V4)) { - RNP_LOG("wrong key packet version"); + if (!pkt.get(ver)) { + RNP_LOG("unable to retrieve key packet version"); return RNP_ERROR_BAD_FORMAT; } + switch(ver) { + case PGP_V2: [[fallthrough]]; + case PGP_V3: [[fallthrough]]; + case PGP_V4: + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + break; +#endif + default: + RNP_LOG("wrong key packet version"); + return RNP_ERROR_BAD_FORMAT; + } version = (pgp_version_t) ver; /* creation time */ if (!pkt.get(creation_time)) { @@ -1246,6 +1279,15 @@ pgp_key_pkt_t::parse(pgp_source_t &src) RNP_LOG("wrong v3 pk algorithm"); return RNP_ERROR_BAD_FORMAT; } +#if defined(ENABLE_CRYPTO_REFRESH) + /* v6 length field for public key material */ + if (version == PGP_V6) { + uint32_t material_len; + if (!pkt.get(material_len)) { + return RNP_ERROR_BAD_FORMAT; + } + } +#endif /* algorithm specific fields */ switch (alg) { case PGP_PKA_RSA: @@ -1312,15 +1354,40 @@ pgp_key_pkt_t::parse(pgp_source_t &src) RNP_LOG("failed to read key protection"); return RNP_ERROR_BAD_FORMAT; } +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6 && usage == 255) { + RNP_LOG("Error when parsing S2K usage: A version 6 packet MUST NOT use the value 255."); + return RNP_ERROR_BAD_FORMAT; + } +#endif sec_protection.s2k.usage = (pgp_s2k_usage_t) usage; sec_protection.cipher_mode = PGP_CIPHER_MODE_CFB; +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6 && sec_protection.s2k.usage != PGP_S2KU_NONE) { + // V6 packages contain the count of the optional 1-byte parameters + uint8_t s2k_params_count; + if (!pkt.get(s2k_params_count)) { + RNP_LOG("failed to read key protection"); + } + } +#endif + switch (sec_protection.s2k.usage) { case PGP_S2KU_NONE: break; case PGP_S2KU_ENCRYPTED: case PGP_S2KU_ENCRYPTED_AND_HASHED: { /* we have s2k */ +#if defined(ENABLE_CRYPTO_REFRESH) + if (version == PGP_V6) { + // V6 packages contain the count of the optional 1-byte parameters + uint8_t s2k_params_count; + if (!pkt.get(s2k_params_count)) { + RNP_LOG("failed to read key protection"); + } + } +#endif uint8_t salg = 0; if (!pkt.get(salg) || !pkt.get(sec_protection.s2k)) { RNP_LOG("failed to read key protection"); @@ -1370,20 +1437,8 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_SUCCESS; } -void -pgp_key_pkt_t::fill_hashed_data() +void pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t & hbody) { - /* we don't have a need to write v2-v3 signatures */ - if (version != PGP_V4) { - RNP_LOG("unknown key version %d", (int) version); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - - pgp_packet_body_t hbody(PGP_PKT_RESERVED); - hbody.add_byte(version); - hbody.add_uint32(creation_time); - hbody.add_byte(alg); - /* Algorithm specific fields */ switch (alg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: @@ -1421,6 +1476,38 @@ pgp_key_pkt_t::fill_hashed_data() RNP_LOG("unknown key algorithm: %d", (int) alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } +} + +void +pgp_key_pkt_t::fill_hashed_data() +{ + /* we don't have a need to write v2-v3 signatures */ + switch(version) { + case PGP_V4: + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + break; +#endif + default: + RNP_LOG("unknown key version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + pgp_packet_body_t hbody(PGP_PKT_RESERVED); + hbody.add_byte(version); + hbody.add_uint32(creation_time); + hbody.add_byte(alg); + + /* Algorithm specific fields */ + pgp_packet_body_t alg_spec_fields(PGP_PKT_RESERVED); + make_alg_spec_fields_for_public_key(alg_spec_fields); +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6) { + hbody.add_uint32(alg_spec_fields.size()); + } +#endif + hbody.add(alg_spec_fields.data(), alg_spec_fields.size()); hashed_data = (uint8_t *) malloc(hbody.size()); if (!hashed_data) { diff --git a/src/librepgp/stream-key.h b/src/librepgp/stream-key.h index a19a98645..d34639bd3 100644 --- a/src/librepgp/stream-key.h +++ b/src/librepgp/stream-key.h @@ -69,6 +69,10 @@ typedef struct pgp_key_pkt_t { * pgp_key_pkt_t::write() on the newly generated key */ void fill_hashed_data(); 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); } pgp_key_pkt_t; /* userid/userattr with all the corresponding signatures */ diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 729d2f261..86ee11154 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -673,6 +673,13 @@ pgp_packet_body_t::add(const void *data, size_t len) data_.insert(data_.end(), (uint8_t *) data, (uint8_t *) data + len); } +void +pgp_packet_body_t::add(const std::vector &data) +{ + add(data.data(), data.size()); +} + + void pgp_packet_body_t::add_byte(uint8_t bt) { @@ -745,7 +752,19 @@ pgp_packet_body_t::add_subpackets(const pgp_signature_t &sig, bool hashed) if (spbody.data_.size() > 0xffff) { throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - add_uint16(spbody.data_.size()); + switch(sig.version) { + case PGP_V4: + add_uint16(spbody.data_.size()); + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + add_uint32(spbody.data_.size()); + break; +#endif + default: + RNP_LOG("should not reach this code"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } add(spbody.data_.data(), spbody.data_.size()); } diff --git a/src/librepgp/stream-packet.h b/src/librepgp/stream-packet.h index 72b1c48e3..cd5f77280 100644 --- a/src/librepgp/stream-packet.h +++ b/src/librepgp/stream-packet.h @@ -119,6 +119,8 @@ typedef struct pgp_packet_body_t { bool get(pgp_s2k_t &s2k) noexcept; /** @brief append some bytes to the packet body */ void add(const void *data, size_t len); + /** @brief append some bytes to the packet body */ + void add(const std::vector &data); /** @brief append single byte to the packet body */ void add_byte(uint8_t bt); /** @brief append big endian 16-bit value to the packet body */ diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index 74828594c..a609fac8e 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -48,12 +48,36 @@ void signature_hash_key(const pgp_key_pkt_t &key, rnp::Hash &hash) { - uint8_t hdr[3] = {0x99, 0x00, 0x00}; - if (key.hashed_data) { - write_uint16(hdr + 1, key.hashed_len); - hash.add(hdr, 3); - hash.add(key.hashed_data, key.hashed_len); - return; + switch (key.version) { + case PGP_V2: + [[fallthrough]]; + case PGP_V3: + [[fallthrough]]; + case PGP_V4: { + uint8_t hdr[3] = {0x99, 0x00, 0x00}; + if (key.hashed_data) { + write_uint16(hdr + 1, key.hashed_len); + hash.add(hdr, sizeof(hdr)); + hash.add(key.hashed_data, key.hashed_len); + return; + } + break; + } +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: { + uint8_t hdr[5] = {0x9b, 0x00, 0x00, 0x00, 0x00}; + if (key.hashed_data) { + write_uint32(hdr + 1, key.hashed_len); + hash.add(hdr, sizeof(hdr)); + hash.add(key.hashed_data, key.hashed_len); + return; + } + break; + } +#endif + default: + RNP_LOG("should not reach this code"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); } /* call self recursively if hashed data is not filled, to overcome const restriction */ @@ -92,7 +116,7 @@ signature_hash_certification(const pgp_signature_t & sig, const pgp_key_pkt_t & key, const pgp_userid_pkt_t &userid) { - auto hash = signature_init(key.material, sig.halg); + auto hash = signature_init(key, sig); signature_hash_key(key, *hash); signature_hash_userid(userid, *hash, sig.version); return hash; @@ -103,7 +127,7 @@ signature_hash_binding(const pgp_signature_t &sig, const pgp_key_pkt_t & key, const pgp_key_pkt_t & subkey) { - auto hash = signature_init(key.material, sig.halg); + auto hash = signature_init(key, sig); signature_hash_key(key, *hash); signature_hash_key(subkey, *hash); return hash; @@ -112,7 +136,7 @@ signature_hash_binding(const pgp_signature_t &sig, std::unique_ptr signature_hash_direct(const pgp_signature_t &sig, const pgp_key_pkt_t &key) { - auto hash = signature_init(key.material, sig.halg); + auto hash = signature_init(key, sig); signature_hash_key(key, *hash); return hash; } @@ -373,6 +397,11 @@ pgp_sig_subpkt_t::parse() fields.issuer_fp.len = len - 1; } break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_SIG_SUBPKT_PREFERRED_AEAD_CIPHERSUITES: + // TODO-V6: needs implementation + break; +#endif case PGP_SIG_SUBPKT_PRIVATE_100: case PGP_SIG_SUBPKT_PRIVATE_101: case PGP_SIG_SUBPKT_PRIVATE_102: @@ -429,6 +458,12 @@ pgp_signature_t::pgp_signature_t(const pgp_signature_t &src) palg = src.palg; halg = src.halg; memcpy(lbits, src.lbits, sizeof(src.lbits)); +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6) { + salt_size = src.salt_size; + memcpy(salt, src.salt, salt_size); + } +#endif creation_time = src.creation_time; signer = src.signer; @@ -458,6 +493,12 @@ pgp_signature_t::pgp_signature_t(pgp_signature_t &&src) palg = src.palg; halg = src.halg; memcpy(lbits, src.lbits, sizeof(src.lbits)); +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6) { + salt_size = src.salt_size; + memcpy(salt, src.salt, salt_size); + } +#endif creation_time = src.creation_time; signer = src.signer; hashed_len = src.hashed_len; @@ -508,6 +549,12 @@ pgp_signature_t::operator=(const pgp_signature_t &src) palg = src.palg; halg = src.halg; memcpy(lbits, src.lbits, sizeof(src.lbits)); +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6) { + salt_size = src.salt_size; + memcpy(salt, src.salt, salt_size); + } +#endif creation_time = src.creation_time; signer = src.signer; @@ -540,6 +587,7 @@ pgp_signature_t::operator==(const pgp_signature_t &src) const if ((lbits[0] != src.lbits[0]) || (lbits[1] != src.lbits[1])) { return false; } + // TODO-V6: could also compare salt if ((hashed_len != src.hashed_len) || memcmp(hashed_data, src.hashed_data, hashed_len)) { return false; } @@ -573,7 +621,8 @@ pgp_signature_t::get_id() const } pgp_sig_subpkt_t * -pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) +pgp_signature_t:: +get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) { if (version < PGP_V4) { return NULL; @@ -642,11 +691,30 @@ pgp_signature_t::keyid() const noexcept memcpy(res.data(), subpkt->fields.issuer, PGP_KEY_ID_SIZE); return res; } - if ((subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR))) { - memcpy(res.data(), - subpkt->fields.issuer_fp.fp + subpkt->fields.issuer_fp.len - PGP_KEY_ID_SIZE, - PGP_KEY_ID_SIZE); - return res; + switch (version) { + case PGP_V4: { + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false); + if (subpkt) { + memcpy(res.data(), subpkt->fields.issuer, PGP_KEY_ID_SIZE); + } else if ((subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR))) { + memcpy(res.data(), + subpkt->fields.issuer_fp.fp + subpkt->fields.issuer_fp.len - + PGP_KEY_ID_SIZE, + PGP_KEY_ID_SIZE); + } + break; + } +#ifdef ENABLE_CRYPTO_REFRESH + case PGP_V6: { + const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR); + if (subpkt) { + memcpy(res.data(), subpkt->fields.issuer_fp.fp, PGP_KEY_ID_SIZE); + } + break; + } +#endif + default: + break; } return res; } @@ -676,7 +744,7 @@ pgp_signature_t::has_keyfp() const return false; } const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR); - return subpkt && (subpkt->fields.issuer_fp.len <= PGP_FINGERPRINT_SIZE); + return subpkt && (subpkt->fields.issuer_fp.len <= PGP_MAX_FINGERPRINT_SIZE); } pgp_fingerprint_t @@ -1143,9 +1211,9 @@ pgp_signature_t::matches_onepass(const pgp_one_pass_sig_t &onepass) const } rnp_result_t -pgp_signature_t::parse_v3(pgp_packet_body_t &pkt) +pgp_signature_t::parse_v2v3(pgp_packet_body_t &pkt) { - /* parse v3-specific fields, not the whole signature */ + /* parse v2/v3-specific fields, not the whole signature */ uint8_t buf[16] = {}; if (!pkt.get(buf, 16)) { RNP_LOG("cannot get enough bytes"); @@ -1249,12 +1317,12 @@ pgp_signature_t::parse_subpackets(uint8_t *buf, size_t len, bool hashed) } rnp_result_t -pgp_signature_t::parse_v4(pgp_packet_body_t &pkt) +pgp_signature_t::parse_v4up(pgp_packet_body_t &pkt) { - /* parse v4-specific fields, not the whole signature */ - uint8_t buf[5]; - if (!pkt.get(buf, 5)) { - RNP_LOG("cannot get first 5 bytes"); + /* parse v4 (and up) specific fields, not the whole signature */ + uint8_t buf[3]; + if (!pkt.get(buf, 3)) { + RNP_LOG("cannot get first 3 bytes"); return RNP_ERROR_BAD_FORMAT; } @@ -1265,34 +1333,85 @@ pgp_signature_t::parse_v4(pgp_packet_body_t &pkt) /* hash algorithm */ halg = (pgp_hash_alg_t) buf[2]; /* hashed subpackets length */ - uint16_t splen = read_uint16(&buf[3]); - /* hashed subpackets length + 2 bytes of length of unhashed subpackets */ - if (pkt.left() < (size_t)(splen + 2)) { + + size_t splen; + size_t splen_size = 2; +#if defined(ENABLE_CRYPTO_REFRESH) + uint8_t splen_buf[4]; + switch (version) { + case PGP_V4: + splen_size = 2; + break; + case PGP_V6: + splen_size = 4; + break; + default: + RNP_LOG("unsupported signature version: %d", (int) version); + return RNP_ERROR_BAD_FORMAT; } +#else + uint8_t splen_buf[2]; +#endif + + if (!pkt.get(splen_buf, splen_size)) { + RNP_LOG("cannot get hashed len"); + return RNP_ERROR_BAD_FORMAT; + } + switch (version) { + case PGP_V4: + splen = read_uint16(splen_buf); + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + splen = read_uint32(splen_buf); + break; +#endif + default: + RNP_LOG("unsupported signature version: %d", (int) version); + return RNP_ERROR_BAD_FORMAT; + } + + /* hashed subpackets length + splen_size bytes of length of unhashed subpackets */ + if (pkt.left() < (size_t)(splen + splen_size)) { RNP_LOG("wrong packet or hashed subpackets length"); return RNP_ERROR_BAD_FORMAT; } /* building hashed data */ free(hashed_data); - if (!(hashed_data = (uint8_t *) malloc(splen + 6))) { + if (!(hashed_data = (uint8_t *) malloc(splen + 4 + splen_size))) { RNP_LOG("allocation failed"); return RNP_ERROR_OUT_OF_MEMORY; } hashed_data[0] = version; - memcpy(hashed_data + 1, buf, 5); + memcpy(hashed_data + 1, buf, sizeof(buf)); + memcpy(hashed_data + 1 + sizeof(buf), splen_buf, splen_size); - if (!pkt.get(hashed_data + 6, splen)) { + if (!pkt.get(hashed_data + 4 + splen_size, splen)) { RNP_LOG("cannot get hashed subpackets data"); return RNP_ERROR_BAD_FORMAT; } - hashed_len = splen + 6; + hashed_len = splen + 4 + splen_size; /* parsing hashed subpackets */ - if (!parse_subpackets(hashed_data + 6, splen, true)) { + if (!parse_subpackets(hashed_data + 4 + splen_size, splen, true)) { RNP_LOG("failed to parse hashed subpackets"); return RNP_ERROR_BAD_FORMAT; } + /* reading unhashed subpackets */ - if (!pkt.get(splen)) { - RNP_LOG("cannot get unhashed len"); + if (!pkt.get(splen_buf, splen_size)) { + RNP_LOG("cannot get hashed len"); + return RNP_ERROR_BAD_FORMAT; + } + switch (version) { + case PGP_V4: + splen = read_uint16(splen_buf); + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + splen = read_uint32(splen_buf); + break; +#endif + default: + RNP_LOG("unsupported signature version: %d", (int) version); return RNP_ERROR_BAD_FORMAT; } if (pkt.left() < splen) { @@ -1320,13 +1439,20 @@ pgp_signature_t::parse(pgp_packet_body_t &pkt) } version = (pgp_version_t) ver; - /* v3 or v4 signature body */ + /* v3 or v4 or v6 signature body */ rnp_result_t res; - if ((ver == PGP_V2) || (ver == PGP_V3)) { - res = parse_v3(pkt); - } else if (ver == PGP_V4) { - res = parse_v4(pkt); - } else { + switch(ver) { + case PGP_V2: [[fallthrough]]; + case PGP_V3: + res = parse_v2v3(pkt); + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: [[fallthrough]]; +#endif + case PGP_V4: + res = parse_v4up(pkt); + break; + default: RNP_LOG("unknown signature version: %d", (int) ver); res = RNP_ERROR_BAD_FORMAT; } @@ -1340,6 +1466,24 @@ pgp_signature_t::parse(pgp_packet_body_t &pkt) RNP_LOG("not enough data for hash left bits"); return RNP_ERROR_BAD_FORMAT; } + +#if defined(ENABLE_CRYPTO_REFRESH) + if (ver == PGP_V6) { + if(!pkt.get(salt_size)) { + RNP_LOG("not enough data for v6 salt size octet"); + return RNP_ERROR_BAD_FORMAT; + } + if(salt_size != rnp::Hash::size(halg)/2) { + RNP_LOG("invalid salt size"); + return RNP_ERROR_BAD_FORMAT; + } + if(!pkt.get(salt, salt_size)) { + RNP_LOG("not enough data for v6 signature salt"); + return RNP_ERROR_BAD_FORMAT; + } + } +#endif + /* raw signature material */ material_len = pkt.left(); if (!material_len) { @@ -1424,7 +1568,16 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const void pgp_signature_t::write(pgp_dest_t &dst) const { - if ((version < PGP_V2) || (version > PGP_V4)) { + switch(version) { + case PGP_V2: [[fallthrough]]; + case PGP_V3: [[fallthrough]]; + case PGP_V4: + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + break; +#endif + default: RNP_LOG("don't know version %d", (int) version); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } @@ -1445,6 +1598,12 @@ pgp_signature_t::write(pgp_dest_t &dst) const pktbody.add_subpackets(*this, false); } pktbody.add(lbits, 2); +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_V6) { + pktbody.add_byte(salt_size); + pktbody.add(salt, salt_size); + } +#endif /* write mpis */ pktbody.add(material_buf, material_len); pktbody.write(dst); @@ -1493,9 +1652,18 @@ void pgp_signature_t::fill_hashed_data() { /* we don't have a need to write v2-v3 signatures */ - if ((version < PGP_V2) || (version > PGP_V4)) { - RNP_LOG("don't know version %d", (int) version); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + switch(version) { + case PGP_V2: [[fallthrough]]; + case PGP_V3: [[fallthrough]]; + case PGP_V4: + break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + break; +#endif + default: + RNP_LOG("don't know version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } pgp_packet_body_t hbody(PGP_PKT_RESERVED); if (version < PGP_V4) { diff --git a/src/librepgp/stream-sig.h b/src/librepgp/stream-sig.h index 4f36c381f..0f522d421 100644 --- a/src/librepgp/stream-sig.h +++ b/src/librepgp/stream-sig.h @@ -39,8 +39,8 @@ typedef struct pgp_signature_t { pgp_sig_type_t type_; std::vector preferred(pgp_sig_subpacket_type_t type) const; void set_preferred(const std::vector &data, pgp_sig_subpacket_type_t type); - rnp_result_t parse_v3(pgp_packet_body_t &pkt); - rnp_result_t parse_v4(pgp_packet_body_t &pkt); + rnp_result_t parse_v2v3(pgp_packet_body_t &pkt); + rnp_result_t parse_v4up(pgp_packet_body_t &pkt); bool parse_subpackets(uint8_t *buf, size_t len, bool hashed); public: @@ -58,9 +58,15 @@ typedef struct pgp_signature_t { uint32_t creation_time; pgp_key_id_t signer; - /* v4 - only fields */ + /* common v4 and v6 fields */ std::vector subpkts; + #if defined(ENABLE_CRYPTO_REFRESH) + /* v6 - only fields */ + uint8_t salt[PGP_MAX_SALT_SIZE_V6_SIG]; + uint8_t salt_size; + #endif + pgp_signature_t() : type_(PGP_SIG_BINARY), version(PGP_VUNKNOWN), palg(PGP_PKA_NOTHING), halg(PGP_HASH_UNKNOWN), hashed_data(NULL), hashed_len(0), material_buf(NULL), diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index b17ef65db..cf8865fd9 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -25,6 +25,7 @@ */ #include "config.h" +#include "repgp/repgp_def.h" #include #include #include @@ -1134,11 +1135,13 @@ signed_write_signature(pgp_dest_signed_param_t *param, try { pgp_signature_t sig; if (signer->onepass.version) { - signer->key->sign_init(sig, signer->onepass.halg, param->ctx->ctx->time()); + signer->key->sign_init( + param->ctx->ctx->rng, sig, signer->onepass.halg, param->ctx->ctx->time(), signer->key->version()); sig.palg = signer->onepass.palg; sig.set_type(signer->onepass.type); } else { - signer->key->sign_init(sig, signer->halg, param->ctx->ctx->time()); + signer->key->sign_init( + param->ctx->ctx->rng, sig, signer->halg, param->ctx->ctx->time(), signer->key->version()); /* line below should be checked */ sig.set_type(param->ctx->detached ? PGP_SIG_BINARY : PGP_SIG_TEXT); } diff --git a/src/rnp/fficli.cpp b/src/rnp/fficli.cpp index d4cd4c38d..bc6551eef 100644 --- a/src/rnp/fficli.cpp +++ b/src/rnp/fficli.cpp @@ -25,6 +25,7 @@ */ #include "config.h" +#include "rnpcfg.h" #include #include #include @@ -1624,6 +1625,12 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) goto done; } +#if defined(ENABLE_CRYPTO_REFRESH) + if(cfg.get_bool(CFG_KG_V6_KEY)) { + rnp_op_generate_set_v6_key(genkey); + } +#endif + fprintf(rnp->userio_out, "Generating a new key...\n"); if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &primary)) { ERR_MSG("Primary key generation failed."); @@ -1665,6 +1672,11 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) ERR_MSG("Failed to set hash algorithm."); goto done; } +#if defined(ENABLE_CRYPTO_REFRESH) + if(cfg.get_bool(CFG_KG_V6_KEY)) { + rnp_op_generate_set_v6_key(genkey); + } +#endif if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &subkey)) { ERR_MSG("Subkey generation failed."); goto done; @@ -1747,7 +1759,16 @@ key_matches_string(rnp_key_handle_t handle, const std::string &str) } /* check fingerprint */ - if (len == RNP_FP_SIZE * 2) { + size_t fp_size = RNP_FP_V4_SIZE; +#if defined(ENABLE_CRYPTO_REFRESH) + uint32_t key_version; + rnp_key_get_version(handle, &key_version); + + if (key_version == RNP_PGP_VER_6) { + fp_size = RNP_FP_V6_SIZE; + } +#endif + if (len == fp_size * 2) { if (rnp_key_get_fprint(handle, &id)) { goto done; } @@ -2792,6 +2813,8 @@ cli_rnp_encrypt_and_sign(const rnp_cfg &cfg, } } + + /* adding encrypting keys if pk-encryption is used */ if (cfg.get_bool(CFG_ENCRYPT_PK)) { std::vector keynames = cfg.get_list(CFG_RECIPIENTS); diff --git a/src/rnp/fficli.h b/src/rnp/fficli.h index 7db29dc1a..7e1b6a477 100644 --- a/src/rnp/fficli.h +++ b/src/rnp/fficli.h @@ -268,8 +268,12 @@ void rnp_win_clear_args(int argc, char **argv); #endif /* TODO: we should decide what to do with functions/constants/defines below */ +#define RNP_FP_V4_SIZE 20 +#if defined(ENABLE_CRYPTO_REFRESH) +#define RNP_PGP_VER_6 6 +#define RNP_FP_V6_SIZE 32 +#endif #define RNP_KEYID_SIZE 8 -#define RNP_FP_SIZE 20 #define RNP_GRIP_SIZE 20 #define ERR_MSG(...) \ diff --git a/src/rnp/rnp.cpp b/src/rnp/rnp.cpp index 5dddaca8b..08efbe1e3 100644 --- a/src/rnp/rnp.cpp +++ b/src/rnp/rnp.cpp @@ -60,6 +60,10 @@ static const char *usage = " -V, --version Print RNP version information.\n" " -e, --encrypt Encrypt data using the public key(s).\n" " -r, --recipient Specify recipient's key via uid/keyid/fingerprint.\n" +#if defined(ENABLE_CRYPTO_REFRESH) + " --v3-pkesk-only Only create v3 PKESK (otherwise v6 will be created if " + "appropriate).\n" +#endif " --cipher name Specify symmetric cipher, used for encryption.\n" " --aead[=EAX, OCB] Use AEAD for encryption.\n" " -z 0..9 Set the compression level.\n" diff --git a/src/rnp/rnpcfg.h b/src/rnp/rnpcfg.h index c9478bbd8..1d044804d 100644 --- a/src/rnp/rnpcfg.h +++ b/src/rnp/rnpcfg.h @@ -116,6 +116,7 @@ #define CFG_KG_PROT_HASH "kg-prot-hash" #define CFG_KG_PROT_ALG "kg-prot-alg" #define CFG_KG_PROT_ITERATIONS "kg-prot-iterations" +#define CFG_KG_V6_KEY "kg-v6-key" /* represents a boolean property: non-empty string means 'true' */ /* rnp CLI config : contains all the system-dependent and specified by the user configuration * options */ diff --git a/src/rnpkeys/tui.cpp b/src/rnpkeys/tui.cpp index 6454f8e3a..69ce260d4 100644 --- a/src/rnpkeys/tui.cpp +++ b/src/rnpkeys/tui.cpp @@ -236,7 +236,10 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) "\t(16) DSA + ElGamal\n" "\t(17) DSA + RSA\n" // TODO: See #584 "\t(19) ECDSA + ECDH\n" - "\t(22) EDDSA + X25519\n" +#if defined(ENABLE_CRYPTO_REFRESH) + "\t(21) EDDSA + ECDH (v6 key) \n" +#endif + "\t(22) EDDSA + ECDH (v4 key) \n" "\t(99) SM2\n" "> "); if (!rnp_secure_get_long_from_fd(input_fp, option, false)) { @@ -288,6 +291,12 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) cfg.set_str(CFG_KG_SUBKEY_CURVE, curve); break; } +#if defined(ENABLE_CRYPTO_REFRESH) + case 21: { + cfg.set_str(CFG_KG_V6_KEY, "true"); + [[fallthrough]]; + } +#endif case 22: { cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_EDDSA); cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_ECDH); diff --git a/src/tests/ffi-enc.cpp b/src/tests/ffi-enc.cpp index 6aebf4727..d69617286 100644 --- a/src/tests/ffi-enc.cpp +++ b/src/tests/ffi-enc.cpp @@ -735,6 +735,119 @@ TEST_F(rnp_tests, test_ffi_decrypt_pk_unlocked) rnp_ffi_destroy(ffi); } +#if defined(ENABLE_CRYPTO_REFRESH) +TEST_F(rnp_tests, test_ffi_decrypt_v6_pkesk_test_vector) +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + assert_true(import_all_keys(ffi, "data/test_v6_valid_data/transferable_seckey_v6.asc")); + + assert_rnp_success(rnp_input_from_path(&input, "data/test_v6_valid_data/v6pkesk.asc")); + assert_non_null(input); + assert_rnp_success(rnp_output_to_null(&output)); + assert_rnp_success(rnp_decrypt(ffi, input, output)); + + // cleanup + rnp_input_destroy(input); + rnp_output_destroy(output); +} + +TEST_F(rnp_tests, test_ffi_encrypt_pk_with_v6_key) +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + rnp_output_t output = NULL; + rnp_op_encrypt_t op = NULL; + const char * plaintext = "data1"; + + // setup FFI + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + + assert_true(import_all_keys(ffi, "data/test_v6_valid_data/transferable_seckey_v6.asc")); + + // RNP_LOG_HEX("key id", ffi->secring->keys.front().keyid().data(), + // ffi->secring->keys.front().keyid().size()); RNP_LOG_HEX("key id", + // ffi->secring->keys.back().keyid().data(), ffi->secring->keys.back().keyid().size()); + + std::vector ciphers = {"AES128", "AES192", "AES256"}; + std::vector aead_modes = {"None", "EAX", "OCB"}; + std::vector enable_pkeskv6_modes = {true, false}; + + for (auto enable_pkeskv6 : enable_pkeskv6_modes) + for (auto aead : aead_modes) + for (auto cipher : ciphers) { + // write out some data + FILE *fp = fopen("plaintext", "wb"); + assert_non_null(fp); + assert_int_equal(1, fwrite(plaintext, strlen(plaintext), 1, fp)); + assert_int_equal(0, fclose(fp)); + + // create input+output + assert_rnp_success(rnp_input_from_path(&input, "plaintext")); + assert_non_null(input); + assert_rnp_success(rnp_output_to_path(&output, "encrypted")); + assert_non_null(output); + // create encrypt operation + assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output)); + // add recipients + rnp_key_handle_t key = NULL; + assert_rnp_success(rnp_locate_key(ffi, "keyid", "12c83f1e706f6308", &key)); + assert_non_null(key); + + assert_rnp_failure(rnp_op_encrypt_add_recipient(op, NULL)); // what for ? + assert_rnp_success(rnp_op_encrypt_add_recipient(op, key)); + if (enable_pkeskv6) { + assert_rnp_success(rnp_op_encrypt_enable_pkesk_v6(op)); + } + rnp_key_handle_destroy(key); + key = NULL; + + // set the data encryption cipher + if ((aead == "None") && enable_pkeskv6) { + // already enabled v6 pkesk, does not make any sense to set AEAD to None + // explicitly. + assert_rnp_failure(rnp_op_encrypt_set_aead(op, aead.c_str())); + } else { + assert_rnp_success(rnp_op_encrypt_set_aead(op, aead.c_str())); + } + assert_rnp_success(rnp_op_encrypt_set_cipher(op, cipher.c_str())); + + // execute the operation + assert_rnp_success(rnp_op_encrypt_execute(op)); + + // make sure the output file was created + assert_true(rnp_file_exists("encrypted")); + + // cleanup + assert_rnp_success(rnp_input_destroy(input)); + input = NULL; + assert_rnp_success(rnp_output_destroy(output)); + output = NULL; + assert_rnp_success(rnp_op_encrypt_destroy(op)); + op = NULL; + + /* decrypt */ + + // decrypt + assert_rnp_success(rnp_input_from_path(&input, "encrypted")); + assert_non_null(input); + assert_rnp_success(rnp_output_to_path(&output, "decrypted")); + assert_non_null(output); + assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL)); + assert_rnp_success(rnp_decrypt(ffi, input, output)); + // cleanup + rnp_input_destroy(input); + input = NULL; + rnp_output_destroy(output); + output = NULL; + } + rnp_ffi_destroy(ffi); +} +#endif + TEST_F(rnp_tests, test_ffi_encrypt_pk_key_provider) { rnp_ffi_t ffi = NULL; diff --git a/src/tests/generatekey.cpp b/src/tests/generatekey.cpp index b846ebb4b..bf948b7ba 100644 --- a/src/tests/generatekey.cpp +++ b/src/tests/generatekey.cpp @@ -1148,6 +1148,9 @@ TEST_F(rnp_tests, test_generated_key_sigs) pgp_signature_info_t ssiginfo = {}; memset(&desc, 0, sizeof(desc)); +#if defined(ENABLE_CRYPTO_REFRESH) + desc.pgp_version = PGP_V4; +#endif desc.crypto.key_alg = PGP_PKA_RSA; desc.crypto.rsa.modulus_bit_len = 1024; desc.crypto.ctx = &global_ctx; diff --git a/src/tests/key-store-search.cpp b/src/tests/key-store-search.cpp index 4070b0dab..aabd4bd01 100644 --- a/src/tests/key-store-search.cpp +++ b/src/tests/key-store-search.cpp @@ -69,9 +69,9 @@ TEST_F(rnp_tests, test_key_store_search) // and fingerprint pgp_fingerprint_t &fp = (pgp_fingerprint_t &) key.fp(); assert_true( - rnp::hex_decode(testdata[i].keyid, fp.fingerprint, PGP_FINGERPRINT_SIZE)); + rnp::hex_decode(testdata[i].keyid, fp.fingerprint, PGP_FINGERPRINT_V4_SIZE)); fp.fingerprint[0] = (uint8_t) n; - fp.length = PGP_FINGERPRINT_SIZE; + fp.length = PGP_FINGERPRINT_V4_SIZE; // set the userids for (size_t uidn = 0; testdata[i].userids[uidn]; uidn++) { pgp_transferable_userid_t tuid; diff --git a/src/tests/support.cpp b/src/tests/support.cpp index 2867304d6..4b333c37e 100644 --- a/src/tests/support.cpp +++ b/src/tests/support.cpp @@ -807,9 +807,9 @@ rnp_tests_get_key_by_fpr(rnp_key_store_t *keyring, const std::string &keyid) if (!keyring || keyid.empty() || !rnp::is_hex(keyid)) { return NULL; } - std::vector keyid_bin(PGP_FINGERPRINT_SIZE, 0); + std::vector keyid_bin(PGP_MAX_FINGERPRINT_SIZE, 0); size_t binlen = rnp::hex_decode(keyid.c_str(), keyid_bin.data(), keyid_bin.size()); - if (binlen > PGP_FINGERPRINT_SIZE) { + if (binlen > PGP_MAX_FINGERPRINT_SIZE) { return NULL; } pgp_fingerprint_t fp = {{}, static_cast(binlen)}; From 744fe3ea24c52362a14ae7be43b601d4d91b3093 Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Wed, 26 Jul 2023 12:28:18 +0200 Subject: [PATCH 02/20] added v6 PKESK and v2 SEIPD addressed various feedback comments --- include/repgp/repgp_def.h | 26 +- include/rnp/rnp_err.h | 1 + src/lib/CMakeLists.txt | 26 +- src/lib/crypto/hkdf.cpp | 72 ++++ src/lib/crypto/hkdf.hpp | 74 ++++ src/lib/crypto/hkdf_botan.cpp | 79 ++++ src/lib/crypto/hkdf_botan.hpp | 67 ++++ src/lib/crypto/symmetric.h | 6 + src/lib/generate-key.cpp | 2 +- src/lib/pgp-key.h | 1 + src/lib/rnp.cpp | 22 ++ src/lib/types.h | 10 + src/librepgp/stream-common.cpp | 15 + src/librepgp/stream-common.h | 5 + src/librepgp/stream-ctx.cpp | 13 + src/librepgp/stream-ctx.h | 9 + src/librepgp/stream-dump.cpp | 9 + src/librepgp/stream-packet.cpp | 99 ++++- src/librepgp/stream-packet.h | 14 +- src/librepgp/stream-parse.cpp | 356 +++++++++++++++--- src/librepgp/stream-parse.h | 9 + src/librepgp/stream-write.cpp | 209 ++++++++-- src/librepgp/v2_seipd.cpp | 84 +++++ src/librepgp/v2_seipd.h | 36 ++ src/rnp/fficli.cpp | 7 + src/rnp/rnp.cpp | 11 + src/rnp/rnpcfg.h | 3 + src/tests/CMakeLists.txt | 12 +- .../transferable_pubkey_v6.asc | 12 + .../transferable_seckey_v6.asc | 14 + src/tests/data/test_v6_valid_data/v6pkesk.asc | 8 + src/tests/ffi-key.cpp | 27 ++ src/tests/hkdf.cpp | 36 ++ 33 files changed, 1273 insertions(+), 101 deletions(-) create mode 100644 src/lib/crypto/hkdf.cpp create mode 100644 src/lib/crypto/hkdf.hpp create mode 100644 src/lib/crypto/hkdf_botan.cpp create mode 100644 src/lib/crypto/hkdf_botan.hpp create mode 100644 src/librepgp/v2_seipd.cpp create mode 100644 src/librepgp/v2_seipd.h create mode 100644 src/tests/data/test_v6_valid_data/transferable_pubkey_v6.asc create mode 100644 src/tests/data/test_v6_valid_data/transferable_seckey_v6.asc create mode 100644 src/tests/data/test_v6_valid_data/v6pkesk.asc create mode 100644 src/tests/hkdf.cpp diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index 2a7fff4d9..15cd13b1b 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -105,7 +105,9 @@ #define PGP_MAX_FINGERPRINT_HEX_SIZE (PGP_MAX_FINGERPRINT_SIZE * 2) + 1 /* SEIPDv2 salt length */ +#ifdef ENABLE_CRYPTO_REFRESH #define PGP_SEIPDV2_SALT_LEN 32 +#endif /* Size of the key grip */ #define PGP_KEY_GRIP_SIZE 20 @@ -457,7 +459,17 @@ typedef enum { PGP_C_UNKNOWN = 255 } pgp_compression_type_t; -enum { PGP_SE_IP_DATA_VERSION = 1, PGP_PKSK_V3 = 3, PGP_SKSK_V4 = 4, PGP_SKSK_V5 = 5 }; +enum { PGP_SKSK_V4 = 4, PGP_SKSK_V5 = 5 }; +typedef enum { + PGP_PKSK_V3 = 3, +#if defined(ENABLE_CRYPTO_REFRESH) + PGP_PKSK_V6 = 6 +#endif +} pgp_pkesk_version_t; +typedef enum { + PGP_SE_IP_DATA_V1 = 1, + PGP_SE_IP_DATA_V2 = 2 +} pgp_seipd_version_t; /** Version. * OpenPGP has two different protocol versions: version 3 and version 4. @@ -526,7 +538,15 @@ typedef enum pgp_key_store_format_t { } pgp_key_store_format_t; namespace rnp { -enum class AuthType { None, MDC, AEADv1 }; -} +enum class AuthType { + None, + MDC, + AEADv1, +#ifdef ENABLE_CRYPTO_REFRESH + AEADv2 +#endif +}; + +} // namespace rnp #endif diff --git a/include/rnp/rnp_err.h b/include/rnp/rnp_err.h index f4ff179e5..49bef4f47 100644 --- a/include/rnp/rnp_err.h +++ b/include/rnp/rnp_err.h @@ -57,6 +57,7 @@ enum { RNP_ERROR_KEY_NOT_FOUND, RNP_ERROR_NO_SUITABLE_KEY, RNP_ERROR_DECRYPT_FAILED, + RNP_ERROR_ENCRYPT_FAILED, RNP_ERROR_RNG, RNP_ERROR_SIGNING_FAILED, RNP_ERROR_NO_SIGNATURES_FOUND, diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 40715f998..590911ad0 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -52,6 +52,11 @@ if(CRYPTO_BACKEND_BOTAN3) set(CMAKE_CXX_STANDARD 20) 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() + # generate a config.h include(CheckIncludeFileCXX) include(CheckCXXSymbolExists) @@ -173,10 +178,13 @@ if(CRYPTO_BACKEND_BOTAN) resolve_feature_state(ENABLE_AEAD "AEAD_EAX;AEAD_OCB") resolve_feature_state(ENABLE_TWOFISH "TWOFISH") resolve_feature_state(ENABLE_IDEA "IDEA") - # Botan supports Brainpool curves together with SECP via the ECC_GROUP define + resolve_feature_state(ENABLE_CRYPTO_REFRESH "HKDF") resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH") resolve_feature_state(ENABLE_CAST5 "CAST_128") resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160") + # Botan supports Brainpool curves together with SECP via the ECC_GROUP define + + set(CMAKE_REQUIRED_INCLUDES) endif() if(CRYPTO_BACKEND_OPENSSL) @@ -212,6 +220,7 @@ if(CRYPTO_BACKEND_OPENSSL) openssl_nope(ENABLE_SM2 "it's on our roadmap, see https://github.com/rnpgp/rnp/issues/1877") #resolve_feature_state(ENABLE_SM2 "SM2;SM3;SM4-ECB") openssl_nope(ENABLE_TWOFISH "Twofish isn't and won't be supported by OpenSSL, see https://github.com/openssl/openssl/issues/2046") + openssl_nope(ENABLE_CRYPTO_REFRESH, "not yet implemented") endif() configure_file(config.h.in config.h) @@ -271,6 +280,12 @@ elseif(CRYPTO_BACKEND_BOTAN) if(ENABLE_SM2) list(APPEND CRYPTO_SOURCES crypto/sm2.cpp) endif() + if(ENABLE_CRYPTO_REFRESH) + list(APPEND CRYPTO_SOURCES + crypto/hkdf.cpp + crypto/hkdf_botan.cpp + ) + endif() else() message(FATAL_ERROR "Unknown crypto backend: ${CRYPTO_BACKEND}.") endif() @@ -279,6 +294,14 @@ list(APPEND CRYPTO_SOURCES crypto/backend_version.cpp) # sha11collisiondetection sources list(APPEND CRYPTO_SOURCES crypto/hash_sha1cd.cpp crypto/sha1cd/sha1.c crypto/sha1cd/ubc_check.c) + +set(CRYPTO_REFRESH_SOURCES ) +if(ENABLE_CRYPTO_REFRESH) + list(APPEND CRYPTO_REFRESH_SOURCES + ../librepgp/v2_seipd.cpp + ) +endif() + add_library(librnp-obj OBJECT # librepgp ../librepgp/stream-armor.cpp @@ -290,6 +313,7 @@ add_library(librnp-obj OBJECT ../librepgp/stream-parse.cpp ../librepgp/stream-sig.cpp ../librepgp/stream-write.cpp + ${CRYPTO_REFRESH_SOURCES} # librekey ../librekey/key_store_g10.cpp diff --git a/src/lib/crypto/hkdf.cpp b/src/lib/crypto/hkdf.cpp new file mode 100644 index 000000000..6aebc3d66 --- /dev/null +++ b/src/lib/crypto/hkdf.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 "config.h" + +#if defined(ENABLE_CRYPTO_REFRESH) + +#include "hkdf.hpp" + +#if defined(CRYPTO_BACKEND_BOTAN) +#include "hkdf_botan.hpp" +#endif +#if defined(CRYPTO_BACKEND_OPENSSL) +#error HKDF not implemented for OpenSSL Backend +#endif + +namespace rnp { +std::unique_ptr +Hkdf::create(pgp_hash_alg_t alg) +{ +#if defined(CRYPTO_BACKEND_OPENSSL) +#error HKDF not implemented for OpenSSL + // return Hash_OpenSSL::create(alg); +#elif defined(CRYPTO_BACKEND_BOTAN) + return Hkdf_Botan::create(alg); +#else +#error "Crypto backend not specified" +#endif +} + +size_t +Hkdf::size() const +{ + return size_; +} + +pgp_hash_alg_t Hkdf::alg() const +{ + return hash_alg_; +} + +Hkdf::~Hkdf() +{ +} + +} // namespace rnp + +#endif diff --git a/src/lib/crypto/hkdf.hpp b/src/lib/crypto/hkdf.hpp new file mode 100644 index 000000000..081aa11b2 --- /dev/null +++ b/src/lib/crypto/hkdf.hpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 CRYPTO_HKDF_H_ +#define CRYPTO_HKDF_H_ + +#include "config.h" + +#ifdef ENABLE_CRYPTO_REFRESH + +#include +#include "types.h" + +namespace rnp { +class Hkdf { + /*HKDF is used with SHA256 as hash algorithm, the session key as Initial Keying Material + * (IKM), the salt as salt, and the Packet Tag in OpenPGP format encoding (bits 7 and 6 + * set, bits 5-0 carry the packet tag), version number, cipher algorithm octet, AEAD + * algorithm octet, and chunk size octet as info parameter.*/ + + protected: + pgp_hash_alg_t hash_alg_; + size_t size_; + Hkdf(pgp_hash_alg_t hash_alg) : hash_alg_(hash_alg) + { + size_ = Hash::size(hash_alg); + }; + + public: + static std::unique_ptr create(pgp_hash_alg_t alg); + + pgp_hash_alg_t alg() const; + size_t size() const; + + virtual void extract_expand(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_len, + const uint8_t *info, + size_t info_len, + uint8_t * output_buf, + size_t output_length) = 0; + + virtual ~Hkdf(); +}; + +} // namespace rnp + +#endif + +#endif diff --git a/src/lib/crypto/hkdf_botan.cpp b/src/lib/crypto/hkdf_botan.cpp new file mode 100644 index 000000000..6d8afc3f7 --- /dev/null +++ b/src/lib/crypto/hkdf_botan.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 "config.h" + +#ifdef ENABLE_CRYPTO_REFRESH + +#include "hkdf_botan.hpp" +#include "hash_botan.hpp" + +namespace rnp { + +Hkdf_Botan::Hkdf_Botan(pgp_hash_alg_t hash_alg) : Hkdf(hash_alg) +{ +} + +std::unique_ptr +Hkdf_Botan::create(pgp_hash_alg_t alg) +{ + return std::unique_ptr(new Hkdf_Botan(alg)); +} + + +std::string Hkdf_Botan::alg() const +{ + return std::string("HKDF(") + Hash_Botan::name_backend(Hkdf::alg()) + ")"; +} + +void +Hkdf_Botan::extract_expand(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_len, + const uint8_t *info, + size_t info_len, + uint8_t * output_buf, + size_t output_length) +{ + std::unique_ptr kdf = Botan::KDF::create_or_throw(Hkdf_Botan::alg(), ""); + + Botan::secure_vector OKM; + OKM = kdf->derive_key(output_length, + ikm, ikm_len, + salt, salt_len, + info, info_len); + + memcpy(output_buf, Botan::unlock(OKM).data(), output_length); +} + +Hkdf_Botan::~Hkdf_Botan() +{ +} + +} // namespace rnp + +#endif diff --git a/src/lib/crypto/hkdf_botan.hpp b/src/lib/crypto/hkdf_botan.hpp new file mode 100644 index 000000000..6d7325c57 --- /dev/null +++ b/src/lib/crypto/hkdf_botan.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 CRYPTO_HKDF_BOTAN_HPP_ +#define CRYPTO_HKDF_BOTAN_HPP_ + +#include "config.h" + +#ifdef ENABLE_CRYPTO_REFRESH + +#include "hkdf.hpp" +#include "botan/kdf.h" + +namespace rnp { + +class Hkdf_Botan : public Hkdf { + private: + std::string alg() const; + + public: + // std::unique_ptr fn_; + + Hkdf_Botan(pgp_hash_alg_t alg); + Hkdf_Botan(const Hkdf_Botan &src); + + virtual ~Hkdf_Botan(); + + static std::unique_ptr create(pgp_hash_alg_t alg); + + void extract_expand(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_len, + const uint8_t *info, + size_t info_len, + uint8_t * output_buf, + size_t output_length); +}; + +} // namespace rnp + +#endif + +#endif diff --git a/src/lib/crypto/symmetric.h b/src/lib/crypto/symmetric.h index a50fe9a18..ab502b27f 100644 --- a/src/lib/crypto/symmetric.h +++ b/src/lib/crypto/symmetric.h @@ -69,6 +69,12 @@ /* Maximum AEAD nonce length */ #define PGP_AEAD_MAX_NONCE_LEN 16 +#ifdef ENABLE_CRYPTO_REFRESH +#define PGP_AEAD_MAX_NONCE_OR_SALT_LEN PGP_SEIPDV2_SALT_LEN +#else +#define PGP_AEAD_MAX_NONCE_OR_SALT_LEN PGP_AEAD_MAX_NONCE_LEN +#endif + /* Authentication tag len for AEAD/EAX and AEAD/OCB */ #define PGP_AEAD_EAX_OCB_TAG_LEN 16 diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index e4acedebd..c43b4cec9 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -428,7 +428,7 @@ pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, } /* generate the raw subkey */ pgp_key_pkt_t secpkt; - if (!pgp_generate_seckey(desc.crypto, secpkt, false)) { + if (!pgp_generate_seckey(desc.crypto, secpkt, false, desc.pgp_version)) { return false; } pgp_key_pkt_t pubpkt = pgp_key_pkt_t(secpkt, true); diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 11f9b96ca..8253e3347 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -236,6 +236,7 @@ struct pgp_key_t { bool is_secret() const; bool is_primary() const; bool is_subkey() const; + bool is_seipdv2_capable() const; /** @brief check if a key is currently locked, i.e. secret fields are not decrypted. * Note: Key locking does not apply to unprotected keys. */ diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index a47f1943a..d021951cf 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -765,6 +765,8 @@ rnp_result_to_string(rnp_result_t result) return "No suitable key"; case RNP_ERROR_DECRYPT_FAILED: return "Decryption failed"; + case RNP_ERROR_ENCRYPT_FAILED: + return "Encryption failed"; case RNP_ERROR_RNG: return "Failure of random number generator"; case RNP_ERROR_SIGNING_FAILED: @@ -2533,6 +2535,20 @@ try { } FFI_GUARD +#if defined(ENABLE_CRYPTO_REFRESH) +rnp_result_t +rnp_op_encrypt_enable_pkesk_v6(rnp_op_encrypt_t op) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + + op->rnpctx.enable_pkesk_v6 = true; + return RNP_SUCCESS; +} +FFI_GUARD +#endif + rnp_result_t rnp_op_encrypt_add_signature(rnp_op_encrypt_t op, rnp_key_handle_t key, @@ -2660,6 +2676,12 @@ try { FFI_LOG(op->ffi, "Invalid AEAD algorithm: %s", alg); return RNP_ERROR_BAD_PARAMETERS; } +#ifdef ENABLE_CRYPTO_REFRESH +if(op->rnpctx.aalg == PGP_AEAD_NONE && op->rnpctx.enable_pkesk_v6) { + FFI_LOG(op->ffi, "Setting AEAD algorithm to PGP_AEAD_NONE (%s) would contradict the previously enabled PKESKv6 setting", alg); + return RNP_ERROR_BAD_PARAMETERS; + } +#endif return RNP_SUCCESS; } FFI_GUARD diff --git a/src/lib/types.h b/src/lib/types.h index e311f09a3..aefdcfa7a 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -363,6 +363,16 @@ typedef struct pgp_aead_hdr_t { } } pgp_aead_hdr_t; +#ifdef ENABLE_CRYPTO_REFRESH +typedef struct pgp_seipdv2_hdr_t { + pgp_seipd_version_t version; /* version of the SEIPD packet */ + pgp_symm_alg_t cipher_alg; /* underlying symmetric algorithm */ + pgp_aead_alg_t aead_alg; /* AEAD algorithm, i.e. EAX, OCB, etc */ + uint8_t chunk_size_octet; /* chunk size octet */ + uint8_t salt[PGP_SEIPDV2_SALT_LEN]; /* SEIPDv2 salt value */ +} pgp_seipdv2_hdr_t; +#endif + /** litdata_type_t */ typedef enum { PGP_LDT_BINARY = 'b', diff --git a/src/librepgp/stream-common.cpp b/src/librepgp/stream-common.cpp index 334f93b52..6786c4b6e 100644 --- a/src/librepgp/stream-common.cpp +++ b/src/librepgp/stream-common.cpp @@ -1210,3 +1210,18 @@ dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit) dst_flush(dst); return dst->werr; } + + +#if defined(ENABLE_CRYPTO_REFRESH) +bool have_pkesk_checksum(pgp_pubkey_alg_t alg) +{ + return true; + +} + +bool do_encrypt_pkesk_v3_alg_id(pgp_pubkey_alg_t alg) +{ + /* matches the same algorithms */ + return have_pkesk_checksum(alg); +} +#endif diff --git a/src/librepgp/stream-common.h b/src/librepgp/stream-common.h index 02279d3ba..aec5e554f 100644 --- a/src/librepgp/stream-common.h +++ b/src/librepgp/stream-common.h @@ -553,4 +553,9 @@ class MemoryDest : public Dest { }; } // namespace rnp +#if defined(ENABLE_CRYPTO_REFRESH) +bool have_pkesk_checksum(pgp_pubkey_alg_t alg); +bool do_encrypt_pkesk_v3_alg_id(pgp_pubkey_alg_t alg); +#endif + #endif diff --git a/src/librepgp/stream-ctx.cpp b/src/librepgp/stream-ctx.cpp index 28b5444f4..0aaf9c99f 100644 --- a/src/librepgp/stream-ctx.cpp +++ b/src/librepgp/stream-ctx.cpp @@ -67,3 +67,16 @@ rnp_ctx_t::add_encryption_password(const std::string &password, passwords.push_back(info); return RNP_SUCCESS; } + + +#if defined(ENABLE_CRYPTO_REFRESH) +bool +rnp_ctx_t::pkeskv6_capable() { + for(pgp_key_t *key : recipients) { + if(key->version() < PGP_V6) { + return false; + } + } + return true; +} +#endif diff --git a/src/librepgp/stream-ctx.h b/src/librepgp/stream-ctx.h index b9e0c105e..539f11dce 100644 --- a/src/librepgp/stream-ctx.h +++ b/src/librepgp/stream-ctx.h @@ -70,8 +70,10 @@ typedef struct rnp_symmetric_pass_info_t { * - halg : hash algorithm used during key derivation for password-based encryption * - ealg, aalg, abits : symmetric encryption algorithm and AEAD parameters if used * - recipients : list of key ids used to encrypt data to + * - enable_pkesk_v6 : if true and each recipient in the list of recipients has the capability, allows PKESKv5/SEIPDv2 * - passwords : list of passwords used for password-based encryption * - filename, filemtime, zalg, zlevel : see previous + * - pkeskv6_capable() : returns true if all keys support PKESKv6+SEIPDv2, false otherwise (will use PKESKv3 + SEIPDv1) * * For signing of any kind (attached, detached, cleartext): * - clearsign, detached : controls kind of the signed data. Both are mutually-exclusive. @@ -102,6 +104,9 @@ typedef struct rnp_ctx_t { bool overwrite{}; /* allow to overwrite output file if exists */ bool armor{}; /* whether to use ASCII armor on output */ bool no_wrap{}; /* do not wrap source in literal data packet */ +#if defined(ENABLE_CRYPTO_REFRESH) + bool enable_pkesk_v6{}; /* allows pkesk v6 if list of recipients is suitable */ +#endif std::list recipients{}; /* recipients of the encrypted message */ std::list passwords{}; /* passwords to encrypt message */ std::list signers{}; /* keys to which sign message */ @@ -118,6 +123,10 @@ typedef struct rnp_ctx_t { pgp_hash_alg_t halg, pgp_symm_alg_t ealg, size_t iterations = 0); + +#if defined(ENABLE_CRYPTO_REFRESH) + bool pkeskv6_capable(); +#endif } rnp_ctx_t; #endif diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 4b74584d5..069a86947 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -1021,7 +1021,16 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d indent_dest_increase(dst); dst_printf(dst, "version: %d\n", (int) pkey.version); +#if defined(ENABLE_CRYPTO_REFRESH) + if(pkey.version == PGP_PKSK_V6) { + dst_print_fp(dst, NULL, pkey.fp); + } + else { + dst_print_keyid(dst, NULL, pkey.key_id); + } +#else dst_print_keyid(dst, NULL, pkey.key_id); +#endif dst_print_palg(dst, NULL, pkey.alg); dst_printf(dst, "encrypted material:\n"); indent_dest_increase(dst); diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 86ee11154..36898d45f 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -1032,8 +1032,24 @@ pgp_pk_sesskey_t::write(pgp_dest_t &dst) const { pgp_packet_body_t pktbody(PGP_PKT_PK_SESSION_KEY); pktbody.add_byte(version); - pktbody.add(key_id); +#if defined(ENABLE_CRYPTO_REFRESH) + if(version == PGP_PKSK_V3) { +#endif + pktbody.add(key_id); +#if defined(ENABLE_CRYPTO_REFRESH) + } + else { // PGP_PKSK_V6 + pktbody.add_byte(1 + fp.length); // A one-octet size of the following two fields. + pktbody.add_byte((fp.length == PGP_FINGERPRINT_V6_SIZE) ? PGP_V6 : PGP_V4); + pktbody.add(fp.fingerprint, fp.length); + } +#endif pktbody.add_byte(alg); +#if defined(ENABLE_CRYPTO_REFRESH) + if((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { + pktbody.add_byte(salg); /* added as plaintext */ + } +#endif pktbody.add(material_buf.data(), material_buf.size()); pktbody.write(dst); } @@ -1048,16 +1064,75 @@ pgp_pk_sesskey_t::parse(pgp_source_t &src) } /* version */ uint8_t bt = 0; - if (!pkt.get(bt) || (bt != PGP_PKSK_V3)) { - RNP_LOG("wrong packet version"); + if (!pkt.get(bt)) { + RNP_LOG("Error when reading packet version"); return RNP_ERROR_BAD_FORMAT; } - version = bt; - /* key id */ - if (!pkt.get(key_id)) { - RNP_LOG("failed to get key id"); +#if defined(ENABLE_CRYPTO_REFRESH) + if((bt != PGP_PKSK_V3) && (bt != PGP_PKSK_V6)) { +#else + if((bt != PGP_PKSK_V3)) { +#endif + RNP_LOG("wrong packet version"); return RNP_ERROR_BAD_FORMAT; } + version = (pgp_pkesk_version_t) bt; + +#if defined(ENABLE_CRYPTO_REFRESH) + if (version == PGP_PKSK_V3) +#endif + { + /* key id */ + if (!pkt.get(key_id)) { + RNP_LOG("failed to get key id"); + return RNP_ERROR_BAD_FORMAT; + } + } +#if defined(ENABLE_CRYPTO_REFRESH) + else { // PGP_PKSK_V6 + uint8_t fp_and_key_ver_len; // A one-octet size of the following two fields. + if (!pkt.get(fp_and_key_ver_len)) { + RNP_LOG("Error when reading length of next two fields"); + return RNP_ERROR_BAD_FORMAT; + } + if((fp_and_key_ver_len != 1 + PGP_FINGERPRINT_V4_SIZE) + && (fp_and_key_ver_len != 1 + PGP_FINGERPRINT_V6_SIZE)) { + RNP_LOG("Invalid size for key version + length field"); + return RNP_ERROR_BAD_FORMAT; + } + + size_t fp_len; + uint8_t fp_key_version; + if (!pkt.get(fp_key_version)) { + RNP_LOG("Error when reading key version"); + return RNP_ERROR_BAD_FORMAT; + } + switch(fp_key_version) { + case 0: // anonymous + fp_len = 0; + break; + case PGP_V4: + fp_len = PGP_FINGERPRINT_V4_SIZE; + break; + case PGP_V6: + fp_len = PGP_FINGERPRINT_V6_SIZE; + break; + default: + RNP_LOG("wrong key version used with PKESK v6"); + return RNP_ERROR_BAD_FORMAT; + } + fp.length = fp_len; + if(fp.length && (fp.length != fp_and_key_ver_len - 1)) { + RNP_LOG("size mismatch (fingerprint size and fp+key version length field)"); + return RNP_ERROR_BAD_FORMAT; + } + if (!pkt.get(fp.fingerprint, fp.length)) { + RNP_LOG("Error when reading fingerprint"); + return RNP_ERROR_BAD_FORMAT; + } + } +#endif + /* public key algorithm */ if (!pkt.get(bt)) { RNP_LOG("failed to get palg"); @@ -1065,6 +1140,16 @@ pgp_pk_sesskey_t::parse(pgp_source_t &src) } alg = (pgp_pubkey_alg_t) bt; +#if defined(ENABLE_CRYPTO_REFRESH) + if((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { + if (!pkt.get(bt)) { + RNP_LOG("failed to get salg"); + return RNP_ERROR_BAD_FORMAT; + } + } + salg = (pgp_symm_alg_t) bt; +#endif + /* raw signature material */ if (!pkt.left()) { RNP_LOG("No encrypted material"); diff --git a/src/librepgp/stream-packet.h b/src/librepgp/stream-packet.h index cd5f77280..2dadc42b0 100644 --- a/src/librepgp/stream-packet.h +++ b/src/librepgp/stream-packet.h @@ -157,11 +157,19 @@ typedef struct pgp_packet_body_t { /** public-key encrypted session key packet */ typedef struct pgp_pk_sesskey_t { - unsigned version{}; - pgp_key_id_t key_id{}; + pgp_pkesk_version_t version{}; pgp_pubkey_alg_t alg{}; std::vector material_buf{}; + /* v3 PKESK */ + pgp_key_id_t key_id{}; + pgp_symm_alg_t salg; + +#if defined(ENABLE_CRYPTO_REFRESH) + /* v6 PKESK */ + pgp_fingerprint_t fp{}; +#endif + void write(pgp_dest_t &dst) const; rnp_result_t parse(pgp_source_t &src); /** @@ -184,7 +192,7 @@ typedef struct pgp_sk_sesskey_t { pgp_s2k_t s2k{}; uint8_t enckey[PGP_MAX_KEY_SIZE + PGP_AEAD_MAX_TAG_LEN + 1]{}; unsigned enckeylen{}; - /* v5 specific fields */ + /* v5/v6 specific fields */ pgp_aead_alg_t aalg{}; uint8_t iv[PGP_MAX_BLOCK_SIZE]{}; unsigned ivlen{}; diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 07e663ce9..27ed19cae 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -48,6 +48,10 @@ #include "crypto/signatures.h" #include "fingerprint.h" #include "pgp-key.h" +#ifdef ENABLE_CRYPTO_REFRESH +#include "crypto/hkdf.hpp" +#include "v2_seipd.h" +#endif #ifdef HAVE_ZLIB_H #include @@ -100,6 +104,9 @@ typedef struct pgp_source_encrypted_param_t { size_t aead_adlen{}; /* length of the additional data */ pgp_symm_alg_t salg; /* data encryption algorithm */ pgp_parse_handler_t * handler{}; /* parsing handler with callbacks */ +#ifdef ENABLE_CRYPTO_REFRESH + pgp_seipdv2_hdr_t seipdv2_hdr; /* SEIPDv2 encryption parameters */ +#endif pgp_source_encrypted_param_t() : auth_type(rnp::AuthType::None), salg(PGP_SA_UNKNOWN) { @@ -108,8 +115,20 @@ typedef struct pgp_source_encrypted_param_t { bool use_cfb() { - return auth_type != rnp::AuthType::AEADv1; + return (auth_type != rnp::AuthType::AEADv1 +#ifdef ENABLE_CRYPTO_REFRESH + && auth_type != rnp::AuthType::AEADv2 +#endif + ); + } + +#ifdef ENABLE_CRYPTO_REFRESH + bool is_v2_seipd() const + { + return auth_type == rnp::AuthType::AEADv2; } +#endif + } pgp_source_encrypted_param_t; typedef struct pgp_source_signed_param_t { @@ -164,6 +183,25 @@ typedef struct pgp_source_partial_param_t { bool last; /* current part is last */ } pgp_source_partial_param_t; + +namespace +{ + + bool is_valid_seipd_version(uint8_t version) + { + if(version == 1 +#ifdef ENABLE_CRYPTO_REFRESH + || version == 2 +#endif + ) + { + return true; + } + return false; + } + +} + static bool is_pgp_source(pgp_source_t &src) { @@ -447,8 +485,7 @@ encrypted_start_aead_chunk(pgp_source_encrypted_param_t *param, size_t idx, bool uint8_t nonce[PGP_AEAD_MAX_NONCE_LEN]; size_t nlen; - /* set chunk index for additional data */ - write_uint64(param->aead_ad + param->aead_adlen - 8, idx); + size_t default_ad_len = param->aead_adlen; if (last) { uint64_t total = idx * param->chunklen; @@ -464,9 +501,47 @@ encrypted_start_aead_chunk(pgp_source_encrypted_param_t *param, size_t idx, bool param->aead_adlen += 8; } - if (!pgp_cipher_aead_set_ad(¶m->decrypt, param->aead_ad, param->aead_adlen)) { - RNP_LOG("failed to set ad"); - return false; + switch (param->auth_type) { + case rnp::AuthType::MDC: + break; // cannot happen + case rnp::AuthType::None: + break; // cannot happen + case rnp::AuthType::AEADv1: + /* set chunk index for additional data */ + write_uint64(param->aead_ad + default_ad_len - 8, idx); + + if (!pgp_cipher_aead_set_ad(¶m->decrypt, param->aead_ad, param->aead_adlen)) { + RNP_LOG("failed to set ad"); + return false; + } + break; + +#ifdef ENABLE_CRYPTO_REFRESH + case rnp::AuthType::AEADv2: + /* set chunk index for additional data */ + write_uint64(param->aead_ad + default_ad_len - 8, idx); + std::vector add_data_seipd_v2 = { + static_cast(PGP_PKT_SE_IP_DATA | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT), + static_cast(param->seipdv2_hdr.version), + static_cast(param->seipdv2_hdr.cipher_alg), + static_cast(param->seipdv2_hdr.aead_alg), + param->seipdv2_hdr.chunk_size_octet}; + + if (param->is_v2_seipd()) { + if (last) { + std::copy(¶m->aead_ad[5], + ¶m->aead_ad[5 + 8], + std::back_inserter(add_data_seipd_v2)); + } + if (!pgp_cipher_aead_set_ad( + ¶m->decrypt, add_data_seipd_v2.data(), add_data_seipd_v2.size())) { + RNP_LOG("failed to set ad"); + return false; + } + } + break; + +#endif } /* setup chunk */ @@ -1388,6 +1463,22 @@ encrypted_start_aead(pgp_source_encrypted_param_t *param, pgp_symm_alg_t alg, ui if (alg != param->aead_hdr.ealg) { return false; } +#ifdef ENABLE_CRYPTO_REFRESH + std::vector seipd_v2_key; + if (param->is_v2_seipd()) { + seipd_v2_aead_fields_t aead_fields = + seipd_v2_key_and_nonce_derivation(param->seipdv2_hdr, key); + seipd_v2_key = aead_fields.key; + key = std::move(seipd_v2_key.data()); + //param->seipd_v2_nonce = std::move(aead_fields.nonce); + if(aead_fields.nonce.size() > sizeof(param->aead_hdr.iv)) + { + // signalling error would be better here + aead_fields.nonce.resize(sizeof(param->aead_hdr.iv)); + } + memcpy(param->aead_hdr.iv, aead_fields.nonce.data(), aead_fields.nonce.size()); + } +#endif /* initialize cipher with key */ if (!pgp_cipher_aead_init( @@ -1426,6 +1517,19 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, return false; } +#if defined(ENABLE_CRYPTO_REFRESH) + /* Crypto Refresh: + - The payload following any v6 PKESK or v6 SKESK packet MUST be a v2 SEIPD. + - implementations MUST NOT precede a v2 SEIPD payload with either v3 PKESK or v4 + SKESK packets. */ + if ((param->is_v2_seipd() && !(sesskey->version == PGP_PKSK_V6)) || + (param->auth_type == rnp::AuthType::MDC && !(sesskey->version == PGP_PKSK_V3))) { + RNP_LOG("Attempt to mix SEIPD v1 with PKESK v6 or SEIPD v2 with PKESK v3"); + return false; + } + +#endif + rnp::secure_array decbuf; /* Decrypting session key value */ rnp_result_t err; @@ -1493,49 +1597,98 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, return false; } - /* Check algorithm and key length */ - if (!pgp_is_sa_supported(decbuf[0])) { - RNP_LOG("Unsupported symmetric algorithm %" PRIu8, decbuf[0]); - return false; + uint8_t * decbuf_sesskey = decbuf.data(); + size_t decbuf_sesskey_len = declen; +#if defined(ENABLE_CRYPTO_REFRESH) + if(do_encrypt_pkesk_v3_alg_id(sesskey->alg)) +#endif + { + sesskey->salg = static_cast(decbuf[0]); } + size_t keylen = pgp_key_size(sesskey->salg); + if (sesskey->version == PGP_PKSK_V3) { + /* Check algorithm and key length */ + if (!pgp_is_sa_supported(sesskey->salg)) { + RNP_LOG("Unsupported symmetric algorithm %" PRIu8, sesskey->salg); + return false; + } - pgp_symm_alg_t salg = static_cast(decbuf[0]); - size_t keylen = pgp_key_size(salg); - if (declen != keylen + 3) { - RNP_LOG("invalid symmetric key length"); - return false; - } +#if defined(ENABLE_CRYPTO_REFRESH) + size_t alg_id_bytes = do_encrypt_pkesk_v3_alg_id(sesskey->alg) ? 1 : 0; + size_t checksum_bytes = have_pkesk_checksum(sesskey->alg) ? 2 : 0; +#else + size_t alg_id_bytes = 1; + size_t checksum_bytes = 2; +#endif - /* Validate checksum */ - rnp::secure_array checksum; - for (unsigned i = 1; i <= keylen; i++) { - checksum[0] += decbuf[i]; - } + if (decbuf_sesskey_len != keylen + alg_id_bytes + checksum_bytes) { + RNP_LOG("invalid symmetric key length"); + return false; + } - if ((checksum[0] & 0xffff) != - (decbuf[keylen + 2] | ((unsigned) decbuf[keylen + 1] << 8))) { - RNP_LOG("wrong checksum\n"); - return false; + /* skip over the first byte (if present) to aligns the code for all cases. */ + decbuf_sesskey += alg_id_bytes; } +#if defined(ENABLE_CRYPTO_REFRESH) + else { // V6 PKESK + /* compute the expected key length from the decbuf_sesskey_len and check */ + keylen = have_pkesk_checksum(sesskey->alg) ? decbuf_sesskey_len - 2 : decbuf_sesskey_len; + if(pgp_key_size(param->aead_hdr.ealg) != keylen) { + RNP_LOG("invalid symmetric key length"); + return false; + } + } +#endif - if (param->use_cfb()) { - /* Decrypt header */ - res = encrypted_decrypt_cfb_header(param, salg, &decbuf[1]); - } else { - /* Start AEAD decrypting, assuming we have correct key */ - res = encrypted_start_aead(param, salg, &decbuf[1]); +#if defined(ENABLE_CRYPTO_REFRESH) + if(have_pkesk_checksum(sesskey->alg)) +#endif + { + /* Validate checksum */ + rnp::secure_array checksum; + for (unsigned i = 0; i < keylen; i++) { + checksum[0] += decbuf_sesskey[i]; + } + + if ((checksum[0] & 0xffff) != + (decbuf_sesskey[keylen + 1] | ((unsigned) decbuf_sesskey[keylen] << 8))) { + RNP_LOG("wrong checksum\n"); + return false; + } } - if (res) { - param->salg = salg; + +#if defined(ENABLE_CRYPTO_REFRESH) + if (sesskey->version == PGP_PKSK_V3) +#endif + { + if (param->use_cfb()) { + /* Decrypt header */ + res = encrypted_decrypt_cfb_header(param, sesskey->salg, decbuf_sesskey); + } else { + /* Start AEAD decrypting, assuming we have correct key */ + res = encrypted_start_aead(param, sesskey->salg, decbuf_sesskey); + } + if (res) { + param->salg = sesskey->salg; + } + return res; + } +#if defined(ENABLE_CRYPTO_REFRESH) + else { // PGP_PKSK_V6 + pgp_symm_alg_t salg = + param->aead_hdr.ealg; // NOTEMTG: salg not part of the v6 PKESK, assignment here + // just to make the following call "happy" + return encrypted_start_aead(param, salg, decbuf_sesskey); } - return res; +#endif } #if defined(ENABLE_AEAD) static bool encrypted_sesk_set_ad(pgp_crypt_t *crypt, pgp_sk_sesskey_t *skey) { - /* TODO: this method is exact duplicate as in stream-write.c. Not sure where to put it */ + /* TODO: this method is exact duplicate as in stream-write.c. Not sure where to put it + */ uint8_t ad_data[4]; ad_data[0] = PGP_PKT_SK_SESSION_KEY | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; @@ -1877,6 +2030,39 @@ get_compressed_src_alg(pgp_source_t *src, uint8_t *alg) return true; } +static bool +parse_aead_chunk_size(uint8_t chunk_size_octet, size_t &chunk_size) +{ + if (chunk_size_octet > 56) { + RNP_LOG("too large chunk size: %d", chunk_size_octet); + return false; + } + if (chunk_size_octet > 16) { + RNP_LOG("Warning: AEAD chunk bits > 16."); + } + chunk_size = 1L << (chunk_size_octet + 6); + return true; +} + +#if defined(ENABLE_CRYPTO_REFRESH) +bool +get_seipdv2_src_hdr(pgp_source_t *src, pgp_seipdv2_hdr_t *hdr) +{ + uint8_t hdrbt[3 + PGP_SEIPDV2_SALT_LEN] = {0}; + + if (!src_read_eq(src, hdrbt, sizeof(hdrbt))) { + return false; + } + + hdr->version = PGP_SE_IP_DATA_V2; + hdr->cipher_alg = (pgp_symm_alg_t) hdrbt[0]; + hdr->aead_alg = (pgp_aead_alg_t) hdrbt[1]; + hdr->chunk_size_octet = hdrbt[2]; + std::memcpy(hdr->salt, &hdrbt[3], PGP_SEIPDV2_SALT_LEN); + return true; +} +#endif + bool get_aead_src_hdr(pgp_source_t *src, pgp_aead_hdr_t *hdr) { @@ -1989,7 +2175,7 @@ encrypted_read_packet_data(pgp_source_encrypted_param_t *param) } /* check AEAD encrypted data packet header */ - if (param->aead_hdr.version != 1) { + if (!is_valid_seipd_version(param->aead_hdr.version)) { RNP_LOG("unknown aead ver: %d", param->aead_hdr.version); return RNP_ERROR_BAD_FORMAT; } @@ -1997,14 +2183,11 @@ encrypted_read_packet_data(pgp_source_encrypted_param_t *param) RNP_LOG("unknown aead alg: %d", (int) param->aead_hdr.aalg); return RNP_ERROR_BAD_FORMAT; } - if (param->aead_hdr.csize > 56) { - RNP_LOG("too large chunk size: %d", param->aead_hdr.csize); + + /* parse chunk size */ + if (!parse_aead_chunk_size(param->aead_hdr.csize, param->chunklen)) { return RNP_ERROR_BAD_FORMAT; } - if (param->aead_hdr.csize > 16) { - RNP_LOG("Warning: AEAD chunk bits > 16."); - } - param->chunklen = 1L << (param->aead_hdr.csize + 6); /* build additional data */ param->aead_adlen = 13; @@ -2012,16 +2195,65 @@ encrypted_read_packet_data(pgp_source_encrypted_param_t *param) memcpy(param->aead_ad + 1, hdr, 4); memset(param->aead_ad + 5, 0, 8); } else if (ptype == PGP_PKT_SE_IP_DATA) { - uint8_t mdcver; - if (!src_read_eq(param->pkt.readsrc, &mdcver, 1)) { + uint8_t SEIPD_version; + if (!src_read_eq(param->pkt.readsrc, &SEIPD_version, 1)) { return RNP_ERROR_READ; } - if (mdcver != 1) { - RNP_LOG("unknown mdc ver: %d", (int) mdcver); + if (SEIPD_version == PGP_SE_IP_DATA_V1) { + param->auth_type = rnp::AuthType::MDC; + param->auth_validated = false; + } +#ifdef ENABLE_CRYPTO_REFRESH + else if (SEIPD_version == PGP_SE_IP_DATA_V2) { + /* SKESK v6 is not yet implemented, thus we must not attempt to decrypt + SEIPDv2 here + TODO: Once SKESK v6 is implemented, replace this check with a check for + consistency between SEIPD and SKESK version + */ + if(param->symencs.size() > 0) { + RNP_LOG("SEIPDv2 not usable with SKESK version"); + return RNP_ERROR_BAD_FORMAT; + } + + param->auth_type = rnp::AuthType::AEADv2; + param->seipdv2_hdr.version = PGP_SE_IP_DATA_V2; + uint8_t hdr[4]; + if (!src_peek_eq(param->pkt.readsrc, hdr, 4)) { + return RNP_ERROR_READ; + } + + if (!get_seipdv2_src_hdr(param->pkt.readsrc, ¶m->seipdv2_hdr)) { + RNP_LOG("failed to read SEIPDv2 header"); + return RNP_ERROR_READ; + } + + /* check SEIPDv2 packet header */ + if ((param->seipdv2_hdr.aead_alg != PGP_AEAD_EAX) && + (param->seipdv2_hdr.aead_alg != PGP_AEAD_OCB)) { + RNP_LOG("unknown AEAD alg: %d", (int) param->seipdv2_hdr.aead_alg); + return RNP_ERROR_BAD_FORMAT; + } + + /* parse chunk size */ + if (!parse_aead_chunk_size(param->seipdv2_hdr.chunk_size_octet, param->chunklen)) { + return RNP_ERROR_BAD_FORMAT; + } + + /* build additional data */ + param->aead_adlen = 5; + param->aead_ad[0] = param->pkt.hdr.hdr[0]; + memcpy(param->aead_ad + 1, hdr, 4); + + param->aead_hdr.aalg = param->seipdv2_hdr.aead_alg; + param->aead_hdr.csize = param->seipdv2_hdr.chunk_size_octet; // needed? + param->aead_hdr.ealg = param->seipdv2_hdr.cipher_alg; + } +#endif + else { + RNP_LOG("unknown SEIPD version: %d", (int) SEIPD_version); return RNP_ERROR_BAD_FORMAT; } - param->auth_type = rnp::AuthType::MDC; } param->auth_validated = false; @@ -2054,7 +2286,12 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t goto finish; } - src->read = !param->use_cfb() ? encrypted_src_read_aead : encrypted_src_read_cfb; + src->read = (!param->use_cfb() +#ifdef ENABLE_CRYPTO_REFRESH + || param->is_v2_seipd() +#endif +) + ? encrypted_src_read_aead : encrypted_src_read_cfb; /* Obtaining the symmetric key */ if (!handler->password_provider) { @@ -2085,7 +2322,17 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t errcode = RNP_ERROR_NO_SUITABLE_KEY; while (pubidx < param->pubencs.size()) { auto &pubenc = param->pubencs[pubidx]; - keyctx.search.by.keyid = pubenc.key_id; +#if defined(ENABLE_CRYPTO_REFRESH) + if (pubenc.version == PGP_PKSK_V3) { +#endif + keyctx.search.by.keyid = pubenc.key_id; +#if defined(ENABLE_CRYPTO_REFRESH) + } else { // PGP_PKSK_V6 + keyctx.search.by.fingerprint = pubenc.fp; + keyctx.search.type = PGP_KEY_SEARCH_FINGERPRINT; + } +#endif + /* Get the key if any */ pgp_key_t *seckey = pgp_request_key(handler->key_provider, &keyctx); if (!seckey) { @@ -2093,7 +2340,16 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t continue; } /* Check whether key fits our needs */ - bool hidden = pubenc.key_id == pgp_key_id_t({}); + bool hidden; +#if defined(ENABLE_CRYPTO_REFRESH) + if (pubenc.version == PGP_PKSK_V3) { +#endif + hidden = (pubenc.key_id == pgp_key_id_t({})); +#if defined(ENABLE_CRYPTO_REFRESH) + } else { // PGP_PKSK_V6 + hidden = (pubenc.fp.length == 0); + } +#endif if (!hidden || (++hidden_tries >= MAX_HIDDEN_TRIES)) { pubidx++; } diff --git a/src/librepgp/stream-parse.h b/src/librepgp/stream-parse.h index 4f22b9a6c..1bee9fd82 100644 --- a/src/librepgp/stream-parse.h +++ b/src/librepgp/stream-parse.h @@ -113,6 +113,15 @@ rnp_result_t init_literal_src(pgp_source_t *src, pgp_source_t *readsrc); */ bool get_literal_src_hdr(pgp_source_t *src, pgp_literal_hdr_t *hdr); +#if defined(ENABLE_CRYPTO_REFRESH) +/* @brief Get the SEIPDv2 packet information fields (not the OpenPGP packet header) + * @param src SEIPDv2-encrypted data source (starting from packet data itself, not the header) + * @param hdr pointer to header structure, where result will be stored + * @return true on success or false otherwise + */ +bool get_seipdv2_src_hdr(pgp_source_t *src, pgp_seipdv2_hdr_t *hdr); +#endif + /* @brief Get the AEAD-encrypted packet information fields (not the OpenPGP packet header) * @param src AEAD-encrypted data source (starting from packet data itself, not the header) * @param hdr pointer to header structure, where result will be stored diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index cf8865fd9..ef59f32fd 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -56,6 +56,9 @@ #include "defaults.h" #include #include +#ifdef ENABLE_CRYPTO_REFRESH +#include "v2_seipd.h" +#endif /* 8192 bytes, as GnuPG */ #define PGP_PARTIAL_PKT_SIZE_BITS (13) @@ -99,6 +102,31 @@ typedef struct pgp_dest_encrypted_param_t { size_t chunkidx; /* index of the current AEAD chunk */ size_t cachelen; /* how many bytes are in cache, for AEAD */ uint8_t cache[PGP_AEAD_CACHE_LEN]; /* pre-allocated cache for encryption */ +#ifdef ENABLE_CRYPTO_REFRESH + std::array v2_seipd_salt; /* SEIPDv2 salt value */ +#endif + + bool is_aead_auth() + { + switch (this->auth_type) { + case rnp::AuthType::AEADv1: +#ifdef ENABLE_CRYPTO_REFRESH + case rnp::AuthType::AEADv2: +#endif + return true; + break; + case rnp::AuthType::MDC: + case rnp::AuthType::None: + return false; + } + }; + +#ifdef ENABLE_CRYPTO_REFRESH + bool is_v2_seipd() const + { + return this->auth_type == rnp::AuthType::AEADv2; + } +#endif } pgp_dest_encrypted_param_t; typedef struct pgp_dest_signer_info_t { @@ -344,7 +372,9 @@ encrypted_start_aead_chunk(pgp_dest_encrypted_param_t *param, size_t idx, bool l } /* set chunk index for additional data */ - write_uint64(param->ad + param->adlen - 8, idx); + if (param->auth_type == rnp::AuthType::AEADv1) { + write_uint64(param->ad + param->adlen - 8, idx); + } if (last) { if (!(param->chunkout + param->cachelen)) { @@ -371,6 +401,9 @@ encrypted_start_aead_chunk(pgp_dest_encrypted_param_t *param, size_t idx, bool l /* set chunk index for nonce */ nlen = pgp_cipher_aead_nonce(param->aalg, param->iv, nonce, idx); + if (!nlen) { + RNP_LOG("ERROR: when starting encrypted AEAD chunk: could not determine nonce length"); + } /* start cipher */ res = pgp_cipher_aead_start(¶m->encrypt, nonce, nlen); @@ -457,7 +490,7 @@ encrypted_dst_finish(pgp_dest_t *dst) { pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; - if (param->auth_type == rnp::AuthType::AEADv1) { + if (param->is_aead_auth()) { #if !defined(ENABLE_AEAD) RNP_LOG("AEAD is not enabled."); rnp_result_t res = RNP_ERROR_NOT_IMPLEMENTED; @@ -503,7 +536,7 @@ encrypted_dst_close(pgp_dest_t *dst, bool discard) return; } - if (param->auth_type == rnp::AuthType::AEADv1) { + if (param->is_aead_auth()) { #if defined(ENABLE_AEAD) pgp_cipher_aead_destroy(¶m->encrypt); #endif @@ -520,7 +553,8 @@ encrypted_add_recipient(pgp_write_handler_t *handler, pgp_dest_t * dst, pgp_key_t * userkey, const uint8_t * key, - const unsigned keylen) + const unsigned keylen, + pgp_pkesk_version_t pkesk_version) { pgp_pk_sesskey_t pkey; pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; @@ -533,23 +567,63 @@ encrypted_add_recipient(pgp_write_handler_t *handler, } /* Fill pkey */ - pkey.version = PGP_PKSK_V3; + pkey.version = pkesk_version; pkey.alg = userkey->alg(); + /* set key_id (used for PKESK v3) and fingerprint (used for PKESK v6) */ pkey.key_id = userkey->keyid(); - +#if defined(ENABLE_CRYPTO_REFRESH) + if (pkey.version == (uint8_t) PGP_V6) { + pkey.fp = userkey->fp(); + } +#endif + /* Encrypt the session key */ rnp::secure_array enckey; - enckey[0] = param->ctx->ealg; - memcpy(&enckey[1], key, keylen); + uint8_t *sesskey = enckey.data(); /* pointer to the actual session key */ + size_t enckey_len = keylen; + + pkey.salg = param->ctx->ealg; + +#if defined(ENABLE_CRYPTO_REFRESH) + if (pkey.version == PGP_PKSK_V3) { + size_t key_offset; + if(do_encrypt_pkesk_v3_alg_id(pkey.alg)) { + /* for pre-crypto-refresh algorithms, algorithm ID is part of the session key */ + key_offset = 1; + enckey[0] = pkey.salg; + } else { + key_offset = 0; + } +#else + enckey[0] = pkey.salg; + size_t key_offset = 1; +#endif + memcpy(&enckey[key_offset], key, keylen); + sesskey += key_offset; + enckey_len += key_offset; +#if defined(ENABLE_CRYPTO_REFRESH) + } + else { // PGP_PKSK_V6 + memcpy(&enckey[0], key, keylen); + } +#endif - /* Calculate checksum */ - rnp::secure_array checksum; +#if defined(ENABLE_CRYPTO_REFRESH) + if(have_pkesk_checksum(pkey.alg)) +#endif + { + /* Calculate checksum */ + rnp::secure_array checksum; + + for (unsigned i = 0; i < keylen; i++) { + checksum[0] += sesskey[i]; + } + sesskey[keylen] = (checksum[0] >> 8) & 0xff; + sesskey[keylen + 1] = checksum[0] & 0xff; - for (unsigned i = 1; i <= keylen; i++) { - checksum[0] += enckey[i]; + /* increment enckey_len by checksum */ + enckey_len += 2; } - enckey[keylen + 1] = (checksum[0] >> 8) & 0xff; - enckey[keylen + 2] = checksum[0] & 0xff; pgp_encrypted_material_t material; @@ -559,7 +633,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, ret = rsa_encrypt_pkcs1(&handler->ctx->ctx->rng, &material.rsa, enckey.data(), - keylen + 3, + enckey_len, &userkey->material().rsa); if (ret) { RNP_LOG("rsa_encrypt_pkcs1 failed"); @@ -572,7 +646,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, ret = sm2_encrypt(&handler->ctx->ctx->rng, &material.sm2, enckey.data(), - keylen + 3, + enckey_len, PGP_HASH_SM3, &userkey->material().ec); if (ret) { @@ -594,7 +668,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, ret = ecdh_encrypt_pkcs5(&handler->ctx->ctx->rng, &material.ecdh, enckey.data(), - keylen + 3, + enckey_len, &userkey->material().ec, userkey->fp()); if (ret) { @@ -607,7 +681,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, ret = elgamal_encrypt_pkcs1(&handler->ctx->ctx->rng, &material.eg, enckey.data(), - keylen + 3, + enckey_len, &userkey->material().eg); if (ret) { RNP_LOG("pgp_elgamal_public_encrypt failed"); @@ -794,7 +868,7 @@ encrypted_start_aead(pgp_dest_encrypted_param_t *param, uint8_t *enckey) RNP_LOG("AEAD support is not enabled."); return RNP_ERROR_NOT_IMPLEMENTED; #else - uint8_t hdr[4 + PGP_AEAD_MAX_NONCE_LEN]; + uint8_t hdr[4 + PGP_AEAD_MAX_NONCE_OR_SALT_LEN]; size_t nlen; if (pgp_block_size(param->ctx->ealg) != 16) { @@ -802,32 +876,75 @@ encrypted_start_aead(pgp_dest_encrypted_param_t *param, uint8_t *enckey) } /* fill header */ +#ifdef ENABLE_CRYPTO_REFRESH + hdr[0] = param->auth_type == rnp::AuthType::AEADv2 ? 2 : 1; +#else hdr[0] = 1; +#endif hdr[1] = param->ctx->ealg; hdr[2] = param->ctx->aalg; hdr[3] = param->ctx->abits; /* generate iv */ nlen = pgp_cipher_aead_nonce_len(param->ctx->aalg); + uint8_t *iv_or_salt = param->iv; + size_t iv_or_salt_len = nlen; +#ifdef ENABLE_CRYPTO_REFRESH + if (param->auth_type == rnp::AuthType::AEADv2) { + iv_or_salt = param->v2_seipd_salt.data(); + iv_or_salt_len = param->v2_seipd_salt.size(); + } +#endif try { - param->ctx->ctx->rng.get(param->iv, nlen); + param->ctx->ctx->rng.get(iv_or_salt, iv_or_salt_len); } catch (const std::exception &e) { return RNP_ERROR_RNG; } - memcpy(hdr + 4, param->iv, nlen); - + memcpy(hdr + 4, iv_or_salt, iv_or_salt_len); /* output header */ - dst_write(param->pkt.writedst, hdr, 4 + nlen); + dst_write(param->pkt.writedst, hdr, 4 + iv_or_salt_len); /* initialize encryption */ param->chunklen = 1L << (hdr[3] + 6); param->chunkout = 0; /* fill additional/authenticated data */ - param->ad[0] = PGP_PKT_AEAD_ENCRYPTED | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; + uint8_t raw_packet_tag = PGP_PKT_AEAD_ENCRYPTED; +#ifdef ENABLE_CRYPTO_REFRESH + if (param->auth_type == rnp::AuthType::AEADv2) { + raw_packet_tag = PGP_PKT_SE_IP_DATA; + } +#endif + param->ad[0] = raw_packet_tag | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT; memcpy(param->ad + 1, hdr, 4); - memset(param->ad + 5, 0, 8); - param->adlen = 13; +#ifdef ENABLE_CRYPTO_REFRESH + if (param->auth_type == rnp::AuthType::AEADv2) { + param->adlen = 5; + } else { +#endif + memset(param->ad + 5, 0, 8); + param->adlen = 13; +#ifdef ENABLE_CRYPTO_REFRESH + } + seipd_v2_aead_fields_t s2_fields; + if (param->auth_type == rnp::AuthType::AEADv2) { + param->aalg = param->ctx->aalg; + pgp_seipdv2_hdr_t v2_seipd_hdr; + v2_seipd_hdr.cipher_alg = param->ctx->ealg; + v2_seipd_hdr.aead_alg = param->ctx->aalg; + v2_seipd_hdr.chunk_size_octet = param->ctx->abits; + v2_seipd_hdr.version = PGP_SE_IP_DATA_V2; + memcpy(v2_seipd_hdr.salt, iv_or_salt, PGP_SEIPDV2_SALT_LEN); + s2_fields = seipd_v2_key_and_nonce_derivation(v2_seipd_hdr, enckey); + enckey = s2_fields.key.data(); + if(s2_fields.nonce.size() > sizeof(param->iv)) + { + // would be better to indicate an error + s2_fields.nonce.resize(sizeof(param->iv)); + } + std::memcpy(param->iv, s2_fields.nonce.data(), s2_fields.nonce.size()); + } +#endif /* initialize cipher */ if (!pgp_cipher_aead_init( @@ -884,18 +1001,25 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr } param->auth_type = handler->ctx->aalg == PGP_AEAD_NONE ? rnp::AuthType::MDC : rnp::AuthType::AEADv1; + + pkeycount = handler->ctx->recipients.size(); + skeycount = handler->ctx->passwords.size(); + +#if defined(ENABLE_CRYPTO_REFRESH) + /* in the case of PKESK (pkeycount > 0) and all keys are PKESKv6/SEIPDv2 capable, ugprade to AEADv2 */ + if (handler->ctx->enable_pkesk_v6 && handler->ctx->pkeskv6_capable() && pkeycount > 0) { + param->auth_type = rnp::AuthType::AEADv2; + } +#endif param->aalg = handler->ctx->aalg; param->ctx = handler->ctx; param->pkt.origdst = writedst; - dst->write = param->auth_type == rnp::AuthType::AEADv1 ? encrypted_dst_write_aead : - encrypted_dst_write_cfb; + // the following assignment is covered for the v2 SEIPD case further below + dst->write = param->is_aead_auth() ? encrypted_dst_write_aead : encrypted_dst_write_cfb; dst->finish = encrypted_dst_finish; dst->close = encrypted_dst_close; dst->type = PGP_STREAM_ENCRYPTED; - pkeycount = handler->ctx->recipients.size(); - skeycount = handler->ctx->passwords.size(); - rnp::secure_array enckey; /* content encryption key */ if (!pkeycount && !skeycount) { RNP_LOG("no recipients"); @@ -903,7 +1027,7 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr goto finish; } - if ((pkeycount > 0) || (skeycount > 1) || (param->auth_type == rnp::AuthType::AEADv1)) { + if ((pkeycount > 0) || (skeycount > 1) || param->is_aead_auth()) { try { handler->ctx->ctx->rng.get(enckey.data(), keylen); } catch (const std::exception &e) { @@ -915,7 +1039,19 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr /* Configuring and writing pk-encrypted session keys */ for (auto recipient : handler->ctx->recipients) { - ret = encrypted_add_recipient(handler, dst, recipient, enckey.data(), keylen); + pgp_pkesk_version_t pkesk_version = PGP_PKSK_V3; +#if defined(ENABLE_CRYPTO_REFRESH) + if (param->auth_type == rnp::AuthType::AEADv2) { + pkesk_version = PGP_PKSK_V6; + } + if(handler->ctx->aalg == PGP_AEAD_NONE) { + // set default AEAD if not set + // TODO-V6: is this the right place to set the default algorithm? + param->ctx->aalg = DEFAULT_AEAD_ALG; + } +#endif + ret = encrypted_add_recipient( + handler, dst, recipient, enckey.data(), keylen, pkesk_version); if (ret) { goto finish; } @@ -938,6 +1074,11 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr /* We do not generate PGP_PKT_SE_DATA, leaving this just in case */ param->pkt.tag = param->auth_type == rnp::AuthType::MDC ? PGP_PKT_SE_IP_DATA : PGP_PKT_SE_DATA; +#ifdef ENABLE_CRYPTO_REFRESH + if(param->auth_type == rnp::AuthType::AEADv2) { + param->pkt.tag = PGP_PKT_SE_IP_DATA; + } +#endif } /* initializing partial data length writer */ @@ -948,7 +1089,7 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr goto finish; } - if (param->auth_type == rnp::AuthType::AEADv1) { + if (param->is_aead_auth()) { /* initialize AEAD encryption */ ret = encrypted_start_aead(param, enckey.data()); } else { diff --git a/src/librepgp/v2_seipd.cpp b/src/librepgp/v2_seipd.cpp new file mode 100644 index 000000000..4bb2ee19a --- /dev/null +++ b/src/librepgp/v2_seipd.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). + * 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 "config.h" + +#ifdef ENABLE_CRYPTO_REFRESH + +#include "v2_seipd.h" +#include "logging.h" +#include "crypto/hkdf.hpp" + +seipd_v2_aead_fields_t +seipd_v2_key_and_nonce_derivation(pgp_seipdv2_hdr_t &hdr, uint8_t *sesskey) +{ + auto hkdf = rnp::Hkdf::create(PGP_HASH_SHA256); + + size_t sesskey_len = pgp_key_size(hdr.cipher_alg); + uint32_t nonce_size = 0; + uint32_t key_size = pgp_key_size(hdr.cipher_alg); + + switch (hdr.aead_alg) { + case PGP_AEAD_EAX: + nonce_size = 16; + break; + case PGP_AEAD_OCB: + nonce_size = 15; + break; + case PGP_AEAD_NONE: + case PGP_AEAD_UNKNOWN: + RNP_LOG("only EAX and OCB is supported for v2 SEIPD packets"); + throw rnp::rnp_exception(RNP_ERROR_NOT_SUPPORTED); + } + const uint8_t info[5] = { + static_cast(PGP_PKT_SE_IP_DATA | PGP_PTAG_ALWAYS_SET | PGP_PTAG_NEW_FORMAT), + static_cast(hdr.version), + static_cast(hdr.cipher_alg), + static_cast(hdr.aead_alg), + hdr.chunk_size_octet}; + uint32_t out_size = key_size + nonce_size - 8; + std::vector hkdf_out(out_size); + hkdf->extract_expand(hdr.salt, + sizeof(hdr.salt), + sesskey, + sesskey_len, + info, + sizeof(info), + hkdf_out.data(), + hkdf_out.size()); + + seipd_v2_aead_fields_t result; + result.key = std::vector(hkdf_out.data(), hkdf_out.data() + key_size); + result.nonce = + std::vector(hkdf_out.data() + key_size, hkdf_out.data() + hkdf_out.size()); + for (uint32_t i = 0; i < 8; i++) { + // fill up the nonce with zero octets + result.nonce.push_back(0); + } + return result; +} + +#endif diff --git a/src/librepgp/v2_seipd.h b/src/librepgp/v2_seipd.h new file mode 100644 index 000000000..00243036e --- /dev/null +++ b/src/librepgp/v2_seipd.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). + * 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 +#include +#include "types.h" + +struct seipd_v2_aead_fields_t { + std::vector key, nonce; +}; + +seipd_v2_aead_fields_t +seipd_v2_key_and_nonce_derivation(pgp_seipdv2_hdr_t &hdr, uint8_t *sesskey); diff --git a/src/rnp/fficli.cpp b/src/rnp/fficli.cpp index bc6551eef..fc6a965e4 100644 --- a/src/rnp/fficli.cpp +++ b/src/rnp/fficli.cpp @@ -2834,6 +2834,13 @@ cli_rnp_encrypt_and_sign(const rnp_cfg &cfg, } } +#if defined(ENABLE_CRYPTO_REFRESH) + /* enable or disable v6 PKESK creation*/ + if (!cfg.get_bool(CFG_V3_PKESK_ONLY)) { + rnp_op_encrypt_enable_pkesk_v6(op); + } +#endif + /* adding signatures if encrypt-and-sign is used */ if (cfg.get_bool(CFG_SIGN_NEEDED)) { rnp_op_encrypt_set_creation_time(op, cfg.get_sig_creation()); diff --git a/src/rnp/rnp.cpp b/src/rnp/rnp.cpp index 08efbe1e3..3dfcad852 100644 --- a/src/rnp/rnp.cpp +++ b/src/rnp/rnp.cpp @@ -129,6 +129,9 @@ enum optdefs { OPT_KEY_STORE_FORMAT, OPT_USERID, OPT_RECIPIENT, +#if defined(ENABLE_CRYPTO_REFRESH) + OPT_V3_PKESK_ONLY, +#endif OPT_ARMOR, OPT_HOMEDIR, OPT_DETACHED, @@ -193,6 +196,9 @@ static struct option options[] = { {"keystore-format", required_argument, NULL, OPT_KEY_STORE_FORMAT}, {"userid", required_argument, NULL, OPT_USERID}, {"recipient", required_argument, NULL, OPT_RECIPIENT}, +#if defined(ENABLE_CRYPTO_REFRESH) + {"v3-pkesk-only", optional_argument, NULL, OPT_V3_PKESK_ONLY}, +#endif {"home", required_argument, NULL, OPT_HOMEDIR}, {"homedir", required_argument, NULL, OPT_HOMEDIR}, {"keyfile", required_argument, NULL, OPT_KEYFILE}, @@ -405,6 +411,11 @@ setoption(rnp_cfg &cfg, int val, const char *arg) case OPT_RECIPIENT: cfg.add_str(CFG_RECIPIENTS, arg); return true; +#if defined(ENABLE_CRYPTO_REFRESH) + case OPT_V3_PKESK_ONLY: + cfg.set_bool(CFG_V3_PKESK_ONLY, true); + return true; +#endif case OPT_ARMOR: cfg.set_bool(CFG_ARMOR, true); return true; diff --git a/src/rnp/rnpcfg.h b/src/rnp/rnpcfg.h index 1d044804d..120f77d9a 100644 --- a/src/rnp/rnpcfg.h +++ b/src/rnp/rnpcfg.h @@ -50,6 +50,9 @@ #define CFG_NEEDSSECKEY "needsseckey" /* needs secret key for the ongoing operation */ #define CFG_USERID "userid" /* userid for the ongoing operation */ #define CFG_RECIPIENTS "recipients" /* list of encrypted data recipients */ +#if defined(ENABLE_CRYPTO_REFRESH) + #define CFG_V3_PKESK_ONLY "v3-pkesk-only" /* disable v6 PKESK */ +#endif #define CFG_SIGNERS "signers" /* list of signers */ #define CFG_HOMEDIR "homedir" /* home directory - folder with keyrings and so on */ #define CFG_KEYFILE "keyfile" /* path to the file with key(s), used instead of keyring */ diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index c539d761d..f8c81f4a9 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -82,7 +82,7 @@ if(CRYPTO_BACKEND_BOTAN3) set(CMAKE_CXX_STANDARD 20) endif() -add_executable(rnp_tests +set(RNP_TEST_SOURCES ../rnp/rnpcfg.cpp ../rnp/fficli.cpp ../rnp/rnp.cpp @@ -146,7 +146,15 @@ add_executable(rnp_tests fuzz_dump.cpp fuzz_verify_detached.cpp fuzz_verify.cpp -) + ) + +if(ENABLE_CRYPTO_REFRESH) + list(APPEND RNP_TEST_SOURCES + hkdf.cpp) +endif() + +add_executable(rnp_tests ${RNP_TEST_SOURCES}) + if(MSVC) find_package(WindowsSDK) GetUMWindowsSDKLibraryDir(WIN_LIBRARY_DIR) diff --git a/src/tests/data/test_v6_valid_data/transferable_pubkey_v6.asc b/src/tests/data/test_v6_valid_data/transferable_pubkey_v6.asc new file mode 100644 index 000000000..7cdbdda57 --- /dev/null +++ b/src/tests/data/test_v6_valid_data/transferable_pubkey_v6.asc @@ -0,0 +1,12 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf +GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy +KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw +gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE +QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn ++eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh +BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8 +j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805 +I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg== +-----END PGP PUBLIC KEY BLOCK----- diff --git a/src/tests/data/test_v6_valid_data/transferable_seckey_v6.asc b/src/tests/data/test_v6_valid_data/transferable_seckey_v6.asc new file mode 100644 index 000000000..976b460c0 --- /dev/null +++ b/src/tests/data/test_v6_valid_data/transferable_seckey_v6.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB +exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ +BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6 +2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh +RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe +7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/ +LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG +GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6 +2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE +M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr +k0mXubZvyl4GBg== +-----END PGP PRIVATE KEY BLOCK----- diff --git a/src/tests/data/test_v6_valid_data/v6pkesk.asc b/src/tests/data/test_v6_valid_data/v6pkesk.asc new file mode 100644 index 000000000..f0d0c2112 --- /dev/null +++ b/src/tests/data/test_v6_valid_data/v6pkesk.asc @@ -0,0 +1,8 @@ +-----BEGIN PGP MESSAGE----- + +wV0GIQYSyD8ecG9jCP4VGkF3Q6HwM3kOk+mXhIjR2zeNqZMIhRmHzxjV8bU/gXzO +WgBM85PMiVi93AZfJfhK9QmxfdNnZBjeo1VDeVZheQHgaVf7yopqR6W1FT6NOrfS +aQIHAgZhZBZTW+CwcW1g4FKlbExAf56zaw76/prQoN+bAzxpohup69LA7JW/Vp0l +yZnuSj3hcFj0DfqLTGgr4/u717J+sPWbtQBfgMfG9AOIwwrUBqsFE9zW+f1zdlYo +bhF30A+IitsxxA== +-----END PGP MESSAGE----- \ No newline at end of file diff --git a/src/tests/ffi-key.cpp b/src/tests/ffi-key.cpp index 7b7c5d6b4..5cfad144d 100644 --- a/src/tests/ffi-key.cpp +++ b/src/tests/ffi-key.cpp @@ -3155,6 +3155,33 @@ TEST_F(rnp_tests, test_ffi_malformed_keys_import) rnp_ffi_destroy(ffi); } +#if defined(ENABLE_CRYPTO_REFRESH) +TEST_F(rnp_tests, test_ffi_v6_sig_subpackets) +{ + rnp_ffi_t ffi = NULL; + + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL)); + assert_rnp_success(rnp_ffi_set_pass_provider(ffi, unused_getpasscb, NULL)); + + rnp_op_generate_t op = NULL; + assert_rnp_success(rnp_op_generate_create(&op, ffi, "EDDSA")); + assert_rnp_success(rnp_op_generate_set_v6_key(op)); + assert_rnp_success(rnp_op_generate_set_userid(op, "test")); + assert_rnp_success(rnp_op_generate_add_usage(op, "sign")); + assert_rnp_success(rnp_op_generate_add_usage(op, "certify")); + assert_rnp_success(rnp_op_generate_set_expiration(op, 0)); + assert_rnp_success(rnp_op_generate_execute(op)); + rnp_key_handle_t primary = NULL; + assert_rnp_success(rnp_op_generate_get_key(op, &primary)); + + assert_true(primary->pub->get_sig(0).sig.has_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, false)); // MUST NOT have issuer key id extension + assert_false(primary->pub->get_sig(0).sig.has_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false)); // SHOULD have issuer fingerprint + + rnp_op_generate_destroy(op); +} +#endif + TEST_F(rnp_tests, test_ffi_iterated_key_import) { rnp_ffi_t ffi = NULL; diff --git a/src/tests/hkdf.cpp b/src/tests/hkdf.cpp new file mode 100644 index 000000000..079ed57e7 --- /dev/null +++ b/src/tests/hkdf.cpp @@ -0,0 +1,36 @@ +#include "rnp_tests.h" + +#if defined(CRYPTO_BACKEND_BOTAN) && defined(ENABLE_CRYPTO_REFRESH) +#include "crypto/hkdf_botan.hpp" + +TEST_F(rnp_tests, hkdf_test_case_1) +{ + /* rfc5869 Test Case 1 + Hash = SHA-256 + IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets) + salt = 0x000102030405060708090a0b0c (13 octets) + info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets) + L = 42 + + PRK = 0x077709362c2e32df0ddc3f0dc47bba63 + 90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets) + OKM = 0x3cb25f25faacd57a90434f64d0362f2a + 2d2d0a90cf1a5a4c5db02d56ecc4c5bf + 34007208d5b887185865 (42 octets) + */ + + std::vector IKM = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; + std::vector salt = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}; + std::vector info = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9}; + std::vector PRK_expected = {0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5}; + std::vector OKM_expected = {0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65}; + size_t L = 42; + + std::unique_ptr hkdf = rnp::Hkdf::create(PGP_HASH_SHA256); + + uint8_t OKM[L]; + hkdf->extract_expand(salt.data(), salt.size(), IKM.data(), IKM.size(), info.data(), info.size(), OKM, L); + assert_memory_equal(OKM, OKM_expected.data(), OKM_expected.size()); +} + +#endif From e3b72cc61567d9c6cf8aac1a22a2229e25140edf Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Wed, 26 Jul 2023 13:34:31 +0200 Subject: [PATCH 03/20] add standalone v6 Ed25519 algorithm --- include/repgp/repgp_def.h | 6 ++- include/rnp/rnp.h | 1 + src/lib/CMakeLists.txt | 1 + src/lib/crypto.cpp | 16 ++++++ src/lib/crypto/common.h | 3 ++ src/lib/crypto/ec.h | 12 +++++ src/lib/crypto/ecdsa.cpp | 2 +- src/lib/crypto/ecdsa.h | 2 + src/lib/crypto/ed25519.cpp | 90 ++++++++++++++++++++++++++++++++++ src/lib/crypto/ed25519.h | 53 ++++++++++++++++++++ src/lib/crypto/hash.hpp | 1 + src/lib/crypto/hash_common.cpp | 6 +++ src/lib/crypto/signatures.cpp | 13 +++++ src/lib/generate-key.cpp | 7 +++ src/lib/pgp-key.cpp | 38 +++++++++++--- src/lib/rnp.cpp | 19 +++++++ src/lib/types.h | 7 +++ src/librekey/rnp_key_store.cpp | 5 ++ src/librepgp/stream-dump.cpp | 28 +++++++++++ src/librepgp/stream-key.cpp | 43 ++++++++++++++++ src/librepgp/stream-sig.cpp | 16 ++++++ 21 files changed, 361 insertions(+), 8 deletions(-) create mode 100644 src/lib/crypto/ed25519.cpp create mode 100644 src/lib/crypto/ed25519.h diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index 15cd13b1b..aa312e3d3 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -220,8 +220,12 @@ typedef enum : uint8_t { * (X9.42, as defined for * IETF-S/MIME) */ PGP_PKA_EDDSA = 22, /* EdDSA from draft-ietf-openpgp-rfc4880bis */ - PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ +#if defined(ENABLE_CRYPTO_REFRESH) + PGP_PKA_ED25519 = 27, /* v6 / Crypto Refresh */ +#endif + + PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ PGP_PKA_PRIVATE00 = 100, /* Private/Experimental Algorithm */ PGP_PKA_PRIVATE01 = 101, /* Private/Experimental Algorithm */ PGP_PKA_PRIVATE02 = 102, /* Private/Experimental Algorithm */ diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index e972c9464..73ee3d1ea 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -3398,6 +3398,7 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_ECDH "ECDH" #define RNP_ALGNAME_ECDSA "ECDSA" #define RNP_ALGNAME_EDDSA "EDDSA" +#define RNP_ALGNAME_ED25519 "ED25519" #define RNP_ALGNAME_IDEA "IDEA" #define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" #define RNP_ALGNAME_CAST5 "CAST5" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 590911ad0..84ae5d33c 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -284,6 +284,7 @@ elseif(CRYPTO_BACKEND_BOTAN) list(APPEND CRYPTO_SOURCES crypto/hkdf.cpp crypto/hkdf_botan.cpp + crypto/ed25519.cpp ) endif() else() diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index 7535eb5c9..815feef76 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -155,6 +155,14 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, 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; +#endif default: RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); return false; @@ -195,6 +203,10 @@ key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key case PGP_PKA_ECDSA: case PGP_PKA_SM2: return (key1->ec.curve == key2->ec.curve) && mpi_equal(&key1->ec.p, &key2->ec.p); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return (key1->ed25519.pub == key2->ed25519.pub); +#endif default: RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); return false; @@ -242,6 +254,10 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) 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); +#endif default: RNP_LOG("unknown public key algorithm: %d", (int) material->alg); } diff --git a/src/lib/crypto/common.h b/src/lib/crypto/common.h index 3d9b8378e..d9c6ebfb5 100644 --- a/src/lib/crypto/common.h +++ b/src/lib/crypto/common.h @@ -39,6 +39,9 @@ #include "ecdsa.h" #include "sm2.h" #include "eddsa.h" +#if defined(ENABLE_CRYPTO_REFRESH) +#include "ed25519.h" +#endif /* symmetric crypto */ #include "symmetric.h" /* hash */ diff --git a/src/lib/crypto/ec.h b/src/lib/crypto/ec.h index 07cb8e810..ae2d88bd6 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 #define MAX_CURVE_BIT_SIZE 521 // secp521r1 /* Maximal byte size of elliptic curve order (NIST P-521) */ @@ -89,6 +90,17 @@ typedef struct pgp_ec_signature_t { pgp_mpi_t s; } pgp_ec_signature_t; +#if defined(ENABLE_CRYPTO_REFRESH) +typedef struct pgp_ed25519_key_t { + std::vector pub; // \ native encoding + std::vector priv; // / +} pgp_ed25519_key_t; + +typedef struct pgp_ed25519_signature_t { + std::vector sig; // native encoding +} pgp_ed25519_signature_t; +#endif + /* * @brief Finds curve ID by hex representation of OID * diff --git a/src/lib/crypto/ecdsa.cpp b/src/lib/crypto/ecdsa.cpp index 26816a5c0..3a96cae3a 100644 --- a/src/lib/crypto/ecdsa.cpp +++ b/src/lib/crypto/ecdsa.cpp @@ -112,7 +112,7 @@ ecdsa_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret) return ret; } -static const char * +const char * ecdsa_padding_str_for(pgp_hash_alg_t hash_alg) { switch (hash_alg) { diff --git a/src/lib/crypto/ecdsa.h b/src/lib/crypto/ecdsa.h index aebfe6a68..83f97c12b 100644 --- a/src/lib/crypto/ecdsa.h +++ b/src/lib/crypto/ecdsa.h @@ -44,6 +44,8 @@ rnp_result_t ecdsa_verify(const pgp_ec_signature_t *sig, size_t hash_len, const pgp_ec_key_t * key); +const char * ecdsa_padding_str_for(pgp_hash_alg_t hash_alg); + /* * @brief Returns hash which should be used with the curve * diff --git a/src/lib/crypto/ed25519.cpp b/src/lib/crypto/ed25519.cpp new file mode 100644 index 000000000..bb52fa776 --- /dev/null +++ b/src/lib/crypto/ed25519.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "ed25519.h" +#include "logging.h" +#include "utils.h" + +#include +#include +#include + + + +rnp_result_t generate_ed25519_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey) +{ + Botan::Ed25519_PrivateKey private_key(*(rng->obj())); + const size_t key_len = 32; + auto priv_pub = Botan::unlock(private_key.raw_private_key_bits()); + assert(priv_pub.size() == 2 * key_len); + privkey = std::vector(priv_pub.begin(), priv_pub.begin() + key_len); + pubkey = std::vector(priv_pub.begin() + key_len, priv_pub.end()); + + return RNP_SUCCESS; +} + +rnp_result_t ed25519_sign_native(rnp::RNG *rng, std::vector &sig_out, const std::vector &key, const uint8_t *hash, size_t hash_len) +{ + Botan::Ed25519_PrivateKey priv_key(Botan::secure_vector(key.begin(), key.end())); + auto signer = Botan::PK_Signer(priv_key, *(rng->obj()), "Pure"); + sig_out = signer.sign_message(hash, hash_len, *(rng->obj())); + + return RNP_SUCCESS; +} + +rnp_result_t ed25519_verify_native(const std::vector &sig, const std::vector &key, const uint8_t *hash, size_t hash_len) +{ + Botan::Ed25519_PublicKey pub_key(key); + auto verifier = Botan::PK_Verifier(pub_key, "Pure"); + if(verifier.verify_message(hash, hash_len, sig.data(), sig.size())) { + return RNP_SUCCESS; + } + return RNP_ERROR_VERIFICATION_FAILED; +} + +rnp_result_t +ed25519_validate_key_native(rnp::RNG *rng, const pgp_ed25519_key_t *key, bool secret) +{ + Botan::Ed25519_PublicKey pub_key(key->pub); + if(!pub_key.check_key(*(rng->obj()), false)) { + return RNP_ERROR_BAD_PARAMETERS; + } + + if(secret) { + Botan::Ed25519_PrivateKey priv_key(Botan::secure_vector(key->priv.begin(), key->priv.end())); + if(!priv_key.check_key(*(rng->obj()), false)) { + return RNP_ERROR_SIGNING_FAILED; + } + } + + return RNP_SUCCESS; +} \ No newline at end of file diff --git a/src/lib/crypto/ed25519.h b/src/lib/crypto/ed25519.h new file mode 100644 index 000000000..a7f5e1688 --- /dev/null +++ b/src/lib/crypto/ed25519.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 ED25519_H_ +#define ED25519_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include "crypto/ec.h" + +/* implements ED25519 with native format (V6 and PQC) */ + +rnp_result_t generate_ed25519_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey); + +rnp_result_t ed25519_sign_native(rnp::RNG *rng, std::vector &sig_out, const std::vector &key, const uint8_t *hash, size_t hash_len); + +rnp_result_t ed25519_verify_native(const std::vector &sig, const std::vector &key, const uint8_t *hash, size_t hash_len); + +rnp_result_t ed25519_validate_key_native(rnp::RNG *rng, const pgp_ed25519_key_t *key, bool secret); + +#endif \ No newline at end of file diff --git a/src/lib/crypto/hash.hpp b/src/lib/crypto/hash.hpp index 7fcb81770..7bf763e6b 100644 --- a/src/lib/crypto/hash.hpp +++ b/src/lib/crypto/hash.hpp @@ -57,6 +57,7 @@ class Hash { virtual std::unique_ptr clone() const = 0; virtual void add(const void *buf, size_t len) = 0; + virtual void add(const std::vector &val); virtual void add(uint32_t val); virtual void add(const pgp_mpi_t &mpi); virtual size_t finish(uint8_t *digest = NULL) = 0; diff --git a/src/lib/crypto/hash_common.cpp b/src/lib/crypto/hash_common.cpp index 194cb07ad..8a45f229a 100644 --- a/src/lib/crypto/hash_common.cpp +++ b/src/lib/crypto/hash_common.cpp @@ -100,6 +100,12 @@ CRC24::create() #endif } +void +Hash::add(const std::vector &val) +{ + add(val.data(), val.size()); +} + void Hash::add(uint32_t val) { diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 8fa45b61d..52a33453a 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -137,6 +137,14 @@ signature_calculate(pgp_signature_t & sig, 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) { @@ -256,6 +264,11 @@ signature_validate(const pgp_signature_t & sig, 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); diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index c43b4cec9..bc4eb5820 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -55,6 +55,9 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_RESERVED_DH, "Reserved for Diffie-Hellman (X9.42)"}, {PGP_PKA_EDDSA, "EdDSA"}, {PGP_PKA_SM2, "SM2"}, +#if defined(ENABLE_CRYPTO_REFRESH) + {PGP_PKA_ED25519, "ED25519"}, +#endif {PGP_PKA_PRIVATE00, "Private/Experimental"}, {PGP_PKA_PRIVATE01, "Private/Experimental"}, {PGP_PKA_PRIVATE02, "Private/Experimental"}, @@ -249,6 +252,10 @@ get_numbits(const rnp_keygen_crypto_params_t *crypto) return 0; } } +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return 255; +#endif case PGP_PKA_DSA: return crypto->dsa.p_bitlen; case PGP_PKA_ELGAMAL: diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 5f162e407..a6adadbdd 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -193,6 +193,11 @@ pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) case PGP_PKA_EDDSA: return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); +#endif + case PGP_PKA_SM2: return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH | PGP_KF_ENCRYPT); @@ -2738,6 +2743,24 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) return true; } +pgp_curve_t +pgp_key_material_t::get_curve() const +{ + switch (alg) { + case PGP_PKA_ECDH: [[fallthrough]]; + case PGP_PKA_ECDSA: [[fallthrough]]; + case PGP_PKA_EDDSA: [[fallthrough]]; + case PGP_PKA_SM2: + return ec.curve; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return PGP_CURVE_ED25519; +#endif + default: + return PGP_CURVE_UNKNOWN; + } +} + size_t pgp_key_material_t::bits() const { @@ -2751,13 +2774,16 @@ pgp_key_material_t::bits() const case PGP_PKA_ELGAMAL: case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: return 8 * mpi_bytes(&eg.y); - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: + case PGP_PKA_ECDH: [[fallthrough]]; + case PGP_PKA_ECDSA: [[fallthrough]]; + case PGP_PKA_EDDSA: [[fallthrough]]; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: [[fallthrough]]; +#endif case PGP_PKA_SM2: { - // bn_num_bytes returns value <= curve order - const ec_curve_desc_t *curve = get_curve_desc(ec.curve); - return curve ? curve->bitlen : 0; + /* handle ecc cases */ + const ec_curve_desc_t *curve_desc = get_curve_desc(get_curve()); + return curve_desc ? curve_desc->bitlen : 0; } default: RNP_LOG("Unknown public key alg: %d", (int) alg); diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index d021951cf..e020ded79 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -162,6 +162,9 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_ECDSA, RNP_ALGNAME_ECDSA}, {PGP_PKA_EDDSA, RNP_ALGNAME_EDDSA}, {PGP_PKA_SM2, RNP_ALGNAME_SM2}, +#if defined(ENABLE_CRYPTO_REFRESH) + {PGP_PKA_ED25519, RNP_ALGNAME_ED25519}, +#endif {0, NULL}}; static const id_str_pair symm_alg_map[] = {{PGP_SA_IDEA, RNP_ALGNAME_IDEA}, @@ -5213,6 +5216,10 @@ default_key_flags(pgp_pubkey_alg_t alg, bool subkey) case PGP_PKA_ECDH: case PGP_PKA_ELGAMAL: return PGP_KF_ENCRYPT; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); +#endif default: return PGP_KF_NONE; } @@ -7451,6 +7458,10 @@ add_json_secret_mpis(json_object *jso, pgp_key_t *key) 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: + return RNP_SUCCESS; /* TODO */ +#endif default: return RNP_ERROR_NOT_SUPPORTED; } @@ -7483,6 +7494,10 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) case PGP_PKA_EDDSA: case PGP_PKA_SM2: return add_json_mpis(jso, "r", &material.ecc.r, "s", &material.ecc.s, NULL); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return RNP_SUCCESS; /* TODO */ +#endif default: // TODO: we could use info->unknown and add a hex string of raw data here return RNP_ERROR_NOT_SUPPORTED; @@ -7700,6 +7715,10 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } } break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + return RNP_SUCCESS; /* TODO */ +#endif default: break; } diff --git a/src/lib/types.h b/src/lib/types.h index aefdcfa7a..1d0a304bd 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -188,7 +188,11 @@ typedef struct pgp_key_material_t { 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 */ +#endif + pgp_curve_t get_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); @@ -205,6 +209,9 @@ typedef struct pgp_signature_material_t { pgp_ec_signature_t ecc; pgp_eg_signature_t eg; }; +#if defined(ENABLE_CRYPTO_REFRESH) + pgp_ed25519_signature_t ed25519; // non-trivial type cannot be member in union +#endif } pgp_signature_material_t; /** diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index a8873c6f7..284796216 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -739,6 +739,11 @@ rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) case PGP_PKA_SM2: grip_hash_ec(*hash, key->ec); break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + hash->add(key->ed25519.pub); + break; +#endif default: RNP_LOG("unsupported public-key algorithm %d", (int) key->alg); return false; diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 069a86947..75d2bd279 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -143,6 +143,9 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_RESERVED_DH, "Reserved for DH (X9.42)"}, {PGP_PKA_EDDSA, "EdDSA"}, {PGP_PKA_SM2, "SM2"}, +#if defined(ENABLE_CRYPTO_REFRESH) + {PGP_PKA_ED25519, "Ed25519"}, +#endif {0x00, NULL}, }; @@ -799,6 +802,11 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t dst_print_mpi(dst, "eg r", &material.eg.r, ctx->dump_mpi); dst_print_mpi(dst, "eg s", &material.eg.s, ctx->dump_mpi); break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + dst_print_vec(dst, "ed25519 sig", material.ed25519.sig, ctx->dump_mpi); + break; +#endif default: dst_printf(dst, "unknown algorithm\n"); } @@ -893,6 +901,11 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) dst_printf(dst, "ecdh key wrap algorithm: %d\n", (int) key.material.ec.key_wrap_alg); break; } +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + dst_print_vec(dst, "ed25519", key.material.ed25519.pub, ctx->dump_mpi); + break; +#endif default: dst_printf(dst, "unknown public key algorithm\n"); } @@ -1858,6 +1871,11 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, return RNP_ERROR_OUT_OF_MEMORY; } break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + /* TODO */ + break; +#endif default: break; } @@ -1971,6 +1989,11 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) } break; } +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + /* TODO */ + break; +#endif default: break; } @@ -2100,6 +2123,11 @@ stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_obj return RNP_ERROR_OUT_OF_MEMORY; } break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + /* TODO */ + break; +#endif default:; } diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index 9d4bf4544..d171c1537 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -48,6 +48,7 @@ #include "crypto/signatures.h" #include "crypto/mem.h" #include "../librekey/key_store_pgp.h" +#include "str-utils.h" #include #include #include @@ -596,6 +597,8 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) try { /* parse mpis depending on algorithm */ pgp_packet_body_t body(mpis, len); + + std::vector tmpbuf; #if defined(ENABLE_CRYPTO_REFRESH) std::vector tmpbuf; @@ -633,6 +636,18 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) 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; + } +#endif default: RNP_LOG("unknown pk alg : %d", (int) key.alg); return RNP_ERROR_BAD_PARAMETERS; @@ -756,6 +771,11 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) 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; +#endif default: RNP_LOG("unknown pk alg : %d", (int) key.alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); @@ -899,6 +919,12 @@ forget_secret_key_fields(pgp_key_material_t *key) case PGP_PKA_ECDH: mpi_forget(&key->ec.x); 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; +#endif default: RNP_LOG("unknown key algorithm: %d", (int) key->alg); } @@ -1335,6 +1361,18 @@ pgp_key_pkt_t::parse(pgp_source_t &src) 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; + } +#endif default: RNP_LOG("unknown key algorithm: %d", (int) alg); return RNP_ERROR_BAD_FORMAT; @@ -1472,6 +1510,11 @@ void pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t & hbod 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; +#endif default: RNP_LOG("unknown key algorithm: %d", (int) alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index a609fac8e..e92937ba5 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1553,6 +1553,17 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const return false; } break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: { + const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_25519); + material.ed25519.sig.resize(2 * BITS_TO_BYTES(ec_desc->bitlen)); + if (!pkt.get(material.ed25519.sig.data(), material.ed25519.sig.size())) { + RNP_LOG("failed to parse ED25519 signature data"); + return false; + } + break; + } +#endif default: RNP_LOG("Unknown pk algorithm : %d", (int) palg); return false; @@ -1634,6 +1645,11 @@ pgp_signature_t::write_material(const pgp_signature_material_t &material) pktbody.add(material.eg.r); pktbody.add(material.eg.s); break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: + pktbody.add(material.ed25519.sig); + break; +#endif default: RNP_LOG("Unknown pk algorithm : %d", (int) palg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); From 1e1757cab61ecac843a7de619b2837a7d93d51b9 Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Wed, 26 Jul 2023 13:37:24 +0200 Subject: [PATCH 04/20] add standalone v6 X25519 encryption algorithm; add ecdh kem and ecdsa/eddsa abstraction for the following PQC integration --- include/repgp/repgp_def.h | 1 + include/rnp/rnp.h | 1 + src/lib/CMakeLists.txt | 2 + src/lib/crypto.cpp | 10 ++ src/lib/crypto/common.h | 1 + src/lib/crypto/ec.cpp | 81 +++++++++ src/lib/crypto/ec.h | 26 +++ src/lib/crypto/ecdh.cpp | 39 +++++ src/lib/crypto/ecdh.h | 39 +++++ src/lib/crypto/exdsa_ecdhkem.cpp | 285 +++++++++++++++++++++++++++++++ src/lib/crypto/exdsa_ecdhkem.h | 183 ++++++++++++++++++++ src/lib/crypto/x25519.cpp | 166 ++++++++++++++++++ src/lib/crypto/x25519.h | 60 +++++++ src/lib/generate-key.cpp | 3 + src/lib/pgp-key.cpp | 5 + src/lib/rnp.cpp | 10 ++ src/lib/types.h | 12 +- src/librekey/rnp_key_store.cpp | 3 + src/librepgp/stream-common.cpp | 9 +- src/librepgp/stream-ctx.cpp | 2 +- src/librepgp/stream-dump.cpp | 12 ++ src/librepgp/stream-key.cpp | 30 ++++ src/librepgp/stream-packet.cpp | 28 +++ src/librepgp/stream-parse.cpp | 10 ++ src/librepgp/stream-write.cpp | 28 +++ src/rnpkeys/tui.cpp | 11 ++ src/tests/CMakeLists.txt | 1 + src/tests/exdsa_ecdhkem.cpp | 93 ++++++++++ src/tests/ffi-key.cpp | 55 ++++++ src/tests/ffi.cpp | 6 +- 30 files changed, 1204 insertions(+), 8 deletions(-) create mode 100644 src/lib/crypto/exdsa_ecdhkem.cpp create mode 100644 src/lib/crypto/exdsa_ecdhkem.h create mode 100644 src/lib/crypto/x25519.cpp create mode 100644 src/lib/crypto/x25519.h create mode 100644 src/tests/exdsa_ecdhkem.cpp diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index aa312e3d3..ed45c952e 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -222,6 +222,7 @@ typedef enum : uint8_t { PGP_PKA_EDDSA = 22, /* EdDSA from draft-ietf-openpgp-rfc4880bis */ #if defined(ENABLE_CRYPTO_REFRESH) + PGP_PKA_X25519 = 25, /* v6 / Crypto Refresh */ PGP_PKA_ED25519 = 27, /* v6 / Crypto Refresh */ #endif diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 73ee3d1ea..0aa0413db 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -3399,6 +3399,7 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_ECDSA "ECDSA" #define RNP_ALGNAME_EDDSA "EDDSA" #define RNP_ALGNAME_ED25519 "ED25519" +#define RNP_ALGNAME_X25519 "X25519" #define RNP_ALGNAME_IDEA "IDEA" #define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" #define RNP_ALGNAME_CAST5 "CAST5" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 84ae5d33c..48d5e4aa4 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -285,6 +285,8 @@ elseif(CRYPTO_BACKEND_BOTAN) crypto/hkdf.cpp crypto/hkdf_botan.cpp crypto/ed25519.cpp + crypto/x25519.cpp + crypto/exdsa_ecdhkem.cpp ) endif() else() diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index 815feef76..6f8511d2a 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -162,6 +162,12 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, 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 default: RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); @@ -206,6 +212,8 @@ key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key #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 default: RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); @@ -257,6 +265,8 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) #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 default: RNP_LOG("unknown public key algorithm: %d", (int) material->alg); diff --git a/src/lib/crypto/common.h b/src/lib/crypto/common.h index d9c6ebfb5..9576588cf 100644 --- a/src/lib/crypto/common.h +++ b/src/lib/crypto/common.h @@ -40,6 +40,7 @@ #include "sm2.h" #include "eddsa.h" #if defined(ENABLE_CRYPTO_REFRESH) +#include "x25519.h" #include "ed25519.h" #endif /* symmetric crypto */ diff --git a/src/lib/crypto/ec.cpp b/src/lib/crypto/ec.cpp index 144c362ea..25db0f3f0 100644 --- a/src/lib/crypto/ec.cpp +++ b/src/lib/crypto/ec.cpp @@ -32,6 +32,13 @@ #include "utils.h" #include "mem.h" #include "bn.h" +#if defined(ENABLE_CRYPTO_REFRESH) +#include "x25519.h" +#include "ed25519.h" +#include "botan/bigint.h" +#include "botan/ecdh.h" +#include +#endif static id_str_pair ec_algo_to_botan[] = { {PGP_PKA_ECDH, "ECDH"}, @@ -185,3 +192,77 @@ ec_generate(rnp::RNG * rng, bn_free(x); return ret; } + +#if defined(ENABLE_CRYPTO_REFRESH) +static bool is_generic_prime_curve(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_NIST_P_256: [[fallthrough]]; + case PGP_CURVE_NIST_P_384: [[fallthrough]]; + case PGP_CURVE_NIST_P_521: [[fallthrough]]; + case PGP_CURVE_BP256: [[fallthrough]]; + case PGP_CURVE_BP384: [[fallthrough]]; + case PGP_CURVE_BP512: [[fallthrough]]; + case PGP_CURVE_P256K1: + return true; + default: + return false; + } +} + +static rnp_result_t ec_generate_generic_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve, + pgp_pubkey_alg_t alg) +{ + if(!is_generic_prime_curve(curve)) { + RNP_LOG("expected generic prime curve"); + return RNP_ERROR_BAD_PARAMETERS; + } + + const ec_curve_desc_t *ec_desc = get_curve_desc(curve); + const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); + + Botan::ECDH_PrivateKey privkey_botan(*(rng->obj()), Botan::EC_Group(ec_desc->botan_name)); + Botan::BigInt pub_x = privkey_botan.public_point().get_affine_x(); + Botan::BigInt pub_y = privkey_botan.public_point().get_affine_y(); + Botan::BigInt x = privkey_botan.private_value(); + + // pubkey: 0x04 || X || Y + pubkey = Botan::unlock(Botan::BigInt::encode_fixed_length_int_pair(pub_x, pub_y, curve_order)); // zero-pads to the given size + pubkey.insert(pubkey.begin(), 0x04); + + privkey = std::vector(curve_order); + x.binary_encode(privkey.data(), privkey.size()); // zero-pads to the given size + + assert(pubkey.size() == 2 * curve_order + 1); + assert(privkey.size() == curve_order); + + return RNP_SUCCESS; +} + +rnp_result_t ec_generate_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve, + pgp_pubkey_alg_t alg) +{ + if(curve == PGP_CURVE_25519) { + return generate_x25519_native(rng, privkey, pubkey); + } + else if(curve == PGP_CURVE_ED25519) { + return generate_ed25519_native(rng, privkey, pubkey); + } + else if(is_generic_prime_curve(curve)) { + if(alg != PGP_PKA_ECDH && alg != PGP_PKA_ECDSA) { + RNP_LOG("alg and curve mismatch"); + return RNP_ERROR_BAD_PARAMETERS; + } + return ec_generate_generic_native(rng, privkey, pubkey, curve, alg); + } + else { + RNP_LOG("invalid curve"); + return RNP_ERROR_BAD_PARAMETERS; + } +} +#endif \ No newline at end of file diff --git a/src/lib/crypto/ec.h b/src/lib/crypto/ec.h index ae2d88bd6..cef5c3039 100644 --- a/src/lib/crypto/ec.h +++ b/src/lib/crypto/ec.h @@ -99,6 +99,16 @@ typedef struct pgp_ed25519_key_t { typedef struct pgp_ed25519_signature_t { std::vector sig; // native encoding } pgp_ed25519_signature_t; + +typedef struct pgp_x25519_key_t { + std::vector pub; // \ native encoding + std::vector priv; // / +} pgp_x25519_key_t; + +typedef struct pgp_x25519_encrypted_t { + std::vector eph_key; + std::vector enc_sess_key; +} pgp_x25519_encrypted_t; #endif /* @@ -182,4 +192,20 @@ bool x25519_tweak_bits(pgp_ec_key_t &key); */ bool x25519_bits_tweaked(const pgp_ec_key_t &key); +/* + * @brief Generates EC keys in "native" or SEC1-encoded uncompressed format + * + * @param rng initialized rnp::RNG context* + * @param privkey private key to be generated + * @param pubkey public key to be generated + * @param curve chosen curve + * @param alg algorithm id + * + * @returns RNP_ERROR_BAD_PARAMETERS if the curve or alg parameter is invalid. + */ +rnp_result_t ec_generate_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve, + pgp_pubkey_alg_t alg); #endif diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index 574b3b868..df9f7df7a 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -28,6 +28,7 @@ #include #include "hash_botan.hpp" #include "ecdh.h" +#include "ec.h" #include "ecdh_utils.h" #include "symmetric.h" #include "types.h" @@ -388,3 +389,41 @@ ecdh_decrypt_pkcs5(uint8_t * out, botan_privkey_destroy(prv_key); return ret; } + +#if defined(ENABLE_CRYPTO_REFRESH) +rnp_result_t ecdh_kem_gen_keypair_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve) +{ + return ec_generate_native(rng, privkey, pubkey, curve, PGP_PKA_ECDH); +} + +rnp_result_t exdsa_gen_keypair_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve) +{ + pgp_pubkey_alg_t alg; + switch(curve) + { + case PGP_CURVE_ED25519: + alg = PGP_PKA_EDDSA; + break; + case PGP_CURVE_NIST_P_256: [[fallthrough]]; + case PGP_CURVE_NIST_P_384: [[fallthrough]]; + case PGP_CURVE_NIST_P_521: [[fallthrough]]; + case PGP_CURVE_BP256: [[fallthrough]]; + case PGP_CURVE_BP384: [[fallthrough]]; + case PGP_CURVE_BP512: [[fallthrough]]; + case PGP_CURVE_P256K1: + alg = PGP_PKA_ECDSA; + break; + default: + RNP_LOG("invalid curve for ECDSA/EDDSA"); + return RNP_ERROR_BAD_PARAMETERS; + } + return ec_generate_native(rng, privkey, pubkey, curve, alg); +} + +#endif \ No newline at end of file diff --git a/src/lib/crypto/ecdh.h b/src/lib/crypto/ecdh.h index 017e1e69e..a0d61c601 100644 --- a/src/lib/crypto/ecdh.h +++ b/src/lib/crypto/ecdh.h @@ -28,6 +28,7 @@ #define ECDH_H_ #include "crypto/ec.h" +#include /* Max size of wrapped and obfuscated key size * @@ -114,4 +115,42 @@ rnp_result_t ecdh_decrypt_pkcs5(uint8_t * out, const pgp_ec_key_t * key, const pgp_fingerprint_t & fingerprint); + +#if defined(ENABLE_CRYPTO_REFRESH) +/* Generate an ECDH key pair in "native" format, i.e., + * no changes to the format specified in the respective standard + * are applied (uncompressed SEC1 and RFC 7748). + * + * @param rng initialized rnp::RNG object + * @param privkey [out] the generated private key + * @param pubkey [out] the generated public key + * @param curve the curve for which a key pair is generated + * + * @return RNP_SUCCESS on success and output parameters are populated + * @return RNP_ERROR_BAD_PARAMETERS unexpected input provided + */ +rnp_result_t ecdh_kem_gen_keypair_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve); + +/* Generate an ECDSA or EdDSA key pair in "native" format, i.e., + * no changes to the format specified in the respective standard + * are applied (uncompressed SEC1 and RFC 7748). + * + * @param rng initialized rnp::RNG object + * @param privkey [out] the generated private key + * @param pubkey [out] the generated public key + * @param curve the curve for which a key pair is generated + * + * @return RNP_SUCCESS on success and output parameters are populated + * @return RNP_ERROR_BAD_PARAMETERS unexpected input provided + */ +rnp_result_t exdsa_gen_keypair_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve); + +#endif + #endif // ECDH_H_ diff --git a/src/lib/crypto/exdsa_ecdhkem.cpp b/src/lib/crypto/exdsa_ecdhkem.cpp new file mode 100644 index 000000000..b1912bcb8 --- /dev/null +++ b/src/lib/crypto/exdsa_ecdhkem.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "exdsa_ecdhkem.h" +#include "ecdh.h" +#include "ecdsa.h" +#include "ec.h" +#include "types.h" +#include "logging.h" +#include "string.h" +#include "utils.h" +#include + +ec_key_t::~ec_key_t() {} + +ec_key_t::ec_key_t(pgp_curve_t curve) + : curve_(curve) +{} + +ecdh_kem_public_key_t::ecdh_kem_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) + : ec_key_t(curve), + key_(std::vector(key_buf, key_buf + key_buf_len)) +{} +ecdh_kem_public_key_t::ecdh_kem_public_key_t(std::vector key, pgp_curve_t curve) + : ec_key_t(curve), + key_(key) +{} + +ecdh_kem_private_key_t::ecdh_kem_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) + : ec_key_t(curve), + key_(key_buf, key_buf + key_buf_len) +{} +ecdh_kem_private_key_t::ecdh_kem_private_key_t(std::vector key, pgp_curve_t curve) + : ec_key_t(curve), + key_(Botan::secure_vector(key.begin(), key.end())) +{} + +Botan::ECDH_PrivateKey +ecdh_kem_private_key_t::botan_key_ecdh(rnp::RNG *rng) const +{ + assert(curve_ >= PGP_CURVE_NIST_P_256 && curve_ <= PGP_CURVE_P256K1); + const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); + return Botan::ECDH_PrivateKey(*(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_)); +} + +Botan::ECDH_PublicKey +ecdh_kem_public_key_t::botan_key_ecdh(rnp::RNG *rng) const +{ + assert(curve_ >= PGP_CURVE_NIST_P_256 && curve_ <= PGP_CURVE_P256K1); + + const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); + Botan::EC_Group group(ec_desc->botan_name); + const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); + Botan::BigInt x(key_.data() + 1, curve_order); + Botan::BigInt y(key_.data() + 1 + curve_order, curve_order); + return Botan::ECDH_PublicKey(group, group.point(x, y)); +} + + +Botan::Curve25519_PrivateKey +ecdh_kem_private_key_t::botan_key_x25519() const +{ + assert(curve_ == PGP_CURVE_25519); + return Botan::Curve25519_PrivateKey(key_); +} + +Botan::Curve25519_PublicKey +ecdh_kem_public_key_t::botan_key_x25519() const +{ + assert(curve_ == PGP_CURVE_25519); + return Botan::Curve25519_PublicKey(key_); +} + +rnp_result_t +ecdh_kem_public_key_t::encapsulate(rnp::RNG *rng, std::vector &ciphertext, std::vector &symmetric_key) { + if (curve_ == PGP_CURVE_25519) { + Botan::Curve25519_PrivateKey eph_prv_key(*(rng->obj())); + ciphertext = eph_prv_key.public_value(); + Botan::PK_Key_Agreement key_agreement(eph_prv_key, *(rng->obj()), "Raw"); + symmetric_key = Botan::unlock(key_agreement.derive_key(0, key_).bits_of()); + } else { + const ec_curve_desc_t *curve_desc = get_curve_desc(curve_); + if (!curve_desc) { + RNP_LOG("unknown curve"); + return RNP_ERROR_NOT_SUPPORTED; + } + + Botan::EC_Group domain(curve_desc->botan_name); + Botan::ECDH_PrivateKey eph_prv_key(*(rng->obj()), domain); + Botan::PK_Key_Agreement key_agreement(eph_prv_key, *(rng->obj()), "Raw"); + ciphertext = eph_prv_key.public_value(); + symmetric_key = Botan::unlock(key_agreement.derive_key(0, key_).bits_of()); + } + return RNP_SUCCESS; +} + +rnp_result_t +ecdh_kem_private_key_t::decapsulate(rnp::RNG *rng, const std::vector &ciphertext, std::vector &plaintext) +{ + if (curve_ == PGP_CURVE_25519) { + Botan::Curve25519_PrivateKey priv_key = botan_key_x25519(); + Botan::PK_Key_Agreement key_agreement(priv_key, *(rng->obj()), "Raw"); + plaintext = Botan::unlock(key_agreement.derive_key(0, ciphertext).bits_of()); + } else { + Botan::ECDH_PrivateKey priv_key = botan_key_ecdh(rng); + Botan::PK_Key_Agreement key_agreement(priv_key, *(rng->obj()), "Raw"); + plaintext = Botan::unlock(key_agreement.derive_key(0, ciphertext).bits_of()); + } + return RNP_SUCCESS; +} + +rnp_result_t +ec_key_t::generate_ecdh_kem_key_pair(rnp::RNG *rng, ecdh_kem_key_t *out, pgp_curve_t curve) +{ + std::vector pub, priv; + rnp_result_t result = ecdh_kem_gen_keypair_native(rng, priv, pub, curve); + if(result != RNP_SUCCESS) { + RNP_LOG("error when generating EC key pair"); + return result; + } + + out->priv = ecdh_kem_private_key_t(priv, curve); + out->pub = ecdh_kem_public_key_t(pub, curve); + + return RNP_SUCCESS; +} + + +exdsa_public_key_t::exdsa_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) + : ec_key_t(curve), + key_(key_buf, key_buf + key_buf_len) +{} +exdsa_public_key_t::exdsa_public_key_t(std::vector key, pgp_curve_t curve) + : ec_key_t(curve), + key_(key) +{} + +exdsa_private_key_t::exdsa_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) + : ec_key_t(curve), + key_(key_buf, key_buf + key_buf_len) +{} +exdsa_private_key_t::exdsa_private_key_t(std::vector key, pgp_curve_t curve) + : ec_key_t(curve), + key_(Botan::secure_vector(key.begin(), key.end())) +{} + + +rnp_result_t +ec_key_t::generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t curve) +{ + std::vector pub, priv; + rnp_result_t result = exdsa_gen_keypair_native(rng, priv, pub, curve); + if(result != RNP_SUCCESS) { + RNP_LOG("error when generating EC key pair"); + return result; + } + + out->priv = exdsa_private_key_t(priv, curve); + out->pub = exdsa_public_key_t(pub, curve); + + return RNP_SUCCESS; +} + +Botan::ECDSA_PrivateKey +exdsa_private_key_t::botan_key(rnp::RNG *rng) const +{ + const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); + Botan::ECDSA_PrivateKey priv_key(*(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_)); + return priv_key; +} + +Botan::ECDSA_PublicKey +exdsa_public_key_t::botan_key() const +{ + // format: 04 | X | Y + const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); + Botan::EC_Group group(ec_desc->botan_name); + const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); + Botan::BigInt x(key_.data() + 1, curve_order); + Botan::BigInt y(key_.data() + 1 + curve_order, curve_order); + return Botan::ECDSA_PublicKey(group, group.point(x, y)); +} + +/* NOTE hash_alg unused for ed25519/x25519 curves */ +rnp_result_t +exdsa_private_key_t::sign(rnp::RNG *rng, std::vector &sig_out, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const +{ + if(curve_ == PGP_CURVE_ED25519) { + return ed25519_sign_native(rng, sig_out, Botan::unlock(key_), hash, hash_len); + } + else { + Botan::ECDSA_PrivateKey priv_key = botan_key(rng); + auto signer = Botan::PK_Signer(priv_key, *(rng->obj()), ecdsa_padding_str_for(hash_alg)); + sig_out = signer.sign_message(hash, hash_len, *(rng->obj())); + } + return RNP_SUCCESS; +} + +rnp_result_t +exdsa_public_key_t::verify(const std::vector &sig, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const +{ + if(curve_ == PGP_CURVE_ED25519) { + return ed25519_verify_native(sig, key_, hash, hash_len); + } + else { + Botan::ECDSA_PublicKey pub_key = botan_key(); + auto verifier = Botan::PK_Verifier(pub_key, ecdsa_padding_str_for(hash_alg)); + if(verifier.verify_message(hash, hash_len, sig.data(), sig.size())) { + return RNP_SUCCESS; + } + } + return RNP_ERROR_VERIFICATION_FAILED; +} + +bool +exdsa_public_key_t::is_valid(rnp::RNG *rng) const { + if(curve_ == PGP_CURVE_ED25519) { + Botan::Ed25519_PublicKey pub_key(key_); + return pub_key.check_key(*(rng->obj()), false); + } else { + Botan::ECDSA_PublicKey pub_key = botan_key(); + return pub_key.check_key(*(rng->obj()), false); + } +} + +bool +exdsa_private_key_t::is_valid(rnp::RNG *rng) const { + if(curve_ == PGP_CURVE_ED25519) { + Botan::Ed25519_PrivateKey priv_key(key_); + return priv_key.check_key(*(rng->obj()), false); + } else { + auto priv_key = botan_key(rng); + return priv_key.check_key(*(rng->obj()), false); + } +} + +bool +ecdh_kem_public_key_t::is_valid(rnp::RNG *rng) const { + if(curve_ == PGP_CURVE_25519) { + auto pub_key = botan_key_x25519(); + return pub_key.check_key(*(rng->obj()), false); + } else { + auto pub_key = botan_key_ecdh(rng); + return pub_key.check_key(*(rng->obj()), false); + } +} + +bool +ecdh_kem_private_key_t::is_valid(rnp::RNG *rng) const { + if(curve_ == PGP_CURVE_25519) { + auto priv_key = botan_key_x25519(); + return priv_key.check_key(*(rng->obj()), false); + } else { + auto priv_key = botan_key_ecdh(rng); + return priv_key.check_key(*(rng->obj()), false); + } +} + diff --git a/src/lib/crypto/exdsa_ecdhkem.h b/src/lib/crypto/exdsa_ecdhkem.h new file mode 100644 index 000000000..6bd67a653 --- /dev/null +++ b/src/lib/crypto/exdsa_ecdhkem.h @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 ECDH_KEM_H_ +#define ECDH_KEM_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include +#include "botan/secmem.h" +#include +#include +#include +#include +#include + + +struct ecdh_kem_key_t; /* forward declaration */ +struct exdsa_key_t; /* forward declaration */ + +class ec_key_t { + +public: + virtual ~ec_key_t() = 0; + ec_key_t(pgp_curve_t curve); + ec_key_t() = default; + + static rnp_result_t generate_ecdh_kem_key_pair(rnp::RNG *rng, ecdh_kem_key_t *out, pgp_curve_t curve); + static rnp_result_t generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t curve); + + pgp_curve_t get_curve() const + { + return curve_; + } + +protected: + pgp_curve_t curve_; +}; + +class ecdh_kem_public_key_t : public ec_key_t { + +public: + ecdh_kem_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); + ecdh_kem_public_key_t(std::vector key_buf, pgp_curve_t curve); + ecdh_kem_public_key_t() = default; + + bool operator==(const ecdh_kem_public_key_t &rhs) const + { + return (curve_ == rhs.curve_) && (key_ == rhs.key_); + } + + bool is_valid(rnp::RNG *rng) const; + + std::vector get_encoded() const + { + return key_; + } + + rnp_result_t encapsulate(rnp::RNG *rng, std::vector &ciphertext, std::vector &symmetric_key); + +private: + Botan::ECDH_PublicKey botan_key_ecdh(rnp::RNG *rng) const; + Botan::Curve25519_PublicKey botan_key_x25519() const; + + std::vector key_; +}; + + +class ecdh_kem_private_key_t : public ec_key_t { + +public: + ecdh_kem_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); + ecdh_kem_private_key_t(std::vector key_buf, pgp_curve_t curve); + ecdh_kem_private_key_t() = default; + + bool is_valid(rnp::RNG *rng) const; + + std::vector get_encoded() const + { + return Botan::unlock(key_); + } + + rnp_result_t decapsulate(rnp::RNG *rng, const std::vector &ciphertext, std::vector &plaintext); + +private: + Botan::ECDH_PrivateKey botan_key_ecdh(rnp::RNG *rng) const; + Botan::Curve25519_PrivateKey botan_key_x25519() const; + + Botan::secure_vector key_; +}; + +typedef struct ecdh_kem_key_t { + ecdh_kem_private_key_t priv; + ecdh_kem_public_key_t pub; +} ecdh_kem_key_t; + + +class exdsa_public_key_t : public ec_key_t { + +public: + exdsa_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); + exdsa_public_key_t(std::vector key_buf, pgp_curve_t curve); + exdsa_public_key_t() = default; + + bool operator==(const exdsa_public_key_t &rhs) const + { + return (curve_ == rhs.curve_) && (key_ == rhs.key_); + } + + bool is_valid(rnp::RNG *rng) const; + + std::vector get_encoded() const + { + return key_; + } + + rnp_result_t verify(const std::vector &sig, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const; + +private: + Botan::ECDSA_PublicKey botan_key() const; + + std::vector key_; +}; + +class exdsa_private_key_t : public ec_key_t { + +public: + exdsa_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); + exdsa_private_key_t(std::vector key_buf, pgp_curve_t curve); + exdsa_private_key_t() = default; + + bool is_valid(rnp::RNG *rng) const; + + std::vector get_encoded() const + { + return Botan::unlock(key_); + } + + rnp_result_t sign(rnp::RNG *rng, std::vector &sig_out, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const; + +private: + Botan::ECDSA_PrivateKey botan_key(rnp::RNG *rng) const; + + Botan::secure_vector key_; +}; + +typedef struct exdsa_key_t { + exdsa_private_key_t priv; + exdsa_public_key_t pub; +} exdsa_key_t; + + + +#endif \ No newline at end of file diff --git a/src/lib/crypto/x25519.cpp b/src/lib/crypto/x25519.cpp new file mode 100644 index 000000000..ffa38308f --- /dev/null +++ b/src/lib/crypto/x25519.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "x25519.h" +#include "exdsa_ecdhkem.h" +#include "hkdf.hpp" +#include "utils.h" +#include "botan/rfc3394.h" + +static void x25519_hkdf(std::vector &derived_key, const std::vector &ephemeral_pubkey_material, const std::vector &recipient_pubkey_material, const std::vector &shared_key) +{ + /* The shared secret is passed to HKDF (see {{RFC5869}}) using SHA256, and the UTF-8-encoded string "OpenPGP X25519" as the info parameter. */ + static const std::vector info = {'O', 'p', 'e', 'n', 'P', 'G', 'P', ' ', 'X', '2', '5', '5', '1', '9'}; + auto kdf = rnp::Hkdf::create(PGP_HASH_SHA256); + derived_key.resize(pgp_key_size(PGP_SA_AES_128)); // 128-bit AES key wrap + + std::vector kdf_input; + kdf_input.insert(kdf_input.end(), std::begin(ephemeral_pubkey_material), std::end(ephemeral_pubkey_material)); + kdf_input.insert(kdf_input.end(), std::begin(recipient_pubkey_material), std::end(recipient_pubkey_material)); + kdf_input.insert(kdf_input.end(), std::begin(shared_key), std::end(shared_key)); + + kdf->extract_expand(NULL, 0, // no salt + kdf_input.data(), + kdf_input.size(), + info.data(), + info.size(), + derived_key.data(), + derived_key.size()); +} + +rnp_result_t generate_x25519_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey) +{ + Botan::Curve25519_PrivateKey priv_key(*(rng->obj())); + pubkey = priv_key.public_value(); + privkey = Botan::unlock(priv_key.raw_private_key_bits()); + + return RNP_SUCCESS; +} + +rnp_result_t x25519_native_encrypt(rnp::RNG * rng, + const std::vector &pubkey, + const uint8_t * in, + size_t in_len, + pgp_x25519_encrypted_t *encrypted) +{ + rnp_result_t ret; + std::vector shared_key; + std::vector derived_key; + + if(!in_len || (in_len % 8) != 0) { + RNP_LOG("incorrect size of in, AES key wrap requires a multiple of 8 bytes"); + return RNP_ERROR_BAD_FORMAT; + } + + /* encapsulation */ + ecdh_kem_public_key_t ecdhkem_pubkey(pubkey, PGP_CURVE_25519); + ret = ecdhkem_pubkey.encapsulate(rng, encrypted->eph_key, shared_key); + if(ret != RNP_SUCCESS) { + RNP_LOG("encapsulation failed"); + return ret; + } + + x25519_hkdf(derived_key, encrypted->eph_key, pubkey, shared_key); + + Botan::SymmetricKey kek(derived_key); + try { + encrypted->enc_sess_key = Botan::unlock(Botan::rfc3394_keywrap(Botan::secure_vector(in, in+in_len), kek)); + } catch (const std::exception &e) { + RNP_LOG("Keywrap failed: %s", e.what()); + return RNP_ERROR_ENCRYPT_FAILED; + } + + return RNP_SUCCESS; +} + +rnp_result_t x25519_native_decrypt(rnp::RNG * rng, + const pgp_x25519_key_t &keypair, + const pgp_x25519_encrypted_t *encrypted, + uint8_t *decbuf, + size_t *decbuf_len) +{ + rnp_result_t ret; + std::vector shared_key; + std::vector derived_key; + + static const size_t x25519_pubkey_size = 32; + if(encrypted->eph_key.size() != x25519_pubkey_size) { + RNP_LOG("Wrong ephemeral public key size"); + return RNP_ERROR_BAD_FORMAT; + } + if(!encrypted->enc_sess_key.size()) { + // TODO: could do a check for possible sizes + RNP_LOG("No encrypted session key provided"); + return RNP_ERROR_BAD_FORMAT; + } + + /* decapsulate */ + ecdh_kem_private_key_t ecdhkem_privkey(keypair.priv, PGP_CURVE_25519); + ret = ecdhkem_privkey.decapsulate(rng, encrypted->eph_key, shared_key); + if(ret != RNP_SUCCESS) { + RNP_LOG("decapsulation failed"); + return ret; + } + + x25519_hkdf(derived_key, encrypted->eph_key, keypair.pub, shared_key); + + Botan::SymmetricKey kek(derived_key); + auto tmp_out = Botan::rfc3394_keyunwrap(Botan::secure_vector(encrypted->enc_sess_key.begin(), encrypted->enc_sess_key.end()), kek); + if(*decbuf_len < tmp_out.size()) { + RNP_LOG("buffer for decryption result too small"); + return RNP_ERROR_DECRYPT_FAILED; + } + *decbuf_len = tmp_out.size(); + memcpy(decbuf, tmp_out.data(), tmp_out.size()); + + return RNP_SUCCESS; +} + +rnp_result_t +x25519_validate_key_native(rnp::RNG *rng, const pgp_x25519_key_t *key, bool secret) +{ + bool valid_pub; + bool valid_priv; + + Botan::Curve25519_PublicKey pub_key(key->priv); + valid_pub = pub_key.check_key(*(rng->obj()), false); + + if(secret) { + Botan::Curve25519_PrivateKey priv_key(Botan::secure_vector(key->priv.begin(), key->priv.end())); + valid_priv = priv_key.check_key(*(rng->obj()), false); + } else { + valid_priv = true; + } + + // check key returns true for successful check + return (valid_pub && valid_priv) ? RNP_SUCCESS : RNP_ERROR_BAD_PARAMETERS; +} \ No newline at end of file diff --git a/src/lib/crypto/x25519.h b/src/lib/crypto/x25519.h new file mode 100644 index 000000000..b0a22ba83 --- /dev/null +++ b/src/lib/crypto/x25519.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 X25519_H_ +#define X25519_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include "crypto/ec.h" + +rnp_result_t generate_x25519_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey); + +rnp_result_t x25519_native_encrypt(rnp::RNG * rng, + const std::vector &pubkey, + const uint8_t * in, + size_t in_len, + pgp_x25519_encrypted_t *encrypted); + +rnp_result_t x25519_native_decrypt(rnp::RNG * rng, + const pgp_x25519_key_t &keypair, + const pgp_x25519_encrypted_t *encrypted, + uint8_t *decbuf, + size_t *decbuf_len); + + +rnp_result_t x25519_validate_key_native(rnp::RNG *rng, const pgp_x25519_key_t *key, bool secret); + +#endif \ No newline at end of file diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index bc4eb5820..4a31d6127 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -57,6 +57,7 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_SM2, "SM2"}, #if defined(ENABLE_CRYPTO_REFRESH) {PGP_PKA_ED25519, "ED25519"}, + {PGP_PKA_X25519, "X25519"}, #endif {PGP_PKA_PRIVATE00, "Private/Experimental"}, {PGP_PKA_PRIVATE01, "Private/Experimental"}, @@ -255,6 +256,8 @@ get_numbits(const rnp_keygen_crypto_params_t *crypto) #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: return 255; + case PGP_PKA_X25519: + return 255; #endif case PGP_PKA_DSA: return crypto->dsa.p_bitlen; diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index a6adadbdd..e68746c20 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -196,6 +196,8 @@ pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); + case PGP_PKA_X25519: + return PGP_KF_ENCRYPT; #endif case PGP_PKA_SM2: @@ -2755,6 +2757,8 @@ pgp_key_material_t::get_curve() const #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; @@ -2779,6 +2783,7 @@ pgp_key_material_t::bits() const case PGP_PKA_EDDSA: [[fallthrough]]; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: [[fallthrough]]; + case PGP_PKA_X25519: [[fallthrough]]; #endif case PGP_PKA_SM2: { /* handle ecc cases */ diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index e020ded79..9c3b60062 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -164,6 +164,7 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_SM2, RNP_ALGNAME_SM2}, #if defined(ENABLE_CRYPTO_REFRESH) {PGP_PKA_ED25519, RNP_ALGNAME_ED25519}, + {PGP_PKA_X25519, RNP_ALGNAME_X25519}, #endif {0, NULL}}; @@ -324,6 +325,10 @@ pub_alg_supported(int alg) case PGP_PKA_EDDSA: #if defined(ENABLE_SM2) case PGP_PKA_SM2: +#endif +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_X25519: + case PGP_PKA_ED25519: #endif return true; default: @@ -5219,6 +5224,8 @@ default_key_flags(pgp_pubkey_alg_t alg, bool subkey) #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); + case PGP_PKA_X25519: + return PGP_KF_ENCRYPT; #endif default: return PGP_KF_NONE; @@ -7460,6 +7467,7 @@ add_json_secret_mpis(json_object *jso, pgp_key_t *key) 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 default: @@ -7496,6 +7504,7 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) return add_json_mpis(jso, "r", &material.ecc.r, "s", &material.ecc.s, NULL); #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: + case PGP_PKA_X25519: return RNP_SUCCESS; /* TODO */ #endif default: @@ -7717,6 +7726,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) } break; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: + case PGP_PKA_X25519: return RNP_SUCCESS; /* TODO */ #endif default: diff --git a/src/lib/types.h b/src/lib/types.h index 1d0a304bd..7c6645125 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -190,6 +190,7 @@ typedef struct pgp_key_material_t { }; #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 pgp_curve_t get_curve() const; /* return curve for EC algorithms, PGP_CURVE_UNKNOWN otherwise */ @@ -219,11 +220,14 @@ typedef struct pgp_signature_material_t { */ typedef struct pgp_encrypted_material_t { union { - pgp_rsa_encrypted_t rsa; - pgp_eg_encrypted_t eg; - pgp_sm2_encrypted_t sm2; - pgp_ecdh_encrypted_t ecdh; + pgp_rsa_encrypted_t rsa; + pgp_eg_encrypted_t eg; + pgp_sm2_encrypted_t sm2; + pgp_ecdh_encrypted_t ecdh; }; +#if defined(ENABLE_CRYPTO_REFRESH) + pgp_x25519_encrypted_t x25519; // non-trivial type cannot be member in union +#endif } pgp_encrypted_material_t; typedef struct pgp_s2k_t { diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index 284796216..0ea023308 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -743,6 +743,9 @@ rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) case PGP_PKA_ED25519: hash->add(key->ed25519.pub); break; + case PGP_PKA_X25519: + hash->add(key->x25519.pub); + break; #endif default: RNP_LOG("unsupported public-key algorithm %d", (int) key->alg); diff --git a/src/librepgp/stream-common.cpp b/src/librepgp/stream-common.cpp index 6786c4b6e..6be09cc0e 100644 --- a/src/librepgp/stream-common.cpp +++ b/src/librepgp/stream-common.cpp @@ -1215,8 +1215,13 @@ dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit) #if defined(ENABLE_CRYPTO_REFRESH) bool have_pkesk_checksum(pgp_pubkey_alg_t alg) { - return true; - + switch(alg) + { + case PGP_PKA_X25519: + return false; + default: + return true; + } } bool do_encrypt_pkesk_v3_alg_id(pgp_pubkey_alg_t alg) diff --git a/src/librepgp/stream-ctx.cpp b/src/librepgp/stream-ctx.cpp index 0aaf9c99f..5a2d388e1 100644 --- a/src/librepgp/stream-ctx.cpp +++ b/src/librepgp/stream-ctx.cpp @@ -79,4 +79,4 @@ rnp_ctx_t::pkeskv6_capable() { } return true; } -#endif +#endif \ No newline at end of file diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 75d2bd279..618ca3c66 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -145,6 +145,7 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_SM2, "SM2"}, #if defined(ENABLE_CRYPTO_REFRESH) {PGP_PKA_ED25519, "Ed25519"}, + {PGP_PKA_X25519, "X25519"}, #endif {0x00, NULL}, }; @@ -905,6 +906,9 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) 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; #endif default: dst_printf(dst, "unknown public key algorithm\n"); @@ -1070,6 +1074,12 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d dst_printf(dst, "ecdh m: %d bytes\n", (int) material.ecdh.mlen); } break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_X25519: + dst_print_vec(dst, "x25519 ephemeral public key", material.x25519.eph_key, ctx->dump_mpi); + dst_print_vec(dst, "x25519 encrypted session key", material.x25519.enc_sess_key, ctx->dump_mpi); + break; +#endif default: dst_printf(dst, "unknown public key algorithm\n"); } @@ -1991,6 +2001,7 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: + case PGP_PKA_X25519: /* TODO */ break; #endif @@ -2125,6 +2136,7 @@ stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_obj break; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: + case PGP_PKA_X25519: /* TODO */ break; #endif diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index d171c1537..c6f6ab629 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -647,6 +647,16 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) 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 default: RNP_LOG("unknown pk alg : %d", (int) key.alg); @@ -775,6 +785,9 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) case PGP_PKA_ED25519: body.add(key.material.ed25519.priv); break; + case PGP_PKA_X25519: + body.add(key.material.x25519.priv); + break; #endif default: RNP_LOG("unknown pk alg : %d", (int) key.alg); @@ -924,6 +937,10 @@ forget_secret_key_fields(pgp_key_material_t *key) 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 default: RNP_LOG("unknown key algorithm: %d", (int) key->alg); @@ -1372,6 +1389,16 @@ pgp_key_pkt_t::parse(pgp_source_t &src) 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 default: RNP_LOG("unknown key algorithm: %d", (int) alg); @@ -1514,6 +1541,9 @@ void pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t & hbod case PGP_PKA_ED25519: hbody.add(material.ed25519.pub); break; + case PGP_PKA_X25519: + hbody.add(material.x25519.pub); + break; #endif default: RNP_LOG("unknown key algorithm: %d", (int) alg); diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 36898d45f..6aaff3434 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -1222,6 +1222,27 @@ pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const } break; } +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_X25519: { + const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_25519); + material.x25519.eph_key.resize(BITS_TO_BYTES(ec_desc->bitlen)); + if (!pkt.get(material.x25519.eph_key.data(), material.x25519.eph_key.size())) { + RNP_LOG("failed to parse X25519 PKESK (eph. pubkey)"); + return false; + } + uint8_t enc_sesskey_len; + if(!pkt.get(enc_sesskey_len)) { + RNP_LOG("failed to parse X25519 PKESK (enc sesskey length)"); + return false; + } + material.x25519.enc_sess_key.resize(enc_sesskey_len); + if (!pkt.get(material.x25519.enc_sess_key.data(), enc_sesskey_len)) { + RNP_LOG("failed to parse X25519 PKESK (enc sesskey)"); + return false; + } + break; + } +#endif default: RNP_LOG("unknown pk alg %d", (int) alg); return false; @@ -1256,6 +1277,13 @@ pgp_pk_sesskey_t::write_material(const pgp_encrypted_material_t &material) pktbody.add(material.eg.g); pktbody.add(material.eg.m); break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_X25519: + pktbody.add(material.x25519.eph_key); + pktbody.add_byte(static_cast(material.x25519.enc_sess_key.size())); + pktbody.add(material.x25519.enc_sess_key); + break; +#endif default: RNP_LOG("Unknown pk alg: %d", (int) alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 27ed19cae..44dad974d 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1592,6 +1592,16 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, } 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_SUCCESS) { + RNP_LOG("X25519 decryption error %u", err); + return false; + } + break; +#endif default: RNP_LOG("unsupported public key algorithm %d\n", seckey->alg); return false; diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index ef59f32fd..14738e2f8 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -566,6 +566,21 @@ encrypted_add_recipient(pgp_write_handler_t *handler, return RNP_ERROR_NO_SUITABLE_KEY; } +#if defined(ENABLE_CRYPTO_REFRESH) + /* Crypto Refresh: For X25519/X448 PKESKv3, AES is mandated */ + if(userkey->alg() == PGP_PKA_X25519 && pkesk_version == PGP_PKSK_V3) { + switch(param->ctx->ealg) { + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + break; + default: + RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric algorithm that is not AES."); + return RNP_ERROR_DECRYPT_FAILED; + } + } +#endif + /* Fill pkey */ pkey.version = pkesk_version; pkey.alg = userkey->alg(); @@ -689,6 +704,19 @@ encrypted_add_recipient(pgp_write_handler_t *handler, } 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 default: RNP_LOG("unsupported alg: %d", (int) userkey->alg()); return ret; diff --git a/src/rnpkeys/tui.cpp b/src/rnpkeys/tui.cpp index 69ce260d4..2d7d7abea 100644 --- a/src/rnpkeys/tui.cpp +++ b/src/rnpkeys/tui.cpp @@ -240,6 +240,9 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) "\t(21) EDDSA + ECDH (v6 key) \n" #endif "\t(22) EDDSA + ECDH (v4 key) \n" +#if defined(ENABLE_CRYPTO_REFRESH) + "\t(23) ED25519 + X25519 (v6 key) \n" +#endif "\t(99) SM2\n" "> "); if (!rnp_secure_get_long_from_fd(input_fp, option, false)) { @@ -303,6 +306,14 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) cfg.set_str(CFG_KG_SUBKEY_CURVE, "Curve25519"); break; } +#if defined(ENABLE_CRYPTO_REFRESH) + case 23: { + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_ED25519); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_X25519); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + } +#endif case 99: { cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SM2); cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_SM2); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f8c81f4a9..0d34eb882 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -134,6 +134,7 @@ set(RNP_TEST_SOURCES user-prefs.cpp utils-hex2bin.cpp utils-rnpcfg.cpp + exdsa_ecdhkem.cpp issues/1030.cpp issues/1115.cpp issues/1171.cpp diff --git a/src/tests/exdsa_ecdhkem.cpp b/src/tests/exdsa_ecdhkem.cpp new file mode 100644 index 000000000..393cab058 --- /dev/null +++ b/src/tests/exdsa_ecdhkem.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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. + */ + +#if defined(ENABLE_CRYPTO_REFRESH) + +#include "rnp_tests.h" +#include "crypto/exdsa_ecdhkem.h" +#include "crypto/bn.h" + +TEST_F(rnp_tests, test_ecdh_kem) +{ + std::vector ciphertext; + std::vector symmetric_key; + std::vector symmetric_key2; + ecdh_kem_key_t key_pair; + pgp_curve_t curve_list[] = {PGP_CURVE_NIST_P_256, PGP_CURVE_NIST_P_384, PGP_CURVE_NIST_P_521, PGP_CURVE_BP256, PGP_CURVE_BP384, PGP_CURVE_BP512, PGP_CURVE_25519}; + + for (auto curve : curve_list) { + /* keygen */ + assert_rnp_success(ec_key_t::generate_ecdh_kem_key_pair(&global_ctx.rng, &key_pair, curve)); + + /* kem encaps / decaps */ + assert_rnp_success(key_pair.pub.encapsulate(&global_ctx.rng, ciphertext, symmetric_key)); + assert_rnp_success(key_pair.priv.decapsulate(&global_ctx.rng, ciphertext, symmetric_key2)); + + /* both parties should have the same key share */ + assert_int_equal(symmetric_key.size(), symmetric_key2.size()); + assert_memory_equal(symmetric_key.data(), symmetric_key2.data(), symmetric_key.size()); + + /* test invalid ciphertext */ + ciphertext.data()[4] += 1; + if(curve != PGP_CURVE_25519) { // Curve25519 accepts any 32-byte array + assert_throw(key_pair.priv.decapsulate(&global_ctx.rng, ciphertext, symmetric_key)); + } + } +} + +TEST_F(rnp_tests, test_exdsa) +{ + pgp_hash_alg_t hash_alg = PGP_HASH_SHA256; + std::vector msg(32); + exdsa_key_t key_pair; + pgp_curve_t curve_list[] = {PGP_CURVE_NIST_P_256, PGP_CURVE_NIST_P_384, PGP_CURVE_NIST_P_521, PGP_CURVE_BP256, PGP_CURVE_BP384, PGP_CURVE_BP512, PGP_CURVE_ED25519}; + //pgp_curve_t curve_list[] = {PGP_CURVE_ED25519}; + + for (auto curve : curve_list) { + /* keygen */ + assert_rnp_success(ec_key_t::generate_exdsa_key_pair(&global_ctx.rng, &key_pair, curve)); + + /* sign and verify */ + std::vector sig; + assert_rnp_success(key_pair.priv.sign(&global_ctx.rng, sig, msg.data(), msg.size(), hash_alg)); + assert_rnp_success(key_pair.pub.verify(sig, msg.data(), msg.size(), hash_alg)); + + /* test invalid msg / hash */ + msg.data()[4] -= 1; + assert_rnp_failure(key_pair.pub.verify(sig, msg.data(), msg.size(), hash_alg)); + + /* test invalid sig */ + msg.data()[4] += 1; + sig.data()[4] -= 1; + assert_rnp_failure(key_pair.pub.verify(sig, msg.data(), msg.size(), hash_alg)); + } +} + +#endif diff --git a/src/tests/ffi-key.cpp b/src/tests/ffi-key.cpp index 5cfad144d..5eb90243d 100644 --- a/src/tests/ffi-key.cpp +++ b/src/tests/ffi-key.cpp @@ -3180,6 +3180,61 @@ TEST_F(rnp_tests, test_ffi_v6_sig_subpackets) rnp_op_generate_destroy(op); } + +TEST_F(rnp_tests, test_ffi_v6_cert_import) +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + size_t keycount = 255; + + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + assert_rnp_success( + rnp_input_from_path(&input, "data/test_v6_valid_data/transferable_pubkey_v6.asc")); + assert_rnp_success( + rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64, NULL)); + rnp_input_destroy(input); + assert_rnp_success(rnp_get_public_key_count(ffi, &keycount)); + assert_int_equal(keycount, 2); + assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount)); + assert_int_equal(keycount, 0); + + /* check that fingerprint is correct by checking the fingerprint in the signature (coming from the correct input data) vs the computed fingerprint value of the primary key. + Issuer fingerprint is the priamry's key fingerprint for the primary and its subkeys */ + pgp_fingerprint_t primary_fp; + for (pgp_key_t key : ffi->pubring->keys) { + if(key.is_primary()) + { + primary_fp = key.fp(); + } + } + + for (pgp_key_t key : ffi->pubring->keys) { + /* get first sig and its issuer fpr subpacket */ + pgp_subsig_t subsig = key.get_sig(0); + const pgp_sig_subpkt_t* issuer_fpr = subsig.sig.get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, false); + assert_non_null(issuer_fpr); + + /* check that fingerprints match */ + assert_int_equal(key.fp().length, PGP_FINGERPRINT_V6_SIZE); + assert_memory_equal(issuer_fpr->data + 1, primary_fp.fingerprint, primary_fp.length); // first byte in data is the version - skip + } +} + +TEST_F(rnp_tests, test_ffi_v6_seckey_import) +{ + rnp_ffi_t ffi = NULL; + rnp_input_t input = NULL; + size_t keycount = 255; + + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + assert_rnp_success( + rnp_input_from_path(&input, "data/test_v6_valid_data/transferable_seckey_v6.asc")); + assert_rnp_success( + rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64, NULL)); + rnp_input_destroy(input); + assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount)); + assert_int_equal(keycount, 2); +} #endif TEST_F(rnp_tests, test_ffi_iterated_key_import) diff --git a/src/tests/ffi.cpp b/src/tests/ffi.cpp index 781fdfd2b..da8349f64 100644 --- a/src/tests/ffi.cpp +++ b/src/tests/ffi.cpp @@ -3109,7 +3109,11 @@ TEST_F(rnp_tests, test_ffi_supported_features) /* public key algorithm */ assert_rnp_success(rnp_supported_features(RNP_FEATURE_PK_ALG, &features)); assert_non_null(features); - assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2)); + size_t crypto_refresh_opt = 0; +#if defined(ENABLE_CRYPTO_REFRESH) + crypto_refresh_opt = 2; // X25519 + ED25519 +#endif + assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + crypto_refresh_opt)); rnp_buffer_destroy(features); assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "RSA", &supported)); assert_true(supported); From 012fd6a151501651b62863f564d3efd9ad40c5d7 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 13 Jun 2023 08:45:27 +0200 Subject: [PATCH 05/20] add dilithium standalone functionality correction of dilithium based on rnp feedback --- CMakeLists.txt | 5 ++ src/lib/CMakeLists.txt | 17 ++++ src/lib/config.h.in | 1 + src/lib/crypto/dilithium.cpp | 122 ++++++++++++++++++++++++++++ src/lib/crypto/dilithium.h | 114 ++++++++++++++++++++++++++ src/lib/crypto/dilithium_common.cpp | 97 ++++++++++++++++++++++ src/lib/crypto/dilithium_common.h | 41 ++++++++++ src/tests/CMakeLists.txt | 1 + src/tests/pqc.cpp | 54 ++++++++++++ 9 files changed, 452 insertions(+) create mode 100644 src/lib/crypto/dilithium.cpp create mode 100644 src/lib/crypto/dilithium.h create mode 100644 src/lib/crypto/dilithium_common.cpp create mode 100644 src/lib/crypto/dilithium_common.h create mode 100644 src/tests/pqc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dcde416a..522aeaf57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,11 @@ tristate_feature_auto(ENABLE_CAST5 "Enable CAST5 cipher support.") tristate_feature_auto(ENABLE_RIPEMD160 "Enable RIPEMD-160 hash support.") option(ENABLE_CRYPTO_REFRESH "Enable crypto-refresh support (v6)") +option(ENABLE_PQC "Enable PQC support - requires ENABLE_CRYPTO_REFRESH") + +if((NOT ENABLE_CRYPTO_REFRESH) AND ENABLE_PQC) + message(FATAL_ERROR "ENABLE_PQC requires ENABLE_CRYPTO_REFRESH") +endif() set(ENABLE_DOC Auto CACHE STRING "Enable building documentation.") diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 48d5e4aa4..6b18985c0 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -52,6 +52,15 @@ if(CRYPTO_BACKEND_BOTAN3) set(CMAKE_CXX_STANDARD 20) endif() +if(ENABLE_PQC) + if (NOT CRYPTO_BACKEND_BOTAN3) + message(FATAL_ERROR "ENABLE_PQC requires Botan 3 as crypto backend") + endif() + if (NOT ENABLE_CRYPTO_REFRESH) + message(FATAL_ERROR "ENABLE_PQC requires ENABLE_CRYPTO_REFRESH") + endif() +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") @@ -179,6 +188,7 @@ if(CRYPTO_BACKEND_BOTAN) resolve_feature_state(ENABLE_TWOFISH "TWOFISH") resolve_feature_state(ENABLE_IDEA "IDEA") resolve_feature_state(ENABLE_CRYPTO_REFRESH "HKDF") + resolve_feature_state(ENABLE_PQC "DILITHIUM") resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH") resolve_feature_state(ENABLE_CAST5 "CAST_128") resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160") @@ -221,6 +231,7 @@ if(CRYPTO_BACKEND_OPENSSL) #resolve_feature_state(ENABLE_SM2 "SM2;SM3;SM4-ECB") openssl_nope(ENABLE_TWOFISH "Twofish isn't and won't be supported by OpenSSL, see https://github.com/openssl/openssl/issues/2046") openssl_nope(ENABLE_CRYPTO_REFRESH, "not yet implemented") + openssl_nope(ENABLE_PQC, "not yet implemented") endif() configure_file(config.h.in config.h) @@ -289,6 +300,12 @@ elseif(CRYPTO_BACKEND_BOTAN) crypto/exdsa_ecdhkem.cpp ) endif() + if(ENABLE_PQC) + list(APPEND CRYPTO_SOURCES + crypto/dilithium.cpp + crypto/dilithium_common.cpp + ) + endif() else() message(FATAL_ERROR "Unknown crypto backend: ${CRYPTO_BACKEND}.") endif() diff --git a/src/lib/config.h.in b/src/lib/config.h.in index 5086c41ce..5a9396e34 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -61,6 +61,7 @@ #cmakedefine ENABLE_BRAINPOOL #cmakedefine ENABLE_IDEA #cmakedefine ENABLE_CRYPTO_REFRESH +#cmakedefine ENABLE_PQC #cmakedefine ENABLE_BLOWFISH #cmakedefine ENABLE_CAST5 #cmakedefine ENABLE_RIPEMD160 diff --git a/src/lib/crypto/dilithium.cpp b/src/lib/crypto/dilithium.cpp new file mode 100644 index 000000000..af3aeea75 --- /dev/null +++ b/src/lib/crypto/dilithium.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "dilithium.h" +#include + +namespace { + +Botan::DilithiumMode +rnp_dilithium_param_to_botan_dimension(dilithium_parameter_e mode) +{ + Botan::DilithiumMode result = Botan::DilithiumMode::Dilithium8x7; + if (mode == dilithium_parameter_e::dilithium_L3) { + result = Botan::DilithiumMode::Dilithium6x5; + } + return result; +} + +} // namespace + +std::vector +pgp_dilithium_private_key_t::sign(rnp::RNG *rng, const uint8_t *msg, size_t msg_len) const +{ + assert(is_initialized_); + auto priv_key = botan_key(); + + auto signer = Botan::PK_Signer(priv_key, *rng->obj(), ""); + std::vector signature = signer.sign_message(msg, msg_len, *rng->obj()); + // std::vector signature; + + return signature; +} + +Botan::Dilithium_PublicKey +pgp_dilithium_public_key_t::botan_key() const +{ + return Botan::Dilithium_PublicKey(key_encoded_, + rnp_dilithium_param_to_botan_dimension(dilithium_param_)); +} + +Botan::Dilithium_PrivateKey +pgp_dilithium_private_key_t::botan_key() const +{ + Botan::secure_vector priv_sv(key_encoded_.data(), + key_encoded_.data() + key_encoded_.size()); + return Botan::Dilithium_PrivateKey( + priv_sv, rnp_dilithium_param_to_botan_dimension(this->dilithium_param_)); +} + +bool +pgp_dilithium_public_key_t::verify_signature(const uint8_t *msg, + size_t msg_len, + const uint8_t *signature, + size_t signature_len) const +{ + assert(is_initialized_); + auto pub_key = botan_key(); + + auto verificator = Botan::PK_Verifier(pub_key, ""); + return verificator.verify_message(msg, msg_len, signature, signature_len); +} + +std::pair +dilithium_generate_keypair( + rnp::RNG *rng, dilithium_parameter_e dilithium_param) +{ + Botan::Dilithium_PrivateKey priv_key(*rng->obj(), + rnp_dilithium_param_to_botan_dimension(dilithium_param)); + + std::unique_ptr pub_key = priv_key.public_key(); + Botan::secure_vector priv_bits = priv_key.private_key_bits(); + return std::make_pair( + pgp_dilithium_public_key_t(pub_key->public_key_bits(), dilithium_param), + pgp_dilithium_private_key_t(priv_bits.data(), priv_bits.size(), dilithium_param)); +} + +bool +pgp_dilithium_public_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized_) { + return false; + } + + auto key = botan_key(); + return key.check_key(*(rng->obj()), false); +} + +bool +pgp_dilithium_private_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized_) { + return false; + } + + auto key = botan_key(); + return key.check_key(*(rng->obj()), false); +} diff --git a/src/lib/crypto/dilithium.h b/src/lib/crypto/dilithium.h new file mode 100644 index 000000000..a93c32176 --- /dev/null +++ b/src/lib/crypto/dilithium.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 DILITHIUM_H_ +#define DILITHIUM_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include +#include + +enum dilithium_parameter_e { dilithium_L3, dilithium_L5 }; + +class pgp_dilithium_private_key_t { + public: + pgp_dilithium_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + dilithium_parameter_e param); + pgp_dilithium_private_key_t(std::vector const &key_encoded, + dilithium_parameter_e param); + pgp_dilithium_private_key_t() = default; + + bool is_valid(rnp::RNG *rng) const; + + dilithium_parameter_e + param() const + { + return dilithium_param_; + } + + std::vector sign(rnp::RNG *rng, const uint8_t *msg, size_t msg_len) const; + std::vector + get_encoded() const + { + return Botan::unlock(key_encoded_); + }; + + private: + Botan::Dilithium_PrivateKey botan_key() const; + + Botan::secure_vector key_encoded_; + dilithium_parameter_e dilithium_param_; + bool is_initialized_ = false; +}; + +class pgp_dilithium_public_key_t { + public: + pgp_dilithium_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + dilithium_parameter_e mode); + pgp_dilithium_public_key_t(std::vector const &key_encoded, + dilithium_parameter_e mode); + pgp_dilithium_public_key_t() = default; + + bool operator==(const pgp_dilithium_public_key_t &rhs) const + { + return (dilithium_param_ == rhs.dilithium_param_) && (key_encoded_ == rhs.key_encoded_); + } + + bool verify_signature(const uint8_t *msg, + size_t msg_len, + const uint8_t *signature, + size_t signature_len) const; + + bool is_valid(rnp::RNG *rng) const; + + std::vector + get_encoded() const + { + return key_encoded_; + }; + + private: + Botan::Dilithium_PublicKey botan_key() const; + + std::vector key_encoded_; + dilithium_parameter_e dilithium_param_; + bool is_initialized_ = false; +}; + +std::pair dilithium_generate_keypair( + rnp::RNG *rng, dilithium_parameter_e dilithium_param); + +#endif \ No newline at end of file diff --git a/src/lib/crypto/dilithium_common.cpp b/src/lib/crypto/dilithium_common.cpp new file mode 100644 index 000000000..a98df723d --- /dev/null +++ b/src/lib/crypto/dilithium_common.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "dilithium.h" +#include "types.h" +#include "logging.h" + +pgp_dilithium_public_key_t::pgp_dilithium_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + dilithium_parameter_e param) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), dilithium_param_(param), is_initialized_(true) +{ +} + +pgp_dilithium_public_key_t::pgp_dilithium_public_key_t(std::vector const &key_encoded, + dilithium_parameter_e param) + : key_encoded_(key_encoded), dilithium_param_(param), is_initialized_(true) +{ +} + +pgp_dilithium_private_key_t::pgp_dilithium_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + dilithium_parameter_e param) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), dilithium_param_(param), is_initialized_(true) +{ +} + +pgp_dilithium_private_key_t::pgp_dilithium_private_key_t( + std::vector const &key_encoded, dilithium_parameter_e param) + : key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), + dilithium_param_(param), + is_initialized_(true) +{ +} + +size_t dilithium_privkey_size(dilithium_parameter_e parameter) { + switch(parameter) { + case dilithium_L3: + return 4000; + case dilithium_L5: + return 4864; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t dilithium_pubkey_size(dilithium_parameter_e parameter) { + switch(parameter) { + case dilithium_L3: + return 1952; + case dilithium_L5: + return 2592; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t dilithium_signature_size(dilithium_parameter_e parameter) { + switch(parameter) { + case dilithium_L3: + return 3293; + case dilithium_L5: + return 4595; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} diff --git a/src/lib/crypto/dilithium_common.h b/src/lib/crypto/dilithium_common.h new file mode 100644 index 000000000..8e60ba819 --- /dev/null +++ b/src/lib/crypto/dilithium_common.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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_DILITHIUM_COMMON_H_ +#define RNP_DILITHIUM_COMMON_H_ + +#include "dilithium.h" + + +size_t dilithium_privkey_size(dilithium_parameter_e parameter); +size_t dilithium_pubkey_size(dilithium_parameter_e parameter); +size_t dilithium_signature_size(dilithium_parameter_e parameter); + +#endif \ No newline at end of file diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 0d34eb882..69c2a399b 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -134,6 +134,7 @@ set(RNP_TEST_SOURCES user-prefs.cpp utils-hex2bin.cpp utils-rnpcfg.cpp + pqc.cpp exdsa_ecdhkem.cpp issues/1030.cpp issues/1115.cpp diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp new file mode 100644 index 000000000..35b6347a7 --- /dev/null +++ b/src/tests/pqc.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "config.h" +#if defined(ENABLE_PQC) + +#include "rnp_tests.h" +#include +#include "crypto/dilithium.h" + +TEST_F(rnp_tests, test_dilithium_key_function) +{ + dilithium_parameter_e params[2] = {dilithium_L3, dilithium_L5}; + for (dilithium_parameter_e param : params) { + auto public_and_private_key = dilithium_generate_keypair(&global_ctx.rng, param); + + std::array msg{'H', 'e', 'l', 'l', 'o'}; + + std::vector signature = + public_and_private_key.second.sign(&global_ctx.rng, msg.data(), msg.size()); + + assert_true(public_and_private_key.first.verify_signature( + msg.data(), msg.size(), signature.data(), signature.size())); + } +} + +#endif \ No newline at end of file From c9b1cf59b06e56e8451abf7cad02e9de3ce3d88f Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 13 Jun 2023 09:45:08 +0200 Subject: [PATCH 06/20] add dilithium + ecdsa/eddsa composite algorithm --- include/repgp/repgp_def.h | 10 + include/rnp/rnp.h | 6 + src/lib/CMakeLists.txt | 1 + src/lib/crypto.cpp | 31 ++ src/lib/crypto/common.h | 3 + src/lib/crypto/dilithium_exdsa_composite.cpp | 419 +++++++++++++++++++ src/lib/crypto/dilithium_exdsa_composite.h | 157 +++++++ src/lib/crypto/signatures.cpp | 20 + src/lib/generate-key.cpp | 17 + src/lib/pgp-key.cpp | 10 + src/lib/rnp.cpp | 57 +++ src/lib/types.h | 6 + src/librekey/rnp_key_store.cpp | 10 + src/librepgp/stream-dump.cpp | 48 +++ src/librepgp/stream-key.cpp | 62 ++- src/librepgp/stream-sig.cpp | 24 ++ src/tests/cipher.cpp | 38 ++ src/tests/ffi.cpp | 6 +- src/tests/pqc.cpp | 36 ++ 19 files changed, 958 insertions(+), 3 deletions(-) create mode 100644 src/lib/crypto/dilithium_exdsa_composite.cpp create mode 100644 src/lib/crypto/dilithium_exdsa_composite.h diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index ed45c952e..fc1d825f9 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -226,6 +226,16 @@ typedef enum : uint8_t { PGP_PKA_ED25519 = 27, /* v6 / Crypto Refresh */ #endif +#if defined(ENABLE_PQC) + /* PQC-ECC composite */ + PGP_PKA_DILITHIUM3_ED25519 = 35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-01 */ + //PGP_PKA_DILITHIUM5_ED448 = 36, /* Dilithium 5 + Ed448 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM3_P256 = 37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM5_P384 = 38, /* Dilithium 5 + ECDSA-NIST-P-384 from draft-wussler-openpgp-pqc-00*/ + PGP_PKA_DILITHIUM3_BP256 = 39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM5_BP384 = 40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-01 */ +#endif + PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ PGP_PKA_PRIVATE00 = 100, /* Private/Experimental Algorithm */ PGP_PKA_PRIVATE01 = 101, /* Private/Experimental Algorithm */ diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 0aa0413db..91c9e0da6 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -3400,6 +3400,12 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_EDDSA "EDDSA" #define RNP_ALGNAME_ED25519 "ED25519" #define RNP_ALGNAME_X25519 "X25519" +#define RNP_ALGNAME_DILITHIUM3_ED25519 "DILITHIUM3_ED25519" +#define RNP_ALGNAME_DILITHIUM5_ED448 "DILITHIUM5_ED448" +#define RNP_ALGNAME_DILITHIUM3_P256 "DILITHIUM3_P256" +#define RNP_ALGNAME_DILITHIUM5_P384 "DILITHIUM5_P384" +#define RNP_ALGNAME_DILITHIUM3_BP256 "DILITHIUM3_BP256" +#define RNP_ALGNAME_DILITHIUM5_BP384 "DILITHIUM5_BP384" #define RNP_ALGNAME_IDEA "IDEA" #define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" #define RNP_ALGNAME_CAST5 "CAST5" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 6b18985c0..f30d408a4 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -304,6 +304,7 @@ elseif(CRYPTO_BACKEND_BOTAN) list(APPEND CRYPTO_SOURCES crypto/dilithium.cpp crypto/dilithium_common.cpp + crypto/dilithium_exdsa_composite.cpp ) endif() else() diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index 6f8511d2a..edad860a6 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -168,6 +168,19 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, return false; } break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + 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 Dilithium-ecdsa/eddsa-composite key for PK alg %d", seckey.alg); + return false; + } + break; #endif default: RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); @@ -214,6 +227,15 @@ key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key 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_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return (key1->dilithium_exdsa.pub == key2->dilithium_exdsa.pub); #endif default: RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); @@ -267,6 +289,15 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) 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_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return dilithium_exdsa_validate_key(rng, &material->dilithium_exdsa, material->secret); #endif default: RNP_LOG("unknown public key algorithm: %d", (int) material->alg); diff --git a/src/lib/crypto/common.h b/src/lib/crypto/common.h index 9576588cf..07e1152d8 100644 --- a/src/lib/crypto/common.h +++ b/src/lib/crypto/common.h @@ -39,6 +39,9 @@ #include "ecdsa.h" #include "sm2.h" #include "eddsa.h" +#if defined(ENABLE_PQC) +#include "dilithium_exdsa_composite.h" +#endif #if defined(ENABLE_CRYPTO_REFRESH) #include "x25519.h" #include "ed25519.h" diff --git a/src/lib/crypto/dilithium_exdsa_composite.cpp b/src/lib/crypto/dilithium_exdsa_composite.cpp new file mode 100644 index 000000000..1c24cf0ca --- /dev/null +++ b/src/lib/crypto/dilithium_exdsa_composite.cpp @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "dilithium_exdsa_composite.h" +#include "types.h" +#include "logging.h" + +pgp_dilithium_exdsa_composite_key_t::~pgp_dilithium_exdsa_composite_key_t() {} + +void +pgp_dilithium_exdsa_composite_key_t::initialized_or_throw() const { + if(!is_initialized()) { + RNP_LOG("Trying to use uninitialized dilithium-ecdsa/eddsa key"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } +} + +rnp_result_t +pgp_dilithium_exdsa_composite_key_t::gen_keypair(rnp::RNG *rng, pgp_dilithium_exdsa_key_t *key, pgp_pubkey_alg_t alg) +{ + rnp_result_t res; + pgp_curve_t curve = pk_alg_to_curve_id(alg); + dilithium_parameter_e dilithium_id = pk_alg_to_dilithium_id(alg); + + exdsa_key_t exdsa_key_pair; + + res = ec_key_t::generate_exdsa_key_pair(rng, &exdsa_key_pair, curve); + if(res != RNP_SUCCESS) { + RNP_LOG("generating dilithium exdsa composite key failed when generating exdsa key"); + return res; + } + + auto dilithium_key_pair = dilithium_generate_keypair(rng, dilithium_id); + + key->priv = pgp_dilithium_exdsa_composite_private_key_t(exdsa_key_pair.priv.get_encoded(), dilithium_key_pair.second.get_encoded(), alg); + key->pub = pgp_dilithium_exdsa_composite_public_key_t(exdsa_key_pair.pub.get_encoded(), dilithium_key_pair.first.get_encoded(), alg); + + return RNP_SUCCESS; +} + +size_t +pgp_dilithium_exdsa_composite_key_t::exdsa_curve_privkey_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_ED25519: + return 32; + /* TODO */ + // case PGP_CURVE_ED448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 32; + case PGP_CURVE_NIST_P_384: + return 48; + case PGP_CURVE_BP256: + return 32; + case PGP_CURVE_BP384: + return 48; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t +pgp_dilithium_exdsa_composite_key_t::exdsa_curve_pubkey_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_ED25519: + return 32; + /* TODO */ + // case PGP_CURVE_ED448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 65; + case PGP_CURVE_NIST_P_384: + return 97; + case PGP_CURVE_BP256: + return 65; + case PGP_CURVE_BP384: + return 97; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t +pgp_dilithium_exdsa_composite_key_t::exdsa_curve_signature_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_ED25519: + return 64; + /* TODO */ + // case PGP_CURVE_ED448: + // return 114; + case PGP_CURVE_NIST_P_256: + return 64; + case PGP_CURVE_NIST_P_384: + return 96; + case PGP_CURVE_BP256: + return 64; + case PGP_CURVE_BP384: + return 96; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +dilithium_parameter_e +pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_alg) { + switch(pk_alg) + { + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + return dilithium_L3; + case PGP_PKA_DILITHIUM5_BP384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + //[[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: + return dilithium_L5; + default: + RNP_LOG("invalid PK alg given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +pgp_curve_t +pgp_dilithium_exdsa_composite_key_t::pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg) { + switch(pk_alg) + { + case PGP_PKA_DILITHIUM3_ED25519: + return PGP_CURVE_ED25519; + case PGP_PKA_DILITHIUM3_P256: + return PGP_CURVE_NIST_P_256; + case PGP_PKA_DILITHIUM3_BP256: + return PGP_CURVE_BP256; + case PGP_PKA_DILITHIUM5_BP384: + return PGP_CURVE_BP384; + case PGP_PKA_DILITHIUM5_P384: + return PGP_CURVE_NIST_P_384; + /*case PGP_PKA_DILITHIUM5_ED448: + throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED);*/ + default: + RNP_LOG("invalid PK alg given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); +} + +pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(key_encoded); +} + +pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg), + dilithium_key_(dilithium_key_encoded, pk_alg_to_dilithium_id(pk_alg)), + exdsa_key_(exdsa_key_encoded, pk_alg_to_curve_id(pk_alg)) +{ + if(exdsa_curve_pubkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() + || dilithium_pubkey_size(pk_alg_to_dilithium_id(pk_alg)) != dilithium_key_encoded.size()) + { + RNP_LOG("exdsa or dilithium key length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + is_initialized_ = true; +} + +pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); +} + +pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(key_encoded); +} + +/* copy assignment operator is used on key materials struct and thus needs to be defined for this class as well */ +pgp_dilithium_exdsa_composite_private_key_t& pgp_dilithium_exdsa_composite_private_key_t::operator=(const pgp_dilithium_exdsa_composite_private_key_t& other) +{ + pgp_dilithium_exdsa_composite_key_t::operator=(other); + pk_alg_ = other.pk_alg_; + if(other.is_initialized() && other.dilithium_key_) + { + dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t(other.dilithium_key_->get_encoded(), other.dilithium_key_->param())); + } + if(other.is_initialized() && other.exdsa_key_) + { + exdsa_key_ = std::make_unique(exdsa_private_key_t(other.exdsa_key_->get_encoded(), other.exdsa_key_->get_curve())); + } + + return *this; +} + +pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) +{ + if(exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() + || dilithium_privkey_size(pk_alg_to_dilithium_id(pk_alg)) != dilithium_key_encoded.size()) + { + RNP_LOG("exdsa or dilithium key length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t(dilithium_key_encoded, pk_alg_to_dilithium_id(pk_alg))); + exdsa_key_ = std::make_unique(exdsa_private_key_t(exdsa_key_encoded, pk_alg_to_curve_id(pk_alg))); + is_initialized_ = true; +} + +size_t +pgp_dilithium_exdsa_composite_private_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) +{ + dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return exdsa_curve_privkey_size(curve) + dilithium_privkey_size(dilithium_param); +} + +void +pgp_dilithium_exdsa_composite_private_key_t::parse_component_keys(std::vector key_encoded) +{ + if (key_encoded.size() != encoded_size(pk_alg_)) { + RNP_LOG("Dilithium composite key format invalid: length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg_); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg_)); + + dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, dilithium_param)); + exdsa_key_ = std::make_unique(exdsa_private_key_t(key_encoded.data(), split_at, curve)); + + is_initialized_ = true; +} + +std::vector +pgp_dilithium_exdsa_composite_private_key_t::get_encoded() const { + initialized_or_throw(); + std::vector result; + std::vector exdsa_key_encoded = exdsa_key_->get_encoded(); + std::vector dilithium_key_encoded = dilithium_key_->get_encoded(); + + result.insert(result.end(), std::begin(exdsa_key_encoded), std::end(exdsa_key_encoded)); + result.insert(result.end(), std::begin(dilithium_key_encoded), std::end(dilithium_key_encoded)); + return result; +}; + + +rnp_result_t +pgp_dilithium_exdsa_composite_private_key_t::sign(rnp::RNG *rng, pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *msg, size_t msg_len) const +{ + initialized_or_throw(); + std::vector dilithium_sig; + std::vector exdsa_sig; + rnp_result_t ret; + + try { + dilithium_sig = dilithium_key_->sign(rng, msg, msg_len); + } + catch (const std::exception &e) { + RNP_LOG("%s", e.what()); + return RNP_ERROR_SIGNING_FAILED; + } + ret = exdsa_key_->sign(rng, exdsa_sig, msg, msg_len, hash_alg); + if(ret != RNP_SUCCESS) { + RNP_LOG("exdsa sign failed"); + return RNP_ERROR_SIGNING_FAILED; + } + + sig->sig.assign(exdsa_sig.data(), exdsa_sig.data() + exdsa_sig.size()); + sig->sig.insert(sig->sig.end(), dilithium_sig.begin(), dilithium_sig.end()); + + return RNP_SUCCESS; +} + +void +pgp_dilithium_exdsa_composite_private_key_t::secure_clear() { + // private key buffer is stored in a secure_vector and will be securely erased by the destructor. + dilithium_key_.reset(); + exdsa_key_.reset(); + is_initialized_ = false; +} + +size_t +pgp_dilithium_exdsa_composite_public_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) +{ + dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return exdsa_curve_pubkey_size(curve) + dilithium_pubkey_size(dilithium_param); +} + +void +pgp_dilithium_exdsa_composite_public_key_t::parse_component_keys(std::vector key_encoded) +{ + if (key_encoded.size() != encoded_size(pk_alg_)) { + RNP_LOG("Dilithium composite key format invalid: length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg_); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = exdsa_curve_pubkey_size(pk_alg_to_curve_id(pk_alg_)); + + dilithium_key_ = pgp_dilithium_public_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, dilithium_param); + exdsa_key_ = exdsa_public_key_t(key_encoded.data(), split_at, curve); + + is_initialized_ = true; +} + +std::vector +pgp_dilithium_exdsa_composite_public_key_t::get_encoded() const { + initialized_or_throw(); + std::vector result; + std::vector exdsa_key_encoded = exdsa_key_.get_encoded(); + std::vector dilithium_key_encoded = dilithium_key_.get_encoded(); + + result.insert(result.end(), std::begin(exdsa_key_encoded), std::end(exdsa_key_encoded)); + result.insert(result.end(), std::begin(dilithium_key_encoded), std::end(dilithium_key_encoded)); + return result; +}; + +rnp_result_t +pgp_dilithium_exdsa_composite_public_key_t::verify(const pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *hash, size_t hash_len) const +{ + initialized_or_throw(); + std::vector dilithium_sig; + std::vector exdsa_sig; + + if(sig->sig.size() != sig->composite_signature_size(pk_alg_)) { + RNP_LOG("invalid signature size for dilithium exdsa composite algorithm %d", pk_alg_); + return RNP_ERROR_VERIFICATION_FAILED; + } + + size_t split_at = exdsa_curve_signature_size(pk_alg_to_curve_id(pk_alg_)); + exdsa_sig = std::vector( + sig->sig.data(), + sig->sig.data() + split_at + ); + dilithium_sig = std::vector( + sig->sig.data() + split_at, + sig->sig.data() + sig->sig.size()); + + if(exdsa_key_.verify(exdsa_sig, hash, hash_len, hash_alg) != RNP_SUCCESS + || !dilithium_key_.verify_signature(hash, hash_len, dilithium_sig.data(), dilithium_sig.size())) { + RNP_LOG("could not verify composite signature"); + return RNP_ERROR_VERIFICATION_FAILED; + } + + return RNP_SUCCESS; +} + +bool +pgp_dilithium_exdsa_composite_public_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized()) { + return false; + } + return(exdsa_key_.is_valid(rng) && dilithium_key_.is_valid(rng)); +} + +bool +pgp_dilithium_exdsa_composite_private_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized()) { + return false; + } + return(exdsa_key_->is_valid(rng) && dilithium_key_->is_valid(rng)); +} + +rnp_result_t dilithium_exdsa_validate_key(rnp::RNG *rng, const pgp_dilithium_exdsa_key_t *key, bool secret) +{ + bool valid; + + valid = key->pub.is_valid(rng); + if(secret) { + valid = valid && key->priv.is_valid(rng); + } + if(!valid) { + return RNP_ERROR_GENERIC; + } + + return RNP_SUCCESS; +} diff --git a/src/lib/crypto/dilithium_exdsa_composite.h b/src/lib/crypto/dilithium_exdsa_composite.h new file mode 100644 index 000000000..bf772eb99 --- /dev/null +++ b/src/lib/crypto/dilithium_exdsa_composite.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 DILITHIUM_EXDSA_COMPOSITE_H_ +#define DILITHIUM_EXDSA_COMPOSITE_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include "crypto/dilithium.h" +#include "crypto/dilithium_common.h" +#include "crypto/exdsa_ecdhkem.h" +#include + + +struct pgp_dilithium_exdsa_key_t; /* forward declaration */ + +class pgp_dilithium_exdsa_composite_key_t { + +public: + virtual ~pgp_dilithium_exdsa_composite_key_t() = 0; + + static rnp_result_t gen_keypair(rnp::RNG *rng, pgp_dilithium_exdsa_key_t *key, pgp_pubkey_alg_t alg); + + static size_t exdsa_curve_privkey_size(pgp_curve_t curve); + static size_t exdsa_curve_pubkey_size(pgp_curve_t curve); + static size_t exdsa_curve_signature_size(pgp_curve_t curve); + static pgp_curve_t pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg); + static dilithium_parameter_e pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_alg); + + bool is_initialized() const { + return is_initialized_; + } + +protected: + bool is_initialized_ = false; + void initialized_or_throw() const; +}; + +typedef struct pgp_dilithium_exdsa_signature_t { + std::vector sig; + + static size_t composite_signature_size(pgp_pubkey_alg_t pk_alg) { + return dilithium_signature_size(pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pk_alg)) + + pgp_dilithium_exdsa_composite_key_t::exdsa_curve_signature_size(pgp_dilithium_exdsa_composite_key_t::pk_alg_to_curve_id(pk_alg)); + } +} pgp_dilithium_exdsa_signature_t; + +class pgp_dilithium_exdsa_composite_private_key_t : public pgp_dilithium_exdsa_composite_key_t { + public: + pgp_dilithium_exdsa_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_private_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_private_key_t& operator=(const pgp_dilithium_exdsa_composite_private_key_t &other); + pgp_dilithium_exdsa_composite_private_key_t() = default; + + + rnp_result_t sign(rnp::RNG *rng, pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *msg, size_t msg_len) const; + + std::vector get_encoded() const; + + pgp_pubkey_alg_t pk_alg() const + { + return pk_alg_; + } + + bool is_valid(rnp::RNG *rng) const; + void secure_clear(); + + static size_t encoded_size(pgp_pubkey_alg_t pk_alg); + + private: + void parse_component_keys(std::vector key_encoded); + + pgp_pubkey_alg_t pk_alg_; + + /* dilithium part */ + std::unique_ptr dilithium_key_; + + /* ecc part*/ + std::unique_ptr exdsa_key_; +}; + + +class pgp_dilithium_exdsa_composite_public_key_t : public pgp_dilithium_exdsa_composite_key_t { + public: + pgp_dilithium_exdsa_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_public_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_public_key_t() = default; + + bool operator==(const pgp_dilithium_exdsa_composite_public_key_t &rhs) const + { + return (pk_alg_ == rhs.pk_alg_) && (dilithium_key_ == rhs.dilithium_key_) && (exdsa_key_ == rhs.exdsa_key_); + } + + rnp_result_t verify(const pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *hash, size_t hash_len) const; + + std::vector get_encoded() const; + + pgp_pubkey_alg_t pk_alg() const + { + return pk_alg_; + } + + bool is_valid(rnp::RNG *rng) const; + static size_t encoded_size(pgp_pubkey_alg_t pk_alg); + + private: + void parse_component_keys(std::vector key_encoded); + + pgp_pubkey_alg_t pk_alg_; + + /* dilithium part */ + pgp_dilithium_public_key_t dilithium_key_; + + /* ecc part*/ + exdsa_public_key_t exdsa_key_; +}; + +typedef struct pgp_dilithium_exdsa_key_t { + pgp_dilithium_exdsa_composite_private_key_t priv; + pgp_dilithium_exdsa_composite_public_key_t pub; +} pgp_dilithium_exdsa_key_t; + +rnp_result_t dilithium_exdsa_validate_key(rnp::RNG *rng, const pgp_dilithium_exdsa_key_t *key, bool secret); + +#endif diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 52a33453a..9288dafea 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -195,6 +195,16 @@ signature_calculate(pgp_signature_t & sig, } break; } +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + ret = seckey.dilithium_exdsa.priv.sign(&ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); + break; +#endif default: RNP_LOG("Unsupported algorithm %d", sig.palg); break; @@ -298,6 +308,16 @@ signature_validate(const pgp_signature_t & sig, RNP_LOG("ElGamal are considered as invalid."); ret = RNP_ERROR_SIGNATURE_INVALID; break; +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + ret = key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); + break; +#endif default: RNP_LOG("Unknown algorithm"); ret = RNP_ERROR_BAD_PARAMETERS; diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index 4a31d6127..949f8c3cd 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -58,6 +58,14 @@ static const id_str_pair pubkey_alg_map[] = { #if defined(ENABLE_CRYPTO_REFRESH) {PGP_PKA_ED25519, "ED25519"}, {PGP_PKA_X25519, "X25519"}, +#endif +#if defined(ENABLE_PQC) + {PGP_PKA_DILITHIUM3_ED25519, "Dilithium-ED25519"}, + //{PGP_PKA_DILITHIUM5_ED448, "Dilithium-ED448"}, + {PGP_PKA_DILITHIUM3_P256, "Dilithium-P256"}, + {PGP_PKA_DILITHIUM5_P384, "Dilithium-P384"}, + {PGP_PKA_DILITHIUM3_BP256, "Dilithium-BP256"}, + {PGP_PKA_DILITHIUM5_BP384, "Dilithium-BP384"}, #endif {PGP_PKA_PRIVATE00, "Private/Experimental"}, {PGP_PKA_PRIVATE01, "Private/Experimental"}, @@ -264,6 +272,15 @@ get_numbits(const rnp_keygen_crypto_params_t *crypto) case PGP_PKA_ELGAMAL: case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: return crypto->elgamal.key_bitlen; +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return pgp_dilithium_exdsa_composite_public_key_t::encoded_size(crypto->key_alg) * 8; +#endif default: return 0; } diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index e68746c20..40948be6c 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -207,6 +207,16 @@ pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) case PGP_PKA_ELGAMAL: return PGP_KF_ENCRYPT; +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); +#endif + default: RNP_LOG("unknown pk alg: %d\n", alg); return PGP_KF_NONE; diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 9c3b60062..eed0f138a 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -165,6 +165,14 @@ static const id_str_pair pubkey_alg_map[] = { #if defined(ENABLE_CRYPTO_REFRESH) {PGP_PKA_ED25519, RNP_ALGNAME_ED25519}, {PGP_PKA_X25519, RNP_ALGNAME_X25519}, +#endif +#if defined(ENABLE_PQC) + {PGP_PKA_DILITHIUM3_ED25519, RNP_ALGNAME_DILITHIUM3_ED25519}, + //{PGP_PKA_DILITHIUM5_ED448, RNP_ALGNAME_DILITHIUM5_ED448}, + {PGP_PKA_DILITHIUM3_P256, RNP_ALGNAME_DILITHIUM3_P256}, + {PGP_PKA_DILITHIUM5_P384, RNP_ALGNAME_DILITHIUM5_P384}, + {PGP_PKA_DILITHIUM3_BP256, RNP_ALGNAME_DILITHIUM3_BP256}, + {PGP_PKA_DILITHIUM5_BP384, RNP_ALGNAME_DILITHIUM5_BP384}, #endif {0, NULL}}; @@ -329,6 +337,14 @@ pub_alg_supported(int alg) #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_X25519: case PGP_PKA_ED25519: +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: + //case PGP_PKA_DILITHIUM5_ED448: + case PGP_PKA_DILITHIUM3_P256: + case PGP_PKA_DILITHIUM5_P384: + case PGP_PKA_DILITHIUM3_BP256: + case PGP_PKA_DILITHIUM5_BP384: #endif return true; default: @@ -5226,6 +5242,15 @@ default_key_flags(pgp_pubkey_alg_t alg, bool subkey) return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); case PGP_PKA_X25519: return PGP_KF_ENCRYPT; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); #endif default: return PGP_KF_NONE; @@ -7439,6 +7464,20 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) case PGP_PKA_EDDSA: case PGP_PKA_SM2: return add_json_mpis(jso, "point", &km.ec.p, 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_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return RNP_SUCCESS; /* TODO */ +#endif default: return RNP_ERROR_NOT_SUPPORTED; } @@ -7506,6 +7545,15 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) case PGP_PKA_ED25519: case PGP_PKA_X25519: return RNP_SUCCESS; /* TODO */ +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return RNP_SUCCESS; /* TODO */ #endif default: // TODO: we could use info->unknown and add a hex string of raw data here @@ -7728,6 +7776,15 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) case PGP_PKA_ED25519: case PGP_PKA_X25519: return RNP_SUCCESS; /* TODO */ +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return RNP_SUCCESS; /* TODO */ #endif default: break; diff --git a/src/lib/types.h b/src/lib/types.h index 7c6645125..8226b73f9 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -192,6 +192,9 @@ typedef struct pgp_key_material_t { 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_dilithium_exdsa_key_t dilithium_exdsa; /* non-trivial type, cannot be in a union */ +#endif pgp_curve_t get_curve() const; /* return curve for EC algorithms, PGP_CURVE_UNKNOWN otherwise */ size_t bits() const; @@ -213,6 +216,9 @@ typedef struct pgp_signature_material_t { #if defined(ENABLE_CRYPTO_REFRESH) pgp_ed25519_signature_t ed25519; // non-trivial type cannot be member in union #endif +#if defined(ENABLE_PQC) + pgp_dilithium_exdsa_signature_t dilithium_exdsa; // non-trivial type cannot be member in union +#endif } pgp_signature_material_t; /** diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index 0ea023308..114ce99bf 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -746,6 +746,16 @@ rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) case PGP_PKA_X25519: hash->add(key->x25519.pub); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + hash->add(key->dilithium_exdsa.pub.get_encoded()); + break; #endif default: RNP_LOG("unsupported public-key algorithm %d", (int) key->alg); diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 618ca3c66..1e397696c 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -146,6 +146,14 @@ static const id_str_pair pubkey_alg_map[] = { #if defined(ENABLE_CRYPTO_REFRESH) {PGP_PKA_ED25519, "Ed25519"}, {PGP_PKA_X25519, "X25519"}, +#endif +#if defined(ENABLE_PQC) + {PGP_PKA_DILITHIUM3_ED25519, "Dilithium3 + ED25519"}, + //{PGP_PKA_DILITHIUM5_ED448, "Dilithium + X448"}, + {PGP_PKA_DILITHIUM3_P256, "Dilithium3 + NIST P-256"}, + {PGP_PKA_DILITHIUM5_P384, "Dilithium5 + NIST P-384"}, + {PGP_PKA_DILITHIUM3_BP256, "Dilithium3 + Brainpool256"}, + {PGP_PKA_DILITHIUM5_BP384, "Dilithium5 + Brainpool384"}, #endif {0x00, NULL}, }; @@ -807,6 +815,16 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t case PGP_PKA_ED25519: dst_print_vec(dst, "ed25519 sig", material.ed25519.sig, ctx->dump_mpi); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + dst_print_vec(dst, "dilithium-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); + break; #endif default: dst_printf(dst, "unknown algorithm\n"); @@ -909,6 +927,16 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) case PGP_PKA_X25519: dst_print_vec(dst, "x25519", key.material.x25519.pub, ctx->dump_mpi); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + dst_print_vec(dst, "dilithium-ecdsa/eddsa encodced pubkey", key.material.dilithium_exdsa.pub.get_encoded(), ctx->dump_mpi); + break; #endif default: dst_printf(dst, "unknown public key algorithm\n"); @@ -1885,6 +1913,16 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, case PGP_PKA_ED25519: /* TODO */ break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + /* TODO */ + break; #endif default: break; @@ -2004,6 +2042,16 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) case PGP_PKA_X25519: /* TODO */ break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + /* TODO */ + break; #endif default: break; diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index c6f6ab629..b001cc26f 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -597,8 +597,6 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) try { /* parse mpis depending on algorithm */ pgp_packet_body_t body(mpis, len); - - std::vector tmpbuf; #if defined(ENABLE_CRYPTO_REFRESH) std::vector tmpbuf; @@ -657,6 +655,21 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) key.material.x25519.priv = tmpbuf; break; } +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + 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 dilithium-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; #endif default: RNP_LOG("unknown pk alg : %d", (int) key.alg); @@ -789,6 +802,16 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) body.add(key.material.x25519.priv); break; #endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + body.add(key.material.dilithium_exdsa.priv.get_encoded()); + break; +#endif default: RNP_LOG("unknown pk alg : %d", (int) key.alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); @@ -941,6 +964,16 @@ forget_secret_key_fields(pgp_key_material_t *key) secure_clear(key->x25519.priv.data(), key->x25519.priv.size()); key->x25519.priv.clear(); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + key->dilithium_exdsa.priv.secure_clear(); + break; #endif default: RNP_LOG("unknown key algorithm: %d", (int) key->alg); @@ -1399,6 +1432,21 @@ pgp_key_pkt_t::parse(pgp_source_t &src) material.x25519.pub = tmpbuf; break; } +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + 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 dilithium-ecdsa/eddsa public key data"); + return RNP_ERROR_BAD_FORMAT; + } + material.dilithium_exdsa.pub = pgp_dilithium_exdsa_composite_public_key_t(tmpbuf, alg); + break; #endif default: RNP_LOG("unknown key algorithm: %d", (int) alg); @@ -1544,6 +1592,16 @@ void pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t & hbod case PGP_PKA_X25519: hbody.add(material.x25519.pub); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + hbody.add(material.dilithium_exdsa.pub.get_encoded()); + break; #endif default: RNP_LOG("unknown key algorithm: %d", (int) alg); diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index e92937ba5..b5a8b5d69 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1563,6 +1563,20 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const } break; } +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + material.dilithium_exdsa.sig.resize(pgp_dilithium_exdsa_signature_t::composite_signature_size(palg)); + if (!pkt.get(material.dilithium_exdsa.sig.data(), material.dilithium_exdsa.sig.size())) { + RNP_LOG("failed to get dilithium-ecdsa/eddsa signature"); + return false; + } + break; #endif default: RNP_LOG("Unknown pk algorithm : %d", (int) palg); @@ -1649,6 +1663,16 @@ pgp_signature_t::write_material(const pgp_signature_material_t &material) case PGP_PKA_ED25519: pktbody.add(material.ed25519.sig); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; + //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + pktbody.add(material.dilithium_exdsa.sig); + break; #endif default: RNP_LOG("Unknown pk algorithm : %d", (int) palg); diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 25b98bfa5..17c3e6e5d 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -602,6 +602,44 @@ TEST_F(rnp_tests, test_dsa_verify_negative) assert_int_equal(dsa_verify(&sig, message, h_size, key1), RNP_ERROR_SIGNATURE_INVALID); } +#if defined(ENABLE_PQC) +TEST_F(rnp_tests, dilithium_exdsa_signverify_success) +{ + uint8_t message[64]; + const pgp_hash_alg_t hash_alg = PGP_HASH_SHA512; + + pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, /* PGP_PKA_DILITHIUM5_ED448,*/ PGP_PKA_DILITHIUM3_P256, PGP_PKA_DILITHIUM5_P384, PGP_PKA_DILITHIUM3_BP256, PGP_PKA_DILITHIUM5_BP384}; + + for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { + // 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; + key_desc.key_alg = algs[i]; + key_desc.hash_alg = hash_alg; + key_desc.ctx = &global_ctx; + + pgp_key_pkt_t seckey1; + pgp_key_pkt_t seckey2; + + 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; + + 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))); + + // Fails because of different key used + assert_rnp_failure(key2->pub.verify(&sig, hash_alg, message, sizeof(message))); + } +} +#endif + // platforms known to not have a robust response can compile with // -DS2K_MINIMUM_TUNING_RATIO=2 (or whatever they need) #ifndef S2K_MINIMUM_TUNING_RATIO diff --git a/src/tests/ffi.cpp b/src/tests/ffi.cpp index da8349f64..8a4429e79 100644 --- a/src/tests/ffi.cpp +++ b/src/tests/ffi.cpp @@ -3109,11 +3109,15 @@ TEST_F(rnp_tests, test_ffi_supported_features) /* public key algorithm */ assert_rnp_success(rnp_supported_features(RNP_FEATURE_PK_ALG, &features)); assert_non_null(features); + size_t pqc_opt = 0; size_t crypto_refresh_opt = 0; #if defined(ENABLE_CRYPTO_REFRESH) crypto_refresh_opt = 2; // X25519 + ED25519 #endif - assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + crypto_refresh_opt)); +#if defined(ENABLE_PQC) + pqc_opt = 5; // dilithium+ecc variants +#endif + assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + pqc_opt + crypto_refresh_opt)); rnp_buffer_destroy(features); assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "RSA", &supported)); assert_true(supported); diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp index 35b6347a7..45fd53e05 100644 --- a/src/tests/pqc.cpp +++ b/src/tests/pqc.cpp @@ -51,4 +51,40 @@ TEST_F(rnp_tests, test_dilithium_key_function) } } +TEST_F(rnp_tests, test_dilithium_exdsa_direct) +{ + pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, /* PGP_PKA_DILITHIUM5_ED448,*/ PGP_PKA_DILITHIUM3_P256, PGP_PKA_DILITHIUM5_P384, PGP_PKA_DILITHIUM3_BP256, PGP_PKA_DILITHIUM5_BP384}; + + for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { + uint8_t message[64]; + const pgp_hash_alg_t hash_alg = PGP_HASH_SHA512; + // Generate test data. Mainly to make valgrind not to complain about uninitialized data + global_ctx.rng.get(message, sizeof(message)); + + pgp_dilithium_exdsa_key_t key; + pgp_dilithium_exdsa_signature_t sig; + + assert_rnp_success( + pgp_dilithium_exdsa_composite_key_t::gen_keypair(&global_ctx.rng, &key, algs[i])); + + assert_rnp_success(key.priv.sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message))); + assert_rnp_success(key.pub.verify(&sig, hash_alg, message, sizeof(message))); + + // Fails because message won't verify + message[0] = ~message[0]; + assert_rnp_failure(key.pub.verify(&sig, hash_alg, message, sizeof(message))); + message[0] = ~message[0]; + + // Fails because first sig won't verify + sig.sig.data()[0] = ~sig.sig.data()[0]; + assert_rnp_failure(key.pub.verify(&sig, hash_alg, message, sizeof(message))); + sig.sig.data()[0] = ~sig.sig.data()[0]; + + // Fails because second sig won't verify + sig.sig.data()[sig.sig.size()-1] = ~sig.sig.data()[sig.sig.size()-1]; + assert_rnp_failure(key.pub.verify(&sig, hash_alg, message, sizeof(message))); + sig.sig.data()[sig.sig.size()-1] = ~sig.sig.data()[sig.sig.size()-1]; + } +} + #endif \ No newline at end of file From 64ba6cd31ed68a5fdf36fd951cd8747d56078fa5 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 13 Jun 2023 10:10:21 +0200 Subject: [PATCH 07/20] add kmac functionality --- src/lib/CMakeLists.txt | 4 +- src/lib/crypto/kmac.cpp | 119 ++++++++++++++++++++++++++++++++++ src/lib/crypto/kmac.hpp | 84 ++++++++++++++++++++++++ src/lib/crypto/kmac_botan.cpp | 70 ++++++++++++++++++++ src/lib/crypto/kmac_botan.hpp | 57 ++++++++++++++++ 5 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 src/lib/crypto/kmac.cpp create mode 100644 src/lib/crypto/kmac.hpp create mode 100644 src/lib/crypto/kmac_botan.cpp create mode 100644 src/lib/crypto/kmac_botan.hpp diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index f30d408a4..f611c9090 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -188,7 +188,7 @@ if(CRYPTO_BACKEND_BOTAN) resolve_feature_state(ENABLE_TWOFISH "TWOFISH") resolve_feature_state(ENABLE_IDEA "IDEA") resolve_feature_state(ENABLE_CRYPTO_REFRESH "HKDF") - resolve_feature_state(ENABLE_PQC "DILITHIUM") + resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM") resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH") resolve_feature_state(ENABLE_CAST5 "CAST_128") resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160") @@ -305,6 +305,8 @@ elseif(CRYPTO_BACKEND_BOTAN) crypto/dilithium.cpp crypto/dilithium_common.cpp crypto/dilithium_exdsa_composite.cpp + crypto/kmac.cpp + crypto/kmac_botan.cpp ) endif() else() diff --git a/src/lib/crypto/kmac.cpp b/src/lib/crypto/kmac.cpp new file mode 100644 index 000000000..52ec4e825 --- /dev/null +++ b/src/lib/crypto/kmac.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 "config.h" +#include "kmac.hpp" + +#if defined(CRYPTO_BACKEND_BOTAN) +#include "kmac_botan.hpp" +#endif +#if defined(CRYPTO_BACKEND_OPENSSL) +#error KMAC256 not implemented for OpenSSL Backend +#endif + +namespace rnp { +std::unique_ptr +KMAC256::create() +{ +#if defined(CRYPTO_BACKEND_OPENSSL) +#error KMAC256 not implemented for OpenSSL + // return Hash_OpenSSL::create(); +#elif defined(CRYPTO_BACKEND_BOTAN) + return KMAC256_Botan::create(); +#else +#error "Crypto backend not specified" +#endif +} + +std::vector +KMAC256::domSeparation() const +{ + return domSeparation_; +} + +std::vector +KMAC256::customizationString() const +{ + return customizationString_; +} + +std::vector +KMAC256::counter() const +{ + return counter_; +} + +/* + // Input: + // algID - the algorithm ID encoded as octet + // publicKey - the recipient's encryption sub-key packet + // serialized as octet string + + fixedInfo = algID || SHA3-256(publicKey) +*/ +std::vector +KMAC256::fixedInfo(const std::vector &subkey_pkt_hash, pgp_pubkey_alg_t alg_id) +{ + std::vector result(subkey_pkt_hash); + result.insert(result.begin(), (static_cast(alg_id)));; + return result; +} + +std::vector +KMAC256::encData(const std::vector &ecc_key_share, + const std::vector &ecc_ciphertext, + const std::vector &kyber_key_share, + const std::vector &kyber_ciphertext, + const std::vector &subkey_pkt_hash, + pgp_pubkey_alg_t alg_id) +{ + std::vector enc_data; + std::vector counter_vec = counter(); + std::vector fixedInfo_vec = fixedInfo(subkey_pkt_hash, alg_id); + + /* draft-wussler-openpgp-pqc-01: + + eccKemData = eccKeyShare || eccCipherText + kyberKemData = kyberKeyShare || kyberCipherText + encData = counter || eccKemData || kyberKemData || fixedInfo + */ + enc_data.insert(enc_data.end(), counter_vec.begin(), counter_vec.end()); + enc_data.insert(enc_data.end(), ecc_key_share.begin(), ecc_key_share.end()); + enc_data.insert(enc_data.end(), ecc_ciphertext.begin(), ecc_ciphertext.end()); + enc_data.insert(enc_data.end(), kyber_key_share.begin(), kyber_key_share.end()); + enc_data.insert(enc_data.end(), kyber_ciphertext.begin(), kyber_ciphertext.end()); + enc_data.insert(enc_data.end(), fixedInfo_vec.begin(), fixedInfo_vec.end()); + + return enc_data; +} + + +KMAC256::~KMAC256() +{ +} + +} // namespace rnp diff --git a/src/lib/crypto/kmac.hpp b/src/lib/crypto/kmac.hpp new file mode 100644 index 000000000..20507c3a3 --- /dev/null +++ b/src/lib/crypto/kmac.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 CRYPTO_KMAC_H_ +#define CRYPTO_KMAC_H_ + +#include +#include "types.h" +#include "config.h" +#include "pgp-key.h" + + +namespace rnp { +class KMAC256 { + /* KDF for PQC key combiner according to https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-01 */ + + protected: + /* The value of domSeparation is the UTF-8 encoding of the string "OpenPGPV5CompositeKDF" and MUST be the following octet sequence: + + domSeparation := 4F 70 65 6E 50 47 50 56 35 43 6F + 6D 70 6F 73 69 74 65 4B 44 46 + */ + const std::vector domSeparation_ = std::vector({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x56, 0x35, 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, 0x4B, 0x44, 0x46}); + + /* customizationString := 4B 44 46 */ + const std::vector customizationString_ = std::vector({0x4B, 0x44, 0x46}); + + /* counter - a 4 byte counter set to the value 1 */ + const std::vector counter_ = std::vector({0x00, 0x00, 0x00, 0x01}); + + std::vector domSeparation() const; + std::vector customizationString() const; + std::vector counter() const; + std::vector fixedInfo(const std::vector &subkey_pkt_hash, pgp_pubkey_alg_t alg_id); + std::vector encData(const std::vector &ecc_key_share, + const std::vector &ecc_ciphertext, + const std::vector &kyber_key_share, + const std::vector &kyber_ciphertext, + const std::vector &subkey_pkt_hash, + pgp_pubkey_alg_t alg_id); + + KMAC256() {}; + + public: + static std::unique_ptr create(); + + /* KMAC interface for OpenPGP PQC composite algorithms */ + virtual void compute(const std::vector &ecc_key_share, + const std::vector &ecc_key_ciphertext, + const std::vector &kyber_key_share, + const std::vector &kyber_ciphertext, + const pgp_pubkey_alg_t alg_id, + const std::vector &subkey_pkt_hash, + std::vector &out) = 0; + + virtual ~KMAC256(); +}; + +} // namespace rnp + +#endif diff --git a/src/lib/crypto/kmac_botan.cpp b/src/lib/crypto/kmac_botan.cpp new file mode 100644 index 000000000..55c604cb3 --- /dev/null +++ b/src/lib/crypto/kmac_botan.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 "kmac_botan.hpp" +#include "hash_botan.hpp" +#include "botan/mac.h" + +namespace rnp { + +KMAC256_Botan::KMAC256_Botan() : KMAC256() +{ +} + +std::unique_ptr +KMAC256_Botan::create() +{ + return std::unique_ptr(new KMAC256_Botan()); +} + +void +KMAC256_Botan::compute(const std::vector &ecc_key_share, + const std::vector &ecc_ciphertext, + const std::vector &kyber_key_share, + const std::vector &kyber_ciphertext, + const pgp_pubkey_alg_t alg_id, + const std::vector &subkey_pkt_hash, + std::vector &out) +{ + auto kmac = Botan::MessageAuthenticationCode::create_or_throw("KMAC256(256)"); + + /* the mapping between the KEM Combiner and the MAC interface is: + * key <> domSeparation + * nonce <> customizationString + * message <> encData + */ + + kmac->set_key(domSeparation()); + kmac->start(customizationString()); // set nonce + kmac->update(encData(ecc_key_share, ecc_ciphertext, kyber_key_share, kyber_ciphertext, subkey_pkt_hash, alg_id)); + out = kmac->final_stdvec(); +} + +KMAC256_Botan::~KMAC256_Botan() +{ +} + +} // namespace rnp diff --git a/src/lib/crypto/kmac_botan.hpp b/src/lib/crypto/kmac_botan.hpp new file mode 100644 index 000000000..3da07fffb --- /dev/null +++ b/src/lib/crypto/kmac_botan.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 MTG AG + * 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 HOLDERS 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 CRYPTO_KMAC_BOTAN_HPP_ +#define CRYPTO_KMAC_BOTAN_HPP_ + +#include "kmac.hpp" + +namespace rnp { + +class KMAC256_Botan : public KMAC256 { + + private: + + public: + KMAC256_Botan(); + KMAC256_Botan(const KMAC256_Botan &src); + + virtual ~KMAC256_Botan(); + + static std::unique_ptr create(); + + void compute(const std::vector &ecc_key_share, + const std::vector &ecc_ciphertext, + const std::vector &kyber_key_share, + const std::vector &kyber_ciphertext, + const pgp_pubkey_alg_t alg_id, + const std::vector &subkey_pkt_hash, + std::vector &out) override; +}; + +} // namespace rnp + +#endif From 8be734b33a95a3c93af362a7aae9af99674f8f08 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 13 Jun 2023 10:27:03 +0200 Subject: [PATCH 08/20] add kyber standalone functionality correction of kyber based on rnp feedback --- src/lib/CMakeLists.txt | 4 +- src/lib/crypto/kyber.cpp | 136 ++++++++++++++++++++++++++++++++ src/lib/crypto/kyber.h | 109 +++++++++++++++++++++++++ src/lib/crypto/kyber_common.cpp | 112 ++++++++++++++++++++++++++ src/lib/crypto/kyber_common.h | 41 ++++++++++ src/tests/pqc.cpp | 18 +++++ 6 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 src/lib/crypto/kyber.cpp create mode 100644 src/lib/crypto/kyber.h create mode 100644 src/lib/crypto/kyber_common.cpp create mode 100644 src/lib/crypto/kyber_common.h diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index f611c9090..8d030371b 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -188,7 +188,7 @@ if(CRYPTO_BACKEND_BOTAN) resolve_feature_state(ENABLE_TWOFISH "TWOFISH") resolve_feature_state(ENABLE_IDEA "IDEA") resolve_feature_state(ENABLE_CRYPTO_REFRESH "HKDF") - resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM") + resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM;KYBER") resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH") resolve_feature_state(ENABLE_CAST5 "CAST_128") resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160") @@ -304,6 +304,8 @@ elseif(CRYPTO_BACKEND_BOTAN) list(APPEND CRYPTO_SOURCES crypto/dilithium.cpp crypto/dilithium_common.cpp + crypto/kyber_common.cpp + crypto/kyber.cpp crypto/dilithium_exdsa_composite.cpp crypto/kmac.cpp crypto/kmac_botan.cpp diff --git a/src/lib/crypto/kyber.cpp b/src/lib/crypto/kyber.cpp new file mode 100644 index 000000000..661744216 --- /dev/null +++ b/src/lib/crypto/kyber.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "kyber.h" +#include +#include +#include + +namespace { +Botan::KyberMode +rnp_kyber_param_to_botan_kyber_mode(kyber_parameter_e mode) +{ + Botan::KyberMode result = Botan::KyberMode::Kyber1024; + if (mode == kyber_768) { + result = Botan::KyberMode::Kyber768; + } + return result; +} + +uint32_t +key_share_size_from_kyber_param(kyber_parameter_e param) +{ + if (param == kyber_768) { + return 24; + } + return 32; // kyber_1024 +} +} // namespace + +std::pair +kyber_generate_keypair(rnp::RNG *rng, kyber_parameter_e kyber_param) +{ + Botan::Kyber_PrivateKey kyber_priv(*rng->obj(), rnp_kyber_param_to_botan_kyber_mode(kyber_param)); + + Botan::secure_vector encoded_private_key = kyber_priv.private_key_bits(); + std::unique_ptr kyber_pub = kyber_priv.public_key(); + + std::vector encoded_public_key = kyber_priv.public_key_bits(); + return std::make_pair(pgp_kyber_public_key_t(encoded_public_key, kyber_param), + pgp_kyber_private_key_t(encoded_private_key.data(), + encoded_private_key.size(), + kyber_param)); +} + +Botan::Kyber_PublicKey +pgp_kyber_public_key_t::botan_key() const +{ + return Botan::Kyber_PublicKey(key_encoded_, rnp_kyber_param_to_botan_kyber_mode(kyber_mode_)); +} + +Botan::Kyber_PrivateKey +pgp_kyber_private_key_t::botan_key() const +{ + Botan::secure_vector key_sv(key_encoded_.data(), + key_encoded_.data() + key_encoded_.size()); + return Botan::Kyber_PrivateKey(key_sv, rnp_kyber_param_to_botan_kyber_mode(kyber_mode_)); +} + +kyber_encap_result_t +pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) +{ + assert(is_initialized_); + auto decoded_kyber_pub = botan_key(); + + Botan::PK_KEM_Encryptor kem_enc(decoded_kyber_pub, "Raw", "base"); + Botan::secure_vector encap_key; // this has to go over the wire + Botan::secure_vector data_encryption_key; // this is the key used for + // encryption of the payload data + kem_enc.encrypt(encap_key, data_encryption_key, key_share_size_from_kyber_param(kyber_mode_), *rng->obj()); + kyber_encap_result_t result; + result.ciphertext.insert( + result.ciphertext.end(), encap_key.data(), encap_key.data() + encap_key.size()); + result.symmetric_key.insert(result.symmetric_key.end(), + data_encryption_key.data(), + data_encryption_key.data() + data_encryption_key.size()); + return result; +} + +std::vector +pgp_kyber_private_key_t::decapsulate(rnp::RNG *rng, const uint8_t *ciphertext, size_t ciphertext_len) +{ + assert(is_initialized_); + auto decoded_kyber_priv = botan_key(); + Botan::PK_KEM_Decryptor kem_dec(decoded_kyber_priv, *rng->obj(), "Raw", "base"); + Botan::secure_vector dec_shared_key = kem_dec.decrypt( + ciphertext, ciphertext_len, key_share_size_from_kyber_param(kyber_mode_)); + return std::vector(dec_shared_key.data(), + dec_shared_key.data() + dec_shared_key.size()); +} + +bool +pgp_kyber_public_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized_) { + return false; + } + + auto key = botan_key(); + return key.check_key(*(rng->obj()), false); +} + +bool +pgp_kyber_private_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized_) { + return false; + } + + auto key = botan_key(); + return key.check_key(*(rng->obj()), false); +} diff --git a/src/lib/crypto/kyber.h b/src/lib/crypto/kyber.h new file mode 100644 index 000000000..4d1c3ab06 --- /dev/null +++ b/src/lib/crypto/kyber.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 KYBER_H_ +#define KYBER_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include +#include + +enum kyber_parameter_e { kyber_768, kyber_1024 }; + +struct kyber_encap_result_t { + std::vector ciphertext; + std::vector symmetric_key; +}; + +class pgp_kyber_private_key_t { + public: + pgp_kyber_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode); + pgp_kyber_private_key_t(std::vector const &key_encoded, kyber_parameter_e mode); + pgp_kyber_private_key_t() = default; + + bool is_valid(rnp::RNG *rng) const; + + std::vector decapsulate(rnp::RNG *rng, const uint8_t *ciphertext, size_t ciphertext_len); + std::vector + get_encoded() const + { + return Botan::unlock(key_encoded_); + }; + + kyber_parameter_e + param() const + { + return kyber_mode_; + } + + private: + Botan::Kyber_PrivateKey botan_key() const; + + Botan::secure_vector key_encoded_; + kyber_parameter_e kyber_mode_; + bool is_initialized_ = false; +}; + +class pgp_kyber_public_key_t { + public: + pgp_kyber_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, 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); + + bool operator==(const pgp_kyber_public_key_t &rhs) const + { + return (kyber_mode_ == rhs.kyber_mode_) && (key_encoded_ == rhs.key_encoded_); + } + + bool is_valid(rnp::RNG *rng) const; + + std::vector + get_encoded() const + { + return key_encoded_; + }; + + private: + Botan::Kyber_PublicKey botan_key() const; + + std::vector key_encoded_; + kyber_parameter_e kyber_mode_; + bool is_initialized_ = false; +}; + +std::pair kyber_generate_keypair( + rnp::RNG *rng, kyber_parameter_e kyber_param); + +#endif \ No newline at end of file diff --git a/src/lib/crypto/kyber_common.cpp b/src/lib/crypto/kyber_common.cpp new file mode 100644 index 000000000..a0b1112c4 --- /dev/null +++ b/src/lib/crypto/kyber_common.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "kyber_common.h" +#include "types.h" +#include "logging.h" + +size_t kyber_privkey_size(kyber_parameter_e parameter) { + switch(parameter) { + case kyber_768: + return 2400; + case kyber_1024: + return 3168; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t kyber_pubkey_size(kyber_parameter_e parameter) { + switch(parameter) { + case kyber_768: + return 1184; + case kyber_1024: + return 1568; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t kyber_keyshare_size(kyber_parameter_e parameter) { + switch(parameter) { + case kyber_768: + return 24; + case kyber_1024: + return 32; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t kyber_ciphertext_size(kyber_parameter_e parameter) { + switch(parameter) { + case kyber_768: + return 1088; + case kyber_1024: + return 1568; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +pgp_kyber_public_key_t::pgp_kyber_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode): + key_encoded_(key_encoded, key_encoded + key_encoded_len), + kyber_mode_(mode), + is_initialized_(true) +{ +} + +pgp_kyber_public_key_t::pgp_kyber_public_key_t(std::vector const& key_encoded, kyber_parameter_e mode): + key_encoded_(key_encoded), + kyber_mode_(mode), + is_initialized_(true) +{ +} + + +pgp_kyber_private_key_t::pgp_kyber_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode): + key_encoded_(key_encoded, key_encoded + key_encoded_len), + kyber_mode_(mode), + is_initialized_(true) +{ +} + + +pgp_kyber_private_key_t::pgp_kyber_private_key_t(std::vector const& key_encoded, kyber_parameter_e mode): + key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), + kyber_mode_(mode), + is_initialized_(true) +{ +} + diff --git a/src/lib/crypto/kyber_common.h b/src/lib/crypto/kyber_common.h new file mode 100644 index 000000000..977a9e479 --- /dev/null +++ b/src/lib/crypto/kyber_common.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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_KYBER_COMMON_H_ +#define RNP_KYBER_COMMON_H_ + +#include "kyber.h" + +size_t kyber_privkey_size(kyber_parameter_e parameter); +size_t kyber_pubkey_size(kyber_parameter_e parameter); +size_t kyber_keyshare_size(kyber_parameter_e parameter); +size_t kyber_ciphertext_size(kyber_parameter_e parameter); + +#endif \ No newline at end of file diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp index 45fd53e05..856e1f957 100644 --- a/src/tests/pqc.cpp +++ b/src/tests/pqc.cpp @@ -34,6 +34,24 @@ #include "rnp_tests.h" #include #include "crypto/dilithium.h" +#include "crypto/kyber.h" + +TEST_F(rnp_tests, test_kyber_key_function) +{ + kyber_parameter_e params[2] = {kyber_768, kyber_1024}; + for(kyber_parameter_e param : params) + { + + auto public_and_private_key = kyber_generate_keypair(&global_ctx.rng, param); + + kyber_encap_result_t encap_res = public_and_private_key.first.encapsulate(&global_ctx.rng); + + std::vector decrypted = public_and_private_key.second.decapsulate(&global_ctx.rng, encap_res.ciphertext.data(), encap_res.ciphertext.size()); + assert_int_equal(encap_res.symmetric_key.size(), decrypted.size()); + assert_memory_equal(encap_res.symmetric_key.data(), decrypted.data(), decrypted.size()); + + } +} TEST_F(rnp_tests, test_dilithium_key_function) { From eb8ba12006f3badb66e08c3e1c3999e298a34d23 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 13 Jun 2023 11:30:09 +0200 Subject: [PATCH 09/20] add kyber ecdh composite algorithms conditionally compile RNP_ALGNAME_* macros address some more points of PR review (JRH) corrections of key-gen ui according to rnp feedback SHA3 hash binding for dilithium-exdsa-composite --- include/repgp/repgp_def.h | 7 + include/rnp/rnp.h | 11 + src/lib/CMakeLists.txt | 1 + src/lib/crypto.cpp | 79 +++- src/lib/crypto/common.h | 1 + src/lib/crypto/dilithium.cpp | 12 + src/lib/crypto/dilithium.h | 4 +- src/lib/crypto/dilithium_common.h | 2 +- src/lib/crypto/ec.cpp | 2 +- src/lib/crypto/ecdh.cpp | 2 +- src/lib/crypto/ed25519.cpp | 2 +- src/lib/crypto/ed25519.h | 2 +- src/lib/crypto/exdsa_ecdhkem.h | 4 +- src/lib/crypto/kyber.h | 2 +- src/lib/crypto/kyber_common.h | 2 +- src/lib/crypto/kyber_ecdh_composite.cpp | 530 ++++++++++++++++++++++++ src/lib/crypto/kyber_ecdh_composite.h | 159 +++++++ src/lib/crypto/signatures.cpp | 28 +- src/lib/crypto/x25519.cpp | 2 +- src/lib/crypto/x25519.h | 2 +- src/lib/generate-key.cpp | 65 ++- src/lib/pgp-key.cpp | 74 +++- src/lib/pgp-key.h | 4 + src/lib/rnp.cpp | 114 ++++- src/lib/types.h | 4 + src/librekey/rnp_key_store.cpp | 26 +- src/librepgp/stream-common.cpp | 8 + src/librepgp/stream-ctx.cpp | 2 +- src/librepgp/stream-dump.cpp | 118 +++++- src/librepgp/stream-key.cpp | 140 +++++-- src/librepgp/stream-packet.cpp | 45 ++ src/librepgp/stream-parse.cpp | 21 + src/librepgp/stream-sig.cpp | 28 +- src/librepgp/stream-write.cpp | 22 + src/rnpkeys/tui.cpp | 73 +++- src/tests/cipher.cpp | 40 ++ src/tests/ffi.cpp | 2 +- src/tests/pqc.cpp | 2 +- 38 files changed, 1501 insertions(+), 141 deletions(-) create mode 100644 src/lib/crypto/kyber_ecdh_composite.cpp create mode 100644 src/lib/crypto/kyber_ecdh_composite.h diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index fc1d825f9..d96b45447 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -228,6 +228,13 @@ typedef enum : uint8_t { #if defined(ENABLE_PQC) /* PQC-ECC composite */ + PGP_PKA_KYBER768_X25519 = 29, /* Kyber768 + X25519 from draft-wussler-openpgp-pqc-01 */ + //PGP_PKA_KYBER1024_X448 = 30, /* Kyer1024 + X448 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER768_P256 = 31, /* Kyber768 + NIST P-256 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER1024_P384 = 32, /* Kyber1024 + NIST P-384 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER768_BP256 = 33, /* Kyber768 + Brainpool P256r1 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER1024_BP384 = 34, /* Kyber1024 + Brainpool P384r1 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM3_ED25519 = 35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-01 */ //PGP_PKA_DILITHIUM5_ED448 = 36, /* Dilithium 5 + Ed448 from draft-wussler-openpgp-pqc-01 */ PGP_PKA_DILITHIUM3_P256 = 37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-01 */ diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 91c9e0da6..497e22d06 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -30,6 +30,7 @@ #include #include #include +#include "config.h" #if defined(__cplusplus) extern "C" { @@ -3398,14 +3399,24 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_ECDH "ECDH" #define RNP_ALGNAME_ECDSA "ECDSA" #define RNP_ALGNAME_EDDSA "EDDSA" +#if defined(ENABLE_CRYPTO_REFRESH) #define RNP_ALGNAME_ED25519 "ED25519" #define RNP_ALGNAME_X25519 "X25519" +#endif +#if defined(ENABLE_PQC) +#define RNP_ALGNAME_KYBER768_X25519 "KYBER768_X25519" +#define RNP_ALGNAME_KYBER1024_X448 "KYBER1024_X448" +#define RNP_ALGNAME_KYBER768_P256 "KYBER768_P256" +#define RNP_ALGNAME_KYBER1024_P384 "KYBER1024_P384" +#define RNP_ALGNAME_KYBER768_BP256 "KYBER768_BP256" +#define RNP_ALGNAME_KYBER1024_BP384 "KYBER1024_BP384" #define RNP_ALGNAME_DILITHIUM3_ED25519 "DILITHIUM3_ED25519" #define RNP_ALGNAME_DILITHIUM5_ED448 "DILITHIUM5_ED448" #define RNP_ALGNAME_DILITHIUM3_P256 "DILITHIUM3_P256" #define RNP_ALGNAME_DILITHIUM5_P384 "DILITHIUM5_P384" #define RNP_ALGNAME_DILITHIUM3_BP256 "DILITHIUM3_BP256" #define RNP_ALGNAME_DILITHIUM5_BP384 "DILITHIUM5_BP384" +#endif #define RNP_ALGNAME_IDEA "IDEA" #define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" #define RNP_ALGNAME_CAST5 "CAST5" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 8d030371b..f84c62a12 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -306,6 +306,7 @@ elseif(CRYPTO_BACKEND_BOTAN) crypto/dilithium_common.cpp crypto/kyber_common.cpp crypto/kyber.cpp + crypto/kyber_ecdh_composite.cpp crypto/dilithium_exdsa_composite.cpp crypto/kmac.cpp crypto/kmac_botan.cpp diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index edad860a6..71a108dad 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -170,11 +170,30 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + 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 Kyber-ECDH-composite key for PK alg %d", seckey.alg); + return false; + } + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; 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 Dilithium-ecdsa/eddsa-composite key for PK alg %d", seckey.alg); @@ -229,11 +248,26 @@ key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key return (key1->x25519.pub == key2->x25519.pub); #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return (key1->kyber_ecdh.pub == key2->kyber_ecdh.pub); + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return (key1->dilithium_exdsa.pub == key2->dilithium_exdsa.pub); #endif @@ -291,11 +325,26 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) return x25519_validate_key_native(rng, &material->x25519, material->secret); #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return kyber_ecdh_validate_key(rng, &material->kyber_ecdh, material->secret); + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return dilithium_exdsa_validate_key(rng, &material->dilithium_exdsa, material->secret); #endif diff --git a/src/lib/crypto/common.h b/src/lib/crypto/common.h index 07e1152d8..2709f7060 100644 --- a/src/lib/crypto/common.h +++ b/src/lib/crypto/common.h @@ -40,6 +40,7 @@ #include "sm2.h" #include "eddsa.h" #if defined(ENABLE_PQC) +#include "kyber_ecdh_composite.h" #include "dilithium_exdsa_composite.h" #endif #if defined(ENABLE_CRYPTO_REFRESH) diff --git a/src/lib/crypto/dilithium.cpp b/src/lib/crypto/dilithium.cpp index af3aeea75..b6879cec0 100644 --- a/src/lib/crypto/dilithium.cpp +++ b/src/lib/crypto/dilithium.cpp @@ -120,3 +120,15 @@ pgp_dilithium_private_key_t::is_valid(rnp::RNG *rng) const { auto key = botan_key(); return key.check_key(*(rng->obj()), false); } + +bool +dilithium_hash_allowed(pgp_hash_alg_t hash_alg) +{ + switch (hash_alg) { + case PGP_HASH_SHA3_256: + case PGP_HASH_SHA3_512: + return true; + default: + return false; + } +} \ No newline at end of file diff --git a/src/lib/crypto/dilithium.h b/src/lib/crypto/dilithium.h index a93c32176..8462c5a71 100644 --- a/src/lib/crypto/dilithium.h +++ b/src/lib/crypto/dilithium.h @@ -111,4 +111,6 @@ class pgp_dilithium_public_key_t { std::pair dilithium_generate_keypair( rnp::RNG *rng, dilithium_parameter_e dilithium_param); -#endif \ No newline at end of file +bool dilithium_hash_allowed(pgp_hash_alg_t hash_alg); + +#endif diff --git a/src/lib/crypto/dilithium_common.h b/src/lib/crypto/dilithium_common.h index 8e60ba819..9746a113f 100644 --- a/src/lib/crypto/dilithium_common.h +++ b/src/lib/crypto/dilithium_common.h @@ -38,4 +38,4 @@ size_t dilithium_privkey_size(dilithium_parameter_e parameter); size_t dilithium_pubkey_size(dilithium_parameter_e parameter); size_t dilithium_signature_size(dilithium_parameter_e parameter); -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/ec.cpp b/src/lib/crypto/ec.cpp index 25db0f3f0..6cad2a5b5 100644 --- a/src/lib/crypto/ec.cpp +++ b/src/lib/crypto/ec.cpp @@ -265,4 +265,4 @@ rnp_result_t ec_generate_native(rnp::RNG * rng, return RNP_ERROR_BAD_PARAMETERS; } } -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index df9f7df7a..c304fcedf 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -426,4 +426,4 @@ rnp_result_t exdsa_gen_keypair_native(rnp::RNG * rng, return ec_generate_native(rng, privkey, pubkey, curve, alg); } -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/ed25519.cpp b/src/lib/crypto/ed25519.cpp index bb52fa776..0fcb17ad0 100644 --- a/src/lib/crypto/ed25519.cpp +++ b/src/lib/crypto/ed25519.cpp @@ -87,4 +87,4 @@ ed25519_validate_key_native(rnp::RNG *rng, const pgp_ed25519_key_t *key, bool se } return RNP_SUCCESS; -} \ No newline at end of file +} diff --git a/src/lib/crypto/ed25519.h b/src/lib/crypto/ed25519.h index a7f5e1688..0cb37998e 100644 --- a/src/lib/crypto/ed25519.h +++ b/src/lib/crypto/ed25519.h @@ -50,4 +50,4 @@ rnp_result_t ed25519_verify_native(const std::vector &sig, const std::v rnp_result_t ed25519_validate_key_native(rnp::RNG *rng, const pgp_ed25519_key_t *key, bool secret); -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/exdsa_ecdhkem.h b/src/lib/crypto/exdsa_ecdhkem.h index 6bd67a653..c2c4a5194 100644 --- a/src/lib/crypto/exdsa_ecdhkem.h +++ b/src/lib/crypto/exdsa_ecdhkem.h @@ -178,6 +178,4 @@ typedef struct exdsa_key_t { exdsa_public_key_t pub; } exdsa_key_t; - - -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/kyber.h b/src/lib/crypto/kyber.h index 4d1c3ab06..9eb81859d 100644 --- a/src/lib/crypto/kyber.h +++ b/src/lib/crypto/kyber.h @@ -106,4 +106,4 @@ class pgp_kyber_public_key_t { std::pair kyber_generate_keypair( rnp::RNG *rng, kyber_parameter_e kyber_param); -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/kyber_common.h b/src/lib/crypto/kyber_common.h index 977a9e479..e84f4ddab 100644 --- a/src/lib/crypto/kyber_common.h +++ b/src/lib/crypto/kyber_common.h @@ -38,4 +38,4 @@ size_t kyber_pubkey_size(kyber_parameter_e parameter); size_t kyber_keyshare_size(kyber_parameter_e parameter); size_t kyber_ciphertext_size(kyber_parameter_e parameter); -#endif \ No newline at end of file +#endif diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp new file mode 100644 index 000000000..b3e19e1c1 --- /dev/null +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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 "kyber_ecdh_composite.h" +#include "logging.h" +#include "types.h" +#include "ecdh_utils.h" +#include "kmac.hpp" +#include +#include +#include + +pgp_kyber_ecdh_composite_key_t::~pgp_kyber_ecdh_composite_key_t() {} + +void +pgp_kyber_ecdh_composite_key_t::initialized_or_throw() const { + if(!is_initialized()) { + RNP_LOG("Trying to use uninitialized kyber-ecdh key"); + throw rnp::rnp_exception(RNP_ERROR_GENERIC); /* TODO better return error */ + } +} + +rnp_result_t +pgp_kyber_ecdh_composite_key_t::gen_keypair(rnp::RNG *rng, pgp_kyber_ecdh_key_t *key, pgp_pubkey_alg_t alg) +{ + rnp_result_t res; + pgp_curve_t curve = pk_alg_to_curve_id(alg); + kyber_parameter_e kyber_id = pk_alg_to_kyber_id(alg); + + ecdh_kem_key_t ecdh_key_pair; + + res = ec_key_t::generate_ecdh_kem_key_pair(rng, &ecdh_key_pair, curve); + if(res != RNP_SUCCESS) { + RNP_LOG("generating kyber ecdh composite key failed when generating ecdh key"); + return res; + } + + auto kyber_key_pair = kyber_generate_keypair(rng, kyber_id); + + key->priv = pgp_kyber_ecdh_composite_private_key_t(ecdh_key_pair.priv.get_encoded(), kyber_key_pair.second.get_encoded(), alg); + key->pub = pgp_kyber_ecdh_composite_public_key_t(ecdh_key_pair.pub.get_encoded(), kyber_key_pair.first.get_encoded(), alg); + + return RNP_SUCCESS; +} + +size_t +pgp_kyber_ecdh_composite_key_t::ecdh_curve_privkey_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 32; + case PGP_CURVE_NIST_P_384: + return 48; + case PGP_CURVE_BP256: + return 32; + case PGP_CURVE_BP384: + return 48; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t +pgp_kyber_ecdh_composite_key_t::ecdh_curve_pubkey_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 65; + case PGP_CURVE_NIST_P_384: + return 97; + case PGP_CURVE_BP256: + return 65; + case PGP_CURVE_BP384: + return 97; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t +pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 65; + case PGP_CURVE_NIST_P_384: + return 97; + case PGP_CURVE_BP256: + return 65; + case PGP_CURVE_BP384: + return 97; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t +pgp_kyber_ecdh_composite_key_t::ecdh_curve_keyshare_size(pgp_curve_t curve) { + switch(curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 32; + case PGP_CURVE_NIST_P_384: + return 48; + case PGP_CURVE_BP256: + return 32; + case PGP_CURVE_BP384: + return 48; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +kyber_parameter_e +pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg) { + switch(pk_alg) + { + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + return kyber_768; + case PGP_PKA_KYBER1024_BP384: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + //[[fallthrough]]; + //case PGP_PKA_KYBER1024_X448: + return kyber_1024; + default: + RNP_LOG("invalid PK alg given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +pgp_curve_t +pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg) { + switch(pk_alg) + { + case PGP_PKA_KYBER768_X25519: + return PGP_CURVE_25519; + case PGP_PKA_KYBER768_P256: + return PGP_CURVE_NIST_P_256; + case PGP_PKA_KYBER768_BP256: + return PGP_CURVE_BP256; + case PGP_PKA_KYBER1024_BP384: + return PGP_CURVE_BP384; + case PGP_PKA_KYBER1024_P384: + return PGP_CURVE_NIST_P_384; + /*case PGP_PKA_KYBER1024_X448: + return ... NOT_IMPLEMENTED*/ + default: + RNP_LOG("invalid PK alg given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + + +pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); +} + +pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(key_encoded); +} + +pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) +{ + if(ecdh_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != ecdh_key_encoded.size() + || kyber_privkey_size(pk_alg_to_kyber_id(pk_alg)) != kyber_key_encoded.size()) + { + RNP_LOG("ecdh or kyber key length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + kyber_key_ = std::make_unique(pgp_kyber_private_key_t(kyber_key_encoded, pk_alg_to_kyber_id(pk_alg))); + ecdh_key_ = std::make_unique(ecdh_kem_private_key_t(ecdh_key_encoded, pk_alg_to_curve_id(pk_alg))); + + is_initialized_ = true; +} + +/* copy assignment operator is used on key materials struct and thus needs to be defined for this class as well */ +pgp_kyber_ecdh_composite_private_key_t& pgp_kyber_ecdh_composite_private_key_t::operator=(const pgp_kyber_ecdh_composite_private_key_t& other) +{ + pgp_kyber_ecdh_composite_key_t::operator=(other); + pk_alg_ = other.pk_alg_; + if(other.is_initialized() && other.kyber_key_) + { + kyber_key_ = std::make_unique(pgp_kyber_private_key_t(other.kyber_key_->get_encoded(), other.kyber_key_->param())); + } + if(other.is_initialized() && other.ecdh_key_) + { + ecdh_key_ = std::make_unique(ecdh_kem_private_key_t(other.ecdh_key_->get_encoded(), other.ecdh_key_->get_curve())); + } + + return *this; +} + +size_t +pgp_kyber_ecdh_composite_private_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) +{ + kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return ecdh_curve_privkey_size(curve) + kyber_privkey_size(kyber_param); +} + +void +pgp_kyber_ecdh_composite_private_key_t::parse_component_keys(std::vector key_encoded) { + if (key_encoded.size() != encoded_size(pk_alg_)) { + RNP_LOG("Kyber composite key format invalid: length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg_); + pgp_curve_t ecdh_curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = ecdh_curve_privkey_size(pk_alg_to_curve_id(pk_alg_)); + + kyber_key_ = std::make_unique(pgp_kyber_private_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, kyber_param)); + ecdh_key_ = std::make_unique(ecdh_kem_private_key_t(key_encoded.data(), split_at, ecdh_curve)); + + is_initialized_ = true; +} + + +namespace +{ + std::vector hashed_ecc_keyshare(const std::vector &key_share, const std::vector &ciphertext, pgp_pubkey_alg_t alg_id) + { + /* SHA3-256(X || eccCipherText) or SHA3-256(X || eccCipherText) depending on algorithm */ + + std::vector digest; + pgp_hash_alg_t hash_alg; + + switch(alg_id) + { + case PGP_PKA_KYBER768_X25519: + case PGP_PKA_KYBER768_BP256: + case PGP_PKA_KYBER768_P256: + hash_alg = PGP_HASH_SHA3_256; + break; + //case PGP_PKA_KYBER1024_X448: + case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER1024_BP384: + hash_alg = PGP_HASH_SHA3_512; + break; + default: + RNP_LOG("key combiner does not support this algorithm"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + auto hash = rnp::Hash::create(hash_alg); + hash->add(key_share); + hash->add(ciphertext); + + digest.resize(rnp::Hash::size(hash_alg)); + hash->finish(digest.data()); + + return digest; + } +} + +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 std::vector &subkey_pkt_hash) +{ + initialized_or_throw(); + assert(subkey_pkt_hash.size() == rnp::Hash::size(PGP_HASH_SHA3_256)); + rnp_result_t res; + std::vector ecdh_keyshare; + std::vector hashed_ecdh_keyshare; + std::vector kyber_keyshare; + + if( ((enc->wrapped_sesskey.size() % 8) != 0) || (enc->wrapped_sesskey.size() < 16)) { + RNP_LOG("invalid wrapped AES key length (size is a multiple of 8 octets with 8 octets integrity check)"); + return RNP_ERROR_BAD_PARAMETERS; + } + + // Compute (eccKeyShare) := eccKem.decap(eccCipherText, eccPrivateKey) + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); + std::vector ecdh_encapsulated_keyshare = std::vector(enc->composite_ciphertext.data(), enc->composite_ciphertext.data() + ecdh_curve_ephemeral_size(curve)); + res = ecdh_key_->decapsulate(rng, ecdh_encapsulated_keyshare, ecdh_keyshare); + if(res) { + RNP_LOG("error when decrypting kyber-ecdh encrypted session key"); + return res; + } + hashed_ecdh_keyshare = hashed_ecc_keyshare(ecdh_keyshare, ecdh_encapsulated_keyshare, pk_alg_); + + // Compute (kyberKeyShare) := kyberKem.decap(kyberCipherText, kyberPrivateKey) + std::vector kyber_encapsulated_keyshare = std::vector(enc->composite_ciphertext.begin() + ecdh_curve_ephemeral_size(curve), enc->composite_ciphertext.end()); + kyber_keyshare = kyber_key_->decapsulate(rng, kyber_encapsulated_keyshare.data(), kyber_encapsulated_keyshare.size()); + if(res) { + RNP_LOG("error when decrypting kyber-ecdh encrypted session key"); + return res; + } + + // Compute KEK := multiKeyCombine(eccKeyShare, kyberKeyShare, fixedInfo) as defined in Section 4.2.2 + std::vector kek_vec; + auto kmac = rnp::KMAC256::create(); + kmac->compute(hashed_ecdh_keyshare, ecdh_encapsulated_keyshare, kyber_keyshare, kyber_encapsulated_keyshare, pk_alg(), subkey_pkt_hash, kek_vec); + Botan::SymmetricKey kek(kek_vec); + + // Compute sessionKey := AESKeyUnwrap(KEK, C) with AES-256 as per [RFC3394], aborting if the 64 bit integrity check fails + Botan::secure_vector tmp_out; + try { + tmp_out = Botan::rfc3394_keyunwrap(Botan::secure_vector(enc->wrapped_sesskey.begin(), enc->wrapped_sesskey.end()), kek); + } catch (const std::exception &e) { + RNP_LOG("Keyunwrap failed: %s", e.what()); + return RNP_ERROR_DECRYPT_FAILED; + } + + if(*out_len < tmp_out.size()) { + RNP_LOG("buffer for decryption result too small"); + return RNP_ERROR_DECRYPT_FAILED; + } + *out_len = tmp_out.size(); + memcpy(out, tmp_out.data(), *out_len); + + return RNP_SUCCESS; +} + +void +pgp_kyber_ecdh_composite_private_key_t::secure_clear() { + // private key buffer is stored in a secure_vector and will be securely erased by the destructor. + kyber_key_.reset(); + ecdh_key_.reset(); + is_initialized_ = false; +} + +std::vector +pgp_kyber_ecdh_composite_private_key_t::get_encoded() const { + initialized_or_throw(); + std::vector result; + std::vector ecdh_key_encoded = ecdh_key_->get_encoded(); + std::vector kyber_key_encoded = kyber_key_->get_encoded(); + + result.insert(result.end(), std::begin(ecdh_key_encoded), std::end(ecdh_key_encoded)); + result.insert(result.end(), std::begin(kyber_key_encoded), std::end(kyber_key_encoded)); + return result; +}; + + +pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); +} + +pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): + pk_alg_(pk_alg) +{ + parse_component_keys(key_encoded); +} + +pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg), + kyber_key_(kyber_key_encoded, pk_alg_to_kyber_id(pk_alg)), + ecdh_key_(ecdh_key_encoded, pk_alg_to_curve_id(pk_alg)) +{ + if(ecdh_curve_pubkey_size(pk_alg_to_curve_id(pk_alg)) != ecdh_key_encoded.size() + || kyber_pubkey_size(pk_alg_to_kyber_id(pk_alg)) != kyber_key_encoded.size()) + { + RNP_LOG("ecdh or kyber key length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + is_initialized_ = true; +} + +size_t +pgp_kyber_ecdh_composite_public_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) +{ + kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return ecdh_curve_pubkey_size(curve) + kyber_pubkey_size(kyber_param); +} + +void +pgp_kyber_ecdh_composite_public_key_t::parse_component_keys(std::vector key_encoded) { + if (key_encoded.size() != encoded_size(pk_alg_)) { + RNP_LOG("Kyber composite key format invalid: length mismatch"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + + kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg_); + pgp_curve_t ecdh_curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = ecdh_curve_pubkey_size(pk_alg_to_curve_id(pk_alg_)); + + kyber_key_ = pgp_kyber_public_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, kyber_param); + ecdh_key_ = ecdh_kem_public_key_t(key_encoded.data(), split_at, ecdh_curve); + + is_initialized_ = true; +} + +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, const std::vector &subkey_pkt_hash) +{ + initialized_or_throw(); + assert(subkey_pkt_hash.size() == rnp::Hash::size(PGP_HASH_SHA3_256)); + + rnp_result_t res; + std::vector ecdh_ciphertext; + std::vector ecdh_symmetric_key; + std::vector ecdh_hashed_symmetric_key; + + if((session_key_len % 8) != 0) { + RNP_LOG("AES key wrap requires a multiple of 8 octets as input key"); + return RNP_ERROR_BAD_PARAMETERS; + } + + // Compute (eccCipherText, eccKeyShare) := eccKem.encap(eccPublicKey) + res = ecdh_key_.encapsulate(rng, ecdh_ciphertext, ecdh_symmetric_key); + if(res) { + RNP_LOG("error when encapsulating with ECDH"); + return res; + } + ecdh_hashed_symmetric_key = hashed_ecc_keyshare(ecdh_symmetric_key, ecdh_ciphertext, pk_alg_); + + // Compute (kyberCipherText, kyberKeyShare) := kyberKem.encap(kyberPublicKey) + kyber_encap_result_t kyber_encap = kyber_key_.encapsulate(rng); + + // Compute KEK := multiKeyCombine(eccKeyShare, kyberKeyShare, fixedInfo) as defined in Section 4.2.2 + std::vector kek_vec; + auto kmac = rnp::KMAC256::create(); + kmac->compute(ecdh_hashed_symmetric_key, ecdh_ciphertext, kyber_encap.symmetric_key, kyber_encap.ciphertext, pk_alg(), subkey_pkt_hash, kek_vec); + Botan::SymmetricKey kek(kek_vec); + + // Compute C := AESKeyWrap(KEK, sessionKey) with AES-256 as per [RFC3394] that includes a 64 bit integrity check + try { + out->wrapped_sesskey = Botan::unlock(Botan::rfc3394_keywrap(Botan::secure_vector(session_key, session_key+session_key_len), kek)); + } catch (const std::exception &e) { + RNP_LOG("Keywrap failed: %s", e.what()); + return RNP_ERROR_ENCRYPT_FAILED; + } + + out->composite_ciphertext.assign(ecdh_ciphertext.begin(), ecdh_ciphertext.end()); + out->composite_ciphertext.insert(out->composite_ciphertext.end(), kyber_encap.ciphertext.begin(), kyber_encap.ciphertext.end()); + return RNP_SUCCESS; +} + +std::vector +pgp_kyber_ecdh_composite_public_key_t::get_encoded() const { + initialized_or_throw(); + std::vector result; + std::vector ecdh_key_encoded = ecdh_key_.get_encoded(); + std::vector kyber_key_encoded = kyber_key_.get_encoded(); + + result.insert(result.end(), std::begin(ecdh_key_encoded), std::end(ecdh_key_encoded)); + result.insert(result.end(), std::begin(kyber_key_encoded), std::end(kyber_key_encoded)); + return result; +}; + +bool +pgp_kyber_ecdh_composite_public_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized()) { + return false; + } + return(ecdh_key_.is_valid(rng) && kyber_key_.is_valid(rng)); +} + +bool +pgp_kyber_ecdh_composite_private_key_t::is_valid(rnp::RNG *rng) const { + if(!is_initialized()) { + return false; + } + return(ecdh_key_->is_valid(rng) && kyber_key_->is_valid(rng)); +} + + +rnp_result_t kyber_ecdh_validate_key(rnp::RNG *rng, const pgp_kyber_ecdh_key_t *key, bool secret) { + bool valid; + + valid = key->pub.is_valid(rng); + if(secret) { + valid = valid && key->priv.is_valid(rng); + } + if(!valid) { + return RNP_ERROR_GENERIC; + } + return RNP_SUCCESS; +} diff --git a/src/lib/crypto/kyber_ecdh_composite.h b/src/lib/crypto/kyber_ecdh_composite.h new file mode 100644 index 000000000..2f8c07be7 --- /dev/null +++ b/src/lib/crypto/kyber_ecdh_composite.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 MTG AG + * All rights reserved. + * + * This code is originally derived from software contributed to + * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and + * carried further by Ribose Inc (https://www.ribose.com). + * + * 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 HOLDERS 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_KYBER_ECDH_COMPOSITE_H_ +#define RNP_KYBER_ECDH_COMPOSITE_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include "crypto/kyber.h" +#include "crypto/kyber_common.h" +#include "crypto/ecdh.h" +#include "crypto/exdsa_ecdhkem.h" +#include + +struct pgp_kyber_ecdh_key_t; /* forward declaration */ + +class pgp_kyber_ecdh_composite_key_t { + +public: + virtual ~pgp_kyber_ecdh_composite_key_t() = 0; + + static rnp_result_t gen_keypair(rnp::RNG *rng, pgp_kyber_ecdh_key_t *key, pgp_pubkey_alg_t alg); + + static size_t ecdh_curve_privkey_size(pgp_curve_t curve); + static size_t ecdh_curve_pubkey_size(pgp_curve_t curve); + static size_t ecdh_curve_ephemeral_size(pgp_curve_t curve); + static size_t ecdh_curve_keyshare_size(pgp_curve_t curve); + static pgp_curve_t pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg); + static kyber_parameter_e pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg); + + bool is_initialized() const { + return is_initialized_; + } + +protected: + bool is_initialized_ = false; + void initialized_or_throw() const; +}; + +typedef struct pgp_kyber_ecdh_encrypted_t { + std::vector composite_ciphertext; + std::vector wrapped_sesskey; + + static size_t composite_ciphertext_size(pgp_pubkey_alg_t pk_alg) { + return kyber_ciphertext_size(pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pk_alg)) + + pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size(pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(pk_alg)); + } +} pgp_kyber_ecdh_encrypted_t; + +class pgp_kyber_ecdh_composite_private_key_t : public pgp_kyber_ecdh_composite_key_t { + public: + pgp_kyber_ecdh_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_private_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_private_key_t& operator=(const pgp_kyber_ecdh_composite_private_key_t& other); + pgp_kyber_ecdh_composite_private_key_t() = default; + + + rnp_result_t decrypt(rnp::RNG *rng, uint8_t *out, size_t *out_len, const pgp_kyber_ecdh_encrypted_t *enc, const std::vector &subkey_pkt_hash); + + bool is_valid(rnp::RNG *rng) const; + std::vector get_encoded() const; + + pgp_pubkey_alg_t pk_alg() const + { + return pk_alg_; + } + + void secure_clear(); + + static size_t encoded_size(pgp_pubkey_alg_t pk_alg); + + private: + void parse_component_keys(std::vector key_encoded); + + pgp_pubkey_alg_t pk_alg_; + + /* kyber part */ + std::unique_ptr kyber_key_; + + /* ecc part*/ + std::unique_ptr ecdh_key_; +}; + + +class pgp_kyber_ecdh_composite_public_key_t : public pgp_kyber_ecdh_composite_key_t { + public: + pgp_kyber_ecdh_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_public_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_public_key_t() = default; + + bool operator==(const pgp_kyber_ecdh_composite_public_key_t &rhs) const + { + return (pk_alg_ == rhs.pk_alg_) && (kyber_key_ == rhs.kyber_key_) && (ecdh_key_ == rhs.ecdh_key_); + } + + rnp_result_t encrypt(rnp::RNG *rng, pgp_kyber_ecdh_encrypted_t *out, const uint8_t *in, size_t in_len, const std::vector &subkey_pkt_hash); + + bool is_valid(rnp::RNG *rng) const; + std::vector get_encoded() const; + + pgp_pubkey_alg_t pk_alg() const + { + return pk_alg_; + } + + static size_t encoded_size(pgp_pubkey_alg_t pk_alg); + + private: + void parse_component_keys(std::vector key_encoded); + + pgp_pubkey_alg_t pk_alg_; + + /* kyber part */ + pgp_kyber_public_key_t kyber_key_; + + /* ecc part*/ + ecdh_kem_public_key_t ecdh_key_; +}; + +typedef struct pgp_kyber_ecdh_key_t { + pgp_kyber_ecdh_composite_private_key_t priv; + pgp_kyber_ecdh_composite_public_key_t pub; +} pgp_kyber_ecdh_key_t; + +rnp_result_t kyber_ecdh_validate_key(rnp::RNG *rng, const pgp_kyber_ecdh_key_t *key, bool secret); + +#endif diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 9288dafea..f839aba68 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -196,11 +196,15 @@ signature_calculate(pgp_signature_t & sig, break; } #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: ret = seckey.dilithium_exdsa.priv.sign(&ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); break; @@ -309,11 +313,15 @@ signature_validate(const pgp_signature_t & sig, ret = RNP_ERROR_SIGNATURE_INVALID; break; #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: ret = key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); break; diff --git a/src/lib/crypto/x25519.cpp b/src/lib/crypto/x25519.cpp index ffa38308f..e68f25288 100644 --- a/src/lib/crypto/x25519.cpp +++ b/src/lib/crypto/x25519.cpp @@ -163,4 +163,4 @@ x25519_validate_key_native(rnp::RNG *rng, const pgp_x25519_key_t *key, bool secr // check key returns true for successful check return (valid_pub && valid_priv) ? RNP_SUCCESS : RNP_ERROR_BAD_PARAMETERS; -} \ No newline at end of file +} diff --git a/src/lib/crypto/x25519.h b/src/lib/crypto/x25519.h index b0a22ba83..a24b5922f 100644 --- a/src/lib/crypto/x25519.h +++ b/src/lib/crypto/x25519.h @@ -57,4 +57,4 @@ rnp_result_t x25519_native_decrypt(rnp::RNG * rng, rnp_result_t x25519_validate_key_native(rnp::RNG *rng, const pgp_x25519_key_t *key, bool secret); -#endif \ No newline at end of file +#endif diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index 949f8c3cd..bc2c428d1 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -60,6 +60,12 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_X25519, "X25519"}, #endif #if defined(ENABLE_PQC) + {PGP_PKA_KYBER768_X25519, "Kyber-X25519"}, + //{PGP_PKA_KYBER1024_X448, "Kyber-X448"}, + {PGP_PKA_KYBER768_P256, "Kyber-P256"}, + {PGP_PKA_KYBER1024_P384, "Kyber-P384"}, + {PGP_PKA_KYBER768_BP256, "Kyber-BP256"}, + {PGP_PKA_KYBER1024_BP384, "Kyber-BP384"}, {PGP_PKA_DILITHIUM3_ED25519, "Dilithium-ED25519"}, //{PGP_PKA_DILITHIUM5_ED448, "Dilithium-ED448"}, {PGP_PKA_DILITHIUM3_P256, "Dilithium-P256"}, @@ -273,11 +279,26 @@ get_numbits(const rnp_keygen_crypto_params_t *crypto) case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: return crypto->elgamal.key_bitlen; #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return pgp_kyber_ecdh_composite_public_key_t::encoded_size(crypto->key_alg) * 8; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return pgp_dilithium_exdsa_composite_public_key_t::encoded_size(crypto->key_alg) * 8; #endif @@ -326,6 +347,40 @@ keygen_primary_merge_defaults(rnp_keygen_primary_desc_t &desc) } } +#if defined(ENABLE_PQC) +static bool +pgp_check_key_hash_requirements(rnp_keygen_crypto_params_t &crypto) +{ + switch (crypto.key_alg) { + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + if (!sphincsplus_hash_allowed( + crypto.key_alg, crypto.sphincsplus.param, crypto.hash_alg)) { + return false; + } + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + if (!dilithium_hash_allowed(crypto.hash_alg)) { + return false; + } + break; + default: + break; + } + return true; +} +#endif + bool pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, bool merge_defaults, diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 40948be6c..c35cf48d8 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -208,11 +208,27 @@ pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) return PGP_KF_ENCRYPT; #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return PGP_KF_ENCRYPT; + + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); #endif @@ -1847,15 +1863,8 @@ pgp_key_t::is_signer(const pgp_subsig_t &sig) const return sig.sig.keyfp() == fp(); } if (!sig.sig.has_keyid()) { - return false || ( -#if defined(ENABLE_CRYPTO_REFRESH) - (version() == PGP_V6) // v6 packets MUST NOT include this subpacket, therefore return true for v6 -#else - false -#endif - ); + return false; } - return keyid() == sig.sig.keyid(); } @@ -2755,6 +2764,21 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) return true; } +#if defined(ENABLE_PQC) +std::vector +pgp_key_t::subkey_pkt_hash() const +{ + const pgp_hash_alg_t pk_pkt_hash_alg = PGP_HASH_SHA3_256; + std::vector out(rnp::Hash::size(pk_pkt_hash_alg)); + + auto pk_pkt_hash = rnp::Hash::create(pk_pkt_hash_alg); + pk_pkt_hash->add(rawpkt_.raw); + pk_pkt_hash->finish(out.data()); + + return out; +} +#endif + pgp_curve_t pgp_key_material_t::get_curve() const { @@ -2800,6 +2824,30 @@ pgp_key_material_t::bits() const const ec_curve_desc_t *curve_desc = get_curve_desc(get_curve()); return curve_desc ? curve_desc->bitlen : 0; } +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return 8 * kyber_ecdh.pub.get_encoded().size(); /* public key length */ + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_BP384: + return 8 * dilithium_exdsa.pub.get_encoded().size(); /* public key length*/ +#endif default: RNP_LOG("Unknown public key alg: %d", (int) alg); return 0; diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 8253e3347..89e66f276 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -571,6 +571,10 @@ struct pgp_key_t { bool merge(const pgp_key_t &src); /** @brief Merge subkey with the source, i.e. add all new signatures */ bool merge(const pgp_key_t &src, pgp_key_t *primary); + +#if defined(ENABLE_PQC) + std::vector subkey_pkt_hash() const; +#endif }; namespace rnp { diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index eed0f138a..976798f4a 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -167,6 +167,12 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_X25519, RNP_ALGNAME_X25519}, #endif #if defined(ENABLE_PQC) + {PGP_PKA_KYBER768_X25519, RNP_ALGNAME_KYBER768_X25519}, + //{PGP_PKA_KYBER1024_X448, RNP_ALGNAME_KYBER1024_X448}, + {PGP_PKA_KYBER768_P256, RNP_ALGNAME_KYBER768_P256}, + {PGP_PKA_KYBER1024_P384, RNP_ALGNAME_KYBER1024_P384}, + {PGP_PKA_KYBER768_BP256, RNP_ALGNAME_KYBER768_BP256}, + {PGP_PKA_KYBER1024_BP384, RNP_ALGNAME_KYBER1024_BP384}, {PGP_PKA_DILITHIUM3_ED25519, RNP_ALGNAME_DILITHIUM3_ED25519}, //{PGP_PKA_DILITHIUM5_ED448, RNP_ALGNAME_DILITHIUM5_ED448}, {PGP_PKA_DILITHIUM3_P256, RNP_ALGNAME_DILITHIUM3_P256}, @@ -339,6 +345,12 @@ pub_alg_supported(int alg) case PGP_PKA_ED25519: #endif #if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + //case PGP_PKA_KYBER1024_X448: + case PGP_PKA_KYBER768_P256: + case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER768_BP256: + case PGP_PKA_KYBER1024_BP384: case PGP_PKA_DILITHIUM3_ED25519: //case PGP_PKA_DILITHIUM5_ED448: case PGP_PKA_DILITHIUM3_P256: @@ -5244,11 +5256,26 @@ default_key_flags(pgp_pubkey_alg_t alg, bool subkey) return PGP_KF_ENCRYPT; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return PGP_KF_ENCRYPT; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); #endif @@ -7470,11 +7497,26 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) return RNP_SUCCESS; /* TODO */ #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return RNP_SUCCESS; /* TODO */ + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return RNP_SUCCESS; /* TODO */ #endif @@ -7508,6 +7550,19 @@ add_json_secret_mpis(json_object *jso, pgp_key_t *key) case PGP_PKA_ED25519: case PGP_PKA_X25519: return RNP_SUCCESS; /* TODO */ +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return RNP_SUCCESS; /* TODO */ #endif default: return RNP_ERROR_NOT_SUPPORTED; @@ -7547,11 +7602,15 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) return RNP_SUCCESS; /* TODO */ #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return RNP_SUCCESS; /* TODO */ #endif @@ -7778,11 +7837,26 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_SUCCESS; /* TODO */ #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + return RNP_SUCCESS; /* TODO */ + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return RNP_SUCCESS; /* TODO */ #endif diff --git a/src/lib/types.h b/src/lib/types.h index 8226b73f9..cf32db2d9 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -193,6 +193,7 @@ typedef struct pgp_key_material_t { 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 */ #endif @@ -234,6 +235,9 @@ typedef struct pgp_encrypted_material_t { #if defined(ENABLE_CRYPTO_REFRESH) pgp_x25519_encrypted_t x25519; // non-trivial type cannot be member in union #endif +#if defined(ENABLE_PQC) + pgp_kyber_ecdh_encrypted_t kyber_ecdh; // non-trivial type cannot be member in union +#endif } pgp_encrypted_material_t; typedef struct pgp_s2k_t { diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index 114ce99bf..e968cca48 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -748,11 +748,27 @@ rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + hash->add(key->kyber_ecdh.pub.get_encoded()); + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: hash->add(key->dilithium_exdsa.pub.get_encoded()); break; diff --git a/src/librepgp/stream-common.cpp b/src/librepgp/stream-common.cpp index 6be09cc0e..6a7bae3cb 100644 --- a/src/librepgp/stream-common.cpp +++ b/src/librepgp/stream-common.cpp @@ -1218,6 +1218,14 @@ bool have_pkesk_checksum(pgp_pubkey_alg_t alg) switch(alg) { case PGP_PKA_X25519: +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + //case PGP_PKA_KYBER1024_X448: + case PGP_PKA_KYBER768_P256: + case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER768_BP256: + case PGP_PKA_KYBER1024_BP384: +#endif return false; default: return true; diff --git a/src/librepgp/stream-ctx.cpp b/src/librepgp/stream-ctx.cpp index 5a2d388e1..0aaf9c99f 100644 --- a/src/librepgp/stream-ctx.cpp +++ b/src/librepgp/stream-ctx.cpp @@ -79,4 +79,4 @@ rnp_ctx_t::pkeskv6_capable() { } return true; } -#endif \ No newline at end of file +#endif diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 1e397696c..a73188d67 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -148,6 +148,12 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_X25519, "X25519"}, #endif #if defined(ENABLE_PQC) + {PGP_PKA_KYBER768_X25519, "Kyber768 + X25519"}, + //{PGP_PKA_KYBER1024_X448, "Kyber1024 + X448"}, + {PGP_PKA_KYBER768_P256, "Kyber768 + NIST P-256"}, + {PGP_PKA_KYBER1024_P384, "Kyber1024 + NIST P-384"}, + {PGP_PKA_KYBER768_BP256, "Kyber768 + Brainpool256"}, + {PGP_PKA_KYBER1024_BP384, "Kyber1024 + Brainpool384"}, {PGP_PKA_DILITHIUM3_ED25519, "Dilithium3 + ED25519"}, //{PGP_PKA_DILITHIUM5_ED448, "Dilithium + X448"}, {PGP_PKA_DILITHIUM3_P256, "Dilithium3 + NIST P-256"}, @@ -817,11 +823,15 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: dst_print_vec(dst, "dilithium-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); break; @@ -929,11 +939,30 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + dst_print_vec(dst, + "kyber-ecdh encoded pubkey", + key.material.kyber_ecdh.pub.get_encoded(), + ctx->dump_mpi); + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: dst_print_vec(dst, "dilithium-ecdsa/eddsa encodced pubkey", key.material.dilithium_exdsa.pub.get_encoded(), ctx->dump_mpi); break; @@ -1107,6 +1136,21 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d dst_print_vec(dst, "x25519 ephemeral public key", material.x25519.eph_key, ctx->dump_mpi); dst_print_vec(dst, "x25519 encrypted session key", material.x25519.enc_sess_key, ctx->dump_mpi); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + dst_print_vec(dst, "kyber-ecdh composite ciphertext", material.kyber_ecdh.composite_ciphertext, ctx->dump_mpi); + dst_print_vec(dst, "kyber-ecdh wrapped session key", material.kyber_ecdh.wrapped_sesskey, ctx->dump_mpi); + break; #endif default: dst_printf(dst, "unknown public key algorithm\n"); @@ -1915,11 +1959,15 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: /* TODO */ break; @@ -2044,11 +2092,27 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + // TODO + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: /* TODO */ break; @@ -2187,6 +2251,20 @@ stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_obj case PGP_PKA_X25519: /* TODO */ break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + // TODO + break; #endif default:; } diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index b001cc26f..be8397b1f 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -657,11 +657,32 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) } #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + 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 kyber-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]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; 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())) { @@ -803,11 +824,27 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + body.add(key.material.kyber_ecdh.priv.get_encoded()); + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: body.add(key.material.dilithium_exdsa.priv.get_encoded()); break; @@ -966,11 +1003,27 @@ forget_secret_key_fields(pgp_key_material_t *key) break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + key->kyber_ecdh.priv.secure_clear(); + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: key->dilithium_exdsa.priv.secure_clear(); break; @@ -1434,11 +1487,32 @@ pgp_key_pkt_t::parse(pgp_source_t &src) } #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + 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 kyber-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]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: tmpbuf.resize(pgp_dilithium_exdsa_composite_public_key_t::encoded_size(alg)); if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { @@ -1594,11 +1668,27 @@ void pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t & hbod break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + hbody.add(material.kyber_ecdh.pub.get_encoded()); + break; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: hbody.add(material.dilithium_exdsa.pub.get_encoded()); break; diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 6aaff3434..054369437 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -1242,6 +1242,35 @@ pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const } break; } +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: { + uint8_t wrapped_key_len = 0; + material.kyber_ecdh.composite_ciphertext.resize(pgp_kyber_ecdh_encrypted_t::composite_ciphertext_size(alg)); + if (!pkt.get(material.kyber_ecdh.composite_ciphertext.data(), material.kyber_ecdh.composite_ciphertext.size())) { + RNP_LOG("failed to get kyber-ecdh ciphertext"); + return false; + } + if (!pkt.get(wrapped_key_len)) { + RNP_LOG("failed to get kyber-ecdh wrapped session key length"); + return false; + } + material.kyber_ecdh.wrapped_sesskey.resize(wrapped_key_len); + if (!pkt.get(material.kyber_ecdh.wrapped_sesskey.data(), material.kyber_ecdh.wrapped_sesskey.size())) { + RNP_LOG("failed to get kyber-ecdh session key"); + return false; + } + break; + } #endif default: RNP_LOG("unknown pk alg %d", (int) alg); @@ -1283,6 +1312,22 @@ pgp_pk_sesskey_t::write_material(const pgp_encrypted_material_t &material) pktbody.add_byte(static_cast(material.x25519.enc_sess_key.size())); pktbody.add(material.x25519.enc_sess_key); break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + pktbody.add(material.kyber_ecdh.composite_ciphertext); + pktbody.add_byte(static_cast(material.kyber_ecdh.wrapped_sesskey.size())); + pktbody.add(material.kyber_ecdh.wrapped_sesskey); + break; #endif default: RNP_LOG("Unknown pk alg: %d", (int) alg); diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 44dad974d..e30968ebc 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1601,6 +1601,27 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, return false; } break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: { + pgp_key_t key(*seckey, true); /* make public-key `pgp_key_t` object from seckey */ + declen = decbuf.size(); + err = keymaterial->kyber_ecdh.priv.decrypt(&ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh, key.subkey_pkt_hash()); + if (err != RNP_SUCCESS) { + RNP_LOG("Kyber ECC decryption failure"); + return false; + } + break; + } #endif default: RNP_LOG("unsupported public key algorithm %d\n", seckey->alg); diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index b5a8b5d69..c2dbcfc2f 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1565,11 +1565,15 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const } #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: material.dilithium_exdsa.sig.resize(pgp_dilithium_exdsa_signature_t::composite_signature_size(palg)); if (!pkt.get(material.dilithium_exdsa.sig.data(), material.dilithium_exdsa.sig.size())) { @@ -1665,11 +1669,15 @@ pgp_signature_t::write_material(const pgp_signature_material_t &material) break; #endif #if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_ED25519: + [[fallthrough]]; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + case PGP_PKA_DILITHIUM3_P256: + [[fallthrough]]; + case PGP_PKA_DILITHIUM5_P384: + [[fallthrough]]; + case PGP_PKA_DILITHIUM3_BP256: + [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: pktbody.add(material.dilithium_exdsa.sig); break; diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 14738e2f8..990fb057e 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -716,6 +716,28 @@ encrypted_add_recipient(pgp_write_handler_t *handler, return ret; } break; +#endif +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + ret = userkey->material().kyber_ecdh.pub.encrypt(&handler->ctx->ctx->rng, + &material.kyber_ecdh, + enckey.data(), + enckey_len, + userkey->subkey_pkt_hash()); + if (ret) { + RNP_LOG("Kyber ECC Encrypt failed"); + return ret; + } + break; #endif default: RNP_LOG("unsupported alg: %d", (int) userkey->alg()); diff --git a/src/rnpkeys/tui.cpp b/src/rnpkeys/tui.cpp index 2d7d7abea..cd2272ca6 100644 --- a/src/rnpkeys/tui.cpp +++ b/src/rnpkeys/tui.cpp @@ -237,11 +237,20 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) "\t(17) DSA + RSA\n" // TODO: See #584 "\t(19) ECDSA + ECDH\n" #if defined(ENABLE_CRYPTO_REFRESH) - "\t(21) EDDSA + ECDH (v6 key) \n" + "\t(21) EDDSA + ECDH (v6 key) \n" + "\t(22) EDDSA + ECDH (v4 key) \n" +#else + "\t(22) EDDSA + ECDH\n" #endif - "\t(22) EDDSA + ECDH (v4 key) \n" #if defined(ENABLE_CRYPTO_REFRESH) "\t(23) ED25519 + X25519 (v6 key) \n" +#endif +#if defined(ENABLE_PQC) + "\t(25) (Dilithium3 + Ed25519) + (Kyber768 + X25519)\n" + "\t(27) (Dilithium3 + ECDSA-NIST-P-256) + (Kyber768 + ECDH-NIST-P-256)\n" + "\t(28) (Dilithium5 + ECDSA-NIST-P-384) + (Kyber1024 + ECDH-NIST-P-384)\n" + "\t(29) (Dilithium3 + ECDSA-brainpoolP256r1) + (Kyber768 + ECDH-brainpoolP256r1)\n" + "\t(30) (Dilithium5 + ECDSA-brainpoolP384r1) + (Kyber1024 + ECDH-brainpoolP384r1)\n" #endif "\t(99) SM2\n" "> "); @@ -313,6 +322,38 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) cfg.set_str(CFG_KG_V6_KEY, "true"); break; } +#endif +#if defined(ENABLE_PQC) + case 25: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DILITHIUM3_ED25519); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_X25519); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 27: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DILITHIUM3_P256); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_P256); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 28: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DILITHIUM5_P384); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_P384); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 29: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DILITHIUM3_BP256); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_BP256); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 30: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_DILITHIUM5_BP384); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_BP384); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; #endif case 99: { cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SM2); @@ -347,6 +388,14 @@ rnpkeys_ask_generate_params_subkey(rnp_cfg &cfg, FILE *input_fp) "\t(18) ECDH\n" "\t(19) ECDSA\n" "\t(22) EDDSA\n" +#if defined(ENABLE_PQC) + "\t(25) Kyber768 + X25519\n" + "\t(26) Kyber1024 + X448\n" + "\t(27) Kyber768 + ECDH-NIST-P-256\n" + "\t(28) Kyber1024 + ECDH-NIST-P-384\n" + "\t(29) Kyber768 + ECDH-brainpoolP256r1\n" + "\t(30) Kyber1024 + ECDH-brainpoolP384r1\n" +#endif "\t(99) SM2" "> "); if (!rnp_secure_get_long_from_fd(input_fp, option, false)) { @@ -403,6 +452,26 @@ rnpkeys_ask_generate_params_subkey(rnp_cfg &cfg, FILE *input_fp) cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_EDDSA); break; } +#if defined(ENABLE_PQC) + case 25: + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_X25519); + break; + case 26: + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_X448); + break; + case 27: + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_P256); + break; + case 28: + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_P384); + break; + case 29: + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_BP256); + break; + case 30: + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_BP384); + break; +#endif case 99: { cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_SM2); if (!cfg.has(CFG_KG_HASH)) { diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 17c3e6e5d..6de6b0622 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -603,6 +603,46 @@ TEST_F(rnp_tests, test_dsa_verify_negative) } #if defined(ENABLE_PQC) +TEST_F(rnp_tests, kyber_ecdh_roundtrip) +{ + pgp_pubkey_alg_t algs[] = {PGP_PKA_KYBER768_X25519, + /* PGP_PKA_KYBER1024_X448, */ // X448 not yet implemented + PGP_PKA_KYBER1024_P384, + 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); + + 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 < ARRAY_SIZE(algs); i++) { + rnp_keygen_crypto_params_t key_desc; + key_desc.key_alg = algs[i]; + key_desc.hash_alg = PGP_HASH_SHA512; + key_desc.ctx = &global_ctx; + + 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_key_t key(key_pkt); + assert_rnp_success(key_pkt.material.kyber_ecdh.pub.encrypt(&global_ctx.rng, &enc, plaintext, plaintext_len, key.subkey_pkt_hash())); + assert_rnp_success(key_pkt.material.kyber_ecdh.priv.decrypt(&global_ctx.rng, result, &result_len, &enc, key.subkey_pkt_hash())); + + assert_int_equal(plaintext_len, result_len); + assert_int_equal(memcmp(plaintext, result, result_len), 0); + } +} + TEST_F(rnp_tests, dilithium_exdsa_signverify_success) { uint8_t message[64]; diff --git a/src/tests/ffi.cpp b/src/tests/ffi.cpp index 8a4429e79..526edd6f1 100644 --- a/src/tests/ffi.cpp +++ b/src/tests/ffi.cpp @@ -3115,7 +3115,7 @@ TEST_F(rnp_tests, test_ffi_supported_features) crypto_refresh_opt = 2; // X25519 + ED25519 #endif #if defined(ENABLE_PQC) - pqc_opt = 5; // dilithium+ecc variants + pqc_opt = 10; // kyber+ecc and dilithium+ecc variants #endif assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + pqc_opt + crypto_refresh_opt)); rnp_buffer_destroy(features); diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp index 856e1f957..1756389f9 100644 --- a/src/tests/pqc.cpp +++ b/src/tests/pqc.cpp @@ -105,4 +105,4 @@ TEST_F(rnp_tests, test_dilithium_exdsa_direct) } } -#endif \ No newline at end of file +#endif From 2ab6c04e94382e53cb1a1efc852d140b4b179024 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 13 Jun 2023 13:16:48 +0200 Subject: [PATCH 10/20] add check for PKESK v3 and XX25519 for AES; align pgp_key_t::curve() and pgp_key_material_t::curve() --- src/lib/pgp-key.cpp | 10 ++++++++-- src/lib/types.h | 2 +- src/librepgp/stream-parse.cpp | 12 ++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index c35cf48d8..4c4820ee9 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -1192,6 +1192,12 @@ pgp_key_t::curve() const 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; } @@ -2780,7 +2786,7 @@ pgp_key_t::subkey_pkt_hash() const #endif pgp_curve_t -pgp_key_material_t::get_curve() const +pgp_key_material_t::curve() const { switch (alg) { case PGP_PKA_ECDH: [[fallthrough]]; @@ -2821,7 +2827,7 @@ pgp_key_material_t::bits() const #endif case PGP_PKA_SM2: { /* handle ecc cases */ - const ec_curve_desc_t *curve_desc = get_curve_desc(get_curve()); + const ec_curve_desc_t *curve_desc = get_curve_desc(curve()); return curve_desc ? curve_desc->bitlen : 0; } #if defined(ENABLE_PQC) diff --git a/src/lib/types.h b/src/lib/types.h index cf32db2d9..509f3c65a 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -197,7 +197,7 @@ typedef struct pgp_key_material_t { pgp_dilithium_exdsa_key_t dilithium_exdsa; /* non-trivial type, cannot be in a union */ #endif - pgp_curve_t get_curve() const; /* return curve for EC algorithms, PGP_CURVE_UNKNOWN otherwise */ + 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); diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index e30968ebc..cf3266a28 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1528,6 +1528,18 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, return false; } + /* Crypto Refresh: For X25519/X448 PKESKv3, AES is mandated */ + if(sesskey->alg == PGP_PKA_X25519 && sesskey->version == PGP_PKSK_V3) { + switch(sesskey->salg) { + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + break; + default: + RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric algorithm that is not AES."); + return false; + } + } #endif rnp::secure_array decbuf; From 4d0fc64f23509bea4269075a7483309b85cf659e Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Wed, 14 Jun 2023 14:35:21 +0200 Subject: [PATCH 11/20] correction of code formatting manual correction of code formatting that still deviates --- include/repgp/repgp_def.h | 54 +- include/rnp/rnp.h | 2 +- src/lib/crypto.cpp | 21 +- src/lib/crypto/dilithium.cpp | 17 +- src/lib/crypto/dilithium.h | 12 +- src/lib/crypto/dilithium_common.cpp | 69 +-- src/lib/crypto/dilithium_common.h | 1 - src/lib/crypto/dilithium_exdsa_composite.cpp | 389 +++++++------ src/lib/crypto/dilithium_exdsa_composite.h | 111 ++-- src/lib/crypto/ec.cpp | 82 +-- src/lib/crypto/ec.h | 8 +- src/lib/crypto/ecdh.cpp | 57 +- src/lib/crypto/ecdh.h | 9 +- src/lib/crypto/ecdsa.h | 2 +- src/lib/crypto/ed25519.cpp | 43 +- src/lib/crypto/ed25519.h | 19 +- src/lib/crypto/exdsa_ecdhkem.cpp | 187 ++++--- src/lib/crypto/exdsa_ecdhkem.h | 92 ++-- src/lib/crypto/hkdf.cpp | 4 +- src/lib/crypto/hkdf_botan.cpp | 9 +- src/lib/crypto/kmac.cpp | 9 +- src/lib/crypto/kmac.hpp | 22 +- src/lib/crypto/kmac_botan.cpp | 19 +- src/lib/crypto/kmac_botan.hpp | 8 +- src/lib/crypto/kyber.cpp | 23 +- src/lib/crypto/kyber.h | 25 +- src/lib/crypto/kyber_common.cpp | 116 ++-- src/lib/crypto/kyber_ecdh_composite.cpp | 541 +++++++++++-------- src/lib/crypto/kyber_ecdh_composite.h | 118 ++-- src/lib/crypto/rng.cpp | 3 +- src/lib/crypto/rng.h | 2 +- src/lib/crypto/signatures.cpp | 17 +- src/lib/crypto/signatures.h | 4 +- src/lib/crypto/x25519.cpp | 97 ++-- src/lib/crypto/x25519.h | 27 +- src/lib/pgp-key.cpp | 44 +- src/lib/pgp-key.h | 6 +- src/lib/rnp.cpp | 13 +- src/lib/types.h | 28 +- src/librekey/key_store_kbx.cpp | 3 +- src/librepgp/stream-common.cpp | 32 +- src/librepgp/stream-common.h | 2 +- src/librepgp/stream-ctx.cpp | 8 +- src/librepgp/stream-ctx.h | 8 +- src/librepgp/stream-dump.cpp | 30 +- src/librepgp/stream-key.cpp | 27 +- src/librepgp/stream-packet.cpp | 61 ++- src/librepgp/stream-packet.h | 6 +- src/librepgp/stream-parse.cpp | 95 ++-- src/librepgp/stream-sig.cpp | 27 +- src/librepgp/stream-sig.h | 4 +- src/librepgp/stream-write.cpp | 76 +-- src/librepgp/v2_seipd.h | 4 +- src/rnp/fficli.cpp | 10 +- src/rnp/rnpcfg.h | 9 +- src/rnpkeys/tui.cpp | 18 +- src/tests/cipher.cpp | 29 +- src/tests/exdsa_ecdhkem.cpp | 46 +- src/tests/ffi-key.cpp | 53 +- src/tests/ffi.cpp | 3 +- src/tests/hkdf.cpp | 22 +- src/tests/pqc.cpp | 41 +- 62 files changed, 1663 insertions(+), 1261 deletions(-) diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index d96b45447..95bf1f5bd 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -97,10 +97,10 @@ /* Size of the fingerprint */ #define PGP_FINGERPRINT_V4_SIZE 20 #if defined(ENABLE_CRYPTO_REFRESH) - #define PGP_FINGERPRINT_V6_SIZE 32 - #define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V6_SIZE +#define PGP_FINGERPRINT_V6_SIZE 32 +#define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V6_SIZE #else - #define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V4_SIZE +#define PGP_MAX_FINGERPRINT_SIZE PGP_FINGERPRINT_V4_SIZE #endif #define PGP_MAX_FINGERPRINT_HEX_SIZE (PGP_MAX_FINGERPRINT_SIZE * 2) + 1 @@ -118,7 +118,7 @@ /* V6 Signature Salt */ #if defined(ENABLE_CRYPTO_REFRESH) - #define PGP_MAX_SALT_SIZE_V6_SIG 32 +#define PGP_MAX_SALT_SIZE_V6_SIG 32 #endif /** Old Packet Format Lengths. @@ -228,22 +228,31 @@ typedef enum : uint8_t { #if defined(ENABLE_PQC) /* PQC-ECC composite */ - PGP_PKA_KYBER768_X25519 = 29, /* Kyber768 + X25519 from draft-wussler-openpgp-pqc-01 */ - //PGP_PKA_KYBER1024_X448 = 30, /* Kyer1024 + X448 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_KYBER768_P256 = 31, /* Kyber768 + NIST P-256 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_KYBER1024_P384 = 32, /* Kyber1024 + NIST P-384 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_KYBER768_BP256 = 33, /* Kyber768 + Brainpool P256r1 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_KYBER1024_BP384 = 34, /* Kyber1024 + Brainpool P384r1 from draft-wussler-openpgp-pqc-01 */ - - PGP_PKA_DILITHIUM3_ED25519 = 35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-01 */ - //PGP_PKA_DILITHIUM5_ED448 = 36, /* Dilithium 5 + Ed448 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_DILITHIUM3_P256 = 37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_DILITHIUM5_P384 = 38, /* Dilithium 5 + ECDSA-NIST-P-384 from draft-wussler-openpgp-pqc-00*/ - PGP_PKA_DILITHIUM3_BP256 = 39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_DILITHIUM5_BP384 = 40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER768_X25519 = 29, /* Kyber768 + X25519 from draft-wussler-openpgp-pqc-01 */ + // PGP_PKA_KYBER1024_X448 = 30, /* Kyer1024 + X448 from + // draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER768_P256 = 31, /* Kyber768 + NIST P-256 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER1024_P384 = 32, /* Kyber1024 + NIST P-384 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER768_BP256 = + 33, /* Kyber768 + Brainpool P256r1 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER1024_BP384 = + 34, /* Kyber1024 + Brainpool P384r1 from draft-wussler-openpgp-pqc-01 */ + + PGP_PKA_DILITHIUM3_ED25519 = + 35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-01 */ + // PGP_PKA_DILITHIUM5_ED448 = 36, /* Dilithium 5 + Ed448 from + // draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM3_P256 = + 37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM5_P384 = + 38, /* Dilithium 5 + ECDSA-NIST-P-384 from draft-wussler-openpgp-pqc-00*/ + PGP_PKA_DILITHIUM3_BP256 = + 39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_DILITHIUM5_BP384 = + 40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-01 */ #endif - PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ + PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ PGP_PKA_PRIVATE00 = 100, /* Private/Experimental Algorithm */ PGP_PKA_PRIVATE01 = 101, /* Private/Experimental Algorithm */ PGP_PKA_PRIVATE02 = 102, /* Private/Experimental Algorithm */ @@ -431,7 +440,7 @@ typedef enum { /* PGP_SIG_SUBPKT_INTENDED_RECIPIENT_FINGERPRINT = 35, */ PGP_SIG_SUBPKT_PREFERRED_AEAD_CIPHERSUITES = 39, #endif - PGP_SIG_SUBPKT_PRIVATE_100 = 100, /* private/experimental subpackets */ + PGP_SIG_SUBPKT_PRIVATE_100 = 100, /* private/experimental subpackets */ PGP_SIG_SUBPKT_PRIVATE_101 = 101, PGP_SIG_SUBPKT_PRIVATE_102 = 102, PGP_SIG_SUBPKT_PRIVATE_103 = 103, @@ -488,10 +497,7 @@ typedef enum { PGP_PKSK_V6 = 6 #endif } pgp_pkesk_version_t; -typedef enum { - PGP_SE_IP_DATA_V1 = 1, - PGP_SE_IP_DATA_V2 = 2 -} pgp_seipd_version_t; +typedef enum { PGP_SE_IP_DATA_V1 = 1, PGP_SE_IP_DATA_V2 = 2 } pgp_seipd_version_t; /** Version. * OpenPGP has two different protocol versions: version 3 and version 4. @@ -506,7 +512,7 @@ typedef enum { PGP_V3 = 3, /* Version 3 */ PGP_V4 = 4, /* Version 4 */ #if defined(ENABLE_CRYPTO_REFRESH) - PGP_V6 = 6 /* Version 6 (crypto refresh) */ + PGP_V6 = 6 /* Version 6 (crypto refresh) */ #endif } pgp_version_t; diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 497e22d06..50584a248 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -2995,7 +2995,7 @@ RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_h /** * @brief Enables the creation of PKESK v6 (instead of v3) which results in the use of SEIPDv2. * The actually created version depends on the capabilities of the list of recipients. - * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any time. + * NOTE: This is an experimental feature and this function can be replaced (or removed) at any time. * * @param op opaque encrypting context. Must be allocated and initialized. * @return RNP_SUCCESS or errorcode if failed. diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index 71a108dad..74eb34400 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -157,13 +157,17 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, 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) { + 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) { + 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; } @@ -180,7 +184,8 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, case PGP_PKA_KYBER768_BP256: [[fallthrough]]; case PGP_PKA_KYBER1024_BP384: - if(pgp_kyber_ecdh_composite_key_t::gen_keypair(&crypto.ctx->rng, &seckey.material.kyber_ecdh, seckey.alg)) { + if (pgp_kyber_ecdh_composite_key_t::gen_keypair( + &crypto.ctx->rng, &seckey.material.kyber_ecdh, seckey.alg)) { RNP_LOG("failed to generate Kyber-ECDH-composite key for PK alg %d", seckey.alg); return false; } @@ -195,8 +200,10 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; 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 Dilithium-ecdsa/eddsa-composite key for PK alg %d", seckey.alg); + if (pgp_dilithium_exdsa_composite_key_t::gen_keypair( + &crypto.ctx->rng, &seckey.material.dilithium_exdsa, seckey.alg)) { + RNP_LOG("failed to generate Dilithium-ecdsa/eddsa-composite key for PK alg %d", + seckey.alg); return false; } break; @@ -319,9 +326,9 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) return elgamal_validate_key(&material->eg, material->secret) ? RNP_SUCCESS : RNP_ERROR_GENERIC; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: + case PGP_PKA_ED25519: return ed25519_validate_key_native(rng, &material->ed25519, material->secret); - case PGP_PKA_X25519: + case PGP_PKA_X25519: return x25519_validate_key_native(rng, &material->x25519, material->secret); #endif #if defined(ENABLE_PQC) diff --git a/src/lib/crypto/dilithium.cpp b/src/lib/crypto/dilithium.cpp index b6879cec0..ae1c9e097 100644 --- a/src/lib/crypto/dilithium.cpp +++ b/src/lib/crypto/dilithium.cpp @@ -88,8 +88,7 @@ pgp_dilithium_public_key_t::verify_signature(const uint8_t *msg, } std::pair -dilithium_generate_keypair( - rnp::RNG *rng, dilithium_parameter_e dilithium_param) +dilithium_generate_keypair(rnp::RNG *rng, dilithium_parameter_e dilithium_param) { Botan::Dilithium_PrivateKey priv_key(*rng->obj(), rnp_dilithium_param_to_botan_dimension(dilithium_param)); @@ -102,22 +101,24 @@ dilithium_generate_keypair( } bool -pgp_dilithium_public_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized_) { +pgp_dilithium_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized_) { return false; } - auto key = botan_key(); + auto key = botan_key(); return key.check_key(*(rng->obj()), false); } bool -pgp_dilithium_private_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized_) { +pgp_dilithium_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized_) { return false; } - auto key = botan_key(); + auto key = botan_key(); return key.check_key(*(rng->obj()), false); } diff --git a/src/lib/crypto/dilithium.h b/src/lib/crypto/dilithium.h index 8462c5a71..3bb2a1b51 100644 --- a/src/lib/crypto/dilithium.h +++ b/src/lib/crypto/dilithium.h @@ -69,8 +69,8 @@ class pgp_dilithium_private_key_t { Botan::Dilithium_PrivateKey botan_key() const; Botan::secure_vector key_encoded_; - dilithium_parameter_e dilithium_param_; - bool is_initialized_ = false; + dilithium_parameter_e dilithium_param_; + bool is_initialized_ = false; }; class pgp_dilithium_public_key_t { @@ -82,9 +82,11 @@ class pgp_dilithium_public_key_t { dilithium_parameter_e mode); pgp_dilithium_public_key_t() = default; - bool operator==(const pgp_dilithium_public_key_t &rhs) const + bool + operator==(const pgp_dilithium_public_key_t &rhs) const { - return (dilithium_param_ == rhs.dilithium_param_) && (key_encoded_ == rhs.key_encoded_); + return (dilithium_param_ == rhs.dilithium_param_) && + (key_encoded_ == rhs.key_encoded_); } bool verify_signature(const uint8_t *msg, @@ -105,7 +107,7 @@ class pgp_dilithium_public_key_t { std::vector key_encoded_; dilithium_parameter_e dilithium_param_; - bool is_initialized_ = false; + bool is_initialized_ = false; }; std::pair dilithium_generate_keypair( diff --git a/src/lib/crypto/dilithium_common.cpp b/src/lib/crypto/dilithium_common.cpp index a98df723d..e2269020d 100644 --- a/src/lib/crypto/dilithium_common.cpp +++ b/src/lib/crypto/dilithium_common.cpp @@ -35,7 +35,8 @@ pgp_dilithium_public_key_t::pgp_dilithium_public_key_t(const uint8_t * key_encoded, size_t key_encoded_len, dilithium_parameter_e param) - : key_encoded_(key_encoded, key_encoded + key_encoded_len), dilithium_param_(param), is_initialized_(true) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), dilithium_param_(param), + is_initialized_(true) { } @@ -48,50 +49,56 @@ pgp_dilithium_public_key_t::pgp_dilithium_public_key_t(std::vector cons pgp_dilithium_private_key_t::pgp_dilithium_private_key_t(const uint8_t * key_encoded, size_t key_encoded_len, dilithium_parameter_e param) - : key_encoded_(key_encoded, key_encoded + key_encoded_len), dilithium_param_(param), is_initialized_(true) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), dilithium_param_(param), + is_initialized_(true) { } pgp_dilithium_private_key_t::pgp_dilithium_private_key_t( std::vector const &key_encoded, dilithium_parameter_e param) : key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), - dilithium_param_(param), - is_initialized_(true) + dilithium_param_(param), is_initialized_(true) { } -size_t dilithium_privkey_size(dilithium_parameter_e parameter) { - switch(parameter) { - case dilithium_L3: - return 4000; - case dilithium_L5: - return 4864; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +dilithium_privkey_size(dilithium_parameter_e parameter) +{ + switch (parameter) { + case dilithium_L3: + return 4000; + case dilithium_L5: + return 4864; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -size_t dilithium_pubkey_size(dilithium_parameter_e parameter) { - switch(parameter) { - case dilithium_L3: - return 1952; - case dilithium_L5: - return 2592; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +dilithium_pubkey_size(dilithium_parameter_e parameter) +{ + switch (parameter) { + case dilithium_L3: + return 1952; + case dilithium_L5: + return 2592; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -size_t dilithium_signature_size(dilithium_parameter_e parameter) { - switch(parameter) { - case dilithium_L3: - return 3293; - case dilithium_L5: - return 4595; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +dilithium_signature_size(dilithium_parameter_e parameter) +{ + switch (parameter) { + case dilithium_L3: + return 3293; + case dilithium_L5: + return 4595; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } diff --git a/src/lib/crypto/dilithium_common.h b/src/lib/crypto/dilithium_common.h index 9746a113f..2e677c875 100644 --- a/src/lib/crypto/dilithium_common.h +++ b/src/lib/crypto/dilithium_common.h @@ -33,7 +33,6 @@ #include "dilithium.h" - size_t dilithium_privkey_size(dilithium_parameter_e parameter); size_t dilithium_pubkey_size(dilithium_parameter_e parameter); size_t dilithium_signature_size(dilithium_parameter_e parameter); diff --git a/src/lib/crypto/dilithium_exdsa_composite.cpp b/src/lib/crypto/dilithium_exdsa_composite.cpp index 1c24cf0ca..e54d4f058 100644 --- a/src/lib/crypto/dilithium_exdsa_composite.cpp +++ b/src/lib/crypto/dilithium_exdsa_composite.cpp @@ -32,275 +32,307 @@ #include "types.h" #include "logging.h" -pgp_dilithium_exdsa_composite_key_t::~pgp_dilithium_exdsa_composite_key_t() {} +pgp_dilithium_exdsa_composite_key_t::~pgp_dilithium_exdsa_composite_key_t() +{ +} void -pgp_dilithium_exdsa_composite_key_t::initialized_or_throw() const { - if(!is_initialized()) { +pgp_dilithium_exdsa_composite_key_t::initialized_or_throw() const +{ + if (!is_initialized()) { RNP_LOG("Trying to use uninitialized dilithium-ecdsa/eddsa key"); throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); } } rnp_result_t -pgp_dilithium_exdsa_composite_key_t::gen_keypair(rnp::RNG *rng, pgp_dilithium_exdsa_key_t *key, pgp_pubkey_alg_t alg) +pgp_dilithium_exdsa_composite_key_t::gen_keypair(rnp::RNG * rng, + pgp_dilithium_exdsa_key_t *key, + pgp_pubkey_alg_t alg) { - rnp_result_t res; - pgp_curve_t curve = pk_alg_to_curve_id(alg); + rnp_result_t res; + pgp_curve_t curve = pk_alg_to_curve_id(alg); dilithium_parameter_e dilithium_id = pk_alg_to_dilithium_id(alg); exdsa_key_t exdsa_key_pair; res = ec_key_t::generate_exdsa_key_pair(rng, &exdsa_key_pair, curve); - if(res != RNP_SUCCESS) { + if (res != RNP_SUCCESS) { RNP_LOG("generating dilithium exdsa composite key failed when generating exdsa key"); return res; } auto dilithium_key_pair = dilithium_generate_keypair(rng, dilithium_id); - key->priv = pgp_dilithium_exdsa_composite_private_key_t(exdsa_key_pair.priv.get_encoded(), dilithium_key_pair.second.get_encoded(), alg); - key->pub = pgp_dilithium_exdsa_composite_public_key_t(exdsa_key_pair.pub.get_encoded(), dilithium_key_pair.first.get_encoded(), alg); + key->priv = pgp_dilithium_exdsa_composite_private_key_t( + exdsa_key_pair.priv.get_encoded(), dilithium_key_pair.second.get_encoded(), alg); + key->pub = pgp_dilithium_exdsa_composite_public_key_t( + exdsa_key_pair.pub.get_encoded(), dilithium_key_pair.first.get_encoded(), alg); return RNP_SUCCESS; } size_t -pgp_dilithium_exdsa_composite_key_t::exdsa_curve_privkey_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_ED25519: - return 32; - /* TODO */ - // case PGP_CURVE_ED448: - // return 56; - case PGP_CURVE_NIST_P_256: - return 32; - case PGP_CURVE_NIST_P_384: - return 48; - case PGP_CURVE_BP256: - return 32; - case PGP_CURVE_BP384: - return 48; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_dilithium_exdsa_composite_key_t::exdsa_curve_privkey_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_ED25519: + return 32; + /* TODO */ + // case PGP_CURVE_ED448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 32; + case PGP_CURVE_NIST_P_384: + return 48; + case PGP_CURVE_BP256: + return 32; + case PGP_CURVE_BP384: + return 48; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } size_t -pgp_dilithium_exdsa_composite_key_t::exdsa_curve_pubkey_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_ED25519: - return 32; - /* TODO */ - // case PGP_CURVE_ED448: - // return 56; - case PGP_CURVE_NIST_P_256: - return 65; - case PGP_CURVE_NIST_P_384: - return 97; - case PGP_CURVE_BP256: - return 65; - case PGP_CURVE_BP384: - return 97; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_dilithium_exdsa_composite_key_t::exdsa_curve_pubkey_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_ED25519: + return 32; + /* TODO */ + // case PGP_CURVE_ED448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 65; + case PGP_CURVE_NIST_P_384: + return 97; + case PGP_CURVE_BP256: + return 65; + case PGP_CURVE_BP384: + return 97; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } size_t -pgp_dilithium_exdsa_composite_key_t::exdsa_curve_signature_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_ED25519: - return 64; - /* TODO */ - // case PGP_CURVE_ED448: - // return 114; - case PGP_CURVE_NIST_P_256: - return 64; - case PGP_CURVE_NIST_P_384: - return 96; - case PGP_CURVE_BP256: - return 64; - case PGP_CURVE_BP384: - return 96; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_dilithium_exdsa_composite_key_t::exdsa_curve_signature_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_ED25519: + return 64; + /* TODO */ + // case PGP_CURVE_ED448: + // return 114; + case PGP_CURVE_NIST_P_256: + return 64; + case PGP_CURVE_NIST_P_384: + return 96; + case PGP_CURVE_BP256: + return 64; + case PGP_CURVE_BP384: + return 96; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } dilithium_parameter_e -pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_alg) { - switch(pk_alg) - { - case PGP_PKA_DILITHIUM3_ED25519: +pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_alg) +{ + switch (pk_alg) { + case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_P256: + case PGP_PKA_DILITHIUM3_P256: [[fallthrough]]; - case PGP_PKA_DILITHIUM3_BP256: - return dilithium_L3; - case PGP_PKA_DILITHIUM5_BP384: + case PGP_PKA_DILITHIUM3_BP256: + return dilithium_L3; + case PGP_PKA_DILITHIUM5_BP384: [[fallthrough]]; - case PGP_PKA_DILITHIUM5_P384: + case PGP_PKA_DILITHIUM5_P384: //[[fallthrough]]; - //case PGP_PKA_DILITHIUM5_ED448: + // case PGP_PKA_DILITHIUM5_ED448: return dilithium_L5; - default: + default: RNP_LOG("invalid PK alg given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } pgp_curve_t -pgp_dilithium_exdsa_composite_key_t::pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg) { - switch(pk_alg) - { - case PGP_PKA_DILITHIUM3_ED25519: +pgp_dilithium_exdsa_composite_key_t::pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg) +{ + switch (pk_alg) { + case PGP_PKA_DILITHIUM3_ED25519: return PGP_CURVE_ED25519; - case PGP_PKA_DILITHIUM3_P256: + case PGP_PKA_DILITHIUM3_P256: return PGP_CURVE_NIST_P_256; - case PGP_PKA_DILITHIUM3_BP256: - return PGP_CURVE_BP256; - case PGP_PKA_DILITHIUM5_BP384: + case PGP_PKA_DILITHIUM3_BP256: + return PGP_CURVE_BP256; + case PGP_PKA_DILITHIUM5_BP384: return PGP_CURVE_BP384; - case PGP_PKA_DILITHIUM5_P384: + case PGP_PKA_DILITHIUM5_P384: return PGP_CURVE_NIST_P_384; - /*case PGP_PKA_DILITHIUM5_ED448: - throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED);*/ - default: + /*case PGP_PKA_DILITHIUM5_ED448: + throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED);*/ + default: RNP_LOG("invalid PK alg given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t( + const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); } -pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t( + std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(key_encoded); } -pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg) - : pk_alg_(pk_alg), - dilithium_key_(dilithium_key_encoded, pk_alg_to_dilithium_id(pk_alg)), +pgp_dilithium_exdsa_composite_public_key_t::pgp_dilithium_exdsa_composite_public_key_t( + std::vector const &exdsa_key_encoded, + std::vector const &dilithium_key_encoded, + pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg), dilithium_key_(dilithium_key_encoded, pk_alg_to_dilithium_id(pk_alg)), exdsa_key_(exdsa_key_encoded, pk_alg_to_curve_id(pk_alg)) { - if(exdsa_curve_pubkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() - || dilithium_pubkey_size(pk_alg_to_dilithium_id(pk_alg)) != dilithium_key_encoded.size()) - { + if (exdsa_curve_pubkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() || + dilithium_pubkey_size(pk_alg_to_dilithium_id(pk_alg)) != + dilithium_key_encoded.size()) { RNP_LOG("exdsa or dilithium key length mismatch"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } is_initialized_ = true; } -pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t( + const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); } -pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t( + std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(key_encoded); } -/* copy assignment operator is used on key materials struct and thus needs to be defined for this class as well */ -pgp_dilithium_exdsa_composite_private_key_t& pgp_dilithium_exdsa_composite_private_key_t::operator=(const pgp_dilithium_exdsa_composite_private_key_t& other) +/* copy assignment operator is used on key materials struct and thus needs to be defined for + * this class as well */ +pgp_dilithium_exdsa_composite_private_key_t & +pgp_dilithium_exdsa_composite_private_key_t::operator=( + const pgp_dilithium_exdsa_composite_private_key_t &other) { pgp_dilithium_exdsa_composite_key_t::operator=(other); pk_alg_ = other.pk_alg_; - if(other.is_initialized() && other.dilithium_key_) - { - dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t(other.dilithium_key_->get_encoded(), other.dilithium_key_->param())); + if (other.is_initialized() && other.dilithium_key_) { + dilithium_key_ = + std::make_unique(pgp_dilithium_private_key_t( + other.dilithium_key_->get_encoded(), other.dilithium_key_->param())); } - if(other.is_initialized() && other.exdsa_key_) - { - exdsa_key_ = std::make_unique(exdsa_private_key_t(other.exdsa_key_->get_encoded(), other.exdsa_key_->get_curve())); + if (other.is_initialized() && other.exdsa_key_) { + exdsa_key_ = std::make_unique( + exdsa_private_key_t(other.exdsa_key_->get_encoded(), other.exdsa_key_->get_curve())); } return *this; } -pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg) +pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_private_key_t( + std::vector const &exdsa_key_encoded, + std::vector const &dilithium_key_encoded, + pgp_pubkey_alg_t pk_alg) : pk_alg_(pk_alg) { - if(exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() - || dilithium_privkey_size(pk_alg_to_dilithium_id(pk_alg)) != dilithium_key_encoded.size()) - { + if (exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() || + dilithium_privkey_size(pk_alg_to_dilithium_id(pk_alg)) != + dilithium_key_encoded.size()) { RNP_LOG("exdsa or dilithium key length mismatch"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t(dilithium_key_encoded, pk_alg_to_dilithium_id(pk_alg))); - exdsa_key_ = std::make_unique(exdsa_private_key_t(exdsa_key_encoded, pk_alg_to_curve_id(pk_alg))); + dilithium_key_ = std::make_unique( + pgp_dilithium_private_key_t(dilithium_key_encoded, pk_alg_to_dilithium_id(pk_alg))); + exdsa_key_ = std::make_unique( + exdsa_private_key_t(exdsa_key_encoded, pk_alg_to_curve_id(pk_alg))); is_initialized_ = true; } size_t pgp_dilithium_exdsa_composite_private_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) { - dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg); - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); - return exdsa_curve_privkey_size(curve) + dilithium_privkey_size(dilithium_param); + dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return exdsa_curve_privkey_size(curve) + dilithium_privkey_size(dilithium_param); } -void -pgp_dilithium_exdsa_composite_private_key_t::parse_component_keys(std::vector key_encoded) +void +pgp_dilithium_exdsa_composite_private_key_t::parse_component_keys( + std::vector key_encoded) { if (key_encoded.size() != encoded_size(pk_alg_)) { RNP_LOG("Dilithium composite key format invalid: length mismatch"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg_); - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); - size_t split_at = exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg_)); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg_)); - dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, dilithium_param)); - exdsa_key_ = std::make_unique(exdsa_private_key_t(key_encoded.data(), split_at, curve)); + dilithium_key_ = std::make_unique(pgp_dilithium_private_key_t( + key_encoded.data() + split_at, key_encoded.size() - split_at, dilithium_param)); + exdsa_key_ = std::make_unique( + exdsa_private_key_t(key_encoded.data(), split_at, curve)); is_initialized_ = true; } std::vector -pgp_dilithium_exdsa_composite_private_key_t::get_encoded() const { +pgp_dilithium_exdsa_composite_private_key_t::get_encoded() const +{ initialized_or_throw(); std::vector result; std::vector exdsa_key_encoded = exdsa_key_->get_encoded(); std::vector dilithium_key_encoded = dilithium_key_->get_encoded(); result.insert(result.end(), std::begin(exdsa_key_encoded), std::end(exdsa_key_encoded)); - result.insert(result.end(), std::begin(dilithium_key_encoded), std::end(dilithium_key_encoded)); + result.insert( + result.end(), std::begin(dilithium_key_encoded), std::end(dilithium_key_encoded)); return result; }; - rnp_result_t -pgp_dilithium_exdsa_composite_private_key_t::sign(rnp::RNG *rng, pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *msg, size_t msg_len) const +pgp_dilithium_exdsa_composite_private_key_t::sign(rnp::RNG * rng, + pgp_dilithium_exdsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * msg, + size_t msg_len) const { - initialized_or_throw(); + initialized_or_throw(); std::vector dilithium_sig; std::vector exdsa_sig; - rnp_result_t ret; - + rnp_result_t ret; + try { dilithium_sig = dilithium_key_->sign(rng, msg, msg_len); - } - catch (const std::exception &e) { + } catch (const std::exception &e) { RNP_LOG("%s", e.what()); return RNP_ERROR_SIGNING_FAILED; } ret = exdsa_key_->sign(rng, exdsa_sig, msg, msg_len, hash_alg); - if(ret != RNP_SUCCESS) { + if (ret != RNP_SUCCESS) { RNP_LOG("exdsa sign failed"); return RNP_ERROR_SIGNING_FAILED; } @@ -312,8 +344,10 @@ pgp_dilithium_exdsa_composite_private_key_t::sign(rnp::RNG *rng, pgp_dilithium_e } void -pgp_dilithium_exdsa_composite_private_key_t::secure_clear() { - // private key buffer is stored in a secure_vector and will be securely erased by the destructor. +pgp_dilithium_exdsa_composite_private_key_t::secure_clear() +{ + // private key buffer is stored in a secure_vector and will be securely erased by the + // destructor. dilithium_key_.reset(); exdsa_key_.reset(); is_initialized_ = false; @@ -322,64 +356,68 @@ pgp_dilithium_exdsa_composite_private_key_t::secure_clear() { size_t pgp_dilithium_exdsa_composite_public_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) { - dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg); - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); - return exdsa_curve_pubkey_size(curve) + dilithium_pubkey_size(dilithium_param); + dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return exdsa_curve_pubkey_size(curve) + dilithium_pubkey_size(dilithium_param); } -void -pgp_dilithium_exdsa_composite_public_key_t::parse_component_keys(std::vector key_encoded) +void +pgp_dilithium_exdsa_composite_public_key_t::parse_component_keys( + std::vector key_encoded) { if (key_encoded.size() != encoded_size(pk_alg_)) { RNP_LOG("Dilithium composite key format invalid: length mismatch"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg_); - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); - size_t split_at = exdsa_curve_pubkey_size(pk_alg_to_curve_id(pk_alg_)); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = exdsa_curve_pubkey_size(pk_alg_to_curve_id(pk_alg_)); - dilithium_key_ = pgp_dilithium_public_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, dilithium_param); + dilithium_key_ = pgp_dilithium_public_key_t( + key_encoded.data() + split_at, key_encoded.size() - split_at, dilithium_param); exdsa_key_ = exdsa_public_key_t(key_encoded.data(), split_at, curve); is_initialized_ = true; } std::vector -pgp_dilithium_exdsa_composite_public_key_t::get_encoded() const { +pgp_dilithium_exdsa_composite_public_key_t::get_encoded() const +{ initialized_or_throw(); std::vector result; std::vector exdsa_key_encoded = exdsa_key_.get_encoded(); std::vector dilithium_key_encoded = dilithium_key_.get_encoded(); result.insert(result.end(), std::begin(exdsa_key_encoded), std::end(exdsa_key_encoded)); - result.insert(result.end(), std::begin(dilithium_key_encoded), std::end(dilithium_key_encoded)); + result.insert( + result.end(), std::begin(dilithium_key_encoded), std::end(dilithium_key_encoded)); return result; }; rnp_result_t -pgp_dilithium_exdsa_composite_public_key_t::verify(const pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *hash, size_t hash_len) const +pgp_dilithium_exdsa_composite_public_key_t::verify(const pgp_dilithium_exdsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t *hash, + size_t hash_len) const { - initialized_or_throw(); + initialized_or_throw(); std::vector dilithium_sig; std::vector exdsa_sig; - if(sig->sig.size() != sig->composite_signature_size(pk_alg_)) { + if (sig->sig.size() != sig->composite_signature_size(pk_alg_)) { RNP_LOG("invalid signature size for dilithium exdsa composite algorithm %d", pk_alg_); return RNP_ERROR_VERIFICATION_FAILED; } - + size_t split_at = exdsa_curve_signature_size(pk_alg_to_curve_id(pk_alg_)); - exdsa_sig = std::vector( - sig->sig.data(), - sig->sig.data() + split_at - ); - dilithium_sig = std::vector( - sig->sig.data() + split_at, - sig->sig.data() + sig->sig.size()); - - if(exdsa_key_.verify(exdsa_sig, hash, hash_len, hash_alg) != RNP_SUCCESS - || !dilithium_key_.verify_signature(hash, hash_len, dilithium_sig.data(), dilithium_sig.size())) { + exdsa_sig = std::vector(sig->sig.data(), sig->sig.data() + split_at); + dilithium_sig = + std::vector(sig->sig.data() + split_at, sig->sig.data() + sig->sig.size()); + + if (exdsa_key_.verify(exdsa_sig, hash, hash_len, hash_alg) != RNP_SUCCESS || + !dilithium_key_.verify_signature( + hash, hash_len, dilithium_sig.data(), dilithium_sig.size())) { RNP_LOG("could not verify composite signature"); return RNP_ERROR_VERIFICATION_FAILED; } @@ -388,30 +426,33 @@ pgp_dilithium_exdsa_composite_public_key_t::verify(const pgp_dilithium_exdsa_sig } bool -pgp_dilithium_exdsa_composite_public_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized()) { +pgp_dilithium_exdsa_composite_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized()) { return false; } - return(exdsa_key_.is_valid(rng) && dilithium_key_.is_valid(rng)); + return (exdsa_key_.is_valid(rng) && dilithium_key_.is_valid(rng)); } bool -pgp_dilithium_exdsa_composite_private_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized()) { +pgp_dilithium_exdsa_composite_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized()) { return false; } - return(exdsa_key_->is_valid(rng) && dilithium_key_->is_valid(rng)); + return (exdsa_key_->is_valid(rng) && dilithium_key_->is_valid(rng)); } -rnp_result_t dilithium_exdsa_validate_key(rnp::RNG *rng, const pgp_dilithium_exdsa_key_t *key, bool secret) +rnp_result_t +dilithium_exdsa_validate_key(rnp::RNG *rng, const pgp_dilithium_exdsa_key_t *key, bool secret) { bool valid; valid = key->pub.is_valid(rng); - if(secret) { + if (secret) { valid = valid && key->priv.is_valid(rng); } - if(!valid) { + if (!valid) { return RNP_ERROR_GENERIC; } diff --git a/src/lib/crypto/dilithium_exdsa_composite.h b/src/lib/crypto/dilithium_exdsa_composite.h index bf772eb99..fa4513f3b 100644 --- a/src/lib/crypto/dilithium_exdsa_composite.h +++ b/src/lib/crypto/dilithium_exdsa_composite.h @@ -41,56 +41,74 @@ #include "crypto/exdsa_ecdhkem.h" #include - struct pgp_dilithium_exdsa_key_t; /* forward declaration */ class pgp_dilithium_exdsa_composite_key_t { + public: + virtual ~pgp_dilithium_exdsa_composite_key_t() = 0; -public: - virtual ~pgp_dilithium_exdsa_composite_key_t() = 0; + static rnp_result_t gen_keypair(rnp::RNG * rng, + pgp_dilithium_exdsa_key_t *key, + pgp_pubkey_alg_t alg); - static rnp_result_t gen_keypair(rnp::RNG *rng, pgp_dilithium_exdsa_key_t *key, pgp_pubkey_alg_t alg); + static size_t exdsa_curve_privkey_size(pgp_curve_t curve); + static size_t exdsa_curve_pubkey_size(pgp_curve_t curve); + static size_t exdsa_curve_signature_size(pgp_curve_t curve); + static pgp_curve_t pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg); + static dilithium_parameter_e pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_alg); - static size_t exdsa_curve_privkey_size(pgp_curve_t curve); - static size_t exdsa_curve_pubkey_size(pgp_curve_t curve); - static size_t exdsa_curve_signature_size(pgp_curve_t curve); - static pgp_curve_t pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg); - static dilithium_parameter_e pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_alg); + bool + is_initialized() const + { + return is_initialized_; + } - bool is_initialized() const { - return is_initialized_; - } - -protected: - bool is_initialized_ = false; - void initialized_or_throw() const; + protected: + bool is_initialized_ = false; + void initialized_or_throw() const; }; typedef struct pgp_dilithium_exdsa_signature_t { std::vector sig; - static size_t composite_signature_size(pgp_pubkey_alg_t pk_alg) { - return dilithium_signature_size(pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pk_alg)) - + pgp_dilithium_exdsa_composite_key_t::exdsa_curve_signature_size(pgp_dilithium_exdsa_composite_key_t::pk_alg_to_curve_id(pk_alg)); + static size_t + composite_signature_size(pgp_pubkey_alg_t pk_alg) + { + return dilithium_signature_size( + pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pk_alg)) + + pgp_dilithium_exdsa_composite_key_t::exdsa_curve_signature_size( + pgp_dilithium_exdsa_composite_key_t::pk_alg_to_curve_id(pk_alg)); } } pgp_dilithium_exdsa_signature_t; -class pgp_dilithium_exdsa_composite_private_key_t : public pgp_dilithium_exdsa_composite_key_t { +class pgp_dilithium_exdsa_composite_private_key_t + : public pgp_dilithium_exdsa_composite_key_t { public: - pgp_dilithium_exdsa_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); - pgp_dilithium_exdsa_composite_private_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg); - pgp_dilithium_exdsa_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); - pgp_dilithium_exdsa_composite_private_key_t& operator=(const pgp_dilithium_exdsa_composite_private_key_t &other); + pgp_dilithium_exdsa_composite_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_private_key_t( + std::vector const &exdsa_key_encoded, + std::vector const &dilithium_key_encoded, + pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_private_key_t(std::vector const &key_encoded, + pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_private_key_t &operator=( + const pgp_dilithium_exdsa_composite_private_key_t &other); pgp_dilithium_exdsa_composite_private_key_t() = default; - - rnp_result_t sign(rnp::RNG *rng, pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *msg, size_t msg_len) const; + rnp_result_t sign(rnp::RNG * rng, + pgp_dilithium_exdsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * msg, + size_t msg_len) const; std::vector get_encoded() const; - pgp_pubkey_alg_t pk_alg() const + pgp_pubkey_alg_t + pk_alg() const { - return pk_alg_; + return pk_alg_; } bool is_valid(rnp::RNG *rng) const; @@ -110,29 +128,40 @@ class pgp_dilithium_exdsa_composite_private_key_t : public pgp_dilithium_exdsa_c std::unique_ptr exdsa_key_; }; - class pgp_dilithium_exdsa_composite_public_key_t : public pgp_dilithium_exdsa_composite_key_t { public: - pgp_dilithium_exdsa_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); - pgp_dilithium_exdsa_composite_public_key_t(std::vector const &exdsa_key_encoded, std::vector const &dilithium_key_encoded, pgp_pubkey_alg_t pk_alg); - pgp_dilithium_exdsa_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_public_key_t( + std::vector const &exdsa_key_encoded, + std::vector const &dilithium_key_encoded, + pgp_pubkey_alg_t pk_alg); + pgp_dilithium_exdsa_composite_public_key_t(std::vector const &key_encoded, + pgp_pubkey_alg_t pk_alg); pgp_dilithium_exdsa_composite_public_key_t() = default; - bool operator==(const pgp_dilithium_exdsa_composite_public_key_t &rhs) const + bool + operator==(const pgp_dilithium_exdsa_composite_public_key_t &rhs) const { - return (pk_alg_ == rhs.pk_alg_) && (dilithium_key_ == rhs.dilithium_key_) && (exdsa_key_ == rhs.exdsa_key_); + return (pk_alg_ == rhs.pk_alg_) && (dilithium_key_ == rhs.dilithium_key_) && + (exdsa_key_ == rhs.exdsa_key_); } - rnp_result_t verify(const pgp_dilithium_exdsa_signature_t *sig, pgp_hash_alg_t hash_alg, const uint8_t *hash, size_t hash_len) const; + rnp_result_t verify(const pgp_dilithium_exdsa_signature_t *sig, + pgp_hash_alg_t hash_alg, + const uint8_t * hash, + size_t hash_len) const; std::vector get_encoded() const; - pgp_pubkey_alg_t pk_alg() const + pgp_pubkey_alg_t + pk_alg() const { - return pk_alg_; + return pk_alg_; } - bool is_valid(rnp::RNG *rng) const; + bool is_valid(rnp::RNG *rng) const; static size_t encoded_size(pgp_pubkey_alg_t pk_alg); private: @@ -149,9 +178,11 @@ class pgp_dilithium_exdsa_composite_public_key_t : public pgp_dilithium_exdsa_co typedef struct pgp_dilithium_exdsa_key_t { pgp_dilithium_exdsa_composite_private_key_t priv; - pgp_dilithium_exdsa_composite_public_key_t pub; + pgp_dilithium_exdsa_composite_public_key_t pub; } pgp_dilithium_exdsa_key_t; -rnp_result_t dilithium_exdsa_validate_key(rnp::RNG *rng, const pgp_dilithium_exdsa_key_t *key, bool secret); +rnp_result_t dilithium_exdsa_validate_key(rnp::RNG * rng, + const pgp_dilithium_exdsa_key_t *key, + bool secret); #endif diff --git a/src/lib/crypto/ec.cpp b/src/lib/crypto/ec.cpp index 6cad2a5b5..ef9373507 100644 --- a/src/lib/crypto/ec.cpp +++ b/src/lib/crypto/ec.cpp @@ -194,42 +194,52 @@ ec_generate(rnp::RNG * rng, } #if defined(ENABLE_CRYPTO_REFRESH) -static bool is_generic_prime_curve(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_NIST_P_256: [[fallthrough]]; - case PGP_CURVE_NIST_P_384: [[fallthrough]]; - case PGP_CURVE_NIST_P_521: [[fallthrough]]; - case PGP_CURVE_BP256: [[fallthrough]]; - case PGP_CURVE_BP384: [[fallthrough]]; - case PGP_CURVE_BP512: [[fallthrough]]; - case PGP_CURVE_P256K1: - return true; - default: - return false; +static bool +is_generic_prime_curve(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_NIST_P_256: + [[fallthrough]]; + case PGP_CURVE_NIST_P_384: + [[fallthrough]]; + case PGP_CURVE_NIST_P_521: + [[fallthrough]]; + case PGP_CURVE_BP256: + [[fallthrough]]; + case PGP_CURVE_BP384: + [[fallthrough]]; + case PGP_CURVE_BP512: + [[fallthrough]]; + case PGP_CURVE_P256K1: + return true; + default: + return false; } } -static rnp_result_t ec_generate_generic_native(rnp::RNG * rng, - std::vector &privkey, - std::vector &pubkey, - pgp_curve_t curve, - pgp_pubkey_alg_t alg) +static rnp_result_t +ec_generate_generic_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve, + pgp_pubkey_alg_t alg) { - if(!is_generic_prime_curve(curve)) { + if (!is_generic_prime_curve(curve)) { RNP_LOG("expected generic prime curve"); return RNP_ERROR_BAD_PARAMETERS; } const ec_curve_desc_t *ec_desc = get_curve_desc(curve); - const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); + const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); Botan::ECDH_PrivateKey privkey_botan(*(rng->obj()), Botan::EC_Group(ec_desc->botan_name)); - Botan::BigInt pub_x = privkey_botan.public_point().get_affine_x(); - Botan::BigInt pub_y = privkey_botan.public_point().get_affine_y(); - Botan::BigInt x = privkey_botan.private_value(); + Botan::BigInt pub_x = privkey_botan.public_point().get_affine_x(); + Botan::BigInt pub_y = privkey_botan.public_point().get_affine_y(); + Botan::BigInt x = privkey_botan.private_value(); // pubkey: 0x04 || X || Y - pubkey = Botan::unlock(Botan::BigInt::encode_fixed_length_int_pair(pub_x, pub_y, curve_order)); // zero-pads to the given size + pubkey = Botan::unlock(Botan::BigInt::encode_fixed_length_int_pair( + pub_x, pub_y, curve_order)); // zero-pads to the given size pubkey.insert(pubkey.begin(), 0x04); privkey = std::vector(curve_order); @@ -241,28 +251,26 @@ static rnp_result_t ec_generate_generic_native(rnp::RNG * rng, return RNP_SUCCESS; } -rnp_result_t ec_generate_native(rnp::RNG * rng, - std::vector &privkey, - std::vector &pubkey, - pgp_curve_t curve, - pgp_pubkey_alg_t alg) +rnp_result_t +ec_generate_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve, + pgp_pubkey_alg_t alg) { - if(curve == PGP_CURVE_25519) { + if (curve == PGP_CURVE_25519) { return generate_x25519_native(rng, privkey, pubkey); - } - else if(curve == PGP_CURVE_ED25519) { + } else if (curve == PGP_CURVE_ED25519) { return generate_ed25519_native(rng, privkey, pubkey); - } - else if(is_generic_prime_curve(curve)) { - if(alg != PGP_PKA_ECDH && alg != PGP_PKA_ECDSA) { + } else if (is_generic_prime_curve(curve)) { + if (alg != PGP_PKA_ECDH && alg != PGP_PKA_ECDSA) { RNP_LOG("alg and curve mismatch"); return RNP_ERROR_BAD_PARAMETERS; } return ec_generate_generic_native(rng, privkey, pubkey, curve, alg); - } - else { + } else { RNP_LOG("invalid curve"); - return RNP_ERROR_BAD_PARAMETERS; + return RNP_ERROR_BAD_PARAMETERS; } } #endif diff --git a/src/lib/crypto/ec.h b/src/lib/crypto/ec.h index cef5c3039..aeb843601 100644 --- a/src/lib/crypto/ec.h +++ b/src/lib/crypto/ec.h @@ -203,9 +203,9 @@ bool x25519_bits_tweaked(const pgp_ec_key_t &key); * * @returns RNP_ERROR_BAD_PARAMETERS if the curve or alg parameter is invalid. */ -rnp_result_t ec_generate_native(rnp::RNG * rng, - std::vector &privkey, +rnp_result_t ec_generate_native(rnp::RNG * rng, + std::vector &privkey, std::vector &pubkey, - pgp_curve_t curve, - pgp_pubkey_alg_t alg); + pgp_curve_t curve, + pgp_pubkey_alg_t alg); #endif diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index c304fcedf..85a0b637b 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -391,37 +391,44 @@ ecdh_decrypt_pkcs5(uint8_t * out, } #if defined(ENABLE_CRYPTO_REFRESH) -rnp_result_t ecdh_kem_gen_keypair_native(rnp::RNG * rng, - std::vector &privkey, - std::vector &pubkey, - pgp_curve_t curve) +rnp_result_t +ecdh_kem_gen_keypair_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve) { return ec_generate_native(rng, privkey, pubkey, curve, PGP_PKA_ECDH); } -rnp_result_t exdsa_gen_keypair_native(rnp::RNG * rng, - std::vector &privkey, - std::vector &pubkey, - pgp_curve_t curve) +rnp_result_t +exdsa_gen_keypair_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey, + pgp_curve_t curve) { pgp_pubkey_alg_t alg; - switch(curve) - { - case PGP_CURVE_ED25519: - alg = PGP_PKA_EDDSA; - break; - case PGP_CURVE_NIST_P_256: [[fallthrough]]; - case PGP_CURVE_NIST_P_384: [[fallthrough]]; - case PGP_CURVE_NIST_P_521: [[fallthrough]]; - case PGP_CURVE_BP256: [[fallthrough]]; - case PGP_CURVE_BP384: [[fallthrough]]; - case PGP_CURVE_BP512: [[fallthrough]]; - case PGP_CURVE_P256K1: - alg = PGP_PKA_ECDSA; - break; - default: - RNP_LOG("invalid curve for ECDSA/EDDSA"); - return RNP_ERROR_BAD_PARAMETERS; + switch (curve) { + case PGP_CURVE_ED25519: + alg = PGP_PKA_EDDSA; + break; + case PGP_CURVE_NIST_P_256: + [[fallthrough]]; + case PGP_CURVE_NIST_P_384: + [[fallthrough]]; + case PGP_CURVE_NIST_P_521: + [[fallthrough]]; + case PGP_CURVE_BP256: + [[fallthrough]]; + case PGP_CURVE_BP384: + [[fallthrough]]; + case PGP_CURVE_BP512: + [[fallthrough]]; + case PGP_CURVE_P256K1: + alg = PGP_PKA_ECDSA; + break; + default: + RNP_LOG("invalid curve for ECDSA/EDDSA"); + return RNP_ERROR_BAD_PARAMETERS; } return ec_generate_native(rng, privkey, pubkey, curve, alg); } diff --git a/src/lib/crypto/ecdh.h b/src/lib/crypto/ecdh.h index a0d61c601..7f402035b 100644 --- a/src/lib/crypto/ecdh.h +++ b/src/lib/crypto/ecdh.h @@ -115,7 +115,6 @@ rnp_result_t ecdh_decrypt_pkcs5(uint8_t * out, const pgp_ec_key_t * key, const pgp_fingerprint_t & fingerprint); - #if defined(ENABLE_CRYPTO_REFRESH) /* Generate an ECDH key pair in "native" format, i.e., * no changes to the format specified in the respective standard @@ -129,10 +128,10 @@ rnp_result_t ecdh_decrypt_pkcs5(uint8_t * out, * @return RNP_SUCCESS on success and output parameters are populated * @return RNP_ERROR_BAD_PARAMETERS unexpected input provided */ -rnp_result_t ecdh_kem_gen_keypair_native(rnp::RNG * rng, +rnp_result_t ecdh_kem_gen_keypair_native(rnp::RNG * rng, std::vector &privkey, std::vector &pubkey, - pgp_curve_t curve); + pgp_curve_t curve); /* Generate an ECDSA or EdDSA key pair in "native" format, i.e., * no changes to the format specified in the respective standard @@ -146,10 +145,10 @@ rnp_result_t ecdh_kem_gen_keypair_native(rnp::RNG * rng, * @return RNP_SUCCESS on success and output parameters are populated * @return RNP_ERROR_BAD_PARAMETERS unexpected input provided */ -rnp_result_t exdsa_gen_keypair_native(rnp::RNG * rng, +rnp_result_t exdsa_gen_keypair_native(rnp::RNG * rng, std::vector &privkey, std::vector &pubkey, - pgp_curve_t curve); + pgp_curve_t curve); #endif diff --git a/src/lib/crypto/ecdsa.h b/src/lib/crypto/ecdsa.h index 83f97c12b..86af7ed27 100644 --- a/src/lib/crypto/ecdsa.h +++ b/src/lib/crypto/ecdsa.h @@ -44,7 +44,7 @@ rnp_result_t ecdsa_verify(const pgp_ec_signature_t *sig, size_t hash_len, const pgp_ec_key_t * key); -const char * ecdsa_padding_str_for(pgp_hash_alg_t hash_alg); +const char *ecdsa_padding_str_for(pgp_hash_alg_t hash_alg); /* * @brief Returns hash which should be used with the curve diff --git a/src/lib/crypto/ed25519.cpp b/src/lib/crypto/ed25519.cpp index 0fcb17ad0..50ae8d97d 100644 --- a/src/lib/crypto/ed25519.cpp +++ b/src/lib/crypto/ed25519.cpp @@ -36,15 +36,14 @@ #include #include - - -rnp_result_t generate_ed25519_native(rnp::RNG * rng, - std::vector &privkey, - std::vector &pubkey) +rnp_result_t +generate_ed25519_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey) { Botan::Ed25519_PrivateKey private_key(*(rng->obj())); - const size_t key_len = 32; - auto priv_pub = Botan::unlock(private_key.raw_private_key_bits()); + const size_t key_len = 32; + auto priv_pub = Botan::unlock(private_key.raw_private_key_bits()); assert(priv_pub.size() == 2 * key_len); privkey = std::vector(priv_pub.begin(), priv_pub.begin() + key_len); pubkey = std::vector(priv_pub.begin() + key_len, priv_pub.end()); @@ -52,20 +51,29 @@ rnp_result_t generate_ed25519_native(rnp::RNG * rng, return RNP_SUCCESS; } -rnp_result_t ed25519_sign_native(rnp::RNG *rng, std::vector &sig_out, const std::vector &key, const uint8_t *hash, size_t hash_len) +rnp_result_t +ed25519_sign_native(rnp::RNG * rng, + std::vector & sig_out, + const std::vector &key, + const uint8_t * hash, + size_t hash_len) { Botan::Ed25519_PrivateKey priv_key(Botan::secure_vector(key.begin(), key.end())); - auto signer = Botan::PK_Signer(priv_key, *(rng->obj()), "Pure"); + auto signer = Botan::PK_Signer(priv_key, *(rng->obj()), "Pure"); sig_out = signer.sign_message(hash, hash_len, *(rng->obj())); - + return RNP_SUCCESS; } -rnp_result_t ed25519_verify_native(const std::vector &sig, const std::vector &key, const uint8_t *hash, size_t hash_len) +rnp_result_t +ed25519_verify_native(const std::vector &sig, + const std::vector &key, + const uint8_t * hash, + size_t hash_len) { Botan::Ed25519_PublicKey pub_key(key); - auto verifier = Botan::PK_Verifier(pub_key, "Pure"); - if(verifier.verify_message(hash, hash_len, sig.data(), sig.size())) { + auto verifier = Botan::PK_Verifier(pub_key, "Pure"); + if (verifier.verify_message(hash, hash_len, sig.data(), sig.size())) { return RNP_SUCCESS; } return RNP_ERROR_VERIFICATION_FAILED; @@ -75,13 +83,14 @@ rnp_result_t ed25519_validate_key_native(rnp::RNG *rng, const pgp_ed25519_key_t *key, bool secret) { Botan::Ed25519_PublicKey pub_key(key->pub); - if(!pub_key.check_key(*(rng->obj()), false)) { + if (!pub_key.check_key(*(rng->obj()), false)) { return RNP_ERROR_BAD_PARAMETERS; } - if(secret) { - Botan::Ed25519_PrivateKey priv_key(Botan::secure_vector(key->priv.begin(), key->priv.end())); - if(!priv_key.check_key(*(rng->obj()), false)) { + if (secret) { + Botan::Ed25519_PrivateKey priv_key( + Botan::secure_vector(key->priv.begin(), key->priv.end())); + if (!priv_key.check_key(*(rng->obj()), false)) { return RNP_ERROR_SIGNING_FAILED; } } diff --git a/src/lib/crypto/ed25519.h b/src/lib/crypto/ed25519.h index 0cb37998e..43f1022e3 100644 --- a/src/lib/crypto/ed25519.h +++ b/src/lib/crypto/ed25519.h @@ -40,14 +40,23 @@ /* implements ED25519 with native format (V6 and PQC) */ -rnp_result_t generate_ed25519_native(rnp::RNG * rng, - std::vector &privkey, +rnp_result_t generate_ed25519_native(rnp::RNG * rng, + std::vector &privkey, std::vector &pubkey); -rnp_result_t ed25519_sign_native(rnp::RNG *rng, std::vector &sig_out, const std::vector &key, const uint8_t *hash, size_t hash_len); +rnp_result_t ed25519_sign_native(rnp::RNG * rng, + std::vector & sig_out, + const std::vector &key, + const uint8_t * hash, + size_t hash_len); -rnp_result_t ed25519_verify_native(const std::vector &sig, const std::vector &key, const uint8_t *hash, size_t hash_len); +rnp_result_t ed25519_verify_native(const std::vector &sig, + const std::vector &key, + const uint8_t * hash, + size_t hash_len); -rnp_result_t ed25519_validate_key_native(rnp::RNG *rng, const pgp_ed25519_key_t *key, bool secret); +rnp_result_t ed25519_validate_key_native(rnp::RNG * rng, + const pgp_ed25519_key_t *key, + bool secret); #endif diff --git a/src/lib/crypto/exdsa_ecdhkem.cpp b/src/lib/crypto/exdsa_ecdhkem.cpp index b1912bcb8..b10c188d9 100644 --- a/src/lib/crypto/exdsa_ecdhkem.cpp +++ b/src/lib/crypto/exdsa_ecdhkem.cpp @@ -38,36 +38,43 @@ #include "utils.h" #include -ec_key_t::~ec_key_t() {} +ec_key_t::~ec_key_t() +{ +} -ec_key_t::ec_key_t(pgp_curve_t curve) - : curve_(curve) -{} +ec_key_t::ec_key_t(pgp_curve_t curve) : curve_(curve) +{ +} -ecdh_kem_public_key_t::ecdh_kem_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) - : ec_key_t(curve), - key_(std::vector(key_buf, key_buf + key_buf_len)) -{} +ecdh_kem_public_key_t::ecdh_kem_public_key_t(uint8_t * key_buf, + size_t key_buf_len, + pgp_curve_t curve) + : ec_key_t(curve), key_(std::vector(key_buf, key_buf + key_buf_len)) +{ +} ecdh_kem_public_key_t::ecdh_kem_public_key_t(std::vector key, pgp_curve_t curve) - : ec_key_t(curve), - key_(key) -{} + : ec_key_t(curve), key_(key) +{ +} -ecdh_kem_private_key_t::ecdh_kem_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) - : ec_key_t(curve), - key_(key_buf, key_buf + key_buf_len) -{} +ecdh_kem_private_key_t::ecdh_kem_private_key_t(uint8_t * key_buf, + size_t key_buf_len, + pgp_curve_t curve) + : ec_key_t(curve), key_(key_buf, key_buf + key_buf_len) +{ +} ecdh_kem_private_key_t::ecdh_kem_private_key_t(std::vector key, pgp_curve_t curve) - : ec_key_t(curve), - key_(Botan::secure_vector(key.begin(), key.end())) -{} + : ec_key_t(curve), key_(Botan::secure_vector(key.begin(), key.end())) +{ +} Botan::ECDH_PrivateKey ecdh_kem_private_key_t::botan_key_ecdh(rnp::RNG *rng) const { assert(curve_ >= PGP_CURVE_NIST_P_256 && curve_ <= PGP_CURVE_P256K1); const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); - return Botan::ECDH_PrivateKey(*(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_)); + return Botan::ECDH_PrivateKey( + *(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_)); } Botan::ECDH_PublicKey @@ -76,14 +83,13 @@ ecdh_kem_public_key_t::botan_key_ecdh(rnp::RNG *rng) const assert(curve_ >= PGP_CURVE_NIST_P_256 && curve_ <= PGP_CURVE_P256K1); const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); - Botan::EC_Group group(ec_desc->botan_name); - const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); - Botan::BigInt x(key_.data() + 1, curve_order); - Botan::BigInt y(key_.data() + 1 + curve_order, curve_order); + Botan::EC_Group group(ec_desc->botan_name); + const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); + Botan::BigInt x(key_.data() + 1, curve_order); + Botan::BigInt y(key_.data() + 1 + curve_order, curve_order); return Botan::ECDH_PublicKey(group, group.point(x, y)); } - Botan::Curve25519_PrivateKey ecdh_kem_private_key_t::botan_key_x25519() const { @@ -99,7 +105,10 @@ ecdh_kem_public_key_t::botan_key_x25519() const } rnp_result_t -ecdh_kem_public_key_t::encapsulate(rnp::RNG *rng, std::vector &ciphertext, std::vector &symmetric_key) { +ecdh_kem_public_key_t::encapsulate(rnp::RNG * rng, + std::vector &ciphertext, + std::vector &symmetric_key) +{ if (curve_ == PGP_CURVE_25519) { Botan::Curve25519_PrivateKey eph_prv_key(*(rng->obj())); ciphertext = eph_prv_key.public_value(); @@ -112,8 +121,8 @@ ecdh_kem_public_key_t::encapsulate(rnp::RNG *rng, std::vector &cipherte return RNP_ERROR_NOT_SUPPORTED; } - Botan::EC_Group domain(curve_desc->botan_name); - Botan::ECDH_PrivateKey eph_prv_key(*(rng->obj()), domain); + Botan::EC_Group domain(curve_desc->botan_name); + Botan::ECDH_PrivateKey eph_prv_key(*(rng->obj()), domain); Botan::PK_Key_Agreement key_agreement(eph_prv_key, *(rng->obj()), "Raw"); ciphertext = eph_prv_key.public_value(); symmetric_key = Botan::unlock(key_agreement.derive_key(0, key_).bits_of()); @@ -122,66 +131,68 @@ ecdh_kem_public_key_t::encapsulate(rnp::RNG *rng, std::vector &cipherte } rnp_result_t -ecdh_kem_private_key_t::decapsulate(rnp::RNG *rng, const std::vector &ciphertext, std::vector &plaintext) +ecdh_kem_private_key_t::decapsulate(rnp::RNG * rng, + const std::vector &ciphertext, + std::vector & plaintext) { if (curve_ == PGP_CURVE_25519) { Botan::Curve25519_PrivateKey priv_key = botan_key_x25519(); - Botan::PK_Key_Agreement key_agreement(priv_key, *(rng->obj()), "Raw"); + Botan::PK_Key_Agreement key_agreement(priv_key, *(rng->obj()), "Raw"); plaintext = Botan::unlock(key_agreement.derive_key(0, ciphertext).bits_of()); } else { - Botan::ECDH_PrivateKey priv_key = botan_key_ecdh(rng); + Botan::ECDH_PrivateKey priv_key = botan_key_ecdh(rng); Botan::PK_Key_Agreement key_agreement(priv_key, *(rng->obj()), "Raw"); plaintext = Botan::unlock(key_agreement.derive_key(0, ciphertext).bits_of()); } return RNP_SUCCESS; } -rnp_result_t -ec_key_t::generate_ecdh_kem_key_pair(rnp::RNG *rng, ecdh_kem_key_t *out, pgp_curve_t curve) +rnp_result_t +ec_key_t::generate_ecdh_kem_key_pair(rnp::RNG *rng, ecdh_kem_key_t *out, pgp_curve_t curve) { std::vector pub, priv; - rnp_result_t result = ecdh_kem_gen_keypair_native(rng, priv, pub, curve); - if(result != RNP_SUCCESS) { + rnp_result_t result = ecdh_kem_gen_keypair_native(rng, priv, pub, curve); + if (result != RNP_SUCCESS) { RNP_LOG("error when generating EC key pair"); return result; } - + out->priv = ecdh_kem_private_key_t(priv, curve); out->pub = ecdh_kem_public_key_t(pub, curve); return RNP_SUCCESS; } - exdsa_public_key_t::exdsa_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) - : ec_key_t(curve), - key_(key_buf, key_buf + key_buf_len) -{} + : ec_key_t(curve), key_(key_buf, key_buf + key_buf_len) +{ +} exdsa_public_key_t::exdsa_public_key_t(std::vector key, pgp_curve_t curve) - : ec_key_t(curve), - key_(key) -{} + : ec_key_t(curve), key_(key) +{ +} -exdsa_private_key_t::exdsa_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve) - : ec_key_t(curve), - key_(key_buf, key_buf + key_buf_len) -{} +exdsa_private_key_t::exdsa_private_key_t(uint8_t * key_buf, + size_t key_buf_len, + pgp_curve_t curve) + : ec_key_t(curve), key_(key_buf, key_buf + key_buf_len) +{ +} exdsa_private_key_t::exdsa_private_key_t(std::vector key, pgp_curve_t curve) - : ec_key_t(curve), - key_(Botan::secure_vector(key.begin(), key.end())) -{} - + : ec_key_t(curve), key_(Botan::secure_vector(key.begin(), key.end())) +{ +} -rnp_result_t -ec_key_t::generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t curve) +rnp_result_t +ec_key_t::generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t curve) { std::vector pub, priv; - rnp_result_t result = exdsa_gen_keypair_native(rng, priv, pub, curve); - if(result != RNP_SUCCESS) { + rnp_result_t result = exdsa_gen_keypair_native(rng, priv, pub, curve); + if (result != RNP_SUCCESS) { RNP_LOG("error when generating EC key pair"); return result; } - + out->priv = exdsa_private_key_t(priv, curve); out->pub = exdsa_public_key_t(pub, curve); @@ -191,8 +202,9 @@ ec_key_t::generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t c Botan::ECDSA_PrivateKey exdsa_private_key_t::botan_key(rnp::RNG *rng) const { - const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); - Botan::ECDSA_PrivateKey priv_key(*(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_)); + const ec_curve_desc_t * ec_desc = get_curve_desc(curve_); + Botan::ECDSA_PrivateKey priv_key( + *(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_)); return priv_key; } @@ -201,47 +213,54 @@ exdsa_public_key_t::botan_key() const { // format: 04 | X | Y const ec_curve_desc_t *ec_desc = get_curve_desc(curve_); - Botan::EC_Group group(ec_desc->botan_name); - const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); - Botan::BigInt x(key_.data() + 1, curve_order); - Botan::BigInt y(key_.data() + 1 + curve_order, curve_order); + Botan::EC_Group group(ec_desc->botan_name); + const size_t curve_order = BITS_TO_BYTES(ec_desc->bitlen); + Botan::BigInt x(key_.data() + 1, curve_order); + Botan::BigInt y(key_.data() + 1 + curve_order, curve_order); return Botan::ECDSA_PublicKey(group, group.point(x, y)); } /* NOTE hash_alg unused for ed25519/x25519 curves */ rnp_result_t -exdsa_private_key_t::sign(rnp::RNG *rng, std::vector &sig_out, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const +exdsa_private_key_t::sign(rnp::RNG * rng, + std::vector &sig_out, + const uint8_t * hash, + size_t hash_len, + pgp_hash_alg_t hash_alg) const { - if(curve_ == PGP_CURVE_ED25519) { + if (curve_ == PGP_CURVE_ED25519) { return ed25519_sign_native(rng, sig_out, Botan::unlock(key_), hash, hash_len); - } - else { + } else { Botan::ECDSA_PrivateKey priv_key = botan_key(rng); - auto signer = Botan::PK_Signer(priv_key, *(rng->obj()), ecdsa_padding_str_for(hash_alg)); + auto signer = + Botan::PK_Signer(priv_key, *(rng->obj()), ecdsa_padding_str_for(hash_alg)); sig_out = signer.sign_message(hash, hash_len, *(rng->obj())); } - return RNP_SUCCESS; + return RNP_SUCCESS; } rnp_result_t -exdsa_public_key_t::verify(const std::vector &sig, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const +exdsa_public_key_t::verify(const std::vector &sig, + const uint8_t * hash, + size_t hash_len, + pgp_hash_alg_t hash_alg) const { - if(curve_ == PGP_CURVE_ED25519) { + if (curve_ == PGP_CURVE_ED25519) { return ed25519_verify_native(sig, key_, hash, hash_len); - } - else { + } else { Botan::ECDSA_PublicKey pub_key = botan_key(); auto verifier = Botan::PK_Verifier(pub_key, ecdsa_padding_str_for(hash_alg)); - if(verifier.verify_message(hash, hash_len, sig.data(), sig.size())) { + if (verifier.verify_message(hash, hash_len, sig.data(), sig.size())) { return RNP_SUCCESS; } } - return RNP_ERROR_VERIFICATION_FAILED; + return RNP_ERROR_VERIFICATION_FAILED; } bool -exdsa_public_key_t::is_valid(rnp::RNG *rng) const { - if(curve_ == PGP_CURVE_ED25519) { +exdsa_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (curve_ == PGP_CURVE_ED25519) { Botan::Ed25519_PublicKey pub_key(key_); return pub_key.check_key(*(rng->obj()), false); } else { @@ -251,8 +270,9 @@ exdsa_public_key_t::is_valid(rnp::RNG *rng) const { } bool -exdsa_private_key_t::is_valid(rnp::RNG *rng) const { - if(curve_ == PGP_CURVE_ED25519) { +exdsa_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (curve_ == PGP_CURVE_ED25519) { Botan::Ed25519_PrivateKey priv_key(key_); return priv_key.check_key(*(rng->obj()), false); } else { @@ -262,8 +282,9 @@ exdsa_private_key_t::is_valid(rnp::RNG *rng) const { } bool -ecdh_kem_public_key_t::is_valid(rnp::RNG *rng) const { - if(curve_ == PGP_CURVE_25519) { +ecdh_kem_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (curve_ == PGP_CURVE_25519) { auto pub_key = botan_key_x25519(); return pub_key.check_key(*(rng->obj()), false); } else { @@ -272,9 +293,10 @@ ecdh_kem_public_key_t::is_valid(rnp::RNG *rng) const { } } -bool -ecdh_kem_private_key_t::is_valid(rnp::RNG *rng) const { - if(curve_ == PGP_CURVE_25519) { +bool +ecdh_kem_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (curve_ == PGP_CURVE_25519) { auto priv_key = botan_key_x25519(); return priv_key.check_key(*(rng->obj()), false); } else { @@ -282,4 +304,3 @@ ecdh_kem_private_key_t::is_valid(rnp::RNG *rng) const { return priv_key.check_key(*(rng->obj()), false); } } - diff --git a/src/lib/crypto/exdsa_ecdhkem.h b/src/lib/crypto/exdsa_ecdhkem.h index c2c4a5194..24c80bd2d 100644 --- a/src/lib/crypto/exdsa_ecdhkem.h +++ b/src/lib/crypto/exdsa_ecdhkem.h @@ -43,76 +43,83 @@ #include #include - struct ecdh_kem_key_t; /* forward declaration */ -struct exdsa_key_t; /* forward declaration */ +struct exdsa_key_t; /* forward declaration */ class ec_key_t { - -public: + public: virtual ~ec_key_t() = 0; ec_key_t(pgp_curve_t curve); ec_key_t() = default; - static rnp_result_t generate_ecdh_kem_key_pair(rnp::RNG *rng, ecdh_kem_key_t *out, pgp_curve_t curve); - static rnp_result_t generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t curve); + static rnp_result_t generate_ecdh_kem_key_pair(rnp::RNG * rng, + ecdh_kem_key_t *out, + pgp_curve_t curve); + static rnp_result_t generate_exdsa_key_pair(rnp::RNG * rng, + exdsa_key_t *out, + pgp_curve_t curve); - pgp_curve_t get_curve() const + pgp_curve_t + get_curve() const { return curve_; } -protected: + protected: pgp_curve_t curve_; }; class ecdh_kem_public_key_t : public ec_key_t { - -public: + public: ecdh_kem_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); ecdh_kem_public_key_t(std::vector key_buf, pgp_curve_t curve); ecdh_kem_public_key_t() = default; - bool operator==(const ecdh_kem_public_key_t &rhs) const + bool + operator==(const ecdh_kem_public_key_t &rhs) const { - return (curve_ == rhs.curve_) && (key_ == rhs.key_); + return (curve_ == rhs.curve_) && (key_ == rhs.key_); } bool is_valid(rnp::RNG *rng) const; - std::vector get_encoded() const + std::vector + get_encoded() const { return key_; } - rnp_result_t encapsulate(rnp::RNG *rng, std::vector &ciphertext, std::vector &symmetric_key); + rnp_result_t encapsulate(rnp::RNG * rng, + std::vector &ciphertext, + std::vector &symmetric_key); -private: - Botan::ECDH_PublicKey botan_key_ecdh(rnp::RNG *rng) const; + private: + Botan::ECDH_PublicKey botan_key_ecdh(rnp::RNG *rng) const; Botan::Curve25519_PublicKey botan_key_x25519() const; std::vector key_; }; - class ecdh_kem_private_key_t : public ec_key_t { - -public: + public: ecdh_kem_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); ecdh_kem_private_key_t(std::vector key_buf, pgp_curve_t curve); ecdh_kem_private_key_t() = default; - + bool is_valid(rnp::RNG *rng) const; - std::vector get_encoded() const + std::vector + get_encoded() const { return Botan::unlock(key_); } - rnp_result_t decapsulate(rnp::RNG *rng, const std::vector &ciphertext, std::vector &plaintext); + rnp_result_t decapsulate(rnp::RNG * rng, + const std::vector &ciphertext, + std::vector & plaintext); -private: - Botan::ECDH_PrivateKey botan_key_ecdh(rnp::RNG *rng) const; + private: + Botan::ECDH_PrivateKey botan_key_ecdh(rnp::RNG *rng) const; Botan::Curve25519_PrivateKey botan_key_x25519() const; Botan::secure_vector key_; @@ -120,54 +127,61 @@ class ecdh_kem_private_key_t : public ec_key_t { typedef struct ecdh_kem_key_t { ecdh_kem_private_key_t priv; - ecdh_kem_public_key_t pub; + ecdh_kem_public_key_t pub; } ecdh_kem_key_t; - class exdsa_public_key_t : public ec_key_t { - -public: + public: exdsa_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); exdsa_public_key_t(std::vector key_buf, pgp_curve_t curve); exdsa_public_key_t() = default; - bool operator==(const exdsa_public_key_t &rhs) const + bool + operator==(const exdsa_public_key_t &rhs) const { - return (curve_ == rhs.curve_) && (key_ == rhs.key_); + return (curve_ == rhs.curve_) && (key_ == rhs.key_); } bool is_valid(rnp::RNG *rng) const; - std::vector get_encoded() const + std::vector + get_encoded() const { return key_; } - rnp_result_t verify(const std::vector &sig, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const; + rnp_result_t verify(const std::vector &sig, + const uint8_t * hash, + size_t hash_len, + pgp_hash_alg_t hash_alg) const; -private: + private: Botan::ECDSA_PublicKey botan_key() const; std::vector key_; }; class exdsa_private_key_t : public ec_key_t { - -public: + public: exdsa_private_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve); exdsa_private_key_t(std::vector key_buf, pgp_curve_t curve); exdsa_private_key_t() = default; bool is_valid(rnp::RNG *rng) const; - std::vector get_encoded() const + std::vector + get_encoded() const { return Botan::unlock(key_); } - rnp_result_t sign(rnp::RNG *rng, std::vector &sig_out, const uint8_t *hash, size_t hash_len, pgp_hash_alg_t hash_alg) const; + rnp_result_t sign(rnp::RNG * rng, + std::vector &sig_out, + const uint8_t * hash, + size_t hash_len, + pgp_hash_alg_t hash_alg) const; -private: + private: Botan::ECDSA_PrivateKey botan_key(rnp::RNG *rng) const; Botan::secure_vector key_; @@ -175,7 +189,7 @@ class exdsa_private_key_t : public ec_key_t { typedef struct exdsa_key_t { exdsa_private_key_t priv; - exdsa_public_key_t pub; + exdsa_public_key_t pub; } exdsa_key_t; #endif diff --git a/src/lib/crypto/hkdf.cpp b/src/lib/crypto/hkdf.cpp index 6aebc3d66..e45e3e4c1 100644 --- a/src/lib/crypto/hkdf.cpp +++ b/src/lib/crypto/hkdf.cpp @@ -24,7 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - #include "config.h" #if defined(ENABLE_CRYPTO_REFRESH) @@ -58,7 +57,8 @@ Hkdf::size() const return size_; } -pgp_hash_alg_t Hkdf::alg() const +pgp_hash_alg_t +Hkdf::alg() const { return hash_alg_; } diff --git a/src/lib/crypto/hkdf_botan.cpp b/src/lib/crypto/hkdf_botan.cpp index 6d8afc3f7..1ecbedf50 100644 --- a/src/lib/crypto/hkdf_botan.cpp +++ b/src/lib/crypto/hkdf_botan.cpp @@ -43,8 +43,8 @@ Hkdf_Botan::create(pgp_hash_alg_t alg) return std::unique_ptr(new Hkdf_Botan(alg)); } - -std::string Hkdf_Botan::alg() const +std::string +Hkdf_Botan::alg() const { return std::string("HKDF(") + Hash_Botan::name_backend(Hkdf::alg()) + ")"; } @@ -62,10 +62,7 @@ Hkdf_Botan::extract_expand(const uint8_t *salt, std::unique_ptr kdf = Botan::KDF::create_or_throw(Hkdf_Botan::alg(), ""); Botan::secure_vector OKM; - OKM = kdf->derive_key(output_length, - ikm, ikm_len, - salt, salt_len, - info, info_len); + OKM = kdf->derive_key(output_length, ikm, ikm_len, salt, salt_len, info, info_len); memcpy(output_buf, Botan::unlock(OKM).data(), output_length); } diff --git a/src/lib/crypto/kmac.cpp b/src/lib/crypto/kmac.cpp index 52ec4e825..1101cca43 100644 --- a/src/lib/crypto/kmac.cpp +++ b/src/lib/crypto/kmac.cpp @@ -24,7 +24,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ - #include "config.h" #include "kmac.hpp" @@ -67,7 +66,7 @@ KMAC256::counter() const return counter_; } -/* +/* // Input: // algID - the algorithm ID encoded as octet // publicKey - the recipient's encryption sub-key packet @@ -79,7 +78,8 @@ std::vector KMAC256::fixedInfo(const std::vector &subkey_pkt_hash, pgp_pubkey_alg_t alg_id) { std::vector result(subkey_pkt_hash); - result.insert(result.begin(), (static_cast(alg_id)));; + result.insert(result.begin(), (static_cast(alg_id))); + ; return result; } @@ -89,7 +89,7 @@ KMAC256::encData(const std::vector &ecc_key_share, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, const std::vector &subkey_pkt_hash, - pgp_pubkey_alg_t alg_id) + pgp_pubkey_alg_t alg_id) { std::vector enc_data; std::vector counter_vec = counter(); @@ -111,7 +111,6 @@ KMAC256::encData(const std::vector &ecc_key_share, return enc_data; } - KMAC256::~KMAC256() { } diff --git a/src/lib/crypto/kmac.hpp b/src/lib/crypto/kmac.hpp index 20507c3a3..490f4f6fa 100644 --- a/src/lib/crypto/kmac.hpp +++ b/src/lib/crypto/kmac.hpp @@ -32,18 +32,21 @@ #include "config.h" #include "pgp-key.h" - namespace rnp { class KMAC256 { - /* KDF for PQC key combiner according to https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-01 */ + /* KDF for PQC key combiner according to + * https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-01 */ protected: - /* The value of domSeparation is the UTF-8 encoding of the string "OpenPGPV5CompositeKDF" and MUST be the following octet sequence: + /* The value of domSeparation is the UTF-8 encoding of the string "OpenPGPV5CompositeKDF" + and MUST be the following octet sequence: domSeparation := 4F 70 65 6E 50 47 50 56 35 43 6F 6D 70 6F 73 69 74 65 4B 44 46 */ - const std::vector domSeparation_ = std::vector({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x56, 0x35, 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, 0x4B, 0x44, 0x46}); + const std::vector domSeparation_ = + std::vector({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x56, 0x35, 0x43, 0x6F, + 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, 0x4B, 0x44, 0x46}); /* customizationString := 4B 44 46 */ const std::vector customizationString_ = std::vector({0x4B, 0x44, 0x46}); @@ -54,15 +57,16 @@ class KMAC256 { std::vector domSeparation() const; std::vector customizationString() const; std::vector counter() const; - std::vector fixedInfo(const std::vector &subkey_pkt_hash, pgp_pubkey_alg_t alg_id); + std::vector fixedInfo(const std::vector &subkey_pkt_hash, + pgp_pubkey_alg_t alg_id); std::vector encData(const std::vector &ecc_key_share, const std::vector &ecc_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, const std::vector &subkey_pkt_hash, - pgp_pubkey_alg_t alg_id); + pgp_pubkey_alg_t alg_id); - KMAC256() {}; + KMAC256(){}; public: static std::unique_ptr create(); @@ -72,9 +76,9 @@ class KMAC256 { const std::vector &ecc_key_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, - const pgp_pubkey_alg_t alg_id, + const pgp_pubkey_alg_t alg_id, const std::vector &subkey_pkt_hash, - std::vector &out) = 0; + std::vector & out) = 0; virtual ~KMAC256(); }; diff --git a/src/lib/crypto/kmac_botan.cpp b/src/lib/crypto/kmac_botan.cpp index 55c604cb3..a2a2048bf 100644 --- a/src/lib/crypto/kmac_botan.cpp +++ b/src/lib/crypto/kmac_botan.cpp @@ -45,21 +45,26 @@ KMAC256_Botan::compute(const std::vector &ecc_key_share, const std::vector &ecc_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, - const pgp_pubkey_alg_t alg_id, + const pgp_pubkey_alg_t alg_id, const std::vector &subkey_pkt_hash, - std::vector &out) + std::vector & out) { auto kmac = Botan::MessageAuthenticationCode::create_or_throw("KMAC256(256)"); /* the mapping between the KEM Combiner and the MAC interface is: - * key <> domSeparation - * nonce <> customizationString - * message <> encData - */ + * key <> domSeparation + * nonce <> customizationString + * message <> encData + */ kmac->set_key(domSeparation()); kmac->start(customizationString()); // set nonce - kmac->update(encData(ecc_key_share, ecc_ciphertext, kyber_key_share, kyber_ciphertext, subkey_pkt_hash, alg_id)); + kmac->update(encData(ecc_key_share, + ecc_ciphertext, + kyber_key_share, + kyber_ciphertext, + subkey_pkt_hash, + alg_id)); out = kmac->final_stdvec(); } diff --git a/src/lib/crypto/kmac_botan.hpp b/src/lib/crypto/kmac_botan.hpp index 3da07fffb..0d201427f 100644 --- a/src/lib/crypto/kmac_botan.hpp +++ b/src/lib/crypto/kmac_botan.hpp @@ -32,9 +32,7 @@ namespace rnp { class KMAC256_Botan : public KMAC256 { - - private: - + private: public: KMAC256_Botan(); KMAC256_Botan(const KMAC256_Botan &src); @@ -47,9 +45,9 @@ class KMAC256_Botan : public KMAC256 { const std::vector &ecc_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, - const pgp_pubkey_alg_t alg_id, + const pgp_pubkey_alg_t alg_id, const std::vector &subkey_pkt_hash, - std::vector &out) override; + std::vector & out) override; }; } // namespace rnp diff --git a/src/lib/crypto/kyber.cpp b/src/lib/crypto/kyber.cpp index 661744216..6652fc458 100644 --- a/src/lib/crypto/kyber.cpp +++ b/src/lib/crypto/kyber.cpp @@ -93,7 +93,10 @@ pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) Botan::secure_vector encap_key; // this has to go over the wire Botan::secure_vector data_encryption_key; // this is the key used for // encryption of the payload data - kem_enc.encrypt(encap_key, data_encryption_key, key_share_size_from_kyber_param(kyber_mode_), *rng->obj()); + kem_enc.encrypt(encap_key, + data_encryption_key, + key_share_size_from_kyber_param(kyber_mode_), + *rng->obj()); kyber_encap_result_t result; result.ciphertext.insert( result.ciphertext.end(), encap_key.data(), encap_key.data() + encap_key.size()); @@ -104,7 +107,9 @@ pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) } std::vector -pgp_kyber_private_key_t::decapsulate(rnp::RNG *rng, const uint8_t *ciphertext, size_t ciphertext_len) +pgp_kyber_private_key_t::decapsulate(rnp::RNG * rng, + const uint8_t *ciphertext, + size_t ciphertext_len) { assert(is_initialized_); auto decoded_kyber_priv = botan_key(); @@ -116,21 +121,23 @@ pgp_kyber_private_key_t::decapsulate(rnp::RNG *rng, const uint8_t *ciphertext, s } bool -pgp_kyber_public_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized_) { +pgp_kyber_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized_) { return false; } - auto key = botan_key(); + auto key = botan_key(); return key.check_key(*(rng->obj()), false); } bool -pgp_kyber_private_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized_) { +pgp_kyber_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized_) { return false; } - auto key = botan_key(); + auto key = botan_key(); return key.check_key(*(rng->obj()), false); } diff --git a/src/lib/crypto/kyber.h b/src/lib/crypto/kyber.h index 9eb81859d..e5155e247 100644 --- a/src/lib/crypto/kyber.h +++ b/src/lib/crypto/kyber.h @@ -48,13 +48,17 @@ struct kyber_encap_result_t { class pgp_kyber_private_key_t { public: - pgp_kyber_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode); + pgp_kyber_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + kyber_parameter_e mode); pgp_kyber_private_key_t(std::vector const &key_encoded, kyber_parameter_e mode); pgp_kyber_private_key_t() = default; bool is_valid(rnp::RNG *rng) const; - std::vector decapsulate(rnp::RNG *rng, const uint8_t *ciphertext, size_t ciphertext_len); + std::vector decapsulate(rnp::RNG * rng, + const uint8_t *ciphertext, + size_t ciphertext_len); std::vector get_encoded() const { @@ -71,20 +75,23 @@ class pgp_kyber_private_key_t { Botan::Kyber_PrivateKey botan_key() const; Botan::secure_vector key_encoded_; - kyber_parameter_e kyber_mode_; - bool is_initialized_ = false; + kyber_parameter_e kyber_mode_; + bool is_initialized_ = false; }; class pgp_kyber_public_key_t { public: - pgp_kyber_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode); + pgp_kyber_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + 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); - bool operator==(const pgp_kyber_public_key_t &rhs) const + bool + operator==(const pgp_kyber_public_key_t &rhs) const { - return (kyber_mode_ == rhs.kyber_mode_) && (key_encoded_ == rhs.key_encoded_); + return (kyber_mode_ == rhs.kyber_mode_) && (key_encoded_ == rhs.key_encoded_); } bool is_valid(rnp::RNG *rng) const; @@ -99,8 +106,8 @@ class pgp_kyber_public_key_t { Botan::Kyber_PublicKey botan_key() const; std::vector key_encoded_; - kyber_parameter_e kyber_mode_; - bool is_initialized_ = false; + kyber_parameter_e kyber_mode_; + bool is_initialized_ = false; }; std::pair kyber_generate_keypair( diff --git a/src/lib/crypto/kyber_common.cpp b/src/lib/crypto/kyber_common.cpp index a0b1112c4..0616828b6 100644 --- a/src/lib/crypto/kyber_common.cpp +++ b/src/lib/crypto/kyber_common.cpp @@ -32,81 +32,87 @@ #include "types.h" #include "logging.h" -size_t kyber_privkey_size(kyber_parameter_e parameter) { - switch(parameter) { - case kyber_768: - return 2400; - case kyber_1024: - return 3168; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +kyber_privkey_size(kyber_parameter_e parameter) +{ + switch (parameter) { + case kyber_768: + return 2400; + case kyber_1024: + return 3168; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -size_t kyber_pubkey_size(kyber_parameter_e parameter) { - switch(parameter) { - case kyber_768: - return 1184; - case kyber_1024: - return 1568; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +kyber_pubkey_size(kyber_parameter_e parameter) +{ + switch (parameter) { + case kyber_768: + return 1184; + case kyber_1024: + return 1568; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -size_t kyber_keyshare_size(kyber_parameter_e parameter) { - switch(parameter) { - case kyber_768: - return 24; - case kyber_1024: - return 32; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +kyber_keyshare_size(kyber_parameter_e parameter) +{ + switch (parameter) { + case kyber_768: + return 24; + case kyber_1024: + return 32; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -size_t kyber_ciphertext_size(kyber_parameter_e parameter) { - switch(parameter) { - case kyber_768: - return 1088; - case kyber_1024: - return 1568; - default: - RNP_LOG("invalid parameter given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +size_t +kyber_ciphertext_size(kyber_parameter_e parameter) +{ + switch (parameter) { + case kyber_768: + return 1088; + case kyber_1024: + return 1568; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } -pgp_kyber_public_key_t::pgp_kyber_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode): - key_encoded_(key_encoded, key_encoded + key_encoded_len), - kyber_mode_(mode), - is_initialized_(true) +pgp_kyber_public_key_t::pgp_kyber_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + kyber_parameter_e mode) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), kyber_mode_(mode), + is_initialized_(true) { } -pgp_kyber_public_key_t::pgp_kyber_public_key_t(std::vector const& key_encoded, kyber_parameter_e mode): - key_encoded_(key_encoded), - kyber_mode_(mode), - is_initialized_(true) +pgp_kyber_public_key_t::pgp_kyber_public_key_t(std::vector const &key_encoded, + kyber_parameter_e mode) + : key_encoded_(key_encoded), kyber_mode_(mode), is_initialized_(true) { } - -pgp_kyber_private_key_t::pgp_kyber_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, kyber_parameter_e mode): - key_encoded_(key_encoded, key_encoded + key_encoded_len), - kyber_mode_(mode), - is_initialized_(true) +pgp_kyber_private_key_t::pgp_kyber_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + kyber_parameter_e mode) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), kyber_mode_(mode), + is_initialized_(true) { } - -pgp_kyber_private_key_t::pgp_kyber_private_key_t(std::vector const& key_encoded, kyber_parameter_e mode): - key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), - kyber_mode_(mode), - is_initialized_(true) +pgp_kyber_private_key_t::pgp_kyber_private_key_t(std::vector const &key_encoded, + kyber_parameter_e mode) + : key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), + kyber_mode_(mode), is_initialized_(true) { } - diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp index b3e19e1c1..bb4058b92 100644 --- a/src/lib/crypto/kyber_ecdh_composite.cpp +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -37,212 +37,231 @@ #include #include -pgp_kyber_ecdh_composite_key_t::~pgp_kyber_ecdh_composite_key_t() {} +pgp_kyber_ecdh_composite_key_t::~pgp_kyber_ecdh_composite_key_t() +{ +} void -pgp_kyber_ecdh_composite_key_t::initialized_or_throw() const { - if(!is_initialized()) { +pgp_kyber_ecdh_composite_key_t::initialized_or_throw() const +{ + if (!is_initialized()) { RNP_LOG("Trying to use uninitialized kyber-ecdh key"); - throw rnp::rnp_exception(RNP_ERROR_GENERIC); /* TODO better return error */ + throw rnp::rnp_exception(RNP_ERROR_GENERIC); /* TODO better return error */ } } rnp_result_t -pgp_kyber_ecdh_composite_key_t::gen_keypair(rnp::RNG *rng, pgp_kyber_ecdh_key_t *key, pgp_pubkey_alg_t alg) +pgp_kyber_ecdh_composite_key_t::gen_keypair(rnp::RNG * rng, + pgp_kyber_ecdh_key_t *key, + pgp_pubkey_alg_t alg) { - rnp_result_t res; - pgp_curve_t curve = pk_alg_to_curve_id(alg); + rnp_result_t res; + pgp_curve_t curve = pk_alg_to_curve_id(alg); kyber_parameter_e kyber_id = pk_alg_to_kyber_id(alg); ecdh_kem_key_t ecdh_key_pair; res = ec_key_t::generate_ecdh_kem_key_pair(rng, &ecdh_key_pair, curve); - if(res != RNP_SUCCESS) { + if (res != RNP_SUCCESS) { RNP_LOG("generating kyber ecdh composite key failed when generating ecdh key"); return res; } auto kyber_key_pair = kyber_generate_keypair(rng, kyber_id); - key->priv = pgp_kyber_ecdh_composite_private_key_t(ecdh_key_pair.priv.get_encoded(), kyber_key_pair.second.get_encoded(), alg); - key->pub = pgp_kyber_ecdh_composite_public_key_t(ecdh_key_pair.pub.get_encoded(), kyber_key_pair.first.get_encoded(), alg); + key->priv = pgp_kyber_ecdh_composite_private_key_t( + ecdh_key_pair.priv.get_encoded(), kyber_key_pair.second.get_encoded(), alg); + key->pub = pgp_kyber_ecdh_composite_public_key_t( + ecdh_key_pair.pub.get_encoded(), kyber_key_pair.first.get_encoded(), alg); return RNP_SUCCESS; } size_t -pgp_kyber_ecdh_composite_key_t::ecdh_curve_privkey_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_25519: - return 32; - /* TODO */ - // case PGP_CURVE_X448: - // return 56; - case PGP_CURVE_NIST_P_256: - return 32; - case PGP_CURVE_NIST_P_384: - return 48; - case PGP_CURVE_BP256: - return 32; - case PGP_CURVE_BP384: - return 48; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_kyber_ecdh_composite_key_t::ecdh_curve_privkey_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 32; + case PGP_CURVE_NIST_P_384: + return 48; + case PGP_CURVE_BP256: + return 32; + case PGP_CURVE_BP384: + return 48; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } size_t -pgp_kyber_ecdh_composite_key_t::ecdh_curve_pubkey_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_25519: - return 32; - /* TODO */ - // case PGP_CURVE_X448: - // return 56; - case PGP_CURVE_NIST_P_256: - return 65; - case PGP_CURVE_NIST_P_384: - return 97; - case PGP_CURVE_BP256: - return 65; - case PGP_CURVE_BP384: - return 97; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_kyber_ecdh_composite_key_t::ecdh_curve_pubkey_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 65; + case PGP_CURVE_NIST_P_384: + return 97; + case PGP_CURVE_BP256: + return 65; + case PGP_CURVE_BP384: + return 97; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } size_t -pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_25519: - return 32; - /* TODO */ - // case PGP_CURVE_X448: - // return 56; - case PGP_CURVE_NIST_P_256: - return 65; - case PGP_CURVE_NIST_P_384: - return 97; - case PGP_CURVE_BP256: - return 65; - case PGP_CURVE_BP384: - return 97; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 65; + case PGP_CURVE_NIST_P_384: + return 97; + case PGP_CURVE_BP256: + return 65; + case PGP_CURVE_BP384: + return 97; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } size_t -pgp_kyber_ecdh_composite_key_t::ecdh_curve_keyshare_size(pgp_curve_t curve) { - switch(curve) { - case PGP_CURVE_25519: - return 32; - /* TODO */ - // case PGP_CURVE_X448: - // return 56; - case PGP_CURVE_NIST_P_256: - return 32; - case PGP_CURVE_NIST_P_384: - return 48; - case PGP_CURVE_BP256: - return 32; - case PGP_CURVE_BP384: - return 48; - default: - RNP_LOG("invalid curve given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); +pgp_kyber_ecdh_composite_key_t::ecdh_curve_keyshare_size(pgp_curve_t curve) +{ + switch (curve) { + case PGP_CURVE_25519: + return 32; + /* TODO */ + // case PGP_CURVE_X448: + // return 56; + case PGP_CURVE_NIST_P_256: + return 32; + case PGP_CURVE_NIST_P_384: + return 48; + case PGP_CURVE_BP256: + return 32; + case PGP_CURVE_BP384: + return 48; + default: + RNP_LOG("invalid curve given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } kyber_parameter_e -pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg) { - switch(pk_alg) - { - case PGP_PKA_KYBER768_X25519: +pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg) +{ + switch (pk_alg) { + case PGP_PKA_KYBER768_X25519: [[fallthrough]]; - case PGP_PKA_KYBER768_P256: + case PGP_PKA_KYBER768_P256: [[fallthrough]]; - case PGP_PKA_KYBER768_BP256: - return kyber_768; - case PGP_PKA_KYBER1024_BP384: + case PGP_PKA_KYBER768_BP256: + return kyber_768; + case PGP_PKA_KYBER1024_BP384: [[fallthrough]]; - case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER1024_P384: //[[fallthrough]]; - //case PGP_PKA_KYBER1024_X448: + // case PGP_PKA_KYBER1024_X448: return kyber_1024; - default: + default: RNP_LOG("invalid PK alg given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } pgp_curve_t -pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg) { - switch(pk_alg) - { - case PGP_PKA_KYBER768_X25519: +pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg) +{ + switch (pk_alg) { + case PGP_PKA_KYBER768_X25519: return PGP_CURVE_25519; - case PGP_PKA_KYBER768_P256: + case PGP_PKA_KYBER768_P256: return PGP_CURVE_NIST_P_256; - case PGP_PKA_KYBER768_BP256: - return PGP_CURVE_BP256; - case PGP_PKA_KYBER1024_BP384: + case PGP_PKA_KYBER768_BP256: + return PGP_CURVE_BP256; + case PGP_PKA_KYBER1024_BP384: return PGP_CURVE_BP384; - case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER1024_P384: return PGP_CURVE_NIST_P_384; - /*case PGP_PKA_KYBER1024_X448: - return ... NOT_IMPLEMENTED*/ - default: + /*case PGP_PKA_KYBER1024_X448: + return ... NOT_IMPLEMENTED*/ + default: RNP_LOG("invalid PK alg given"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } } - -pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t( + const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); } -pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t( + std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(key_encoded); } -pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg) +pgp_kyber_ecdh_composite_private_key_t::pgp_kyber_ecdh_composite_private_key_t( + std::vector const &ecdh_key_encoded, + std::vector const &kyber_key_encoded, + pgp_pubkey_alg_t pk_alg) : pk_alg_(pk_alg) { - if(ecdh_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != ecdh_key_encoded.size() - || kyber_privkey_size(pk_alg_to_kyber_id(pk_alg)) != kyber_key_encoded.size()) - { + if (ecdh_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != ecdh_key_encoded.size() || + kyber_privkey_size(pk_alg_to_kyber_id(pk_alg)) != kyber_key_encoded.size()) { RNP_LOG("ecdh or kyber key length mismatch"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - kyber_key_ = std::make_unique(pgp_kyber_private_key_t(kyber_key_encoded, pk_alg_to_kyber_id(pk_alg))); - ecdh_key_ = std::make_unique(ecdh_kem_private_key_t(ecdh_key_encoded, pk_alg_to_curve_id(pk_alg))); + kyber_key_ = std::make_unique( + pgp_kyber_private_key_t(kyber_key_encoded, pk_alg_to_kyber_id(pk_alg))); + ecdh_key_ = std::make_unique( + ecdh_kem_private_key_t(ecdh_key_encoded, pk_alg_to_curve_id(pk_alg))); is_initialized_ = true; } -/* copy assignment operator is used on key materials struct and thus needs to be defined for this class as well */ -pgp_kyber_ecdh_composite_private_key_t& pgp_kyber_ecdh_composite_private_key_t::operator=(const pgp_kyber_ecdh_composite_private_key_t& other) +/* copy assignment operator is used on key materials struct and thus needs to be defined for + * this class as well */ +pgp_kyber_ecdh_composite_private_key_t & +pgp_kyber_ecdh_composite_private_key_t::operator=( + const pgp_kyber_ecdh_composite_private_key_t &other) { pgp_kyber_ecdh_composite_key_t::operator=(other); pk_alg_ = other.pk_alg_; - if(other.is_initialized() && other.kyber_key_) - { - kyber_key_ = std::make_unique(pgp_kyber_private_key_t(other.kyber_key_->get_encoded(), other.kyber_key_->param())); + if (other.is_initialized() && other.kyber_key_) { + kyber_key_ = std::make_unique( + pgp_kyber_private_key_t(other.kyber_key_->get_encoded(), other.kyber_key_->param())); } - if(other.is_initialized() && other.ecdh_key_) - { - ecdh_key_ = std::make_unique(ecdh_kem_private_key_t(other.ecdh_key_->get_encoded(), other.ecdh_key_->get_curve())); + if (other.is_initialized() && other.ecdh_key_) { + ecdh_key_ = std::make_unique(ecdh_kem_private_key_t( + other.ecdh_key_->get_encoded(), other.ecdh_key_->get_curve())); } return *this; @@ -251,115 +270,140 @@ pgp_kyber_ecdh_composite_private_key_t& pgp_kyber_ecdh_composite_private_key_t:: size_t pgp_kyber_ecdh_composite_private_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) { - kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg); - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); - return ecdh_curve_privkey_size(curve) + kyber_privkey_size(kyber_param); + kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return ecdh_curve_privkey_size(curve) + kyber_privkey_size(kyber_param); } void -pgp_kyber_ecdh_composite_private_key_t::parse_component_keys(std::vector key_encoded) { +pgp_kyber_ecdh_composite_private_key_t::parse_component_keys(std::vector key_encoded) +{ if (key_encoded.size() != encoded_size(pk_alg_)) { RNP_LOG("Kyber composite key format invalid: length mismatch"); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg_); - pgp_curve_t ecdh_curve = pk_alg_to_curve_id(pk_alg_); - size_t split_at = ecdh_curve_privkey_size(pk_alg_to_curve_id(pk_alg_)); - - kyber_key_ = std::make_unique(pgp_kyber_private_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, kyber_param)); - ecdh_key_ = std::make_unique(ecdh_kem_private_key_t(key_encoded.data(), split_at, ecdh_curve)); + pgp_curve_t ecdh_curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = ecdh_curve_privkey_size(pk_alg_to_curve_id(pk_alg_)); + + kyber_key_ = std::make_unique(pgp_kyber_private_key_t( + key_encoded.data() + split_at, key_encoded.size() - split_at, kyber_param)); + ecdh_key_ = std::make_unique( + ecdh_kem_private_key_t(key_encoded.data(), split_at, ecdh_curve)); is_initialized_ = true; } - -namespace +namespace { +std::vector +hashed_ecc_keyshare(const std::vector &key_share, + const std::vector &ciphertext, + pgp_pubkey_alg_t alg_id) { - std::vector hashed_ecc_keyshare(const std::vector &key_share, const std::vector &ciphertext, pgp_pubkey_alg_t alg_id) - { - /* SHA3-256(X || eccCipherText) or SHA3-256(X || eccCipherText) depending on algorithm */ - - std::vector digest; - pgp_hash_alg_t hash_alg; - - switch(alg_id) - { - case PGP_PKA_KYBER768_X25519: - case PGP_PKA_KYBER768_BP256: - case PGP_PKA_KYBER768_P256: - hash_alg = PGP_HASH_SHA3_256; - break; - //case PGP_PKA_KYBER1024_X448: - case PGP_PKA_KYBER1024_P384: - case PGP_PKA_KYBER1024_BP384: - hash_alg = PGP_HASH_SHA3_512; - break; - default: - RNP_LOG("key combiner does not support this algorithm"); - throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); - } - - auto hash = rnp::Hash::create(hash_alg); - hash->add(key_share); - hash->add(ciphertext); - - digest.resize(rnp::Hash::size(hash_alg)); - hash->finish(digest.data()); - - return digest; + /* SHA3-256(X || eccCipherText) or SHA3-256(X || eccCipherText) depending on algorithm */ + + std::vector digest; + pgp_hash_alg_t hash_alg; + + switch (alg_id) { + case PGP_PKA_KYBER768_X25519: + case PGP_PKA_KYBER768_BP256: + case PGP_PKA_KYBER768_P256: + hash_alg = PGP_HASH_SHA3_256; + break; + // case PGP_PKA_KYBER1024_X448: + case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER1024_BP384: + hash_alg = PGP_HASH_SHA3_512; + break; + default: + RNP_LOG("key combiner does not support this algorithm"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); } + + auto hash = rnp::Hash::create(hash_alg); + hash->add(key_share); + hash->add(ciphertext); + + digest.resize(rnp::Hash::size(hash_alg)); + hash->finish(digest.data()); + + return digest; } +} // namespace 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 std::vector &subkey_pkt_hash) +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 std::vector &subkey_pkt_hash) { initialized_or_throw(); assert(subkey_pkt_hash.size() == rnp::Hash::size(PGP_HASH_SHA3_256)); - rnp_result_t res; + rnp_result_t res; std::vector ecdh_keyshare; std::vector hashed_ecdh_keyshare; std::vector kyber_keyshare; - if( ((enc->wrapped_sesskey.size() % 8) != 0) || (enc->wrapped_sesskey.size() < 16)) { - RNP_LOG("invalid wrapped AES key length (size is a multiple of 8 octets with 8 octets integrity check)"); + if (((enc->wrapped_sesskey.size() % 8) != 0) || (enc->wrapped_sesskey.size() < 16)) { + RNP_LOG("invalid wrapped AES key length (size is a multiple of 8 octets with 8 octets " + "integrity check)"); return RNP_ERROR_BAD_PARAMETERS; } // Compute (eccKeyShare) := eccKem.decap(eccCipherText, eccPrivateKey) - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); - std::vector ecdh_encapsulated_keyshare = std::vector(enc->composite_ciphertext.data(), enc->composite_ciphertext.data() + ecdh_curve_ephemeral_size(curve)); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg_); + std::vector ecdh_encapsulated_keyshare = std::vector( + enc->composite_ciphertext.data(), + enc->composite_ciphertext.data() + ecdh_curve_ephemeral_size(curve)); res = ecdh_key_->decapsulate(rng, ecdh_encapsulated_keyshare, ecdh_keyshare); - if(res) { + if (res) { RNP_LOG("error when decrypting kyber-ecdh encrypted session key"); return res; } - hashed_ecdh_keyshare = hashed_ecc_keyshare(ecdh_keyshare, ecdh_encapsulated_keyshare, pk_alg_); - + hashed_ecdh_keyshare = + hashed_ecc_keyshare(ecdh_keyshare, ecdh_encapsulated_keyshare, pk_alg_); + // Compute (kyberKeyShare) := kyberKem.decap(kyberCipherText, kyberPrivateKey) - std::vector kyber_encapsulated_keyshare = std::vector(enc->composite_ciphertext.begin() + ecdh_curve_ephemeral_size(curve), enc->composite_ciphertext.end()); - kyber_keyshare = kyber_key_->decapsulate(rng, kyber_encapsulated_keyshare.data(), kyber_encapsulated_keyshare.size()); - if(res) { + std::vector kyber_encapsulated_keyshare = std::vector( + enc->composite_ciphertext.begin() + ecdh_curve_ephemeral_size(curve), + enc->composite_ciphertext.end()); + kyber_keyshare = kyber_key_->decapsulate( + rng, kyber_encapsulated_keyshare.data(), kyber_encapsulated_keyshare.size()); + if (res) { RNP_LOG("error when decrypting kyber-ecdh encrypted session key"); return res; } - // Compute KEK := multiKeyCombine(eccKeyShare, kyberKeyShare, fixedInfo) as defined in Section 4.2.2 + // Compute KEK := multiKeyCombine(eccKeyShare, kyberKeyShare, fixedInfo) as defined in + // Section 4.2.2 std::vector kek_vec; - auto kmac = rnp::KMAC256::create(); - kmac->compute(hashed_ecdh_keyshare, ecdh_encapsulated_keyshare, kyber_keyshare, kyber_encapsulated_keyshare, pk_alg(), subkey_pkt_hash, kek_vec); + auto kmac = rnp::KMAC256::create(); + kmac->compute(hashed_ecdh_keyshare, + ecdh_encapsulated_keyshare, + kyber_keyshare, + kyber_encapsulated_keyshare, + pk_alg(), + subkey_pkt_hash, + kek_vec); Botan::SymmetricKey kek(kek_vec); - // Compute sessionKey := AESKeyUnwrap(KEK, C) with AES-256 as per [RFC3394], aborting if the 64 bit integrity check fails + // Compute sessionKey := AESKeyUnwrap(KEK, C) with AES-256 as per [RFC3394], aborting if + // the 64 bit integrity check fails Botan::secure_vector tmp_out; try { - tmp_out = Botan::rfc3394_keyunwrap(Botan::secure_vector(enc->wrapped_sesskey.begin(), enc->wrapped_sesskey.end()), kek); + tmp_out = + Botan::rfc3394_keyunwrap(Botan::secure_vector(enc->wrapped_sesskey.begin(), + enc->wrapped_sesskey.end()), + kek); } catch (const std::exception &e) { RNP_LOG("Keyunwrap failed: %s", e.what()); return RNP_ERROR_DECRYPT_FAILED; } - if(*out_len < tmp_out.size()) { + if (*out_len < tmp_out.size()) { RNP_LOG("buffer for decryption result too small"); return RNP_ERROR_DECRYPT_FAILED; } @@ -370,15 +414,18 @@ pgp_kyber_ecdh_composite_private_key_t::decrypt(rnp::RNG *rng, uint8_t *out, siz } void -pgp_kyber_ecdh_composite_private_key_t::secure_clear() { - // private key buffer is stored in a secure_vector and will be securely erased by the destructor. +pgp_kyber_ecdh_composite_private_key_t::secure_clear() +{ + // private key buffer is stored in a secure_vector and will be securely erased by the + // destructor. kyber_key_.reset(); ecdh_key_.reset(); is_initialized_ = false; } std::vector -pgp_kyber_ecdh_composite_private_key_t::get_encoded() const { +pgp_kyber_ecdh_composite_private_key_t::get_encoded() const +{ initialized_or_throw(); std::vector result; std::vector ecdh_key_encoded = ecdh_key_->get_encoded(); @@ -389,29 +436,31 @@ pgp_kyber_ecdh_composite_private_key_t::get_encoded() const { return result; }; - -pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t( + const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(std::vector(key_encoded, key_encoded + key_encoded_len)); } -pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg): - pk_alg_(pk_alg) +pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t( + std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg) { parse_component_keys(key_encoded); } -pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg) - : pk_alg_(pk_alg), - kyber_key_(kyber_key_encoded, pk_alg_to_kyber_id(pk_alg)), +pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t( + std::vector const &ecdh_key_encoded, + std::vector const &kyber_key_encoded, + pgp_pubkey_alg_t pk_alg) + : pk_alg_(pk_alg), kyber_key_(kyber_key_encoded, pk_alg_to_kyber_id(pk_alg)), ecdh_key_(ecdh_key_encoded, pk_alg_to_curve_id(pk_alg)) { - if(ecdh_curve_pubkey_size(pk_alg_to_curve_id(pk_alg)) != ecdh_key_encoded.size() - || kyber_pubkey_size(pk_alg_to_kyber_id(pk_alg)) != kyber_key_encoded.size()) - { + if (ecdh_curve_pubkey_size(pk_alg_to_curve_id(pk_alg)) != ecdh_key_encoded.size() || + kyber_pubkey_size(pk_alg_to_kyber_id(pk_alg)) != kyber_key_encoded.size()) { RNP_LOG("ecdh or kyber key length mismatch"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } is_initialized_ = true; } @@ -419,76 +468,95 @@ pgp_kyber_ecdh_composite_public_key_t::pgp_kyber_ecdh_composite_public_key_t(std size_t pgp_kyber_ecdh_composite_public_key_t::encoded_size(pgp_pubkey_alg_t pk_alg) { - kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg); - pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); - return ecdh_curve_pubkey_size(curve) + kyber_pubkey_size(kyber_param); + kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg); + pgp_curve_t curve = pk_alg_to_curve_id(pk_alg); + return ecdh_curve_pubkey_size(curve) + kyber_pubkey_size(kyber_param); } void -pgp_kyber_ecdh_composite_public_key_t::parse_component_keys(std::vector key_encoded) { +pgp_kyber_ecdh_composite_public_key_t::parse_component_keys(std::vector key_encoded) +{ if (key_encoded.size() != encoded_size(pk_alg_)) { RNP_LOG("Kyber composite key format invalid: length mismatch"); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } kyber_parameter_e kyber_param = pk_alg_to_kyber_id(pk_alg_); - pgp_curve_t ecdh_curve = pk_alg_to_curve_id(pk_alg_); - size_t split_at = ecdh_curve_pubkey_size(pk_alg_to_curve_id(pk_alg_)); - - kyber_key_ = pgp_kyber_public_key_t(key_encoded.data() + split_at, key_encoded.size() - split_at, kyber_param); + pgp_curve_t ecdh_curve = pk_alg_to_curve_id(pk_alg_); + size_t split_at = ecdh_curve_pubkey_size(pk_alg_to_curve_id(pk_alg_)); + + kyber_key_ = pgp_kyber_public_key_t( + key_encoded.data() + split_at, key_encoded.size() - split_at, kyber_param); ecdh_key_ = ecdh_kem_public_key_t(key_encoded.data(), split_at, ecdh_curve); is_initialized_ = true; } 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, const std::vector &subkey_pkt_hash) +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, + const std::vector &subkey_pkt_hash) { initialized_or_throw(); assert(subkey_pkt_hash.size() == rnp::Hash::size(PGP_HASH_SHA3_256)); - rnp_result_t res; + rnp_result_t res; std::vector ecdh_ciphertext; std::vector ecdh_symmetric_key; std::vector ecdh_hashed_symmetric_key; - if((session_key_len % 8) != 0) { + if ((session_key_len % 8) != 0) { RNP_LOG("AES key wrap requires a multiple of 8 octets as input key"); return RNP_ERROR_BAD_PARAMETERS; } - + // Compute (eccCipherText, eccKeyShare) := eccKem.encap(eccPublicKey) res = ecdh_key_.encapsulate(rng, ecdh_ciphertext, ecdh_symmetric_key); - if(res) { + if (res) { RNP_LOG("error when encapsulating with ECDH"); return res; } - ecdh_hashed_symmetric_key = hashed_ecc_keyshare(ecdh_symmetric_key, ecdh_ciphertext, pk_alg_); + ecdh_hashed_symmetric_key = + hashed_ecc_keyshare(ecdh_symmetric_key, ecdh_ciphertext, pk_alg_); // Compute (kyberCipherText, kyberKeyShare) := kyberKem.encap(kyberPublicKey) kyber_encap_result_t kyber_encap = kyber_key_.encapsulate(rng); - // Compute KEK := multiKeyCombine(eccKeyShare, kyberKeyShare, fixedInfo) as defined in Section 4.2.2 + // Compute KEK := multiKeyCombine(eccKeyShare, kyberKeyShare, fixedInfo) as defined in + // Section 4.2.2 std::vector kek_vec; - auto kmac = rnp::KMAC256::create(); - kmac->compute(ecdh_hashed_symmetric_key, ecdh_ciphertext, kyber_encap.symmetric_key, kyber_encap.ciphertext, pk_alg(), subkey_pkt_hash, kek_vec); + auto kmac = rnp::KMAC256::create(); + kmac->compute(ecdh_hashed_symmetric_key, + ecdh_ciphertext, + kyber_encap.symmetric_key, + kyber_encap.ciphertext, + pk_alg(), + subkey_pkt_hash, + kek_vec); Botan::SymmetricKey kek(kek_vec); - // Compute C := AESKeyWrap(KEK, sessionKey) with AES-256 as per [RFC3394] that includes a 64 bit integrity check + // Compute C := AESKeyWrap(KEK, sessionKey) with AES-256 as per [RFC3394] that includes a + // 64 bit integrity check try { - out->wrapped_sesskey = Botan::unlock(Botan::rfc3394_keywrap(Botan::secure_vector(session_key, session_key+session_key_len), kek)); + out->wrapped_sesskey = Botan::unlock(Botan::rfc3394_keywrap( + Botan::secure_vector(session_key, session_key + session_key_len), kek)); } catch (const std::exception &e) { RNP_LOG("Keywrap failed: %s", e.what()); return RNP_ERROR_ENCRYPT_FAILED; } - + out->composite_ciphertext.assign(ecdh_ciphertext.begin(), ecdh_ciphertext.end()); - out->composite_ciphertext.insert(out->composite_ciphertext.end(), kyber_encap.ciphertext.begin(), kyber_encap.ciphertext.end()); + out->composite_ciphertext.insert(out->composite_ciphertext.end(), + kyber_encap.ciphertext.begin(), + kyber_encap.ciphertext.end()); return RNP_SUCCESS; } std::vector -pgp_kyber_ecdh_composite_public_key_t::get_encoded() const { +pgp_kyber_ecdh_composite_public_key_t::get_encoded() const +{ initialized_or_throw(); std::vector result; std::vector ecdh_key_encoded = ecdh_key_.get_encoded(); @@ -500,30 +568,33 @@ pgp_kyber_ecdh_composite_public_key_t::get_encoded() const { }; bool -pgp_kyber_ecdh_composite_public_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized()) { +pgp_kyber_ecdh_composite_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized()) { return false; } - return(ecdh_key_.is_valid(rng) && kyber_key_.is_valid(rng)); + return (ecdh_key_.is_valid(rng) && kyber_key_.is_valid(rng)); } bool -pgp_kyber_ecdh_composite_private_key_t::is_valid(rnp::RNG *rng) const { - if(!is_initialized()) { +pgp_kyber_ecdh_composite_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized()) { return false; } - return(ecdh_key_->is_valid(rng) && kyber_key_->is_valid(rng)); + return (ecdh_key_->is_valid(rng) && kyber_key_->is_valid(rng)); } - -rnp_result_t kyber_ecdh_validate_key(rnp::RNG *rng, const pgp_kyber_ecdh_key_t *key, bool secret) { +rnp_result_t +kyber_ecdh_validate_key(rnp::RNG *rng, const pgp_kyber_ecdh_key_t *key, bool secret) +{ bool valid; valid = key->pub.is_valid(rng); - if(secret) { + if (secret) { valid = valid && key->priv.is_valid(rng); } - if(!valid) { + if (!valid) { return RNP_ERROR_GENERIC; } return RNP_SUCCESS; diff --git a/src/lib/crypto/kyber_ecdh_composite.h b/src/lib/crypto/kyber_ecdh_composite.h index 2f8c07be7..3fe3979b8 100644 --- a/src/lib/crypto/kyber_ecdh_composite.h +++ b/src/lib/crypto/kyber_ecdh_composite.h @@ -45,55 +45,72 @@ struct pgp_kyber_ecdh_key_t; /* forward declaration */ class pgp_kyber_ecdh_composite_key_t { + public: + virtual ~pgp_kyber_ecdh_composite_key_t() = 0; + + static rnp_result_t gen_keypair(rnp::RNG * rng, + pgp_kyber_ecdh_key_t *key, + pgp_pubkey_alg_t alg); + + static size_t ecdh_curve_privkey_size(pgp_curve_t curve); + static size_t ecdh_curve_pubkey_size(pgp_curve_t curve); + static size_t ecdh_curve_ephemeral_size(pgp_curve_t curve); + static size_t ecdh_curve_keyshare_size(pgp_curve_t curve); + static pgp_curve_t pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg); + static kyber_parameter_e pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg); + + bool + is_initialized() const + { + return is_initialized_; + } -public: - virtual ~pgp_kyber_ecdh_composite_key_t() = 0; - - static rnp_result_t gen_keypair(rnp::RNG *rng, pgp_kyber_ecdh_key_t *key, pgp_pubkey_alg_t alg); - - static size_t ecdh_curve_privkey_size(pgp_curve_t curve); - static size_t ecdh_curve_pubkey_size(pgp_curve_t curve); - static size_t ecdh_curve_ephemeral_size(pgp_curve_t curve); - static size_t ecdh_curve_keyshare_size(pgp_curve_t curve); - static pgp_curve_t pk_alg_to_curve_id(pgp_pubkey_alg_t pk_alg); - static kyber_parameter_e pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg); - - bool is_initialized() const { - return is_initialized_; - } - -protected: - bool is_initialized_ = false; - void initialized_or_throw() const; + protected: + bool is_initialized_ = false; + void initialized_or_throw() const; }; typedef struct pgp_kyber_ecdh_encrypted_t { std::vector composite_ciphertext; std::vector wrapped_sesskey; - static size_t composite_ciphertext_size(pgp_pubkey_alg_t pk_alg) { - return kyber_ciphertext_size(pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pk_alg)) - + pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size(pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(pk_alg)); + static size_t + composite_ciphertext_size(pgp_pubkey_alg_t pk_alg) + { + return kyber_ciphertext_size( + pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pk_alg)) + + pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size( + pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(pk_alg)); } } pgp_kyber_ecdh_encrypted_t; class pgp_kyber_ecdh_composite_private_key_t : public pgp_kyber_ecdh_composite_key_t { public: - pgp_kyber_ecdh_composite_private_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); - pgp_kyber_ecdh_composite_private_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg); - pgp_kyber_ecdh_composite_private_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); - pgp_kyber_ecdh_composite_private_key_t& operator=(const pgp_kyber_ecdh_composite_private_key_t& other); + pgp_kyber_ecdh_composite_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_private_key_t(std::vector const &ecdh_key_encoded, + std::vector const &kyber_key_encoded, + pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_private_key_t(std::vector const &key_encoded, + pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_private_key_t &operator=( + const pgp_kyber_ecdh_composite_private_key_t &other); pgp_kyber_ecdh_composite_private_key_t() = default; + rnp_result_t decrypt(rnp::RNG * rng, + uint8_t * out, + size_t * out_len, + const pgp_kyber_ecdh_encrypted_t *enc, + const std::vector & subkey_pkt_hash); - rnp_result_t decrypt(rnp::RNG *rng, uint8_t *out, size_t *out_len, const pgp_kyber_ecdh_encrypted_t *enc, const std::vector &subkey_pkt_hash); - - bool is_valid(rnp::RNG *rng) const; + bool is_valid(rnp::RNG *rng) const; std::vector get_encoded() const; - pgp_pubkey_alg_t pk_alg() const + pgp_pubkey_alg_t + pk_alg() const { - return pk_alg_; + return pk_alg_; } void secure_clear(); @@ -112,27 +129,38 @@ class pgp_kyber_ecdh_composite_private_key_t : public pgp_kyber_ecdh_composite_k std::unique_ptr ecdh_key_; }; - class pgp_kyber_ecdh_composite_public_key_t : public pgp_kyber_ecdh_composite_key_t { public: - pgp_kyber_ecdh_composite_public_key_t(const uint8_t *key_encoded, size_t key_encoded_len, pgp_pubkey_alg_t pk_alg); - pgp_kyber_ecdh_composite_public_key_t(std::vector const &ecdh_key_encoded, std::vector const &kyber_key_encoded, pgp_pubkey_alg_t pk_alg); - pgp_kyber_ecdh_composite_public_key_t(std::vector const &key_encoded, pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_public_key_t(std::vector const &ecdh_key_encoded, + std::vector const &kyber_key_encoded, + pgp_pubkey_alg_t pk_alg); + pgp_kyber_ecdh_composite_public_key_t(std::vector const &key_encoded, + pgp_pubkey_alg_t pk_alg); pgp_kyber_ecdh_composite_public_key_t() = default; - - bool operator==(const pgp_kyber_ecdh_composite_public_key_t &rhs) const + + bool + operator==(const pgp_kyber_ecdh_composite_public_key_t &rhs) const { - return (pk_alg_ == rhs.pk_alg_) && (kyber_key_ == rhs.kyber_key_) && (ecdh_key_ == rhs.ecdh_key_); + return (pk_alg_ == rhs.pk_alg_) && (kyber_key_ == rhs.kyber_key_) && + (ecdh_key_ == rhs.ecdh_key_); } - rnp_result_t encrypt(rnp::RNG *rng, pgp_kyber_ecdh_encrypted_t *out, const uint8_t *in, size_t in_len, const std::vector &subkey_pkt_hash); + rnp_result_t encrypt(rnp::RNG * rng, + pgp_kyber_ecdh_encrypted_t *out, + const uint8_t * in, + size_t in_len, + const std::vector &subkey_pkt_hash); - bool is_valid(rnp::RNG *rng) const; + bool is_valid(rnp::RNG *rng) const; std::vector get_encoded() const; - pgp_pubkey_alg_t pk_alg() const + pgp_pubkey_alg_t + pk_alg() const { - return pk_alg_; + return pk_alg_; } static size_t encoded_size(pgp_pubkey_alg_t pk_alg); @@ -151,9 +179,11 @@ class pgp_kyber_ecdh_composite_public_key_t : public pgp_kyber_ecdh_composite_ke typedef struct pgp_kyber_ecdh_key_t { pgp_kyber_ecdh_composite_private_key_t priv; - pgp_kyber_ecdh_composite_public_key_t pub; + pgp_kyber_ecdh_composite_public_key_t pub; } pgp_kyber_ecdh_key_t; -rnp_result_t kyber_ecdh_validate_key(rnp::RNG *rng, const pgp_kyber_ecdh_key_t *key, bool secret); +rnp_result_t kyber_ecdh_validate_key(rnp::RNG * rng, + const pgp_kyber_ecdh_key_t *key, + bool secret); #endif diff --git a/src/lib/crypto/rng.cpp b/src/lib/crypto/rng.cpp index 8acd69e56..63a16e003 100644 --- a/src/lib/crypto/rng.cpp +++ b/src/lib/crypto/rng.cpp @@ -38,8 +38,7 @@ RNG::RNG(Type type) #if defined(ENABLE_CRYPTO_REFRESH) if (type == Type::DRBG) { botan_rng_obj.reset(new Botan::AutoSeeded_RNG); - } - else { + } else { botan_rng_obj.reset(new Botan::System_RNG); } #endif diff --git a/src/lib/crypto/rng.h b/src/lib/crypto/rng.h index 6ac9f58b9..00da52c8e 100644 --- a/src/lib/crypto/rng.h +++ b/src/lib/crypto/rng.h @@ -86,7 +86,7 @@ class RNG { * Note: It is planned to move away from the FFI handle. * For the transition phase, both approaches are implemented. */ - Botan::RandomNumberGenerator* obj() const; + Botan::RandomNumberGenerator *obj() const; #endif #endif }; diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index f839aba68..afcc9d850 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -45,8 +45,7 @@ static void signature_hash_finish(const pgp_signature_t &sig, rnp::Hash &hash, uint8_t *hbuf, size_t &hlen) { hash.add(sig.hashed_data, sig.hashed_len); - if(sig.version >= PGP_V4) - { + if (sig.version >= PGP_V4) { uint8_t trailer[6] = {0x00, 0xff, 0x00, 0x00, 0x00, 0x00}; trailer[0] = sig.version; write_uint32(&trailer[2], sig.hashed_len); @@ -62,8 +61,7 @@ signature_init(const pgp_key_pkt_t &key, const pgp_signature_t &sig) auto hash = rnp::Hash::create(sig.halg); #if defined(ENABLE_CRYPTO_REFRESH) - if (key.version == PGP_V6) - { + if (key.version == PGP_V6) { hash->add(sig.salt, sig.salt_size); } #endif @@ -139,8 +137,9 @@ signature_calculate(pgp_signature_t & sig, 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) { + ret = + ed25519_sign_native(&ctx.rng, material.ed25519.sig, seckey.ed25519.priv, hval, hlen); + if (ret) { RNP_LOG("ed25519 signing failed"); } break; @@ -206,7 +205,8 @@ signature_calculate(pgp_signature_t & sig, case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: - ret = seckey.dilithium_exdsa.priv.sign(&ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); + ret = seckey.dilithium_exdsa.priv.sign( + &ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); break; #endif default: @@ -323,7 +323,8 @@ signature_validate(const pgp_signature_t & sig, case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: - ret = key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); + ret = + key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); break; #endif default: diff --git a/src/lib/crypto/signatures.h b/src/lib/crypto/signatures.h index 8dfa2b270..ae69f72d9 100644 --- a/src/lib/crypto/signatures.h +++ b/src/lib/crypto/signatures.h @@ -35,8 +35,8 @@ * @param hash_alg the digest algo to be used * @param hash digest object that will be initialized */ -std::unique_ptr signature_init(const pgp_key_pkt_t &key, - const pgp_signature_t &sig); +std::unique_ptr signature_init(const pgp_key_pkt_t & key, + const pgp_signature_t &sig); /** * @brief Calculate signature with pre-populated hash diff --git a/src/lib/crypto/x25519.cpp b/src/lib/crypto/x25519.cpp index e68f25288..32628154f 100644 --- a/src/lib/crypto/x25519.cpp +++ b/src/lib/crypto/x25519.cpp @@ -34,30 +34,42 @@ #include "utils.h" #include "botan/rfc3394.h" -static void x25519_hkdf(std::vector &derived_key, const std::vector &ephemeral_pubkey_material, const std::vector &recipient_pubkey_material, const std::vector &shared_key) +static void +x25519_hkdf(std::vector & derived_key, + const std::vector &ephemeral_pubkey_material, + const std::vector &recipient_pubkey_material, + const std::vector &shared_key) { - /* The shared secret is passed to HKDF (see {{RFC5869}}) using SHA256, and the UTF-8-encoded string "OpenPGP X25519" as the info parameter. */ - static const std::vector info = {'O', 'p', 'e', 'n', 'P', 'G', 'P', ' ', 'X', '2', '5', '5', '1', '9'}; + /* The shared secret is passed to HKDF (see {{RFC5869}}) using SHA256, and the + * UTF-8-encoded string "OpenPGP X25519" as the info parameter. */ + static const std::vector info = { + 'O', 'p', 'e', 'n', 'P', 'G', 'P', ' ', 'X', '2', '5', '5', '1', '9'}; auto kdf = rnp::Hkdf::create(PGP_HASH_SHA256); derived_key.resize(pgp_key_size(PGP_SA_AES_128)); // 128-bit AES key wrap std::vector kdf_input; - kdf_input.insert(kdf_input.end(), std::begin(ephemeral_pubkey_material), std::end(ephemeral_pubkey_material)); - kdf_input.insert(kdf_input.end(), std::begin(recipient_pubkey_material), std::end(recipient_pubkey_material)); + kdf_input.insert(kdf_input.end(), + std::begin(ephemeral_pubkey_material), + std::end(ephemeral_pubkey_material)); + kdf_input.insert(kdf_input.end(), + std::begin(recipient_pubkey_material), + std::end(recipient_pubkey_material)); kdf_input.insert(kdf_input.end(), std::begin(shared_key), std::end(shared_key)); - kdf->extract_expand(NULL, 0, // no salt - kdf_input.data(), - kdf_input.size(), - info.data(), - info.size(), - derived_key.data(), - derived_key.size()); + kdf->extract_expand(NULL, + 0, // no salt + kdf_input.data(), + kdf_input.size(), + info.data(), + info.size(), + derived_key.data(), + derived_key.size()); } -rnp_result_t generate_x25519_native(rnp::RNG * rng, - std::vector &privkey, - std::vector &pubkey) +rnp_result_t +generate_x25519_native(rnp::RNG * rng, + std::vector &privkey, + std::vector &pubkey) { Botan::Curve25519_PrivateKey priv_key(*(rng->obj())); pubkey = priv_key.public_value(); @@ -66,17 +78,18 @@ rnp_result_t generate_x25519_native(rnp::RNG * rng, return RNP_SUCCESS; } -rnp_result_t x25519_native_encrypt(rnp::RNG * rng, - const std::vector &pubkey, - const uint8_t * in, - size_t in_len, - pgp_x25519_encrypted_t *encrypted) +rnp_result_t +x25519_native_encrypt(rnp::RNG * rng, + const std::vector &pubkey, + const uint8_t * in, + size_t in_len, + pgp_x25519_encrypted_t * encrypted) { - rnp_result_t ret; + rnp_result_t ret; std::vector shared_key; std::vector derived_key; - if(!in_len || (in_len % 8) != 0) { + if (!in_len || (in_len % 8) != 0) { RNP_LOG("incorrect size of in, AES key wrap requires a multiple of 8 bytes"); return RNP_ERROR_BAD_FORMAT; } @@ -84,16 +97,17 @@ rnp_result_t x25519_native_encrypt(rnp::RNG * rng, /* encapsulation */ ecdh_kem_public_key_t ecdhkem_pubkey(pubkey, PGP_CURVE_25519); ret = ecdhkem_pubkey.encapsulate(rng, encrypted->eph_key, shared_key); - if(ret != RNP_SUCCESS) { + if (ret != RNP_SUCCESS) { RNP_LOG("encapsulation failed"); - return ret; + return ret; } x25519_hkdf(derived_key, encrypted->eph_key, pubkey, shared_key); Botan::SymmetricKey kek(derived_key); try { - encrypted->enc_sess_key = Botan::unlock(Botan::rfc3394_keywrap(Botan::secure_vector(in, in+in_len), kek)); + encrypted->enc_sess_key = Botan::unlock( + Botan::rfc3394_keywrap(Botan::secure_vector(in, in + in_len), kek)); } catch (const std::exception &e) { RNP_LOG("Keywrap failed: %s", e.what()); return RNP_ERROR_ENCRYPT_FAILED; @@ -102,22 +116,23 @@ rnp_result_t x25519_native_encrypt(rnp::RNG * rng, return RNP_SUCCESS; } -rnp_result_t x25519_native_decrypt(rnp::RNG * rng, - const pgp_x25519_key_t &keypair, - const pgp_x25519_encrypted_t *encrypted, - uint8_t *decbuf, - size_t *decbuf_len) +rnp_result_t +x25519_native_decrypt(rnp::RNG * rng, + const pgp_x25519_key_t & keypair, + const pgp_x25519_encrypted_t *encrypted, + uint8_t * decbuf, + size_t * decbuf_len) { - rnp_result_t ret; + rnp_result_t ret; std::vector shared_key; std::vector derived_key; static const size_t x25519_pubkey_size = 32; - if(encrypted->eph_key.size() != x25519_pubkey_size) { + if (encrypted->eph_key.size() != x25519_pubkey_size) { RNP_LOG("Wrong ephemeral public key size"); return RNP_ERROR_BAD_FORMAT; } - if(!encrypted->enc_sess_key.size()) { + if (!encrypted->enc_sess_key.size()) { // TODO: could do a check for possible sizes RNP_LOG("No encrypted session key provided"); return RNP_ERROR_BAD_FORMAT; @@ -126,16 +141,19 @@ rnp_result_t x25519_native_decrypt(rnp::RNG * rng, /* decapsulate */ ecdh_kem_private_key_t ecdhkem_privkey(keypair.priv, PGP_CURVE_25519); ret = ecdhkem_privkey.decapsulate(rng, encrypted->eph_key, shared_key); - if(ret != RNP_SUCCESS) { + if (ret != RNP_SUCCESS) { RNP_LOG("decapsulation failed"); - return ret; + return ret; } x25519_hkdf(derived_key, encrypted->eph_key, keypair.pub, shared_key); Botan::SymmetricKey kek(derived_key); - auto tmp_out = Botan::rfc3394_keyunwrap(Botan::secure_vector(encrypted->enc_sess_key.begin(), encrypted->enc_sess_key.end()), kek); - if(*decbuf_len < tmp_out.size()) { + auto tmp_out = + Botan::rfc3394_keyunwrap(Botan::secure_vector(encrypted->enc_sess_key.begin(), + encrypted->enc_sess_key.end()), + kek); + if (*decbuf_len < tmp_out.size()) { RNP_LOG("buffer for decryption result too small"); return RNP_ERROR_DECRYPT_FAILED; } @@ -154,8 +172,9 @@ x25519_validate_key_native(rnp::RNG *rng, const pgp_x25519_key_t *key, bool secr Botan::Curve25519_PublicKey pub_key(key->priv); valid_pub = pub_key.check_key(*(rng->obj()), false); - if(secret) { - Botan::Curve25519_PrivateKey priv_key(Botan::secure_vector(key->priv.begin(), key->priv.end())); + if (secret) { + Botan::Curve25519_PrivateKey priv_key( + Botan::secure_vector(key->priv.begin(), key->priv.end())); valid_priv = priv_key.check_key(*(rng->obj()), false); } else { valid_priv = true; diff --git a/src/lib/crypto/x25519.h b/src/lib/crypto/x25519.h index a24b5922f..75c9e52a5 100644 --- a/src/lib/crypto/x25519.h +++ b/src/lib/crypto/x25519.h @@ -38,23 +38,24 @@ #include "crypto/rng.h" #include "crypto/ec.h" -rnp_result_t generate_x25519_native(rnp::RNG * rng, - std::vector &privkey, +rnp_result_t generate_x25519_native(rnp::RNG * rng, + std::vector &privkey, std::vector &pubkey); -rnp_result_t x25519_native_encrypt(rnp::RNG * rng, - const std::vector &pubkey, - const uint8_t * in, - size_t in_len, - pgp_x25519_encrypted_t *encrypted); +rnp_result_t x25519_native_encrypt(rnp::RNG * rng, + const std::vector &pubkey, + const uint8_t * in, + size_t in_len, + pgp_x25519_encrypted_t * encrypted); -rnp_result_t x25519_native_decrypt(rnp::RNG * rng, - const pgp_x25519_key_t &keypair, +rnp_result_t x25519_native_decrypt(rnp::RNG * rng, + const pgp_x25519_key_t & keypair, const pgp_x25519_encrypted_t *encrypted, - uint8_t *decbuf, - size_t *decbuf_len); + uint8_t * decbuf, + size_t * decbuf_len); - -rnp_result_t x25519_validate_key_native(rnp::RNG *rng, const pgp_x25519_key_t *key, bool secret); +rnp_result_t x25519_validate_key_native(rnp::RNG * rng, + const pgp_x25519_key_t *key, + bool secret); #endif diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 4c4820ee9..d6fb13c4b 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -2315,20 +2315,24 @@ pgp_key_t::mark_valid() } void -pgp_key_t::sign_init(rnp::RNG &rng, pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation, pgp_version_t version) const +pgp_key_t::sign_init(rnp::RNG & rng, + pgp_signature_t &sig, + pgp_hash_alg_t hash, + uint64_t creation, + pgp_version_t version) const { sig.version = version; sig.halg = pgp_hash_adjust_alg_to_key(hash, &pkt_); sig.palg = alg(); sig.set_keyfp(fp()); sig.set_creation(creation); - if(version == PGP_V4) { + if (version == PGP_V4) { // for v6 issuing keys, this MUST NOT be included sig.set_keyid(keyid()); } #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6) { - sig.salt_size = rnp::Hash::size(sig.halg)/2; + if (version == PGP_V6) { + sig.salt_size = rnp::Hash::size(sig.halg) / 2; rng.get(sig.salt, sig.salt_size); } #endif @@ -2780,7 +2784,7 @@ pgp_key_t::subkey_pkt_hash() const auto pk_pkt_hash = rnp::Hash::create(pk_pkt_hash_alg); pk_pkt_hash->add(rawpkt_.raw); pk_pkt_hash->finish(out.data()); - + return out; } #endif @@ -2789,9 +2793,12 @@ pgp_curve_t pgp_key_material_t::curve() const { switch (alg) { - case PGP_PKA_ECDH: [[fallthrough]]; - case PGP_PKA_ECDSA: [[fallthrough]]; - case PGP_PKA_EDDSA: [[fallthrough]]; + case PGP_PKA_ECDH: + [[fallthrough]]; + case PGP_PKA_ECDSA: + [[fallthrough]]; + case PGP_PKA_EDDSA: + [[fallthrough]]; case PGP_PKA_SM2: return ec.curve; #if defined(ENABLE_CRYPTO_REFRESH) @@ -2818,17 +2825,22 @@ pgp_key_material_t::bits() const case PGP_PKA_ELGAMAL: case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: return 8 * mpi_bytes(&eg.y); - case PGP_PKA_ECDH: [[fallthrough]]; - case PGP_PKA_ECDSA: [[fallthrough]]; - case PGP_PKA_EDDSA: [[fallthrough]]; + case PGP_PKA_ECDH: + [[fallthrough]]; + case PGP_PKA_ECDSA: + [[fallthrough]]; + case PGP_PKA_EDDSA: + [[fallthrough]]; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: [[fallthrough]]; - case PGP_PKA_X25519: [[fallthrough]]; + case PGP_PKA_ED25519: + [[fallthrough]]; + case PGP_PKA_X25519: + [[fallthrough]]; #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; + /* 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: diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 89e66f276..991e298e9 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -460,7 +460,11 @@ struct pgp_key_t { * @param creation signature's creation time. * @param version signature version */ - void sign_init(rnp::RNG &rng, pgp_signature_t &sig, pgp_hash_alg_t hash, uint64_t creation, pgp_version_t version) const; + void sign_init(rnp::RNG & rng, + pgp_signature_t &sig, + pgp_hash_alg_t hash, + uint64_t creation, + pgp_version_t version) const; /** * @brief Calculate a certification and fill signature material. diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 976798f4a..64635c8a3 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -346,13 +346,13 @@ pub_alg_supported(int alg) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - //case PGP_PKA_KYBER1024_X448: + // case PGP_PKA_KYBER1024_X448: case PGP_PKA_KYBER768_P256: case PGP_PKA_KYBER1024_P384: case PGP_PKA_KYBER768_BP256: case PGP_PKA_KYBER1024_BP384: case PGP_PKA_DILITHIUM3_ED25519: - //case PGP_PKA_DILITHIUM5_ED448: + // case PGP_PKA_DILITHIUM5_ED448: case PGP_PKA_DILITHIUM3_P256: case PGP_PKA_DILITHIUM5_P384: case PGP_PKA_DILITHIUM3_BP256: @@ -2713,8 +2713,11 @@ try { return RNP_ERROR_BAD_PARAMETERS; } #ifdef ENABLE_CRYPTO_REFRESH -if(op->rnpctx.aalg == PGP_AEAD_NONE && op->rnpctx.enable_pkesk_v6) { - FFI_LOG(op->ffi, "Setting AEAD algorithm to PGP_AEAD_NONE (%s) would contradict the previously enabled PKESKv6 setting", alg); + if (op->rnpctx.aalg == PGP_AEAD_NONE && op->rnpctx.enable_pkesk_v6) { + FFI_LOG(op->ffi, + "Setting AEAD algorithm to PGP_AEAD_NONE (%s) would contradict the previously " + "enabled PKESKv6 setting", + alg); return RNP_ERROR_BAD_PARAMETERS; } #endif @@ -7495,7 +7498,7 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) case PGP_PKA_ED25519: case PGP_PKA_X25519: return RNP_SUCCESS; /* TODO */ -#endif +#endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: [[fallthrough]]; diff --git a/src/lib/types.h b/src/lib/types.h index 509f3c65a..d22961256 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -190,14 +190,15 @@ typedef struct pgp_key_material_t { }; #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 */ + 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_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 */ #endif - pgp_curve_t curve() const; /* return curve for EC algorithms, PGP_CURVE_UNKNOWN otherwise */ + 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); @@ -218,7 +219,8 @@ typedef struct pgp_signature_material_t { pgp_ed25519_signature_t ed25519; // non-trivial type cannot be member in union #endif #if defined(ENABLE_PQC) - pgp_dilithium_exdsa_signature_t dilithium_exdsa; // non-trivial type cannot be member in union + pgp_dilithium_exdsa_signature_t + dilithium_exdsa; // non-trivial type cannot be member in union #endif } pgp_signature_material_t; @@ -227,10 +229,10 @@ typedef struct pgp_signature_material_t { */ typedef struct pgp_encrypted_material_t { union { - pgp_rsa_encrypted_t rsa; - pgp_eg_encrypted_t eg; - pgp_sm2_encrypted_t sm2; - pgp_ecdh_encrypted_t ecdh; + pgp_rsa_encrypted_t rsa; + pgp_eg_encrypted_t eg; + pgp_sm2_encrypted_t sm2; + pgp_ecdh_encrypted_t ecdh; }; #if defined(ENABLE_CRYPTO_REFRESH) pgp_x25519_encrypted_t x25519; // non-trivial type cannot be member in union @@ -386,11 +388,11 @@ typedef struct pgp_aead_hdr_t { #ifdef ENABLE_CRYPTO_REFRESH typedef struct pgp_seipdv2_hdr_t { - pgp_seipd_version_t version; /* version of the SEIPD packet */ - pgp_symm_alg_t cipher_alg; /* underlying symmetric algorithm */ - pgp_aead_alg_t aead_alg; /* AEAD algorithm, i.e. EAX, OCB, etc */ - uint8_t chunk_size_octet; /* chunk size octet */ - uint8_t salt[PGP_SEIPDV2_SALT_LEN]; /* SEIPDv2 salt value */ + pgp_seipd_version_t version; /* version of the SEIPD packet */ + pgp_symm_alg_t cipher_alg; /* underlying symmetric algorithm */ + pgp_aead_alg_t aead_alg; /* AEAD algorithm, i.e. EAX, OCB, etc */ + uint8_t chunk_size_octet; /* chunk size octet */ + uint8_t salt[PGP_SEIPDV2_SALT_LEN]; /* SEIPDv2 salt value */ } pgp_seipdv2_hdr_t; #endif diff --git a/src/librekey/key_store_kbx.cpp b/src/librekey/key_store_kbx.cpp index 136e00fb0..954e49df5 100644 --- a/src/librekey/key_store_kbx.cpp +++ b/src/librekey/key_store_kbx.cpp @@ -537,7 +537,8 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest for (auto &sfp : key->subkey_fps()) { pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp); if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, key->fp().length) || - //if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, PGP_FINGERPRINT_SIZE) || // from upstream during merge 2023-03-20 + // if (!subkey || !pbuf(&mem.dst(), subkey->fp().fingerprint, PGP_FINGERPRINT_SIZE) + // || // from upstream during merge 2023-03-20 !pu32(&mem.dst(), mem.writeb() - 8) || // offset to keyid (part of fpr for V4) !pu16(&mem.dst(), 0) || // flags, not used by GnuPG !pu16(&mem.dst(), 0)) { // RFU diff --git a/src/librepgp/stream-common.cpp b/src/librepgp/stream-common.cpp index 6a7bae3cb..f1f2270a4 100644 --- a/src/librepgp/stream-common.cpp +++ b/src/librepgp/stream-common.cpp @@ -1211,28 +1211,28 @@ dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit) return dst->werr; } - #if defined(ENABLE_CRYPTO_REFRESH) -bool have_pkesk_checksum(pgp_pubkey_alg_t alg) +bool +have_pkesk_checksum(pgp_pubkey_alg_t alg) { - switch(alg) - { - case PGP_PKA_X25519: + switch (alg) { + case PGP_PKA_X25519: #if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - //case PGP_PKA_KYBER1024_X448: - case PGP_PKA_KYBER768_P256: - case PGP_PKA_KYBER1024_P384: - case PGP_PKA_KYBER768_BP256: - case PGP_PKA_KYBER1024_BP384: + case PGP_PKA_KYBER768_X25519: + // case PGP_PKA_KYBER1024_X448: + case PGP_PKA_KYBER768_P256: + case PGP_PKA_KYBER1024_P384: + case PGP_PKA_KYBER768_BP256: + case PGP_PKA_KYBER1024_BP384: #endif - return false; - default: - return true; - } + return false; + default: + return true; + } } -bool do_encrypt_pkesk_v3_alg_id(pgp_pubkey_alg_t alg) +bool +do_encrypt_pkesk_v3_alg_id(pgp_pubkey_alg_t alg) { /* matches the same algorithms */ return have_pkesk_checksum(alg); diff --git a/src/librepgp/stream-common.h b/src/librepgp/stream-common.h index aec5e554f..32d19fbde 100644 --- a/src/librepgp/stream-common.h +++ b/src/librepgp/stream-common.h @@ -556,6 +556,6 @@ class MemoryDest : public Dest { #if defined(ENABLE_CRYPTO_REFRESH) bool have_pkesk_checksum(pgp_pubkey_alg_t alg); bool do_encrypt_pkesk_v3_alg_id(pgp_pubkey_alg_t alg); -#endif +#endif #endif diff --git a/src/librepgp/stream-ctx.cpp b/src/librepgp/stream-ctx.cpp index 0aaf9c99f..96edbd443 100644 --- a/src/librepgp/stream-ctx.cpp +++ b/src/librepgp/stream-ctx.cpp @@ -68,12 +68,12 @@ rnp_ctx_t::add_encryption_password(const std::string &password, return RNP_SUCCESS; } - #if defined(ENABLE_CRYPTO_REFRESH) bool -rnp_ctx_t::pkeskv6_capable() { - for(pgp_key_t *key : recipients) { - if(key->version() < PGP_V6) { +rnp_ctx_t::pkeskv6_capable() +{ + for (pgp_key_t *key : recipients) { + if (key->version() < PGP_V6) { return false; } } diff --git a/src/librepgp/stream-ctx.h b/src/librepgp/stream-ctx.h index 539f11dce..12639bc4e 100644 --- a/src/librepgp/stream-ctx.h +++ b/src/librepgp/stream-ctx.h @@ -70,10 +70,12 @@ typedef struct rnp_symmetric_pass_info_t { * - halg : hash algorithm used during key derivation for password-based encryption * - ealg, aalg, abits : symmetric encryption algorithm and AEAD parameters if used * - recipients : list of key ids used to encrypt data to - * - enable_pkesk_v6 : if true and each recipient in the list of recipients has the capability, allows PKESKv5/SEIPDv2 + * - enable_pkesk_v6 : if true and each recipient in the list of recipients has the + * capability, allows PKESKv5/SEIPDv2 * - passwords : list of passwords used for password-based encryption * - filename, filemtime, zalg, zlevel : see previous - * - pkeskv6_capable() : returns true if all keys support PKESKv6+SEIPDv2, false otherwise (will use PKESKv3 + SEIPDv1) + * - pkeskv6_capable() : returns true if all keys support PKESKv6+SEIPDv2, false otherwise + * (will use PKESKv3 + SEIPDv1) * * For signing of any kind (attached, detached, cleartext): * - clearsign, detached : controls kind of the signed data. Both are mutually-exclusive. @@ -105,7 +107,7 @@ typedef struct rnp_ctx_t { bool armor{}; /* whether to use ASCII armor on output */ bool no_wrap{}; /* do not wrap source in literal data packet */ #if defined(ENABLE_CRYPTO_REFRESH) - bool enable_pkesk_v6{}; /* allows pkesk v6 if list of recipients is suitable */ + bool enable_pkesk_v6{}; /* allows pkesk v6 if list of recipients is suitable */ #endif std::list recipients{}; /* recipients of the encrypted message */ std::list passwords{}; /* passwords to encrypt message */ diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index a73188d67..1bd0d1afe 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -477,7 +477,6 @@ dst_print_fp(pgp_dest_t *dst, const char *name, const pgp_fingerprint_t &fp) } #endif - static void dst_print_s2k(pgp_dest_t *dst, pgp_s2k_t *s2k) { @@ -833,7 +832,8 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: - dst_print_vec(dst, "dilithium-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); + dst_print_vec( + dst, "dilithium-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); break; #endif default: @@ -964,7 +964,10 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: - dst_print_vec(dst, "dilithium-ecdsa/eddsa encodced pubkey", key.material.dilithium_exdsa.pub.get_encoded(), ctx->dump_mpi); + dst_print_vec(dst, + "dilithium-ecdsa/eddsa encodced pubkey", + key.material.dilithium_exdsa.pub.get_encoded(), + ctx->dump_mpi); break; #endif default: @@ -1096,10 +1099,9 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d dst_printf(dst, "version: %d\n", (int) pkey.version); #if defined(ENABLE_CRYPTO_REFRESH) - if(pkey.version == PGP_PKSK_V6) { + if (pkey.version == PGP_PKSK_V6) { dst_print_fp(dst, NULL, pkey.fp); - } - else { + } else { dst_print_keyid(dst, NULL, pkey.key_id); } #else @@ -1133,8 +1135,10 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d break; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_X25519: - dst_print_vec(dst, "x25519 ephemeral public key", material.x25519.eph_key, ctx->dump_mpi); - dst_print_vec(dst, "x25519 encrypted session key", material.x25519.enc_sess_key, ctx->dump_mpi); + dst_print_vec( + dst, "x25519 ephemeral public key", material.x25519.eph_key, ctx->dump_mpi); + dst_print_vec( + dst, "x25519 encrypted session key", material.x25519.enc_sess_key, ctx->dump_mpi); break; #endif #if defined(ENABLE_PQC) @@ -1148,8 +1152,14 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d case PGP_PKA_KYBER768_BP256: [[fallthrough]]; case PGP_PKA_KYBER1024_BP384: - dst_print_vec(dst, "kyber-ecdh composite ciphertext", material.kyber_ecdh.composite_ciphertext, ctx->dump_mpi); - dst_print_vec(dst, "kyber-ecdh wrapped session key", material.kyber_ecdh.wrapped_sesskey, ctx->dump_mpi); + dst_print_vec(dst, + "kyber-ecdh composite ciphertext", + material.kyber_ecdh.composite_ciphertext, + ctx->dump_mpi); + dst_print_vec(dst, + "kyber-ecdh wrapped session key", + material.kyber_ecdh.wrapped_sesskey, + ctx->dump_mpi); break; #endif default: diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index be8397b1f..b8a078af8 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -542,7 +542,7 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) switch (key.sec_protection.s2k.usage) { case PGP_S2KU_NONE: #if defined(ENABLE_CRYPTO_REFRESH) - if(key.version == PGP_V6) { + if (key.version == PGP_V6) { break; /* checksum removed for v6 and usage byte zero */ } [[fallthrough]]; @@ -672,7 +672,8 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) RNP_LOG("failed to parse kyber-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); + 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]]; @@ -689,7 +690,8 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) RNP_LOG("failed to parse dilithium-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); + key.material.dilithium_exdsa.priv = pgp_dilithium_exdsa_composite_private_key_t( + tmpbuf.data(), tmpbuf.size(), key.alg); break; #endif default: @@ -849,13 +851,13 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) body.add(key.material.dilithium_exdsa.priv.get_encoded()); break; #endif -default: + default: RNP_LOG("unknown pk alg : %d", (int) key.alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } #if defined(ENABLE_CRYPTO_REFRESH) - if(key.version == PGP_V6 && key.sec_protection.s2k.usage == PGP_S2KU_NONE) { + if (key.version == PGP_V6 && key.sec_protection.s2k.usage == PGP_S2KU_NONE) { return; /* checksum removed for v6 and usage byte zero */ } #endif @@ -1012,9 +1014,6 @@ forget_secret_key_fields(pgp_key_material_t *key) [[fallthrough]]; case PGP_PKA_KYBER768_BP256: [[fallthrough]]; - case PGP_PKA_KYBER1024_BP384: - key->kyber_ecdh.priv.secure_clear(); - break; case PGP_PKA_DILITHIUM3_ED25519: [[fallthrough]]; // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; @@ -1542,8 +1541,9 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_ERROR_BAD_FORMAT; } #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6 && usage == 255) { - RNP_LOG("Error when parsing S2K usage: A version 6 packet MUST NOT use the value 255."); + if (version == PGP_V6 && usage == 255) { + RNP_LOG( + "Error when parsing S2K usage: A version 6 packet MUST NOT use the value 255."); return RNP_ERROR_BAD_FORMAT; } #endif @@ -1551,7 +1551,7 @@ pgp_key_pkt_t::parse(pgp_source_t &src) sec_protection.cipher_mode = PGP_CIPHER_MODE_CFB; #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6 && sec_protection.s2k.usage != PGP_S2KU_NONE) { + if (version == PGP_V6 && sec_protection.s2k.usage != PGP_S2KU_NONE) { // V6 packages contain the count of the optional 1-byte parameters uint8_t s2k_params_count; if (!pkt.get(s2k_params_count)) { @@ -1624,7 +1624,8 @@ 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) +void +pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody) { switch (alg) { case PGP_PKA_RSA: @@ -1724,7 +1725,7 @@ pgp_key_pkt_t::fill_hashed_data() pgp_packet_body_t alg_spec_fields(PGP_PKT_RESERVED); make_alg_spec_fields_for_public_key(alg_spec_fields); #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6) { + if (version == PGP_V6) { hbody.add_uint32(alg_spec_fields.size()); } #endif diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 054369437..07f15f442 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -679,7 +679,6 @@ pgp_packet_body_t::add(const std::vector &data) add(data.data(), data.size()); } - void pgp_packet_body_t::add_byte(uint8_t bt) { @@ -1033,12 +1032,11 @@ pgp_pk_sesskey_t::write(pgp_dest_t &dst) const pgp_packet_body_t pktbody(PGP_PKT_PK_SESSION_KEY); pktbody.add_byte(version); #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_PKSK_V3) { + if (version == PGP_PKSK_V3) { #endif pktbody.add(key_id); #if defined(ENABLE_CRYPTO_REFRESH) - } - else { // PGP_PKSK_V6 + } else { // PGP_PKSK_V6 pktbody.add_byte(1 + fp.length); // A one-octet size of the following two fields. pktbody.add_byte((fp.length == PGP_FINGERPRINT_V6_SIZE) ? PGP_V6 : PGP_V4); pktbody.add(fp.fingerprint, fp.length); @@ -1046,7 +1044,7 @@ pgp_pk_sesskey_t::write(pgp_dest_t &dst) const #endif pktbody.add_byte(alg); #if defined(ENABLE_CRYPTO_REFRESH) - if((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { + if ((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { pktbody.add_byte(salg); /* added as plaintext */ } #endif @@ -1069,9 +1067,9 @@ pgp_pk_sesskey_t::parse(pgp_source_t &src) return RNP_ERROR_BAD_FORMAT; } #if defined(ENABLE_CRYPTO_REFRESH) - if((bt != PGP_PKSK_V3) && (bt != PGP_PKSK_V6)) { + if ((bt != PGP_PKSK_V3) && (bt != PGP_PKSK_V6)) { #else - if((bt != PGP_PKSK_V3)) { + if ((bt != PGP_PKSK_V3)) { #endif RNP_LOG("wrong packet version"); return RNP_ERROR_BAD_FORMAT; @@ -1089,40 +1087,40 @@ pgp_pk_sesskey_t::parse(pgp_source_t &src) } } #if defined(ENABLE_CRYPTO_REFRESH) - else { // PGP_PKSK_V6 + else { // PGP_PKSK_V6 uint8_t fp_and_key_ver_len; // A one-octet size of the following two fields. if (!pkt.get(fp_and_key_ver_len)) { RNP_LOG("Error when reading length of next two fields"); return RNP_ERROR_BAD_FORMAT; } - if((fp_and_key_ver_len != 1 + PGP_FINGERPRINT_V4_SIZE) - && (fp_and_key_ver_len != 1 + PGP_FINGERPRINT_V6_SIZE)) { + if ((fp_and_key_ver_len != 1 + PGP_FINGERPRINT_V4_SIZE) && + (fp_and_key_ver_len != 1 + PGP_FINGERPRINT_V6_SIZE)) { RNP_LOG("Invalid size for key version + length field"); return RNP_ERROR_BAD_FORMAT; } - size_t fp_len; + size_t fp_len; uint8_t fp_key_version; if (!pkt.get(fp_key_version)) { RNP_LOG("Error when reading key version"); return RNP_ERROR_BAD_FORMAT; } - switch(fp_key_version) { - case 0: // anonymous - fp_len = 0; - break; - case PGP_V4: - fp_len = PGP_FINGERPRINT_V4_SIZE; - break; - case PGP_V6: - fp_len = PGP_FINGERPRINT_V6_SIZE; - break; - default: - RNP_LOG("wrong key version used with PKESK v6"); - return RNP_ERROR_BAD_FORMAT; + switch (fp_key_version) { + case 0: // anonymous + fp_len = 0; + break; + case PGP_V4: + fp_len = PGP_FINGERPRINT_V4_SIZE; + break; + case PGP_V6: + fp_len = PGP_FINGERPRINT_V6_SIZE; + break; + default: + RNP_LOG("wrong key version used with PKESK v6"); + return RNP_ERROR_BAD_FORMAT; } fp.length = fp_len; - if(fp.length && (fp.length != fp_and_key_ver_len - 1)) { + if (fp.length && (fp.length != fp_and_key_ver_len - 1)) { RNP_LOG("size mismatch (fingerprint size and fp+key version length field)"); return RNP_ERROR_BAD_FORMAT; } @@ -1141,7 +1139,7 @@ pgp_pk_sesskey_t::parse(pgp_source_t &src) alg = (pgp_pubkey_alg_t) bt; #if defined(ENABLE_CRYPTO_REFRESH) - if((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { + if ((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { if (!pkt.get(bt)) { RNP_LOG("failed to get salg"); return RNP_ERROR_BAD_FORMAT; @@ -1231,7 +1229,7 @@ pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const return false; } uint8_t enc_sesskey_len; - if(!pkt.get(enc_sesskey_len)) { + if (!pkt.get(enc_sesskey_len)) { RNP_LOG("failed to parse X25519 PKESK (enc sesskey length)"); return false; } @@ -1255,8 +1253,10 @@ pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const [[fallthrough]]; case PGP_PKA_KYBER1024_BP384: { uint8_t wrapped_key_len = 0; - material.kyber_ecdh.composite_ciphertext.resize(pgp_kyber_ecdh_encrypted_t::composite_ciphertext_size(alg)); - if (!pkt.get(material.kyber_ecdh.composite_ciphertext.data(), material.kyber_ecdh.composite_ciphertext.size())) { + material.kyber_ecdh.composite_ciphertext.resize( + pgp_kyber_ecdh_encrypted_t::composite_ciphertext_size(alg)); + if (!pkt.get(material.kyber_ecdh.composite_ciphertext.data(), + material.kyber_ecdh.composite_ciphertext.size())) { RNP_LOG("failed to get kyber-ecdh ciphertext"); return false; } @@ -1265,7 +1265,8 @@ pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const return false; } material.kyber_ecdh.wrapped_sesskey.resize(wrapped_key_len); - if (!pkt.get(material.kyber_ecdh.wrapped_sesskey.data(), material.kyber_ecdh.wrapped_sesskey.size())) { + if (!pkt.get(material.kyber_ecdh.wrapped_sesskey.data(), + material.kyber_ecdh.wrapped_sesskey.size())) { RNP_LOG("failed to get kyber-ecdh session key"); return false; } diff --git a/src/librepgp/stream-packet.h b/src/librepgp/stream-packet.h index 2dadc42b0..b32f0ef00 100644 --- a/src/librepgp/stream-packet.h +++ b/src/librepgp/stream-packet.h @@ -162,12 +162,12 @@ typedef struct pgp_pk_sesskey_t { std::vector material_buf{}; /* v3 PKESK */ - pgp_key_id_t key_id{}; - pgp_symm_alg_t salg; + pgp_key_id_t key_id{}; + pgp_symm_alg_t salg; #if defined(ENABLE_CRYPTO_REFRESH) /* v6 PKESK */ - pgp_fingerprint_t fp{}; + pgp_fingerprint_t fp{}; #endif void write(pgp_dest_t &dst) const; diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index cf3266a28..3470d3537 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -115,15 +115,16 @@ typedef struct pgp_source_encrypted_param_t { bool use_cfb() { - return (auth_type != rnp::AuthType::AEADv1 -#ifdef ENABLE_CRYPTO_REFRESH + return (auth_type != rnp::AuthType::AEADv1 +#ifdef ENABLE_CRYPTO_REFRESH && auth_type != rnp::AuthType::AEADv2 #endif - ); + ); } -#ifdef ENABLE_CRYPTO_REFRESH - bool is_v2_seipd() const +#ifdef ENABLE_CRYPTO_REFRESH + bool + is_v2_seipd() const { return auth_type == rnp::AuthType::AEADv2; } @@ -183,25 +184,23 @@ typedef struct pgp_source_partial_param_t { bool last; /* current part is last */ } pgp_source_partial_param_t; +namespace { -namespace +bool +is_valid_seipd_version(uint8_t version) { - - bool is_valid_seipd_version(uint8_t version) - { - if(version == 1 + if (version == 1 #ifdef ENABLE_CRYPTO_REFRESH - || version == 2 + || version == 2 #endif - ) - { - return true; - } - return false; + ) { + return true; } - + return false; } +} // namespace + static bool is_pgp_source(pgp_source_t &src) { @@ -1470,9 +1469,8 @@ encrypted_start_aead(pgp_source_encrypted_param_t *param, pgp_symm_alg_t alg, ui seipd_v2_key_and_nonce_derivation(param->seipdv2_hdr, key); seipd_v2_key = aead_fields.key; key = std::move(seipd_v2_key.data()); - //param->seipd_v2_nonce = std::move(aead_fields.nonce); - if(aead_fields.nonce.size() > sizeof(param->aead_hdr.iv)) - { + // param->seipd_v2_nonce = std::move(aead_fields.nonce); + if (aead_fields.nonce.size() > sizeof(param->aead_hdr.iv)) { // signalling error would be better here aead_fields.nonce.resize(sizeof(param->aead_hdr.iv)); } @@ -1529,15 +1527,16 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, } /* Crypto Refresh: For X25519/X448 PKESKv3, AES is mandated */ - if(sesskey->alg == PGP_PKA_X25519 && sesskey->version == PGP_PKSK_V3) { - switch(sesskey->salg) { - case PGP_SA_AES_128: - case PGP_SA_AES_192: - case PGP_SA_AES_256: - break; - default: - RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric algorithm that is not AES."); - return false; + if (sesskey->alg == PGP_PKA_X25519 && sesskey->version == PGP_PKSK_V3) { + switch (sesskey->salg) { + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + break; + default: + RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric " + "algorithm that is not AES."); + return false; } } #endif @@ -1607,8 +1606,9 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, #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_SUCCESS) { + err = x25519_native_decrypt( + &ctx.rng, keymaterial->x25519, &encmaterial.x25519, decbuf.data(), &declen); + if (err != RNP_SUCCESS) { RNP_LOG("X25519 decryption error %u", err); return false; } @@ -1627,7 +1627,8 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, case PGP_PKA_KYBER1024_BP384: { pgp_key_t key(*seckey, true); /* make public-key `pgp_key_t` object from seckey */ declen = decbuf.size(); - err = keymaterial->kyber_ecdh.priv.decrypt(&ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh, key.subkey_pkt_hash()); + err = keymaterial->kyber_ecdh.priv.decrypt( + &ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh, key.subkey_pkt_hash()); if (err != RNP_SUCCESS) { RNP_LOG("Kyber ECC decryption failure"); return false; @@ -1640,10 +1641,10 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, return false; } - uint8_t * decbuf_sesskey = decbuf.data(); - size_t decbuf_sesskey_len = declen; + uint8_t *decbuf_sesskey = decbuf.data(); + size_t decbuf_sesskey_len = declen; #if defined(ENABLE_CRYPTO_REFRESH) - if(do_encrypt_pkesk_v3_alg_id(sesskey->alg)) + if (do_encrypt_pkesk_v3_alg_id(sesskey->alg)) #endif { sesskey->salg = static_cast(decbuf[0]); @@ -1675,8 +1676,9 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, #if defined(ENABLE_CRYPTO_REFRESH) else { // V6 PKESK /* compute the expected key length from the decbuf_sesskey_len and check */ - keylen = have_pkesk_checksum(sesskey->alg) ? decbuf_sesskey_len - 2 : decbuf_sesskey_len; - if(pgp_key_size(param->aead_hdr.ealg) != keylen) { + keylen = + have_pkesk_checksum(sesskey->alg) ? decbuf_sesskey_len - 2 : decbuf_sesskey_len; + if (pgp_key_size(param->aead_hdr.ealg) != keylen) { RNP_LOG("invalid symmetric key length"); return false; } @@ -1684,7 +1686,7 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, #endif #if defined(ENABLE_CRYPTO_REFRESH) - if(have_pkesk_checksum(sesskey->alg)) + if (have_pkesk_checksum(sesskey->alg)) #endif { /* Validate checksum */ @@ -1715,7 +1717,7 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, param->salg = sesskey->salg; } return res; - } + } #if defined(ENABLE_CRYPTO_REFRESH) else { // PGP_PKSK_V6 pgp_symm_alg_t salg = @@ -2254,7 +2256,7 @@ encrypted_read_packet_data(pgp_source_encrypted_param_t *param) TODO: Once SKESK v6 is implemented, replace this check with a check for consistency between SEIPD and SKESK version */ - if(param->symencs.size() > 0) { + if (param->symencs.size() > 0) { RNP_LOG("SEIPDv2 not usable with SKESK version"); return RNP_ERROR_BAD_FORMAT; } @@ -2291,8 +2293,8 @@ encrypted_read_packet_data(pgp_source_encrypted_param_t *param) param->aead_hdr.aalg = param->seipdv2_hdr.aead_alg; param->aead_hdr.csize = param->seipdv2_hdr.chunk_size_octet; // needed? param->aead_hdr.ealg = param->seipdv2_hdr.cipher_alg; - } -#endif + } +#endif else { RNP_LOG("unknown SEIPD version: %d", (int) SEIPD_version); return RNP_ERROR_BAD_FORMAT; @@ -2329,12 +2331,13 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t goto finish; } - src->read = (!param->use_cfb() + src->read = (!param->use_cfb() #ifdef ENABLE_CRYPTO_REFRESH - || param->is_v2_seipd() + || param->is_v2_seipd() #endif -) - ? encrypted_src_read_aead : encrypted_src_read_cfb; + ) ? + encrypted_src_read_aead : + encrypted_src_read_cfb; /* Obtaining the symmetric key */ if (!handler->password_provider) { diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index c2dbcfc2f..fe864ce89 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -399,7 +399,7 @@ pgp_sig_subpkt_t::parse() break; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_SIG_SUBPKT_PREFERRED_AEAD_CIPHERSUITES: - // TODO-V6: needs implementation + // TODO-V6: needs implementation break; #endif case PGP_SIG_SUBPKT_PRIVATE_100: @@ -459,7 +459,7 @@ pgp_signature_t::pgp_signature_t(const pgp_signature_t &src) halg = src.halg; memcpy(lbits, src.lbits, sizeof(src.lbits)); #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6) { + if (version == PGP_V6) { salt_size = src.salt_size; memcpy(salt, src.salt, salt_size); } @@ -494,7 +494,7 @@ pgp_signature_t::pgp_signature_t(pgp_signature_t &&src) halg = src.halg; memcpy(lbits, src.lbits, sizeof(src.lbits)); #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6) { + if (version == PGP_V6) { salt_size = src.salt_size; memcpy(salt, src.salt, salt_size); } @@ -550,7 +550,7 @@ pgp_signature_t::operator=(const pgp_signature_t &src) halg = src.halg; memcpy(lbits, src.lbits, sizeof(src.lbits)); #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6) { + if (version == PGP_V6) { salt_size = src.salt_size; memcpy(salt, src.salt, salt_size); } @@ -621,8 +621,7 @@ pgp_signature_t::get_id() const } pgp_sig_subpkt_t * -pgp_signature_t:: -get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) +pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) { if (version < PGP_V4) { return NULL; @@ -1466,18 +1465,18 @@ pgp_signature_t::parse(pgp_packet_body_t &pkt) RNP_LOG("not enough data for hash left bits"); return RNP_ERROR_BAD_FORMAT; } - + #if defined(ENABLE_CRYPTO_REFRESH) if (ver == PGP_V6) { - if(!pkt.get(salt_size)) { + if (!pkt.get(salt_size)) { RNP_LOG("not enough data for v6 salt size octet"); return RNP_ERROR_BAD_FORMAT; } - if(salt_size != rnp::Hash::size(halg)/2) { + if (salt_size != rnp::Hash::size(halg) / 2) { RNP_LOG("invalid salt size"); return RNP_ERROR_BAD_FORMAT; } - if(!pkt.get(salt, salt_size)) { + if (!pkt.get(salt, salt_size)) { RNP_LOG("not enough data for v6 signature salt"); return RNP_ERROR_BAD_FORMAT; } @@ -1575,8 +1574,10 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: - material.dilithium_exdsa.sig.resize(pgp_dilithium_exdsa_signature_t::composite_signature_size(palg)); - if (!pkt.get(material.dilithium_exdsa.sig.data(), material.dilithium_exdsa.sig.size())) { + material.dilithium_exdsa.sig.resize( + pgp_dilithium_exdsa_signature_t::composite_signature_size(palg)); + if (!pkt.get(material.dilithium_exdsa.sig.data(), + material.dilithium_exdsa.sig.size())) { RNP_LOG("failed to get dilithium-ecdsa/eddsa signature"); return false; } @@ -1628,7 +1629,7 @@ pgp_signature_t::write(pgp_dest_t &dst) const } pktbody.add(lbits, 2); #if defined(ENABLE_CRYPTO_REFRESH) - if(version == PGP_V6) { + if (version == PGP_V6) { pktbody.add_byte(salt_size); pktbody.add(salt, salt_size); } diff --git a/src/librepgp/stream-sig.h b/src/librepgp/stream-sig.h index 0f522d421..a980dc1bb 100644 --- a/src/librepgp/stream-sig.h +++ b/src/librepgp/stream-sig.h @@ -61,11 +61,11 @@ typedef struct pgp_signature_t { /* common v4 and v6 fields */ std::vector subpkts; - #if defined(ENABLE_CRYPTO_REFRESH) +#if defined(ENABLE_CRYPTO_REFRESH) /* v6 - only fields */ uint8_t salt[PGP_MAX_SALT_SIZE_V6_SIG]; uint8_t salt_size; - #endif +#endif pgp_signature_t() : type_(PGP_SIG_BINARY), version(PGP_VUNKNOWN), palg(PGP_PKA_NOTHING), diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 990fb057e..36eca056a 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -106,7 +106,8 @@ typedef struct pgp_dest_encrypted_param_t { std::array v2_seipd_salt; /* SEIPDv2 salt value */ #endif - bool is_aead_auth() + bool + is_aead_auth() { switch (this->auth_type) { case rnp::AuthType::AEADv1: @@ -122,7 +123,8 @@ typedef struct pgp_dest_encrypted_param_t { }; #ifdef ENABLE_CRYPTO_REFRESH - bool is_v2_seipd() const + bool + is_v2_seipd() const { return this->auth_type == rnp::AuthType::AEADv2; } @@ -372,7 +374,7 @@ encrypted_start_aead_chunk(pgp_dest_encrypted_param_t *param, size_t idx, bool l } /* set chunk index for additional data */ - if (param->auth_type == rnp::AuthType::AEADv1) { + if (param->auth_type == rnp::AuthType::AEADv1) { write_uint64(param->ad + param->adlen - 8, idx); } @@ -568,15 +570,16 @@ encrypted_add_recipient(pgp_write_handler_t *handler, #if defined(ENABLE_CRYPTO_REFRESH) /* Crypto Refresh: For X25519/X448 PKESKv3, AES is mandated */ - if(userkey->alg() == PGP_PKA_X25519 && pkesk_version == PGP_PKSK_V3) { - switch(param->ctx->ealg) { - case PGP_SA_AES_128: - case PGP_SA_AES_192: - case PGP_SA_AES_256: - break; - default: - RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric algorithm that is not AES."); - return RNP_ERROR_DECRYPT_FAILED; + if (userkey->alg() == PGP_PKA_X25519 && pkesk_version == PGP_PKSK_V3) { + switch (param->ctx->ealg) { + case PGP_SA_AES_128: + case PGP_SA_AES_192: + case PGP_SA_AES_256: + break; + default: + RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric " + "algorithm that is not AES."); + return RNP_ERROR_DECRYPT_FAILED; } } #endif @@ -591,7 +594,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, pkey.fp = userkey->fp(); } #endif - + /* Encrypt the session key */ rnp::secure_array enckey; uint8_t *sesskey = enckey.data(); /* pointer to the actual session key */ @@ -602,7 +605,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, #if defined(ENABLE_CRYPTO_REFRESH) if (pkey.version == PGP_PKSK_V3) { size_t key_offset; - if(do_encrypt_pkesk_v3_alg_id(pkey.alg)) { + if (do_encrypt_pkesk_v3_alg_id(pkey.alg)) { /* for pre-crypto-refresh algorithms, algorithm ID is part of the session key */ key_offset = 1; enckey[0] = pkey.salg; @@ -610,21 +613,20 @@ encrypted_add_recipient(pgp_write_handler_t *handler, key_offset = 0; } #else - enckey[0] = pkey.salg; - size_t key_offset = 1; + enckey[0] = pkey.salg; + size_t key_offset = 1; #endif memcpy(&enckey[key_offset], key, keylen); sesskey += key_offset; enckey_len += key_offset; #if defined(ENABLE_CRYPTO_REFRESH) - } - else { // PGP_PKSK_V6 + } else { // PGP_PKSK_V6 memcpy(&enckey[0], key, keylen); } #endif #if defined(ENABLE_CRYPTO_REFRESH) - if(have_pkesk_checksum(pkey.alg)) + if (have_pkesk_checksum(pkey.alg)) #endif { /* Calculate checksum */ @@ -711,7 +713,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, enckey.data(), enckey_len, &material.x25519); - if(ret) { + if (ret) { RNP_LOG("x25519 encryption failed"); return ret; } @@ -729,10 +731,10 @@ encrypted_add_recipient(pgp_write_handler_t *handler, [[fallthrough]]; case PGP_PKA_KYBER1024_BP384: ret = userkey->material().kyber_ecdh.pub.encrypt(&handler->ctx->ctx->rng, - &material.kyber_ecdh, - enckey.data(), - enckey_len, - userkey->subkey_pkt_hash()); + &material.kyber_ecdh, + enckey.data(), + enckey_len, + userkey->subkey_pkt_hash()); if (ret) { RNP_LOG("Kyber ECC Encrypt failed"); return ret; @@ -939,7 +941,7 @@ encrypted_start_aead(pgp_dest_encrypted_param_t *param, uint8_t *enckey) nlen = pgp_cipher_aead_nonce_len(param->ctx->aalg); uint8_t *iv_or_salt = param->iv; size_t iv_or_salt_len = nlen; -#ifdef ENABLE_CRYPTO_REFRESH +#ifdef ENABLE_CRYPTO_REFRESH if (param->auth_type == rnp::AuthType::AEADv2) { iv_or_salt = param->v2_seipd_salt.data(); iv_or_salt_len = param->v2_seipd_salt.size(); @@ -987,8 +989,7 @@ encrypted_start_aead(pgp_dest_encrypted_param_t *param, uint8_t *enckey) memcpy(v2_seipd_hdr.salt, iv_or_salt, PGP_SEIPDV2_SALT_LEN); s2_fields = seipd_v2_key_and_nonce_derivation(v2_seipd_hdr, enckey); enckey = s2_fields.key.data(); - if(s2_fields.nonce.size() > sizeof(param->iv)) - { + if (s2_fields.nonce.size() > sizeof(param->iv)) { // would be better to indicate an error s2_fields.nonce.resize(sizeof(param->iv)); } @@ -1056,7 +1057,8 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr skeycount = handler->ctx->passwords.size(); #if defined(ENABLE_CRYPTO_REFRESH) - /* in the case of PKESK (pkeycount > 0) and all keys are PKESKv6/SEIPDv2 capable, ugprade to AEADv2 */ + /* in the case of PKESK (pkeycount > 0) and all keys are PKESKv6/SEIPDv2 capable, ugprade + * to AEADv2 */ if (handler->ctx->enable_pkesk_v6 && handler->ctx->pkeskv6_capable() && pkeycount > 0) { param->auth_type = rnp::AuthType::AEADv2; } @@ -1094,7 +1096,7 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr if (param->auth_type == rnp::AuthType::AEADv2) { pkesk_version = PGP_PKSK_V6; } - if(handler->ctx->aalg == PGP_AEAD_NONE) { + if (handler->ctx->aalg == PGP_AEAD_NONE) { // set default AEAD if not set // TODO-V6: is this the right place to set the default algorithm? param->ctx->aalg = DEFAULT_AEAD_ALG; @@ -1125,7 +1127,7 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr param->pkt.tag = param->auth_type == rnp::AuthType::MDC ? PGP_PKT_SE_IP_DATA : PGP_PKT_SE_DATA; #ifdef ENABLE_CRYPTO_REFRESH - if(param->auth_type == rnp::AuthType::AEADv2) { + if (param->auth_type == rnp::AuthType::AEADv2) { param->pkt.tag = PGP_PKT_SE_IP_DATA; } #endif @@ -1326,13 +1328,19 @@ signed_write_signature(pgp_dest_signed_param_t *param, try { pgp_signature_t sig; if (signer->onepass.version) { - signer->key->sign_init( - param->ctx->ctx->rng, sig, signer->onepass.halg, param->ctx->ctx->time(), signer->key->version()); + signer->key->sign_init(param->ctx->ctx->rng, + sig, + signer->onepass.halg, + param->ctx->ctx->time(), + signer->key->version()); sig.palg = signer->onepass.palg; sig.set_type(signer->onepass.type); } else { - signer->key->sign_init( - param->ctx->ctx->rng, sig, signer->halg, param->ctx->ctx->time(), signer->key->version()); + signer->key->sign_init(param->ctx->ctx->rng, + sig, + signer->halg, + param->ctx->ctx->time(), + signer->key->version()); /* line below should be checked */ sig.set_type(param->ctx->detached ? PGP_SIG_BINARY : PGP_SIG_TEXT); } diff --git a/src/librepgp/v2_seipd.h b/src/librepgp/v2_seipd.h index 00243036e..dc3cf4ff9 100644 --- a/src/librepgp/v2_seipd.h +++ b/src/librepgp/v2_seipd.h @@ -32,5 +32,5 @@ struct seipd_v2_aead_fields_t { std::vector key, nonce; }; -seipd_v2_aead_fields_t -seipd_v2_key_and_nonce_derivation(pgp_seipdv2_hdr_t &hdr, uint8_t *sesskey); +seipd_v2_aead_fields_t seipd_v2_key_and_nonce_derivation(pgp_seipdv2_hdr_t &hdr, + uint8_t * sesskey); diff --git a/src/rnp/fficli.cpp b/src/rnp/fficli.cpp index fc6a965e4..0bb57eb1b 100644 --- a/src/rnp/fficli.cpp +++ b/src/rnp/fficli.cpp @@ -1626,8 +1626,8 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) } #if defined(ENABLE_CRYPTO_REFRESH) - if(cfg.get_bool(CFG_KG_V6_KEY)) { - rnp_op_generate_set_v6_key(genkey); + if (cfg.get_bool(CFG_KG_V6_KEY)) { + rnp_op_generate_set_v6_key(genkey); } #endif @@ -1673,8 +1673,8 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) goto done; } #if defined(ENABLE_CRYPTO_REFRESH) - if(cfg.get_bool(CFG_KG_V6_KEY)) { - rnp_op_generate_set_v6_key(genkey); + if (cfg.get_bool(CFG_KG_V6_KEY)) { + rnp_op_generate_set_v6_key(genkey); } #endif if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &subkey)) { @@ -2813,8 +2813,6 @@ cli_rnp_encrypt_and_sign(const rnp_cfg &cfg, } } - - /* adding encrypting keys if pk-encryption is used */ if (cfg.get_bool(CFG_ENCRYPT_PK)) { std::vector keynames = cfg.get_list(CFG_RECIPIENTS); diff --git a/src/rnp/rnpcfg.h b/src/rnp/rnpcfg.h index 120f77d9a..9f891ba58 100644 --- a/src/rnp/rnpcfg.h +++ b/src/rnp/rnpcfg.h @@ -51,10 +51,10 @@ #define CFG_USERID "userid" /* userid for the ongoing operation */ #define CFG_RECIPIENTS "recipients" /* list of encrypted data recipients */ #if defined(ENABLE_CRYPTO_REFRESH) - #define CFG_V3_PKESK_ONLY "v3-pkesk-only" /* disable v6 PKESK */ +#define CFG_V3_PKESK_ONLY "v3-pkesk-only" /* disable v6 PKESK */ #endif -#define CFG_SIGNERS "signers" /* list of signers */ -#define CFG_HOMEDIR "homedir" /* home directory - folder with keyrings and so on */ +#define CFG_SIGNERS "signers" /* list of signers */ +#define CFG_HOMEDIR "homedir" /* home directory - folder with keyrings and so on */ #define CFG_KEYFILE "keyfile" /* path to the file with key(s), used instead of keyring */ #define CFG_PASSFD "pass-fd" /* password file descriptor */ #define CFG_PASSWD "password" /* password as command-line constant */ @@ -119,7 +119,8 @@ #define CFG_KG_PROT_HASH "kg-prot-hash" #define CFG_KG_PROT_ALG "kg-prot-alg" #define CFG_KG_PROT_ITERATIONS "kg-prot-iterations" -#define CFG_KG_V6_KEY "kg-v6-key" /* represents a boolean property: non-empty string means 'true' */ +#define CFG_KG_V6_KEY \ + "kg-v6-key" /* represents a boolean property: non-empty string means 'true' */ /* rnp CLI config : contains all the system-dependent and specified by the user configuration * options */ diff --git a/src/rnpkeys/tui.cpp b/src/rnpkeys/tui.cpp index cd2272ca6..9b2725f6c 100644 --- a/src/rnpkeys/tui.cpp +++ b/src/rnpkeys/tui.cpp @@ -243,7 +243,7 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) "\t(22) EDDSA + ECDH\n" #endif #if defined(ENABLE_CRYPTO_REFRESH) - "\t(23) ED25519 + X25519 (v6 key) \n" + "\t(23) ED25519 + X25519 (v6 key) \n" #endif #if defined(ENABLE_PQC) "\t(25) (Dilithium3 + Ed25519) + (Kyber768 + X25519)\n" @@ -252,8 +252,8 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) "\t(29) (Dilithium3 + ECDSA-brainpoolP256r1) + (Kyber768 + ECDH-brainpoolP256r1)\n" "\t(30) (Dilithium5 + ECDSA-brainpoolP384r1) + (Kyber1024 + ECDH-brainpoolP384r1)\n" #endif - "\t(99) SM2\n" - "> "); + "\t(99) SM2\n" + "> "); if (!rnp_secure_get_long_from_fd(input_fp, option, false)) { option = 0; continue; @@ -453,22 +453,22 @@ rnpkeys_ask_generate_params_subkey(rnp_cfg &cfg, FILE *input_fp) break; } #if defined(ENABLE_PQC) - case 25: + case 25: cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_X25519); break; - case 26: + case 26: cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_X448); break; - case 27: + case 27: cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_P256); break; - case 28: + case 28: cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_P384); break; - case 29: + case 29: cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_BP256); break; - case 30: + case 30: cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_BP384); break; #endif diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 6de6b0622..e7b443692 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -609,16 +609,15 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) /* PGP_PKA_KYBER1024_X448, */ // X448 not yet implemented PGP_PKA_KYBER1024_P384, PGP_PKA_KYBER768_BP256, - PGP_PKA_KYBER1024_BP384 - }; + 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 plaintext[32] = {0}; + size_t plaintext_len = sizeof(plaintext); + uint8_t result[32] = {0}; + size_t result_len = sizeof(result); - for(size_t i = 0; i < plaintext_len; i++) { + for (size_t i = 0; i < plaintext_len; i++) { plaintext[i] = i; // assures that we do not have a special case with all-zeroes } @@ -635,8 +634,10 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) assert_rnp_success(pgp_fingerprint(key_fpr, key_pkt)); pgp_key_t key(key_pkt); - assert_rnp_success(key_pkt.material.kyber_ecdh.pub.encrypt(&global_ctx.rng, &enc, plaintext, plaintext_len, key.subkey_pkt_hash())); - assert_rnp_success(key_pkt.material.kyber_ecdh.priv.decrypt(&global_ctx.rng, result, &result_len, &enc, key.subkey_pkt_hash())); + assert_rnp_success(key_pkt.material.kyber_ecdh.pub.encrypt( + &global_ctx.rng, &enc, plaintext, plaintext_len, key.subkey_pkt_hash())); + assert_rnp_success(key_pkt.material.kyber_ecdh.priv.decrypt( + &global_ctx.rng, result, &result_len, &enc, key.subkey_pkt_hash())); assert_int_equal(plaintext_len, result_len); assert_int_equal(memcmp(plaintext, result, result_len), 0); @@ -648,14 +649,18 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) uint8_t message[64]; const pgp_hash_alg_t hash_alg = PGP_HASH_SHA512; - pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, /* PGP_PKA_DILITHIUM5_ED448,*/ PGP_PKA_DILITHIUM3_P256, PGP_PKA_DILITHIUM5_P384, PGP_PKA_DILITHIUM3_BP256, PGP_PKA_DILITHIUM5_BP384}; - + pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, + /* PGP_PKA_DILITHIUM5_ED448,*/ PGP_PKA_DILITHIUM3_P256, + PGP_PKA_DILITHIUM5_P384, + PGP_PKA_DILITHIUM3_BP256, + PGP_PKA_DILITHIUM5_BP384}; + for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { // 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; diff --git a/src/tests/exdsa_ecdhkem.cpp b/src/tests/exdsa_ecdhkem.cpp index 393cab058..5b0729b8e 100644 --- a/src/tests/exdsa_ecdhkem.cpp +++ b/src/tests/exdsa_ecdhkem.cpp @@ -39,16 +39,25 @@ TEST_F(rnp_tests, test_ecdh_kem) std::vector ciphertext; std::vector symmetric_key; std::vector symmetric_key2; - ecdh_kem_key_t key_pair; - pgp_curve_t curve_list[] = {PGP_CURVE_NIST_P_256, PGP_CURVE_NIST_P_384, PGP_CURVE_NIST_P_521, PGP_CURVE_BP256, PGP_CURVE_BP384, PGP_CURVE_BP512, PGP_CURVE_25519}; + ecdh_kem_key_t key_pair; + pgp_curve_t curve_list[] = {PGP_CURVE_NIST_P_256, + PGP_CURVE_NIST_P_384, + PGP_CURVE_NIST_P_521, + PGP_CURVE_BP256, + PGP_CURVE_BP384, + PGP_CURVE_BP512, + PGP_CURVE_25519}; for (auto curve : curve_list) { /* keygen */ - assert_rnp_success(ec_key_t::generate_ecdh_kem_key_pair(&global_ctx.rng, &key_pair, curve)); + assert_rnp_success( + ec_key_t::generate_ecdh_kem_key_pair(&global_ctx.rng, &key_pair, curve)); /* kem encaps / decaps */ - assert_rnp_success(key_pair.pub.encapsulate(&global_ctx.rng, ciphertext, symmetric_key)); - assert_rnp_success(key_pair.priv.decapsulate(&global_ctx.rng, ciphertext, symmetric_key2)); + assert_rnp_success( + key_pair.pub.encapsulate(&global_ctx.rng, ciphertext, symmetric_key)); + assert_rnp_success( + key_pair.priv.decapsulate(&global_ctx.rng, ciphertext, symmetric_key2)); /* both parties should have the same key share */ assert_int_equal(symmetric_key.size(), symmetric_key2.size()); @@ -56,27 +65,36 @@ TEST_F(rnp_tests, test_ecdh_kem) /* test invalid ciphertext */ ciphertext.data()[4] += 1; - if(curve != PGP_CURVE_25519) { // Curve25519 accepts any 32-byte array - assert_throw(key_pair.priv.decapsulate(&global_ctx.rng, ciphertext, symmetric_key)); + if (curve != PGP_CURVE_25519) { // Curve25519 accepts any 32-byte array + assert_throw( + key_pair.priv.decapsulate(&global_ctx.rng, ciphertext, symmetric_key)); } } } TEST_F(rnp_tests, test_exdsa) { - pgp_hash_alg_t hash_alg = PGP_HASH_SHA256; + pgp_hash_alg_t hash_alg = PGP_HASH_SHA256; std::vector msg(32); - exdsa_key_t key_pair; - pgp_curve_t curve_list[] = {PGP_CURVE_NIST_P_256, PGP_CURVE_NIST_P_384, PGP_CURVE_NIST_P_521, PGP_CURVE_BP256, PGP_CURVE_BP384, PGP_CURVE_BP512, PGP_CURVE_ED25519}; - //pgp_curve_t curve_list[] = {PGP_CURVE_ED25519}; + exdsa_key_t key_pair; + pgp_curve_t curve_list[] = {PGP_CURVE_NIST_P_256, + PGP_CURVE_NIST_P_384, + PGP_CURVE_NIST_P_521, + PGP_CURVE_BP256, + PGP_CURVE_BP384, + PGP_CURVE_BP512, + PGP_CURVE_ED25519}; + // pgp_curve_t curve_list[] = {PGP_CURVE_ED25519}; for (auto curve : curve_list) { /* keygen */ - assert_rnp_success(ec_key_t::generate_exdsa_key_pair(&global_ctx.rng, &key_pair, curve)); - + assert_rnp_success( + ec_key_t::generate_exdsa_key_pair(&global_ctx.rng, &key_pair, curve)); + /* sign and verify */ std::vector sig; - assert_rnp_success(key_pair.priv.sign(&global_ctx.rng, sig, msg.data(), msg.size(), hash_alg)); + assert_rnp_success( + key_pair.priv.sign(&global_ctx.rng, sig, msg.data(), msg.size(), hash_alg)); assert_rnp_success(key_pair.pub.verify(sig, msg.data(), msg.size(), hash_alg)); /* test invalid msg / hash */ diff --git a/src/tests/ffi-key.cpp b/src/tests/ffi-key.cpp index 5eb90243d..11d9ffdd7 100644 --- a/src/tests/ffi-key.cpp +++ b/src/tests/ffi-key.cpp @@ -3158,7 +3158,7 @@ TEST_F(rnp_tests, test_ffi_malformed_keys_import) #if defined(ENABLE_CRYPTO_REFRESH) TEST_F(rnp_tests, test_ffi_v6_sig_subpackets) { - rnp_ffi_t ffi = NULL; + rnp_ffi_t ffi = NULL; assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); assert_rnp_success(rnp_ffi_set_key_provider(ffi, unused_getkeycb, NULL)); @@ -3174,9 +3174,11 @@ TEST_F(rnp_tests, test_ffi_v6_sig_subpackets) assert_rnp_success(rnp_op_generate_execute(op)); rnp_key_handle_t primary = NULL; assert_rnp_success(rnp_op_generate_get_key(op, &primary)); - - assert_true(primary->pub->get_sig(0).sig.has_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, false)); // MUST NOT have issuer key id extension - assert_false(primary->pub->get_sig(0).sig.has_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false)); // SHOULD have issuer fingerprint + + assert_true(primary->pub->get_sig(0).sig.has_subpkt( + PGP_SIG_SUBPKT_ISSUER_FPR, false)); // MUST NOT have issuer key id extension + assert_false(primary->pub->get_sig(0).sig.has_subpkt( + PGP_SIG_SUBPKT_ISSUER_KEY_ID, false)); // SHOULD have issuer fingerprint rnp_op_generate_destroy(op); } @@ -3185,38 +3187,44 @@ TEST_F(rnp_tests, test_ffi_v6_cert_import) { rnp_ffi_t ffi = NULL; rnp_input_t input = NULL; - size_t keycount = 255; + size_t keycount = 255; assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); assert_rnp_success( rnp_input_from_path(&input, "data/test_v6_valid_data/transferable_pubkey_v6.asc")); assert_rnp_success( - rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64, NULL)); + rnp_import_keys(ffi, + input, + RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64, + NULL)); rnp_input_destroy(input); assert_rnp_success(rnp_get_public_key_count(ffi, &keycount)); assert_int_equal(keycount, 2); assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount)); assert_int_equal(keycount, 0); - /* check that fingerprint is correct by checking the fingerprint in the signature (coming from the correct input data) vs the computed fingerprint value of the primary key. + /* check that fingerprint is correct by checking the fingerprint in the signature (coming + from the correct input data) vs the computed fingerprint value of the primary key. Issuer fingerprint is the priamry's key fingerprint for the primary and its subkeys */ pgp_fingerprint_t primary_fp; for (pgp_key_t key : ffi->pubring->keys) { - if(key.is_primary()) - { - primary_fp = key.fp(); - } + if (key.is_primary()) { + primary_fp = key.fp(); + } } for (pgp_key_t key : ffi->pubring->keys) { - /* get first sig and its issuer fpr subpacket */ - pgp_subsig_t subsig = key.get_sig(0); - const pgp_sig_subpkt_t* issuer_fpr = subsig.sig.get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, false); - assert_non_null(issuer_fpr); - - /* check that fingerprints match */ - assert_int_equal(key.fp().length, PGP_FINGERPRINT_V6_SIZE); - assert_memory_equal(issuer_fpr->data + 1, primary_fp.fingerprint, primary_fp.length); // first byte in data is the version - skip + /* get first sig and its issuer fpr subpacket */ + pgp_subsig_t subsig = key.get_sig(0); + const pgp_sig_subpkt_t *issuer_fpr = + subsig.sig.get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, false); + assert_non_null(issuer_fpr); + + /* check that fingerprints match */ + assert_int_equal(key.fp().length, PGP_FINGERPRINT_V6_SIZE); + assert_memory_equal(issuer_fpr->data + 1, + primary_fp.fingerprint, + primary_fp.length); // first byte in data is the version - skip } } @@ -3224,13 +3232,16 @@ TEST_F(rnp_tests, test_ffi_v6_seckey_import) { rnp_ffi_t ffi = NULL; rnp_input_t input = NULL; - size_t keycount = 255; + size_t keycount = 255; assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); assert_rnp_success( rnp_input_from_path(&input, "data/test_v6_valid_data/transferable_seckey_v6.asc")); assert_rnp_success( - rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64, NULL)); + rnp_import_keys(ffi, + input, + RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_SINGLE | RNP_LOAD_SAVE_BASE64, + NULL)); rnp_input_destroy(input); assert_rnp_success(rnp_get_secret_key_count(ffi, &keycount)); assert_int_equal(keycount, 2); diff --git a/src/tests/ffi.cpp b/src/tests/ffi.cpp index 526edd6f1..3e5521a8e 100644 --- a/src/tests/ffi.cpp +++ b/src/tests/ffi.cpp @@ -3117,7 +3117,8 @@ TEST_F(rnp_tests, test_ffi_supported_features) #if defined(ENABLE_PQC) pqc_opt = 10; // kyber+ecc and dilithium+ecc variants #endif - assert_true(check_features(RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + pqc_opt + crypto_refresh_opt)); + assert_true(check_features( + RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + pqc_opt + crypto_refresh_opt)); rnp_buffer_destroy(features); assert_rnp_success(rnp_supports_feature(RNP_FEATURE_PK_ALG, "RSA", &supported)); assert_true(supported); diff --git a/src/tests/hkdf.cpp b/src/tests/hkdf.cpp index 079ed57e7..abf2633b5 100644 --- a/src/tests/hkdf.cpp +++ b/src/tests/hkdf.cpp @@ -5,7 +5,7 @@ TEST_F(rnp_tests, hkdf_test_case_1) { - /* rfc5869 Test Case 1 + /* rfc5869 Test Case 1 Hash = SHA-256 IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets) salt = 0x000102030405060708090a0b0c (13 octets) @@ -19,17 +19,27 @@ TEST_F(rnp_tests, hkdf_test_case_1) 34007208d5b887185865 (42 octets) */ - std::vector IKM = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; - std::vector salt = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}; + std::vector IKM = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}; + std::vector salt = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c}; std::vector info = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9}; - std::vector PRK_expected = {0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5}; - std::vector OKM_expected = {0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65}; + std::vector PRK_expected = {0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, + 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, + 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5}; + std::vector OKM_expected = { + 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, + 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, + 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65}; size_t L = 42; std::unique_ptr hkdf = rnp::Hkdf::create(PGP_HASH_SHA256); uint8_t OKM[L]; - hkdf->extract_expand(salt.data(), salt.size(), IKM.data(), IKM.size(), info.data(), info.size(), OKM, L); + hkdf->extract_expand( + salt.data(), salt.size(), IKM.data(), IKM.size(), info.data(), info.size(), OKM, L); assert_memory_equal(OKM, OKM_expected.data(), OKM_expected.size()); } diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp index 1756389f9..ccf45d380 100644 --- a/src/tests/pqc.cpp +++ b/src/tests/pqc.cpp @@ -39,17 +39,17 @@ TEST_F(rnp_tests, test_kyber_key_function) { kyber_parameter_e params[2] = {kyber_768, kyber_1024}; - for(kyber_parameter_e param : params) - { + for (kyber_parameter_e param : params) { + auto public_and_private_key = kyber_generate_keypair(&global_ctx.rng, param); - auto public_and_private_key = kyber_generate_keypair(&global_ctx.rng, param); - - kyber_encap_result_t encap_res = public_and_private_key.first.encapsulate(&global_ctx.rng); - - std::vector decrypted = public_and_private_key.second.decapsulate(&global_ctx.rng, encap_res.ciphertext.data(), encap_res.ciphertext.size()); - assert_int_equal(encap_res.symmetric_key.size(), decrypted.size()); - assert_memory_equal(encap_res.symmetric_key.data(), decrypted.data(), decrypted.size()); + kyber_encap_result_t encap_res = + public_and_private_key.first.encapsulate(&global_ctx.rng); + std::vector decrypted = public_and_private_key.second.decapsulate( + &global_ctx.rng, encap_res.ciphertext.data(), encap_res.ciphertext.size()); + assert_int_equal(encap_res.symmetric_key.size(), decrypted.size()); + assert_memory_equal( + encap_res.symmetric_key.data(), decrypted.data(), decrypted.size()); } } @@ -69,23 +69,28 @@ TEST_F(rnp_tests, test_dilithium_key_function) } } -TEST_F(rnp_tests, test_dilithium_exdsa_direct) +TEST_F(rnp_tests, test_dilithium_exdsa_direct) { - pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, /* PGP_PKA_DILITHIUM5_ED448,*/ PGP_PKA_DILITHIUM3_P256, PGP_PKA_DILITHIUM5_P384, PGP_PKA_DILITHIUM3_BP256, PGP_PKA_DILITHIUM5_BP384}; - + pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, + /* PGP_PKA_DILITHIUM5_ED448,*/ PGP_PKA_DILITHIUM3_P256, + PGP_PKA_DILITHIUM5_P384, + PGP_PKA_DILITHIUM3_BP256, + PGP_PKA_DILITHIUM5_BP384}; + for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { uint8_t message[64]; const pgp_hash_alg_t hash_alg = PGP_HASH_SHA512; // Generate test data. Mainly to make valgrind not to complain about uninitialized data global_ctx.rng.get(message, sizeof(message)); - - pgp_dilithium_exdsa_key_t key; + + pgp_dilithium_exdsa_key_t key; pgp_dilithium_exdsa_signature_t sig; assert_rnp_success( - pgp_dilithium_exdsa_composite_key_t::gen_keypair(&global_ctx.rng, &key, algs[i])); + pgp_dilithium_exdsa_composite_key_t::gen_keypair(&global_ctx.rng, &key, algs[i])); - assert_rnp_success(key.priv.sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message))); + assert_rnp_success( + key.priv.sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message))); assert_rnp_success(key.pub.verify(&sig, hash_alg, message, sizeof(message))); // Fails because message won't verify @@ -99,9 +104,9 @@ TEST_F(rnp_tests, test_dilithium_exdsa_direct) sig.sig.data()[0] = ~sig.sig.data()[0]; // Fails because second sig won't verify - sig.sig.data()[sig.sig.size()-1] = ~sig.sig.data()[sig.sig.size()-1]; + sig.sig.data()[sig.sig.size() - 1] = ~sig.sig.data()[sig.sig.size() - 1]; assert_rnp_failure(key.pub.verify(&sig, hash_alg, message, sizeof(message))); - sig.sig.data()[sig.sig.size()-1] = ~sig.sig.data()[sig.sig.size()-1]; + sig.sig.data()[sig.sig.size() - 1] = ~sig.sig.data()[sig.sig.size() - 1]; } } From 19bde747b4e1a8f30528dd9ccdb055b1148dcb5a Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Fri, 30 Jun 2023 12:09:11 +0200 Subject: [PATCH 12/20] update copyright update copyright (2) --- src/lib/crypto/dilithium.cpp | 42 +++++++++---------- src/lib/crypto/dilithium.h | 42 +++++++++---------- src/lib/crypto/dilithium_common.cpp | 42 +++++++++---------- src/lib/crypto/dilithium_common.h | 42 +++++++++---------- src/lib/crypto/dilithium_exdsa_composite.cpp | 42 +++++++++---------- src/lib/crypto/dilithium_exdsa_composite.h | 42 +++++++++---------- src/lib/crypto/ed25519.cpp | 42 +++++++++---------- src/lib/crypto/ed25519.h | 42 +++++++++---------- src/lib/crypto/exdsa_ecdhkem.cpp | 42 +++++++++---------- src/lib/crypto/exdsa_ecdhkem.h | 43 +++++++++----------- src/lib/crypto/hkdf.cpp | 40 +++++++++--------- src/lib/crypto/hkdf.hpp | 40 +++++++++--------- src/lib/crypto/hkdf_botan.cpp | 40 +++++++++--------- src/lib/crypto/hkdf_botan.hpp | 40 +++++++++--------- src/lib/crypto/kmac.cpp | 40 +++++++++--------- src/lib/crypto/kmac.hpp | 40 +++++++++--------- src/lib/crypto/kmac_botan.cpp | 40 +++++++++--------- src/lib/crypto/kmac_botan.hpp | 40 +++++++++--------- src/lib/crypto/kyber.cpp | 42 +++++++++---------- src/lib/crypto/kyber.h | 42 +++++++++---------- src/lib/crypto/kyber_common.cpp | 42 +++++++++---------- src/lib/crypto/kyber_common.h | 42 +++++++++---------- src/lib/crypto/kyber_ecdh_composite.cpp | 42 +++++++++---------- src/lib/crypto/kyber_ecdh_composite.h | 42 +++++++++---------- src/lib/crypto/x25519.cpp | 42 +++++++++---------- src/lib/crypto/x25519.h | 42 +++++++++---------- src/tests/exdsa_ecdhkem.cpp | 42 +++++++++---------- src/tests/pqc.cpp | 42 +++++++++---------- 28 files changed, 541 insertions(+), 620 deletions(-) diff --git a/src/lib/crypto/dilithium.cpp b/src/lib/crypto/dilithium.cpp index ae1c9e097..26c4e974a 100644 --- a/src/lib/crypto/dilithium.cpp +++ b/src/lib/crypto/dilithium.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "dilithium.h" diff --git a/src/lib/crypto/dilithium.h b/src/lib/crypto/dilithium.h index 3bb2a1b51..678cf372a 100644 --- a/src/lib/crypto/dilithium.h +++ b/src/lib/crypto/dilithium.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 DILITHIUM_H_ diff --git a/src/lib/crypto/dilithium_common.cpp b/src/lib/crypto/dilithium_common.cpp index e2269020d..d28c7b678 100644 --- a/src/lib/crypto/dilithium_common.cpp +++ b/src/lib/crypto/dilithium_common.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "dilithium.h" diff --git a/src/lib/crypto/dilithium_common.h b/src/lib/crypto/dilithium_common.h index 2e677c875..40b9a961e 100644 --- a/src/lib/crypto/dilithium_common.h +++ b/src/lib/crypto/dilithium_common.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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_DILITHIUM_COMMON_H_ diff --git a/src/lib/crypto/dilithium_exdsa_composite.cpp b/src/lib/crypto/dilithium_exdsa_composite.cpp index e54d4f058..116d75972 100644 --- a/src/lib/crypto/dilithium_exdsa_composite.cpp +++ b/src/lib/crypto/dilithium_exdsa_composite.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "dilithium_exdsa_composite.h" diff --git a/src/lib/crypto/dilithium_exdsa_composite.h b/src/lib/crypto/dilithium_exdsa_composite.h index fa4513f3b..6e454342b 100644 --- a/src/lib/crypto/dilithium_exdsa_composite.h +++ b/src/lib/crypto/dilithium_exdsa_composite.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 DILITHIUM_EXDSA_COMPOSITE_H_ diff --git a/src/lib/crypto/ed25519.cpp b/src/lib/crypto/ed25519.cpp index 50ae8d97d..240d84819 100644 --- a/src/lib/crypto/ed25519.cpp +++ b/src/lib/crypto/ed25519.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "ed25519.h" diff --git a/src/lib/crypto/ed25519.h b/src/lib/crypto/ed25519.h index 43f1022e3..5ab109d07 100644 --- a/src/lib/crypto/ed25519.h +++ b/src/lib/crypto/ed25519.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 ED25519_H_ diff --git a/src/lib/crypto/exdsa_ecdhkem.cpp b/src/lib/crypto/exdsa_ecdhkem.cpp index b10c188d9..444762518 100644 --- a/src/lib/crypto/exdsa_ecdhkem.cpp +++ b/src/lib/crypto/exdsa_ecdhkem.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "exdsa_ecdhkem.h" diff --git a/src/lib/crypto/exdsa_ecdhkem.h b/src/lib/crypto/exdsa_ecdhkem.h index 24c80bd2d..20b8355a7 100644 --- a/src/lib/crypto/exdsa_ecdhkem.h +++ b/src/lib/crypto/exdsa_ecdhkem.h @@ -1,32 +1,29 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 ECDH_KEM_H_ #define ECDH_KEM_H_ diff --git a/src/lib/crypto/hkdf.cpp b/src/lib/crypto/hkdf.cpp index e45e3e4c1..1ddac874a 100644 --- a/src/lib/crypto/hkdf.cpp +++ b/src/lib/crypto/hkdf.cpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 "config.h" diff --git a/src/lib/crypto/hkdf.hpp b/src/lib/crypto/hkdf.hpp index 081aa11b2..e7d9c67d6 100644 --- a/src/lib/crypto/hkdf.hpp +++ b/src/lib/crypto/hkdf.hpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 CRYPTO_HKDF_H_ diff --git a/src/lib/crypto/hkdf_botan.cpp b/src/lib/crypto/hkdf_botan.cpp index 1ecbedf50..8e700c34d 100644 --- a/src/lib/crypto/hkdf_botan.cpp +++ b/src/lib/crypto/hkdf_botan.cpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 "config.h" diff --git a/src/lib/crypto/hkdf_botan.hpp b/src/lib/crypto/hkdf_botan.hpp index 6d7325c57..19f5f5ee7 100644 --- a/src/lib/crypto/hkdf_botan.hpp +++ b/src/lib/crypto/hkdf_botan.hpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 CRYPTO_HKDF_BOTAN_HPP_ diff --git a/src/lib/crypto/kmac.cpp b/src/lib/crypto/kmac.cpp index 1101cca43..8eca7ac3a 100644 --- a/src/lib/crypto/kmac.cpp +++ b/src/lib/crypto/kmac.cpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 "config.h" diff --git a/src/lib/crypto/kmac.hpp b/src/lib/crypto/kmac.hpp index 490f4f6fa..9813ae81c 100644 --- a/src/lib/crypto/kmac.hpp +++ b/src/lib/crypto/kmac.hpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 CRYPTO_KMAC_H_ diff --git a/src/lib/crypto/kmac_botan.cpp b/src/lib/crypto/kmac_botan.cpp index a2a2048bf..b4a75c739 100644 --- a/src/lib/crypto/kmac_botan.cpp +++ b/src/lib/crypto/kmac_botan.cpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 "kmac_botan.hpp" diff --git a/src/lib/crypto/kmac_botan.hpp b/src/lib/crypto/kmac_botan.hpp index 0d201427f..50696505b 100644 --- a/src/lib/crypto/kmac_botan.hpp +++ b/src/lib/crypto/kmac_botan.hpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2022 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * 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. + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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 HOLDERS 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. + * 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 CRYPTO_KMAC_BOTAN_HPP_ diff --git a/src/lib/crypto/kyber.cpp b/src/lib/crypto/kyber.cpp index 6652fc458..6de7ed762 100644 --- a/src/lib/crypto/kyber.cpp +++ b/src/lib/crypto/kyber.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "kyber.h" diff --git a/src/lib/crypto/kyber.h b/src/lib/crypto/kyber.h index e5155e247..24122ce8d 100644 --- a/src/lib/crypto/kyber.h +++ b/src/lib/crypto/kyber.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 KYBER_H_ diff --git a/src/lib/crypto/kyber_common.cpp b/src/lib/crypto/kyber_common.cpp index 0616828b6..0d70a157d 100644 --- a/src/lib/crypto/kyber_common.cpp +++ b/src/lib/crypto/kyber_common.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "kyber_common.h" diff --git a/src/lib/crypto/kyber_common.h b/src/lib/crypto/kyber_common.h index e84f4ddab..4b7978ef1 100644 --- a/src/lib/crypto/kyber_common.h +++ b/src/lib/crypto/kyber_common.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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_KYBER_COMMON_H_ diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp index bb4058b92..532f2f802 100644 --- a/src/lib/crypto/kyber_ecdh_composite.cpp +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "kyber_ecdh_composite.h" diff --git a/src/lib/crypto/kyber_ecdh_composite.h b/src/lib/crypto/kyber_ecdh_composite.h index 3fe3979b8..03e3c9bf5 100644 --- a/src/lib/crypto/kyber_ecdh_composite.h +++ b/src/lib/crypto/kyber_ecdh_composite.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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_KYBER_ECDH_COMPOSITE_H_ diff --git a/src/lib/crypto/x25519.cpp b/src/lib/crypto/x25519.cpp index 32628154f..f79327845 100644 --- a/src/lib/crypto/x25519.cpp +++ b/src/lib/crypto/x25519.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "x25519.h" diff --git a/src/lib/crypto/x25519.h b/src/lib/crypto/x25519.h index 75c9e52a5..0e6317b03 100644 --- a/src/lib/crypto/x25519.h +++ b/src/lib/crypto/x25519.h @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 X25519_H_ diff --git a/src/tests/exdsa_ecdhkem.cpp b/src/tests/exdsa_ecdhkem.cpp index 5b0729b8e..0e6356984 100644 --- a/src/tests/exdsa_ecdhkem.cpp +++ b/src/tests/exdsa_ecdhkem.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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. */ #if defined(ENABLE_CRYPTO_REFRESH) diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp index ccf45d380..abb608b07 100644 --- a/src/tests/pqc.cpp +++ b/src/tests/pqc.cpp @@ -1,31 +1,27 @@ /* - * Copyright (c) 2023 MTG AG + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). * All rights reserved. * - * This code is originally derived from software contributed to - * The NetBSD Foundation by Alistair Crooks (agc@netbsd.org), and - * carried further by Ribose Inc (https://www.ribose.com). + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: * - * 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. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. * - * 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 HOLDERS 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. + * 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 "config.h" From ad0e455d4f05ddebf0f08a1184fc20b50c1cd93c Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Mon, 10 Jul 2023 09:32:16 +0200 Subject: [PATCH 13/20] clang format --- include/rnp/rnp.h | 3 ++- src/lib/crypto/dilithium.cpp | 10 ++++----- src/lib/crypto/kyber.cpp | 10 +++++---- src/lib/fingerprint.cpp | 3 ++- src/librepgp/stream-dump.cpp | 5 ++++- src/librepgp/stream-key.cpp | 40 +++++++++++++++++---------------- src/librepgp/stream-packet.cpp | 20 ++++++++--------- src/librepgp/stream-sig.cpp | 41 ++++++++++++++++++++-------------- 8 files changed, 74 insertions(+), 58 deletions(-) diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 50584a248..663516352 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -1179,7 +1179,8 @@ RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, #if defined(ENABLE_CRYPTO_REFRESH) /** Set the generated key version to v6. - * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any time. + * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any + * time. * * @param op pointer to opaque key generation context. * @return RNP_SUCCESS or error code if failed. diff --git a/src/lib/crypto/dilithium.cpp b/src/lib/crypto/dilithium.cpp index 26c4e974a..2c0615185 100644 --- a/src/lib/crypto/dilithium.cpp +++ b/src/lib/crypto/dilithium.cpp @@ -57,15 +57,15 @@ pgp_dilithium_private_key_t::sign(rnp::RNG *rng, const uint8_t *msg, size_t msg_ Botan::Dilithium_PublicKey pgp_dilithium_public_key_t::botan_key() const { - return Botan::Dilithium_PublicKey(key_encoded_, - rnp_dilithium_param_to_botan_dimension(dilithium_param_)); + return Botan::Dilithium_PublicKey( + key_encoded_, rnp_dilithium_param_to_botan_dimension(dilithium_param_)); } Botan::Dilithium_PrivateKey pgp_dilithium_private_key_t::botan_key() const { Botan::secure_vector priv_sv(key_encoded_.data(), - key_encoded_.data() + key_encoded_.size()); + key_encoded_.data() + key_encoded_.size()); return Botan::Dilithium_PrivateKey( priv_sv, rnp_dilithium_param_to_botan_dimension(this->dilithium_param_)); } @@ -86,8 +86,8 @@ pgp_dilithium_public_key_t::verify_signature(const uint8_t *msg, std::pair dilithium_generate_keypair(rnp::RNG *rng, dilithium_parameter_e dilithium_param) { - Botan::Dilithium_PrivateKey priv_key(*rng->obj(), - rnp_dilithium_param_to_botan_dimension(dilithium_param)); + Botan::Dilithium_PrivateKey priv_key( + *rng->obj(), rnp_dilithium_param_to_botan_dimension(dilithium_param)); std::unique_ptr pub_key = priv_key.public_key(); Botan::secure_vector priv_bits = priv_key.private_key_bits(); diff --git a/src/lib/crypto/kyber.cpp b/src/lib/crypto/kyber.cpp index 6de7ed762..54845df1b 100644 --- a/src/lib/crypto/kyber.cpp +++ b/src/lib/crypto/kyber.cpp @@ -53,7 +53,8 @@ key_share_size_from_kyber_param(kyber_parameter_e param) std::pair kyber_generate_keypair(rnp::RNG *rng, kyber_parameter_e kyber_param) { - Botan::Kyber_PrivateKey kyber_priv(*rng->obj(), rnp_kyber_param_to_botan_kyber_mode(kyber_param)); + Botan::Kyber_PrivateKey kyber_priv(*rng->obj(), + rnp_kyber_param_to_botan_kyber_mode(kyber_param)); Botan::secure_vector encoded_private_key = kyber_priv.private_key_bits(); std::unique_ptr kyber_pub = kyber_priv.public_key(); @@ -68,14 +69,15 @@ kyber_generate_keypair(rnp::RNG *rng, kyber_parameter_e kyber_param) Botan::Kyber_PublicKey pgp_kyber_public_key_t::botan_key() const { - return Botan::Kyber_PublicKey(key_encoded_, rnp_kyber_param_to_botan_kyber_mode(kyber_mode_)); + return Botan::Kyber_PublicKey(key_encoded_, + rnp_kyber_param_to_botan_kyber_mode(kyber_mode_)); } Botan::Kyber_PrivateKey pgp_kyber_private_key_t::botan_key() const { Botan::secure_vector key_sv(key_encoded_.data(), - key_encoded_.data() + key_encoded_.size()); + key_encoded_.data() + key_encoded_.size()); return Botan::Kyber_PrivateKey(key_sv, rnp_kyber_param_to_botan_kyber_mode(kyber_mode_)); } @@ -108,7 +110,7 @@ pgp_kyber_private_key_t::decapsulate(rnp::RNG * rng, size_t ciphertext_len) { assert(is_initialized_); - auto decoded_kyber_priv = botan_key(); + auto decoded_kyber_priv = botan_key(); Botan::PK_KEM_Decryptor kem_dec(decoded_kyber_priv, *rng->obj(), "Raw", "base"); Botan::secure_vector dec_shared_key = kem_dec.decrypt( ciphertext, ciphertext_len, key_share_size_from_kyber_param(kyber_mode_)); diff --git a/src/lib/fingerprint.cpp b/src/lib/fingerprint.cpp index 2ba304d73..b6464ebb2 100644 --- a/src/lib/fingerprint.cpp +++ b/src/lib/fingerprint.cpp @@ -59,7 +59,8 @@ pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key) switch (key.version) { #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_V6: [[fallthrough]]; + case PGP_V6: + [[fallthrough]]; #endif case PGP_V4: break; diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 1bd0d1afe..cd1c6732d 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -340,7 +340,10 @@ dst_print_mpi(pgp_dest_t *dst, const char *name, pgp_mpi_t *mpi, bool dumpbin) #if defined(ENABLE_CRYPTO_REFRESH) static void -dst_print_vec(pgp_dest_t *dst, const char *name, std::vector const &data, bool dumpbin) +dst_print_vec(pgp_dest_t * dst, + const char * name, + std::vector const &data, + bool dumpbin) { std::vector hex(2 * data.size()); if (!dumpbin) { diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index b8a078af8..b4c9b8a30 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -1356,7 +1356,7 @@ pgp_key_pkt_t::parse(pgp_source_t &src) } #if defined(ENABLE_CRYPTO_REFRESH) - std::vector tmpbuf; + std::vector tmpbuf; #endif pgp_packet_body_t pkt((pgp_pkt_type_t) atag); @@ -1373,18 +1373,20 @@ pgp_key_pkt_t::parse(pgp_source_t &src) RNP_LOG("unable to retrieve key packet version"); return RNP_ERROR_BAD_FORMAT; } - switch(ver) { - case PGP_V2: [[fallthrough]]; - case PGP_V3: [[fallthrough]]; - case PGP_V4: - break; + switch (ver) { + case PGP_V2: + [[fallthrough]]; + case PGP_V3: + [[fallthrough]]; + case PGP_V4: + break; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_V6: - break; + case PGP_V6: + break; #endif - default: - RNP_LOG("wrong key packet version"); - return RNP_ERROR_BAD_FORMAT; + default: + RNP_LOG("wrong key packet version"); + return RNP_ERROR_BAD_FORMAT; } version = (pgp_version_t) ver; /* creation time */ @@ -1704,16 +1706,16 @@ void pgp_key_pkt_t::fill_hashed_data() { /* we don't have a need to write v2-v3 signatures */ - switch(version) { - case PGP_V4: - break; + switch (version) { + case PGP_V4: + break; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_V6: - break; + case PGP_V6: + break; #endif - default: - RNP_LOG("unknown key version %d", (int) version); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + default: + RNP_LOG("unknown key version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } pgp_packet_body_t hbody(PGP_PKT_RESERVED); diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 07f15f442..b547ff012 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -751,18 +751,18 @@ pgp_packet_body_t::add_subpackets(const pgp_signature_t &sig, bool hashed) if (spbody.data_.size() > 0xffff) { throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - switch(sig.version) { - case PGP_V4: - add_uint16(spbody.data_.size()); - break; + switch (sig.version) { + case PGP_V4: + add_uint16(spbody.data_.size()); + break; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_V6: - add_uint32(spbody.data_.size()); - break; + case PGP_V6: + add_uint32(spbody.data_.size()); + break; #endif - default: - RNP_LOG("should not reach this code"); - throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + default: + RNP_LOG("should not reach this code"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); } add(spbody.data_.data(), spbody.data_.size()); } diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index fe864ce89..825ae1f1d 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1346,7 +1346,8 @@ pgp_signature_t::parse_v4up(pgp_packet_body_t &pkt) break; default: RNP_LOG("unsupported signature version: %d", (int) version); - return RNP_ERROR_BAD_FORMAT; } + return RNP_ERROR_BAD_FORMAT; + } #else uint8_t splen_buf[2]; #endif @@ -1440,13 +1441,15 @@ pgp_signature_t::parse(pgp_packet_body_t &pkt) /* v3 or v4 or v6 signature body */ rnp_result_t res; - switch(ver) { - case PGP_V2: [[fallthrough]]; + switch (ver) { + case PGP_V2: + [[fallthrough]]; case PGP_V3: res = parse_v2v3(pkt); break; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_V6: [[fallthrough]]; + case PGP_V6: + [[fallthrough]]; #endif case PGP_V4: res = parse_v4up(pkt); @@ -1598,9 +1601,11 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const void pgp_signature_t::write(pgp_dest_t &dst) const { - switch(version) { - case PGP_V2: [[fallthrough]]; - case PGP_V3: [[fallthrough]]; + switch (version) { + case PGP_V2: + [[fallthrough]]; + case PGP_V3: + [[fallthrough]]; case PGP_V4: break; #if defined(ENABLE_CRYPTO_REFRESH) @@ -1701,18 +1706,20 @@ void pgp_signature_t::fill_hashed_data() { /* we don't have a need to write v2-v3 signatures */ - switch(version) { - case PGP_V2: [[fallthrough]]; - case PGP_V3: [[fallthrough]]; - case PGP_V4: - break; + switch (version) { + case PGP_V2: + [[fallthrough]]; + case PGP_V3: + [[fallthrough]]; + case PGP_V4: + break; #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_V6: - break; + case PGP_V6: + break; #endif - default: - RNP_LOG("don't know version %d", (int) version); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + default: + RNP_LOG("don't know version %d", (int) version); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } pgp_packet_body_t hbody(PGP_PKT_RESERVED); if (version < PGP_V4) { From cfa5b9b02d3aa7e47a1d426d13e979821296de36 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 11 Jul 2023 10:13:47 +0200 Subject: [PATCH 14/20] pqc draft: update dom separation string pqc draft: remove packet hash pqc draft: add ecc pubkey to hashed ecdh key share pqc draft: check AES for v3 PKESK --- include/repgp/repgp_def.h | 24 ++++++++--------- src/lib/crypto/exdsa_ecdhkem.cpp | 12 +++++++++ src/lib/crypto/exdsa_ecdhkem.h | 2 ++ src/lib/crypto/kmac.cpp | 19 +++++--------- src/lib/crypto/kmac.hpp | 21 +++++++-------- src/lib/crypto/kmac_botan.cpp | 2 -- src/lib/crypto/kmac_botan.hpp | 1 - src/lib/crypto/kyber_ecdh_composite.cpp | 18 +++++-------- src/lib/crypto/kyber_ecdh_composite.h | 6 ++--- src/lib/pgp-key.cpp | 15 ----------- src/lib/pgp-key.h | 4 --- src/librepgp/stream-parse.cpp | 35 ++++++++++++++++++++----- src/librepgp/stream-write.cpp | 3 +-- src/tests/cipher.cpp | 4 +-- 14 files changed, 84 insertions(+), 82 deletions(-) diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index 95bf1f5bd..52ded8dc7 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -228,28 +228,28 @@ typedef enum : uint8_t { #if defined(ENABLE_PQC) /* PQC-ECC composite */ - PGP_PKA_KYBER768_X25519 = 29, /* Kyber768 + X25519 from draft-wussler-openpgp-pqc-01 */ + PGP_PKA_KYBER768_X25519 = 29, /* Kyber768 + X25519 from draft-wussler-openpgp-pqc-02 */ // PGP_PKA_KYBER1024_X448 = 30, /* Kyer1024 + X448 from - // draft-wussler-openpgp-pqc-01 */ - PGP_PKA_KYBER768_P256 = 31, /* Kyber768 + NIST P-256 from draft-wussler-openpgp-pqc-01 */ - PGP_PKA_KYBER1024_P384 = 32, /* Kyber1024 + NIST P-384 from draft-wussler-openpgp-pqc-01 */ + // draft-wussler-openpgp-pqc-02 */ + PGP_PKA_KYBER768_P256 = 31, /* Kyber768 + NIST P-256 from draft-wussler-openpgp-pqc-02 */ + PGP_PKA_KYBER1024_P384 = 32, /* Kyber1024 + NIST P-384 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_KYBER768_BP256 = - 33, /* Kyber768 + Brainpool P256r1 from draft-wussler-openpgp-pqc-01 */ + 33, /* Kyber768 + Brainpool P256r1 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_KYBER1024_BP384 = - 34, /* Kyber1024 + Brainpool P384r1 from draft-wussler-openpgp-pqc-01 */ + 34, /* Kyber1024 + Brainpool P384r1 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_DILITHIUM3_ED25519 = - 35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-01 */ + 35, /* Dilithium 3 + Ed25519 from draft-wussler-openpgp-pqc-02 */ // PGP_PKA_DILITHIUM5_ED448 = 36, /* Dilithium 5 + Ed448 from - // draft-wussler-openpgp-pqc-01 */ + // draft-wussler-openpgp-pqc-02 */ PGP_PKA_DILITHIUM3_P256 = - 37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-01 */ + 37, /* Dilithium 3 + ECDSA-NIST-P-256 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_DILITHIUM5_P384 = - 38, /* Dilithium 5 + ECDSA-NIST-P-384 from draft-wussler-openpgp-pqc-00*/ + 38, /* Dilithium 5 + ECDSA-NIST-P-384 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_DILITHIUM3_BP256 = - 39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-01 */ + 39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_DILITHIUM5_BP384 = - 40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-01 */ + 40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-02 */ #endif PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ diff --git a/src/lib/crypto/exdsa_ecdhkem.cpp b/src/lib/crypto/exdsa_ecdhkem.cpp index 444762518..4be3db0f7 100644 --- a/src/lib/crypto/exdsa_ecdhkem.cpp +++ b/src/lib/crypto/exdsa_ecdhkem.cpp @@ -100,6 +100,18 @@ ecdh_kem_public_key_t::botan_key_x25519() const return Botan::Curve25519_PublicKey(key_); } +std::vector +ecdh_kem_private_key_t::get_pubkey_encoded(rnp::RNG *rng) const +{ + if (curve_ == PGP_CURVE_25519) { + Botan::X25519_PrivateKey botan_key = botan_key_x25519(); + return botan_key.public_value(); + } else { + Botan::ECDH_PrivateKey botan_key = botan_key_ecdh(rng); + return botan_key.public_value(); + } +} + rnp_result_t ecdh_kem_public_key_t::encapsulate(rnp::RNG * rng, std::vector &ciphertext, diff --git a/src/lib/crypto/exdsa_ecdhkem.h b/src/lib/crypto/exdsa_ecdhkem.h index 20b8355a7..03fe025d6 100644 --- a/src/lib/crypto/exdsa_ecdhkem.h +++ b/src/lib/crypto/exdsa_ecdhkem.h @@ -111,6 +111,8 @@ class ecdh_kem_private_key_t : public ec_key_t { return Botan::unlock(key_); } + std::vector get_pubkey_encoded(rnp::RNG *rng) const; + rnp_result_t decapsulate(rnp::RNG * rng, const std::vector &ciphertext, std::vector & plaintext); diff --git a/src/lib/crypto/kmac.cpp b/src/lib/crypto/kmac.cpp index 8eca7ac3a..f0bf462ee 100644 --- a/src/lib/crypto/kmac.cpp +++ b/src/lib/crypto/kmac.cpp @@ -68,18 +68,14 @@ KMAC256::counter() const /* // Input: - // algID - the algorithm ID encoded as octet - // publicKey - the recipient's encryption sub-key packet - // serialized as octet string + // algID - the algorithm ID encoded as octet - fixedInfo = algID || SHA3-256(publicKey) + fixedInfo = algID */ std::vector -KMAC256::fixedInfo(const std::vector &subkey_pkt_hash, pgp_pubkey_alg_t alg_id) +KMAC256::fixedInfo(pgp_pubkey_alg_t alg_id) { - std::vector result(subkey_pkt_hash); - result.insert(result.begin(), (static_cast(alg_id))); - ; + std::vector result(static_cast(alg_id)); return result; } @@ -88,14 +84,13 @@ KMAC256::encData(const std::vector &ecc_key_share, const std::vector &ecc_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, - const std::vector &subkey_pkt_hash, - pgp_pubkey_alg_t alg_id) + pgp_pubkey_alg_t alg_id) { std::vector enc_data; std::vector counter_vec = counter(); - std::vector fixedInfo_vec = fixedInfo(subkey_pkt_hash, alg_id); + std::vector fixedInfo_vec = fixedInfo(alg_id); - /* draft-wussler-openpgp-pqc-01: + /* draft-wussler-openpgp-pqc-02: eccKemData = eccKeyShare || eccCipherText kyberKemData = kyberKeyShare || kyberCipherText diff --git a/src/lib/crypto/kmac.hpp b/src/lib/crypto/kmac.hpp index 9813ae81c..a80c8c498 100644 --- a/src/lib/crypto/kmac.hpp +++ b/src/lib/crypto/kmac.hpp @@ -35,18 +35,20 @@ namespace rnp { class KMAC256 { /* KDF for PQC key combiner according to - * https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-01 */ + * https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-02 */ protected: - /* The value of domSeparation is the UTF-8 encoding of the string "OpenPGPV5CompositeKDF" - and MUST be the following octet sequence: + /* The value of domSeparation is the UTF-8 encoding of the string "OpenPGPCompositeKeyDerivationFunction" and MUST be the following octet sequence: + + domSeparation := 4F 70 65 6E 50 47 50 43 6F 6D 70 6F 73 69 74 65 + 4B 65 79 44 65 72 69 76 61 74 69 6F 6E 46 75 6E + 63 74 69 6F 6E - domSeparation := 4F 70 65 6E 50 47 50 56 35 43 6F - 6D 70 6F 73 69 74 65 4B 44 46 */ const std::vector domSeparation_ = - std::vector({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x56, 0x35, 0x43, 0x6F, - 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, 0x4B, 0x44, 0x46}); + std::vector({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, + 0x4B, 0x65, 0x79, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x75, 0x6E, + 0x63, 0x74, 0x69, 0x6F, 0x6E}); /* customizationString := 4B 44 46 */ const std::vector customizationString_ = std::vector({0x4B, 0x44, 0x46}); @@ -57,13 +59,11 @@ class KMAC256 { std::vector domSeparation() const; std::vector customizationString() const; std::vector counter() const; - std::vector fixedInfo(const std::vector &subkey_pkt_hash, - pgp_pubkey_alg_t alg_id); + std::vector fixedInfo(pgp_pubkey_alg_t alg_id); std::vector encData(const std::vector &ecc_key_share, const std::vector &ecc_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, - const std::vector &subkey_pkt_hash, pgp_pubkey_alg_t alg_id); KMAC256(){}; @@ -77,7 +77,6 @@ class KMAC256 { const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, const pgp_pubkey_alg_t alg_id, - const std::vector &subkey_pkt_hash, std::vector & out) = 0; virtual ~KMAC256(); diff --git a/src/lib/crypto/kmac_botan.cpp b/src/lib/crypto/kmac_botan.cpp index b4a75c739..a1947d8dc 100644 --- a/src/lib/crypto/kmac_botan.cpp +++ b/src/lib/crypto/kmac_botan.cpp @@ -46,7 +46,6 @@ KMAC256_Botan::compute(const std::vector &ecc_key_share, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, const pgp_pubkey_alg_t alg_id, - const std::vector &subkey_pkt_hash, std::vector & out) { auto kmac = Botan::MessageAuthenticationCode::create_or_throw("KMAC256(256)"); @@ -63,7 +62,6 @@ KMAC256_Botan::compute(const std::vector &ecc_key_share, ecc_ciphertext, kyber_key_share, kyber_ciphertext, - subkey_pkt_hash, alg_id)); out = kmac->final_stdvec(); } diff --git a/src/lib/crypto/kmac_botan.hpp b/src/lib/crypto/kmac_botan.hpp index 50696505b..fb1711a80 100644 --- a/src/lib/crypto/kmac_botan.hpp +++ b/src/lib/crypto/kmac_botan.hpp @@ -46,7 +46,6 @@ class KMAC256_Botan : public KMAC256 { const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, const pgp_pubkey_alg_t alg_id, - const std::vector &subkey_pkt_hash, std::vector & out) override; }; diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp index 532f2f802..2704b5664 100644 --- a/src/lib/crypto/kyber_ecdh_composite.cpp +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -295,9 +295,10 @@ namespace { std::vector hashed_ecc_keyshare(const std::vector &key_share, const std::vector &ciphertext, + const std::vector &ecc_pubkey, pgp_pubkey_alg_t alg_id) { - /* SHA3-256(X || eccCipherText) or SHA3-256(X || eccCipherText) depending on algorithm */ + /* SHA3-256(X || eccCipherText) or SHA3-512(X || eccCipherText) depending on algorithm */ std::vector digest; pgp_hash_alg_t hash_alg; @@ -321,6 +322,7 @@ hashed_ecc_keyshare(const std::vector &key_share, auto hash = rnp::Hash::create(hash_alg); hash->add(key_share); hash->add(ciphertext); + hash->add(ecc_pubkey); digest.resize(rnp::Hash::size(hash_alg)); hash->finish(digest.data()); @@ -333,11 +335,9 @@ 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 std::vector &subkey_pkt_hash) + const pgp_kyber_ecdh_encrypted_t *enc) { initialized_or_throw(); - assert(subkey_pkt_hash.size() == rnp::Hash::size(PGP_HASH_SHA3_256)); rnp_result_t res; std::vector ecdh_keyshare; std::vector hashed_ecdh_keyshare; @@ -360,7 +360,7 @@ pgp_kyber_ecdh_composite_private_key_t::decrypt(rnp::RNG * return res; } hashed_ecdh_keyshare = - hashed_ecc_keyshare(ecdh_keyshare, ecdh_encapsulated_keyshare, pk_alg_); + hashed_ecc_keyshare(ecdh_keyshare, ecdh_encapsulated_keyshare, ecdh_key_->get_pubkey_encoded(rng), pk_alg_); // Compute (kyberKeyShare) := kyberKem.decap(kyberCipherText, kyberPrivateKey) std::vector kyber_encapsulated_keyshare = std::vector( @@ -382,7 +382,6 @@ pgp_kyber_ecdh_composite_private_key_t::decrypt(rnp::RNG * kyber_keyshare, kyber_encapsulated_keyshare, pk_alg(), - subkey_pkt_hash, kek_vec); Botan::SymmetricKey kek(kek_vec); @@ -492,11 +491,9 @@ 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, - const std::vector &subkey_pkt_hash) + size_t session_key_len) { initialized_or_throw(); - assert(subkey_pkt_hash.size() == rnp::Hash::size(PGP_HASH_SHA3_256)); rnp_result_t res; std::vector ecdh_ciphertext; @@ -515,7 +512,7 @@ pgp_kyber_ecdh_composite_public_key_t::encrypt(rnp::RNG * rng, return res; } ecdh_hashed_symmetric_key = - hashed_ecc_keyshare(ecdh_symmetric_key, ecdh_ciphertext, pk_alg_); + hashed_ecc_keyshare(ecdh_symmetric_key, ecdh_ciphertext, ecdh_key_.get_encoded(), pk_alg_); // Compute (kyberCipherText, kyberKeyShare) := kyberKem.encap(kyberPublicKey) kyber_encap_result_t kyber_encap = kyber_key_.encapsulate(rng); @@ -529,7 +526,6 @@ pgp_kyber_ecdh_composite_public_key_t::encrypt(rnp::RNG * rng, kyber_encap.symmetric_key, kyber_encap.ciphertext, pk_alg(), - subkey_pkt_hash, kek_vec); Botan::SymmetricKey kek(kek_vec); diff --git a/src/lib/crypto/kyber_ecdh_composite.h b/src/lib/crypto/kyber_ecdh_composite.h index 03e3c9bf5..37f878333 100644 --- a/src/lib/crypto/kyber_ecdh_composite.h +++ b/src/lib/crypto/kyber_ecdh_composite.h @@ -97,8 +97,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 std::vector & subkey_pkt_hash); + const pgp_kyber_ecdh_encrypted_t *enc); bool is_valid(rnp::RNG *rng) const; std::vector get_encoded() const; @@ -147,8 +146,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, - const std::vector &subkey_pkt_hash); + size_t in_len); bool is_valid(rnp::RNG *rng) const; std::vector get_encoded() const; diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index d6fb13c4b..74de9ce0e 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -2774,21 +2774,6 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) return true; } -#if defined(ENABLE_PQC) -std::vector -pgp_key_t::subkey_pkt_hash() const -{ - const pgp_hash_alg_t pk_pkt_hash_alg = PGP_HASH_SHA3_256; - std::vector out(rnp::Hash::size(pk_pkt_hash_alg)); - - auto pk_pkt_hash = rnp::Hash::create(pk_pkt_hash_alg); - pk_pkt_hash->add(rawpkt_.raw); - pk_pkt_hash->finish(out.data()); - - return out; -} -#endif - pgp_curve_t pgp_key_material_t::curve() const { diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 991e298e9..6e82d963b 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -575,10 +575,6 @@ struct pgp_key_t { bool merge(const pgp_key_t &src); /** @brief Merge subkey with the source, i.e. add all new signatures */ bool merge(const pgp_key_t &src, pgp_key_t *primary); - -#if defined(ENABLE_PQC) - std::vector subkey_pkt_hash() const; -#endif }; namespace rnp { diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 3470d3537..e3de2c13d 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1494,6 +1494,30 @@ encrypted_start_aead(pgp_source_encrypted_param_t *param, pgp_symm_alg_t alg, ui #endif } +#if defined(ENABLE_CRYPTO_REFRESH) +/* The crypto refresh mandates that for a X25519/X448 PKESKv3, AES MUST be used. + The same is true for the PQC algorithms defined in draft-wussler-openpgp-pqc-02. + */ +static bool +do_enforce_aes_v3pkesk(pgp_pubkey_alg_t alg) +{ + switch(alg) + { +#if defined(ENABLE_PQC) + case PGP_PKA_KYBER768_X25519: [[fallthrough]]; + case PGP_PKA_KYBER768_P256: [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: [[fallthrough]]; +#endif + case PGP_PKA_X25519: + return true; + default: + return false; + } +} +#endif + static bool encrypted_try_key(pgp_source_encrypted_param_t *param, pgp_pk_sesskey_t * sesskey, @@ -1525,17 +1549,16 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, RNP_LOG("Attempt to mix SEIPD v1 with PKESK v6 or SEIPD v2 with PKESK v3"); return false; } - - /* Crypto Refresh: For X25519/X448 PKESKv3, AES is mandated */ - if (sesskey->alg == PGP_PKA_X25519 && sesskey->version == PGP_PKSK_V3) { + + /* check that AES is used when mandated by the standard */ + if (do_enforce_aes_v3pkesk(sesskey->alg) && sesskey->version == PGP_PKSK_V3) { switch (sesskey->salg) { case PGP_SA_AES_128: case PGP_SA_AES_192: case PGP_SA_AES_256: break; default: - RNP_LOG("attempting to use X25519 and v3 PKESK in combination with a symmetric " - "algorithm that is not AES."); + RNP_LOG("For the given asymmetric encryption algorithm in the PKESK, only AES is allowed but another algorithm has been detected."); return false; } } @@ -1628,7 +1651,7 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, pgp_key_t key(*seckey, true); /* make public-key `pgp_key_t` object from seckey */ declen = decbuf.size(); err = keymaterial->kyber_ecdh.priv.decrypt( - &ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh, key.subkey_pkt_hash()); + &ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh); if (err != RNP_SUCCESS) { RNP_LOG("Kyber ECC decryption failure"); return false; diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 36eca056a..a6b9a4ae7 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -733,8 +733,7 @@ encrypted_add_recipient(pgp_write_handler_t *handler, ret = userkey->material().kyber_ecdh.pub.encrypt(&handler->ctx->ctx->rng, &material.kyber_ecdh, enckey.data(), - enckey_len, - userkey->subkey_pkt_hash()); + enckey_len); if (ret) { RNP_LOG("Kyber ECC Encrypt failed"); return ret; diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index e7b443692..9162f339e 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -635,9 +635,9 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) pgp_key_t key(key_pkt); assert_rnp_success(key_pkt.material.kyber_ecdh.pub.encrypt( - &global_ctx.rng, &enc, plaintext, plaintext_len, key.subkey_pkt_hash())); + &global_ctx.rng, &enc, plaintext, plaintext_len)); assert_rnp_success(key_pkt.material.kyber_ecdh.priv.decrypt( - &global_ctx.rng, result, &result_len, &enc, key.subkey_pkt_hash())); + &global_ctx.rng, result, &result_len, &enc)); assert_int_equal(plaintext_len, result_len); assert_int_equal(memcmp(plaintext, result, result_len), 0); From f17d80bbcf105c4197697c761db3e48f39aab17f Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Tue, 11 Jul 2023 12:05:40 +0200 Subject: [PATCH 15/20] clang format --- src/lib/crypto/kmac.cpp | 2 +- src/lib/crypto/kmac.hpp | 11 ++++++----- src/lib/crypto/kmac_botan.cpp | 7 ++----- src/lib/crypto/kyber_ecdh_composite.cpp | 8 ++++---- src/librepgp/stream-parse.cpp | 23 ++++++++++++++--------- src/librepgp/stream-write.cpp | 6 ++---- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/lib/crypto/kmac.cpp b/src/lib/crypto/kmac.cpp index f0bf462ee..3b8f1b726 100644 --- a/src/lib/crypto/kmac.cpp +++ b/src/lib/crypto/kmac.cpp @@ -84,7 +84,7 @@ KMAC256::encData(const std::vector &ecc_key_share, const std::vector &ecc_ciphertext, const std::vector &kyber_key_share, const std::vector &kyber_ciphertext, - pgp_pubkey_alg_t alg_id) + pgp_pubkey_alg_t alg_id) { std::vector enc_data; std::vector counter_vec = counter(); diff --git a/src/lib/crypto/kmac.hpp b/src/lib/crypto/kmac.hpp index a80c8c498..4daa6a52b 100644 --- a/src/lib/crypto/kmac.hpp +++ b/src/lib/crypto/kmac.hpp @@ -38,17 +38,18 @@ class KMAC256 { * https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-02 */ protected: - /* The value of domSeparation is the UTF-8 encoding of the string "OpenPGPCompositeKeyDerivationFunction" and MUST be the following octet sequence: + /* The value of domSeparation is the UTF-8 encoding of the string + "OpenPGPCompositeKeyDerivationFunction" and MUST be the following octet sequence: domSeparation := 4F 70 65 6E 50 47 50 43 6F 6D 70 6F 73 69 74 65 4B 65 79 44 65 72 69 76 61 74 69 6F 6E 46 75 6E 63 74 69 6F 6E */ - const std::vector domSeparation_ = - std::vector({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, - 0x4B, 0x65, 0x79, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x75, 0x6E, - 0x63, 0x74, 0x69, 0x6F, 0x6E}); + const std::vector domSeparation_ = std::vector( + {0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, + 0x69, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x46, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E}); /* customizationString := 4B 44 46 */ const std::vector customizationString_ = std::vector({0x4B, 0x44, 0x46}); diff --git a/src/lib/crypto/kmac_botan.cpp b/src/lib/crypto/kmac_botan.cpp index a1947d8dc..f90eb05b1 100644 --- a/src/lib/crypto/kmac_botan.cpp +++ b/src/lib/crypto/kmac_botan.cpp @@ -58,11 +58,8 @@ KMAC256_Botan::compute(const std::vector &ecc_key_share, kmac->set_key(domSeparation()); kmac->start(customizationString()); // set nonce - kmac->update(encData(ecc_key_share, - ecc_ciphertext, - kyber_key_share, - kyber_ciphertext, - alg_id)); + kmac->update( + encData(ecc_key_share, ecc_ciphertext, kyber_key_share, kyber_ciphertext, alg_id)); out = kmac->final_stdvec(); } diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp index 2704b5664..01ac337f9 100644 --- a/src/lib/crypto/kyber_ecdh_composite.cpp +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -359,8 +359,8 @@ pgp_kyber_ecdh_composite_private_key_t::decrypt(rnp::RNG * RNP_LOG("error when decrypting kyber-ecdh encrypted session key"); return res; } - hashed_ecdh_keyshare = - hashed_ecc_keyshare(ecdh_keyshare, ecdh_encapsulated_keyshare, ecdh_key_->get_pubkey_encoded(rng), pk_alg_); + hashed_ecdh_keyshare = hashed_ecc_keyshare( + ecdh_keyshare, ecdh_encapsulated_keyshare, ecdh_key_->get_pubkey_encoded(rng), pk_alg_); // Compute (kyberKeyShare) := kyberKem.decap(kyberCipherText, kyberPrivateKey) std::vector kyber_encapsulated_keyshare = std::vector( @@ -511,8 +511,8 @@ pgp_kyber_ecdh_composite_public_key_t::encrypt(rnp::RNG * rng, RNP_LOG("error when encapsulating with ECDH"); return res; } - ecdh_hashed_symmetric_key = - hashed_ecc_keyshare(ecdh_symmetric_key, ecdh_ciphertext, ecdh_key_.get_encoded(), pk_alg_); + ecdh_hashed_symmetric_key = hashed_ecc_keyshare( + ecdh_symmetric_key, ecdh_ciphertext, ecdh_key_.get_encoded(), pk_alg_); // Compute (kyberCipherText, kyberKeyShare) := kyberKem.encap(kyberPublicKey) kyber_encap_result_t kyber_encap = kyber_key_.encapsulate(rng); diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index e3de2c13d..4b924bc26 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1501,14 +1501,18 @@ encrypted_start_aead(pgp_source_encrypted_param_t *param, pgp_symm_alg_t alg, ui static bool do_enforce_aes_v3pkesk(pgp_pubkey_alg_t alg) { - switch(alg) - { + switch (alg) { #if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: [[fallthrough]]; - case PGP_PKA_KYBER768_P256: [[fallthrough]]; - case PGP_PKA_KYBER1024_P384: [[fallthrough]]; - case PGP_PKA_KYBER768_BP256: [[fallthrough]]; - case PGP_PKA_KYBER1024_BP384: [[fallthrough]]; + case PGP_PKA_KYBER768_X25519: + [[fallthrough]]; + case PGP_PKA_KYBER768_P256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_P384: + [[fallthrough]]; + case PGP_PKA_KYBER768_BP256: + [[fallthrough]]; + case PGP_PKA_KYBER1024_BP384: + [[fallthrough]]; #endif case PGP_PKA_X25519: return true; @@ -1549,7 +1553,7 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, RNP_LOG("Attempt to mix SEIPD v1 with PKESK v6 or SEIPD v2 with PKESK v3"); return false; } - + /* check that AES is used when mandated by the standard */ if (do_enforce_aes_v3pkesk(sesskey->alg) && sesskey->version == PGP_PKSK_V3) { switch (sesskey->salg) { @@ -1558,7 +1562,8 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, case PGP_SA_AES_256: break; default: - RNP_LOG("For the given asymmetric encryption algorithm in the PKESK, only AES is allowed but another algorithm has been detected."); + RNP_LOG("For the given asymmetric encryption algorithm in the PKESK, only AES is " + "allowed but another algorithm has been detected."); return false; } } diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index a6b9a4ae7..b49798478 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -730,10 +730,8 @@ encrypted_add_recipient(pgp_write_handler_t *handler, case PGP_PKA_KYBER768_BP256: [[fallthrough]]; case PGP_PKA_KYBER1024_BP384: - ret = userkey->material().kyber_ecdh.pub.encrypt(&handler->ctx->ctx->rng, - &material.kyber_ecdh, - enckey.data(), - enckey_len); + ret = userkey->material().kyber_ecdh.pub.encrypt( + &handler->ctx->ctx->rng, &material.kyber_ecdh, enckey.data(), enckey_len); if (ret) { RNP_LOG("Kyber ECC Encrypt failed"); return ret; From bd8ab7300cbfc0738738e2314080ccf28cae4805 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Fri, 28 Jul 2023 16:10:30 +0200 Subject: [PATCH 16/20] add SPHINCS+ check SPHINCS+ Botan feature --- include/repgp/repgp_def.h | 4 + include/rnp/rnp.h | 23 +- src/lib/CMakeLists.txt | 5 +- src/lib/crypto.cpp | 19 ++ src/lib/crypto/common.h | 1 + src/lib/crypto/signatures.cpp | 30 +++ src/lib/crypto/sphincsplus.cpp | 386 +++++++++++++++++++++++++++++++++ src/lib/crypto/sphincsplus.h | 202 +++++++++++++++++ src/lib/generate-key.cpp | 22 ++ src/lib/pgp-key.cpp | 8 + src/lib/rnp.cpp | 53 +++++ src/lib/types.h | 13 +- src/librekey/rnp_key_store.cpp | 5 + src/librepgp/stream-dump.cpp | 25 +++ src/librepgp/stream-key.cpp | 51 +++++ src/librepgp/stream-sig.cpp | 23 ++ src/rnp/fficli.cpp | 16 ++ src/rnp/rnpcfg.h | 4 + src/rnpkeys/tui.cpp | 43 +++- src/tests/cipher.cpp | 43 ++++ src/tests/ffi.cpp | 2 +- src/tests/pqc.cpp | 28 +++ 22 files changed, 996 insertions(+), 10 deletions(-) create mode 100644 src/lib/crypto/sphincsplus.cpp create mode 100644 src/lib/crypto/sphincsplus.h diff --git a/include/repgp/repgp_def.h b/include/repgp/repgp_def.h index 52ded8dc7..16dbae5e5 100644 --- a/include/repgp/repgp_def.h +++ b/include/repgp/repgp_def.h @@ -250,6 +250,10 @@ typedef enum : uint8_t { 39, /* Dilithium 3 + ECDSA-brainpoolP256r1 from draft-wussler-openpgp-pqc-02 */ PGP_PKA_DILITHIUM5_BP384 = 40, /* Dilithium 5 + ECDSA-brainpoolP384r1 from draft-wussler-openpgp-pqc-02 */ + + PGP_PKA_SPHINCSPLUS_SHA2 = 41, /* SPHINCS+-simple-SHA2 from draft-wussler-openpgp-pqc-02 */ + PGP_PKA_SPHINCSPLUS_SHAKE = + 42, /* SPHINCS+-simple-SHAKE from draft-wussler-openpgp-pqc-02 */ #endif PGP_PKA_SM2 = 99, /* SM2 encryption/signature schemes */ diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 663516352..51c6790df 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -1188,6 +1188,24 @@ RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, RNP_API rnp_result_t rnp_op_generate_set_v6_key(rnp_op_generate_t op); #endif +#if defined(ENABLE_PQC) +/** Set the SPHINCS+ parameter set + * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any + * time. + * + * @param op pointer to opaque key generation context. + * @param param string, representing the SHPINCS+ parameter set. + * Possible Values: + * 128s, 128f, 192s, 192f, 256s, 256f + * All parameter sets refer to the simple variant and the hash function is given + * by the algorithm id. + * + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_op_generate_set_sphincsplus_param(rnp_op_generate_t op, + const char * param); +#endif + /** Execute the prepared key or subkey generation operation. * Note: if you set protection algorithm, then you need to specify ffi password provider to * be able to request password for key encryption. @@ -2996,7 +3014,8 @@ RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_h /** * @brief Enables the creation of PKESK v6 (instead of v3) which results in the use of SEIPDv2. * The actually created version depends on the capabilities of the list of recipients. - * NOTE: This is an experimental feature and this function can be replaced (or removed) at any time. + * NOTE: This is an experimental feature and this function can be replaced (or removed) at any + * time. * * @param op opaque encrypting context. Must be allocated and initialized. * @return RNP_SUCCESS or errorcode if failed. @@ -3417,6 +3436,8 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_DILITHIUM5_P384 "DILITHIUM5_P384" #define RNP_ALGNAME_DILITHIUM3_BP256 "DILITHIUM3_BP256" #define RNP_ALGNAME_DILITHIUM5_BP384 "DILITHIUM5_BP384" +#define RNP_ALGNAME_SPHINCSPLUS_SHA2 "SPHINCSPLUS_SHA2" +#define RNP_ALGNAME_SPHINCSPLUS_SHAKE "SPHINCSPLUS_SHAKE" #endif #define RNP_ALGNAME_IDEA "IDEA" #define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index f84c62a12..620e98e59 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -188,7 +188,7 @@ if(CRYPTO_BACKEND_BOTAN) resolve_feature_state(ENABLE_TWOFISH "TWOFISH") resolve_feature_state(ENABLE_IDEA "IDEA") resolve_feature_state(ENABLE_CRYPTO_REFRESH "HKDF") - resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM;KYBER") + resolve_feature_state(ENABLE_PQC "KMAC;DILITHIUM;KYBER;SPHINCS_PLUS_WITH_SHA2;SPHINCS_PLUS_WITH_SHAKE") resolve_feature_state(ENABLE_BLOWFISH "BLOWFISH") resolve_feature_state(ENABLE_CAST5 "CAST_128") resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD_160") @@ -302,8 +302,9 @@ elseif(CRYPTO_BACKEND_BOTAN) endif() if(ENABLE_PQC) list(APPEND CRYPTO_SOURCES - crypto/dilithium.cpp + crypto/dilithium.cpp crypto/dilithium_common.cpp + crypto/sphincsplus.cpp crypto/kyber_common.cpp crypto/kyber.cpp crypto/kyber_ecdh_composite.cpp diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index 74eb34400..876ea117d 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -207,6 +207,17 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, return false; } break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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 SPHINCS+ key for PK alg %d", seckey.alg); + return false; + } + break; #endif default: RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); @@ -277,6 +288,10 @@ key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return (key1->dilithium_exdsa.pub == key2->dilithium_exdsa.pub); + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return (key1->sphincsplus.pub == key2->sphincsplus.pub); #endif default: RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); @@ -354,6 +369,10 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return dilithium_exdsa_validate_key(rng, &material->dilithium_exdsa, material->secret); + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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); diff --git a/src/lib/crypto/common.h b/src/lib/crypto/common.h index 2709f7060..cfa73e24e 100644 --- a/src/lib/crypto/common.h +++ b/src/lib/crypto/common.h @@ -42,6 +42,7 @@ #if defined(ENABLE_PQC) #include "kyber_ecdh_composite.h" #include "dilithium_exdsa_composite.h" +#include "sphincsplus.h" #endif #if defined(ENABLE_CRYPTO_REFRESH) #include "x25519.h" diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index afcc9d850..e4dcf9b13 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -208,6 +208,11 @@ signature_calculate(pgp_signature_t & sig, ret = seckey.dilithium_exdsa.priv.sign( &ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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); @@ -246,6 +251,26 @@ signature_validate(const pgp_signature_t & sig, return RNP_ERROR_SIGNATURE_INVALID; } +#if defined(ENABLE_PQC) + /* check that hash matches key requirements */ + bool hash_alg_valid = false; + switch (key.alg) { + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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) { + RNP_LOG("Signature invalid since hash algorithm requirements are not met for the " + "given key."); + return RNP_ERROR_SIGNATURE_INVALID; + } +#endif + /* Finalize hash */ uint8_t hval[PGP_MAX_HASH_SIZE]; size_t hlen = 0; @@ -326,6 +351,11 @@ signature_validate(const pgp_signature_t & sig, ret = key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + ret = key.sphincsplus.pub.verify(&material.sphincsplus, hval, hlen); + break; #endif default: RNP_LOG("Unknown algorithm"); diff --git a/src/lib/crypto/sphincsplus.cpp b/src/lib/crypto/sphincsplus.cpp new file mode 100644 index 000000000..ea2122769 --- /dev/null +++ b/src/lib/crypto/sphincsplus.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). + * 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 "sphincsplus.h" +#include +#include "logging.h" +#include "types.h" + +namespace { +Botan::Sphincs_Parameter_Set +rnp_sphincsplus_params_to_botan_param(sphincsplus_parameter_t param) +{ + switch (param) { + case sphincsplus_simple_128s: + return Botan::Sphincs_Parameter_Set::Sphincs128Small; + case sphincsplus_simple_128f: + return Botan::Sphincs_Parameter_Set::Sphincs128Fast; + case sphincsplus_simple_192s: + return Botan::Sphincs_Parameter_Set::Sphincs192Small; + case sphincsplus_simple_192f: + return Botan::Sphincs_Parameter_Set::Sphincs192Fast; + case sphincsplus_simple_256s: + return Botan::Sphincs_Parameter_Set::Sphincs256Small; + case sphincsplus_simple_256f: + return Botan::Sphincs_Parameter_Set::Sphincs256Fast; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} +Botan::Sphincs_Hash_Type +rnp_sphincsplus_hash_func_to_botan_hash_func(sphincsplus_hash_func_t hash_func) +{ + switch (hash_func) { + case sphincsplus_sha256: + return Botan::Sphincs_Hash_Type::Sha256; + case sphinscplus_shake256: + return Botan::Sphincs_Hash_Type::Shake256; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +sphincsplus_hash_func_t +rnp_sphincsplus_alg_to_hashfunc(pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_SPHINCSPLUS_SHA2: + return sphincsplus_sha256; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return sphinscplus_shake256; + default: + RNP_LOG("invalid sphincs+ alg id"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +pgp_pubkey_alg_t +rnp_sphincsplus_hashfunc_to_alg(sphincsplus_hash_func_t hashfunc) +{ + switch (hashfunc) { + case sphincsplus_sha256: + return PGP_PKA_SPHINCSPLUS_SHA2; + case sphinscplus_shake256: + return PGP_PKA_SPHINCSPLUS_SHAKE; + default: + RNP_LOG("invalid sphincs+ hashfunc"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} +} // namespace + +pgp_sphincsplus_public_key_t::pgp_sphincsplus_public_key_t(const uint8_t *key_encoded, + size_t key_encoded_len, + sphincsplus_parameter_t param, + sphincsplus_hash_func_t hash_func) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), + pk_alg_(rnp_sphincsplus_hashfunc_to_alg(hash_func)), sphincsplus_param_(param), + sphincsplus_hash_func_(hash_func), is_initialized_(true) +{ +} + +pgp_sphincsplus_public_key_t::pgp_sphincsplus_public_key_t( + std::vector const &key_encoded, + sphincsplus_parameter_t param, + sphincsplus_hash_func_t hash_func) + : key_encoded_(key_encoded), pk_alg_(rnp_sphincsplus_hashfunc_to_alg(hash_func)), + sphincsplus_param_(param), sphincsplus_hash_func_(hash_func), is_initialized_(true) +{ +} + +pgp_sphincsplus_public_key_t::pgp_sphincsplus_public_key_t( + std::vector const &key_encoded, sphincsplus_parameter_t param, pgp_pubkey_alg_t alg) + : key_encoded_(key_encoded), pk_alg_(alg), sphincsplus_param_(param), + sphincsplus_hash_func_(rnp_sphincsplus_alg_to_hashfunc(alg)), is_initialized_(true) +{ +} + +pgp_sphincsplus_private_key_t::pgp_sphincsplus_private_key_t(const uint8_t *key_encoded, + size_t key_encoded_len, + sphincsplus_parameter_t param, + sphincsplus_hash_func_t hash_func) + : key_encoded_(key_encoded, key_encoded + key_encoded_len), + pk_alg_(rnp_sphincsplus_hashfunc_to_alg(hash_func)), sphincsplus_param_(param), + sphincsplus_hash_func_(hash_func), is_initialized_(true) +{ +} + +pgp_sphincsplus_private_key_t::pgp_sphincsplus_private_key_t( + std::vector const &key_encoded, + sphincsplus_parameter_t param, + sphincsplus_hash_func_t hash_func) + : key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), + pk_alg_(rnp_sphincsplus_hashfunc_to_alg(hash_func)), sphincsplus_param_(param), + sphincsplus_hash_func_(hash_func), is_initialized_(true) +{ +} + +pgp_sphincsplus_private_key_t::pgp_sphincsplus_private_key_t( + std::vector const &key_encoded, sphincsplus_parameter_t param, pgp_pubkey_alg_t alg) + : key_encoded_(Botan::secure_vector(key_encoded.begin(), key_encoded.end())), + pk_alg_(alg), sphincsplus_param_(param), + sphincsplus_hash_func_(rnp_sphincsplus_alg_to_hashfunc(alg)), is_initialized_(true) +{ +} + +rnp_result_t +pgp_sphincsplus_private_key_t::sign(rnp::RNG * rng, + pgp_sphincsplus_signature_t *sig, + const uint8_t * msg, + size_t msg_len) const +{ + assert(is_initialized_); + auto priv_key = botan_key(); + + auto signer = Botan::PK_Signer(priv_key, *rng->obj(), ""); + sig->sig = signer.sign_message(msg, msg_len, *rng->obj()); + sig->param = param(); + + return RNP_SUCCESS; +} + +Botan::SphincsPlus_PublicKey +pgp_sphincsplus_public_key_t::botan_key() const +{ + return Botan::SphincsPlus_PublicKey( + key_encoded_, + rnp_sphincsplus_params_to_botan_param(this->sphincsplus_param_), + rnp_sphincsplus_hash_func_to_botan_hash_func(this->sphincsplus_hash_func_)); +} + +Botan::SphincsPlus_PrivateKey +pgp_sphincsplus_private_key_t::botan_key() const +{ + Botan::secure_vector priv_sv(key_encoded_.data(), + key_encoded_.data() + key_encoded_.size()); + return Botan::SphincsPlus_PrivateKey( + priv_sv, + rnp_sphincsplus_params_to_botan_param(this->sphincsplus_param_), + rnp_sphincsplus_hash_func_to_botan_hash_func(this->sphincsplus_hash_func_)); +} + +rnp_result_t +pgp_sphincsplus_public_key_t::verify(const pgp_sphincsplus_signature_t *sig, + const uint8_t * msg, + size_t msg_len) const +{ + assert(is_initialized_); + auto pub_key = botan_key(); + + auto verificator = Botan::PK_Verifier(pub_key, ""); + if (verificator.verify_message(msg, msg_len, sig->sig.data(), sig->sig.size())) { + return RNP_SUCCESS; + } + return RNP_ERROR_SIGNATURE_INVALID; +} + +std::pair +sphincsplus_generate_keypair(rnp::RNG * rng, + sphincsplus_parameter_t sphincsplus_param, + sphincsplus_hash_func_t sphincsplus_hash_func) +{ + Botan::SphincsPlus_PrivateKey priv_key( + *rng->obj(), + rnp_sphincsplus_params_to_botan_param(sphincsplus_param), + rnp_sphincsplus_hash_func_to_botan_hash_func(sphincsplus_hash_func)); + + std::unique_ptr pub_key = priv_key.public_key(); + Botan::secure_vector priv_bits = priv_key.private_key_bits(); + return std::make_pair( + pgp_sphincsplus_public_key_t( + pub_key->public_key_bits(), sphincsplus_param, sphincsplus_hash_func), + pgp_sphincsplus_private_key_t( + priv_bits.data(), priv_bits.size(), sphincsplus_param, sphincsplus_hash_func)); +} + +rnp_result_t +pgp_sphincsplus_generate(rnp::RNG * rng, + pgp_sphincsplus_key_t * material, + sphincsplus_parameter_t param, + pgp_pubkey_alg_t alg) +{ + auto keypair = + sphincsplus_generate_keypair(rng, param, rnp_sphincsplus_alg_to_hashfunc(alg)); + material->pub = keypair.first; + material->priv = keypair.second; + + return RNP_SUCCESS; +} + +bool +pgp_sphincsplus_public_key_t::validate_signature_hash_requirements( + pgp_hash_alg_t hash_alg) const +{ + /* check if key is allowed with the hash algorithm */ + return sphincsplus_hash_allowed(pk_alg_, sphincsplus_param_, hash_alg); +} + +bool +pgp_sphincsplus_public_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized_) { + return false; + } + + auto key = botan_key(); + return key.check_key(*(rng->obj()), false); +} + +bool +pgp_sphincsplus_private_key_t::is_valid(rnp::RNG *rng) const +{ + if (!is_initialized_) { + return false; + } + + auto key = botan_key(); + return key.check_key(*(rng->obj()), false); +} + +rnp_result_t +sphincsplus_validate_key(rnp::RNG *rng, const pgp_sphincsplus_key_t *key, bool secret) +{ + bool valid; + + valid = key->pub.is_valid(rng); + if (secret) { + valid = valid && key->priv.is_valid(rng); + } + if (!valid) { + return RNP_ERROR_GENERIC; + } + + return RNP_SUCCESS; +} + +size_t +sphincsplus_privkey_size(sphincsplus_parameter_t param) +{ + return 2 * sphincsplus_pubkey_size(param); +} + +size_t +sphincsplus_pubkey_size(sphincsplus_parameter_t param) +{ + switch (param) { + case sphincsplus_simple_128s: + return 32; + case sphincsplus_simple_128f: + return 32; + case sphincsplus_simple_192s: + return 48; + case sphincsplus_simple_192f: + return 48; + case sphincsplus_simple_256s: + return 64; + case sphincsplus_simple_256f: + return 64; + default: + RNP_LOG("invalid sphincs+ parameter identifier"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +size_t +sphincsplus_signature_size(sphincsplus_parameter_t param) +{ + switch (param) { + case sphincsplus_simple_128s: + return 7856; + case sphincsplus_simple_128f: + return 17088; + case sphincsplus_simple_192s: + return 16224; + case sphincsplus_simple_192f: + return 35664; + case sphincsplus_simple_256s: + return 29792; + case sphincsplus_simple_256f: + return 49856; + default: + RNP_LOG("invalid sphincs+ parameter identifier"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +bool +sphincsplus_hash_allowed(pgp_pubkey_alg_t pk_alg, + sphincsplus_parameter_t sphincsplus_param, + pgp_hash_alg_t hash_alg) +{ + /* draft-wussler-openpgp-pqc-02 Table 14*/ + switch (pk_alg) { + case PGP_PKA_SPHINCSPLUS_SHA2: + switch (sphincsplus_param) { + case sphincsplus_simple_128s: + [[fallthrough]]; + case sphincsplus_simple_128f: + if (hash_alg != PGP_HASH_SHA256) { + return false; + } + break; + case sphincsplus_simple_192s: + [[fallthrough]]; + case sphincsplus_simple_192f: + [[fallthrough]]; + case sphincsplus_simple_256s: + [[fallthrough]]; + case sphincsplus_simple_256f: + if (hash_alg != PGP_HASH_SHA512) { + return false; + } + break; + } + break; + case PGP_PKA_SPHINCSPLUS_SHAKE: + switch (sphincsplus_param) { + case sphincsplus_simple_128s: + [[fallthrough]]; + case sphincsplus_simple_128f: + if (hash_alg != PGP_HASH_SHA3_256) { + return false; + } + break; + case sphincsplus_simple_192s: + [[fallthrough]]; + case sphincsplus_simple_192f: + [[fallthrough]]; + case sphincsplus_simple_256s: + [[fallthrough]]; + case sphincsplus_simple_256f: + if (hash_alg != PGP_HASH_SHA3_512) { + return false; + } + break; + } + break; + default: + break; + } + return true; +} \ No newline at end of file diff --git a/src/lib/crypto/sphincsplus.h b/src/lib/crypto/sphincsplus.h new file mode 100644 index 000000000..c709bb895 --- /dev/null +++ b/src/lib/crypto/sphincsplus.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023, [MTG AG](https://www.mtg.de). + * 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 SPHINCSPLUS_H_ +#define SPHINCSPLUS_H_ + +#include "config.h" +#include +#include +#include +#include "crypto/rng.h" +#include +#include + +struct pgp_sphincsplus_key_t; +struct pgp_sphincsplus_signature_t; + +typedef enum { sphincsplus_sha256, sphinscplus_shake256 } sphincsplus_hash_func_t; +typedef enum { + sphincsplus_simple_128s = 1, + sphincsplus_simple_128f = 2, + sphincsplus_simple_192s = 3, + sphincsplus_simple_192f = 4, + sphincsplus_simple_256s = 5, + sphincsplus_simple_256f = 6 +} sphincsplus_parameter_t; + +typedef struct pgp_sphincsplus_signature_t { + std::vector sig; + sphincsplus_parameter_t param; +} pgp_sphincsplus_signature_t; + +class pgp_sphincsplus_private_key_t { + public: + pgp_sphincsplus_private_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + sphincsplus_parameter_t sphincs_param, + sphincsplus_hash_func_t sphincs_hash_func); + pgp_sphincsplus_private_key_t(std::vector const &key_encoded, + sphincsplus_parameter_t sphincs_param, + sphincsplus_hash_func_t sphincs_hash_func); + pgp_sphincsplus_private_key_t(std::vector const &key_encoded, + sphincsplus_parameter_t param, + pgp_pubkey_alg_t alg); + pgp_sphincsplus_private_key_t() = default; + + bool is_valid(rnp::RNG *rng) const; + + sphincsplus_parameter_t + param() const + { + return sphincsplus_param_; + } + + pgp_pubkey_alg_t + alg() const + { + return pk_alg_; + } + + sphincsplus_hash_func_t + hash_func() const + { + return sphincsplus_hash_func_; + } + + rnp_result_t sign(rnp::RNG * rng, + pgp_sphincsplus_signature_t *sig, + const uint8_t * msg, + size_t msg_len) const; + std::vector + get_encoded() const + { + return Botan::unlock(key_encoded_); + }; + + void + secure_clear() + { + is_initialized_ = false; + Botan::zap(key_encoded_); + }; + + private: + Botan::SphincsPlus_PrivateKey botan_key() const; + + Botan::secure_vector key_encoded_; + pgp_pubkey_alg_t pk_alg_; + sphincsplus_parameter_t sphincsplus_param_; + sphincsplus_hash_func_t sphincsplus_hash_func_; + bool is_initialized_ = false; +}; + +class pgp_sphincsplus_public_key_t { + public: + pgp_sphincsplus_public_key_t(const uint8_t * key_encoded, + size_t key_encoded_len, + sphincsplus_parameter_t sphincs_param, + sphincsplus_hash_func_t sphincs_hash_func); + pgp_sphincsplus_public_key_t(std::vector const &key_encoded, + sphincsplus_parameter_t sphincs_param, + sphincsplus_hash_func_t sphincs_hash_func); + pgp_sphincsplus_public_key_t(std::vector const &key_encoded, + sphincsplus_parameter_t param, + pgp_pubkey_alg_t alg); + pgp_sphincsplus_public_key_t() = default; + + bool + operator==(const pgp_sphincsplus_public_key_t &rhs) const + { + return (sphincsplus_param_ == rhs.sphincsplus_param_) && + (sphincsplus_hash_func_ == rhs.sphincsplus_hash_func_) && + (key_encoded_ == rhs.key_encoded_); + } + + rnp_result_t verify(const pgp_sphincsplus_signature_t *sig, + const uint8_t * msg, + size_t msg_len) const; + + bool is_valid(rnp::RNG *rng) const; + + bool validate_signature_hash_requirements(pgp_hash_alg_t hash_alg) const; + + sphincsplus_parameter_t + param() const + { + return sphincsplus_param_; + } + + pgp_pubkey_alg_t + alg() const + { + return pk_alg_; + } + + std::vector + get_encoded() const + { + return key_encoded_; + }; + + private: + Botan::SphincsPlus_PublicKey botan_key() const; + + std::vector key_encoded_; + pgp_pubkey_alg_t pk_alg_; + sphincsplus_parameter_t sphincsplus_param_; + sphincsplus_hash_func_t sphincsplus_hash_func_; + bool is_initialized_ = false; +}; + +std::pair +sphincsplus_generate_keypair(rnp::RNG * rng, + sphincsplus_parameter_t sphincs_param, + sphincsplus_hash_func_t sphincs_hash_func); + +rnp_result_t pgp_sphincsplus_generate(rnp::RNG * rng, + pgp_sphincsplus_key_t * material, + sphincsplus_parameter_t param, + pgp_pubkey_alg_t alg); + +rnp_result_t sphincsplus_validate_key(rnp::RNG * rng, + const pgp_sphincsplus_key_t *key, + bool secret); + +typedef struct pgp_sphincsplus_key_t { + pgp_sphincsplus_public_key_t pub; + pgp_sphincsplus_private_key_t priv; +} pgp_sphincsplus_key_t; + +size_t sphincsplus_privkey_size(sphincsplus_parameter_t param); +size_t sphincsplus_pubkey_size(sphincsplus_parameter_t param); +size_t sphincsplus_signature_size(sphincsplus_parameter_t param); + +bool sphincsplus_hash_allowed(pgp_pubkey_alg_t pk_alg, + sphincsplus_parameter_t sphincsplus_param, + pgp_hash_alg_t hash_alg); + +#endif \ No newline at end of file diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index bc2c428d1..88e02e4d4 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -72,6 +72,8 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_DILITHIUM5_P384, "Dilithium-P384"}, {PGP_PKA_DILITHIUM3_BP256, "Dilithium-BP256"}, {PGP_PKA_DILITHIUM5_BP384, "Dilithium-BP384"}, + {PGP_PKA_SPHINCSPLUS_SHA2, "SPHINCS+-SHA2"}, + {PGP_PKA_SPHINCSPLUS_SHAKE, "SPHINCS+-SHAKE"}, #endif {PGP_PKA_PRIVATE00, "Private/Experimental"}, {PGP_PKA_PRIVATE01, "Private/Experimental"}, @@ -301,6 +303,10 @@ get_numbits(const rnp_keygen_crypto_params_t *crypto) [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return pgp_dilithium_exdsa_composite_public_key_t::encoded_size(crypto->key_alg) * 8; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return sphincsplus_pubkey_size(crypto->sphincsplus.param) * 8; #endif default: return 0; @@ -404,6 +410,14 @@ pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, return false; } +#if defined(ENABLE_PQC) + // check hash requirements + if (!pgp_check_key_hash_requirements(desc.crypto)) { + RNP_LOG("invalid hash algorithm for the chosen key"); + return false; + } +#endif + // generate the raw key and fill tag/secret fields pgp_key_pkt_t secpkt; if (!pgp_generate_seckey(desc.crypto, secpkt, true, desc.pgp_version)) { @@ -500,6 +514,14 @@ pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, return false; } +#if defined(ENABLE_PQC) + // check hash requirements + if (!pgp_check_key_hash_requirements(desc.crypto)) { + RNP_LOG("invalid hash algorithm for the chosen key"); + return false; + } +#endif + try { /* decrypt the primary seckey if needed (for signatures) */ rnp::KeyLocker primlock(primary_sec); diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 74de9ce0e..58e62eef2 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -230,6 +230,10 @@ pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); #endif @@ -2850,6 +2854,10 @@ pgp_key_material_t::bits() const [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: return 8 * dilithium_exdsa.pub.get_encoded().size(); /* public key length*/ + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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); diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 64635c8a3..94a90df90 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -179,6 +179,8 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_DILITHIUM5_P384, RNP_ALGNAME_DILITHIUM5_P384}, {PGP_PKA_DILITHIUM3_BP256, RNP_ALGNAME_DILITHIUM3_BP256}, {PGP_PKA_DILITHIUM5_BP384, RNP_ALGNAME_DILITHIUM5_BP384}, + {PGP_PKA_SPHINCSPLUS_SHA2, RNP_ALGNAME_SPHINCSPLUS_SHA2}, + {PGP_PKA_SPHINCSPLUS_SHAKE, RNP_ALGNAME_SPHINCSPLUS_SHAKE}, #endif {0, NULL}}; @@ -357,6 +359,8 @@ pub_alg_supported(int alg) case PGP_PKA_DILITHIUM5_P384: case PGP_PKA_DILITHIUM3_BP256: case PGP_PKA_DILITHIUM5_BP384: + case PGP_PKA_SPHINCSPLUS_SHA2: + case PGP_PKA_SPHINCSPLUS_SHAKE: #endif return true; default: @@ -5280,6 +5284,10 @@ default_key_flags(pgp_pubkey_alg_t alg, bool subkey) case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); #endif default: @@ -5693,6 +5701,39 @@ try { FFI_GUARD #endif +#if defined(ENABLE_PQC) +rnp_result_t +rnp_op_generate_set_sphincsplus_param(rnp_op_generate_t op, const char *param_cstr) +try { + if (!op) { + return RNP_ERROR_NULL_POINTER; + } + + sphincsplus_parameter_t param; + std::string param_str = param_cstr; + + if (param_str == "128s") { + param = sphincsplus_simple_128s; + } else if (param_str == "128f") { + param = sphincsplus_simple_128f; + } else if (param_str == "192s") { + param = sphincsplus_simple_192s; + } else if (param_str == "192f") { + param = sphincsplus_simple_192f; + } else if (param_str == "256s") { + param = sphincsplus_simple_256s; + } else if (param_str == "256f") { + param = sphincsplus_simple_256f; + } else { + return RNP_ERROR_BAD_PARAMETERS; + } + + op->crypto.sphincsplus.param = param; + return RNP_SUCCESS; +} +FFI_GUARD +#endif + rnp_result_t rnp_op_generate_execute(rnp_op_generate_t op) try { @@ -7521,6 +7562,10 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: return RNP_SUCCESS; /* TODO */ #endif default: @@ -7615,6 +7660,10 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: return RNP_SUCCESS; /* TODO */ #endif default: @@ -7861,6 +7910,10 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) case PGP_PKA_DILITHIUM3_BP256: [[fallthrough]]; case PGP_PKA_DILITHIUM5_BP384: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: return RNP_SUCCESS; /* TODO */ #endif default: diff --git a/src/lib/types.h b/src/lib/types.h index d22961256..349568145 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -195,6 +195,7 @@ typedef struct pgp_key_material_t { #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() @@ -220,7 +221,8 @@ typedef struct pgp_signature_material_t { #endif #if defined(ENABLE_PQC) pgp_dilithium_exdsa_signature_t - dilithium_exdsa; // non-trivial type cannot be member in union + 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_signature_material_t; @@ -457,6 +459,12 @@ struct rnp_keygen_elgamal_params_t { size_t key_bitlen; }; +#if defined(ENABLE_PQC) +struct rnp_keygen_sphincsplus_params_t { + sphincsplus_parameter_t param; +}; +#endif + /* structure used to hold context of key generation */ namespace rnp { class SecurityContext; @@ -474,6 +482,9 @@ typedef struct rnp_keygen_crypto_params_t { struct rnp_keygen_rsa_params_t rsa; struct rnp_keygen_dsa_params_t dsa; struct rnp_keygen_elgamal_params_t elgamal; +#if defined(ENABLE_PQC) + struct rnp_keygen_sphincsplus_params_t sphincsplus; +#endif }; } rnp_keygen_crypto_params_t; diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index e968cca48..2af715349 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -772,6 +772,11 @@ rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) case PGP_PKA_DILITHIUM5_BP384: hash->add(key->dilithium_exdsa.pub.get_encoded()); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + hash->add(key->sphincsplus.pub.get_encoded()); + break; #endif default: RNP_LOG("unsupported public-key algorithm %d", (int) key->alg); diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index cd1c6732d..30cd1ff02 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -160,6 +160,8 @@ static const id_str_pair pubkey_alg_map[] = { {PGP_PKA_DILITHIUM5_P384, "Dilithium5 + NIST P-384"}, {PGP_PKA_DILITHIUM3_BP256, "Dilithium3 + Brainpool256"}, {PGP_PKA_DILITHIUM5_BP384, "Dilithium5 + Brainpool384"}, + {PGP_PKA_SPHINCSPLUS_SHA2, "SPHINCS+-SHA2"}, + {PGP_PKA_SPHINCSPLUS_SHAKE, "SPHINCS+-SHAKE"}, #endif {0x00, NULL}, }; @@ -838,6 +840,11 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t dst_print_vec( dst, "dilithium-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + dst_print_vec(dst, "sphincs+ sig", material.sphincsplus.sig, ctx->dump_mpi); + break; #endif default: dst_printf(dst, "unknown algorithm\n"); @@ -972,6 +979,14 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) key.material.dilithium_exdsa.pub.get_encoded(), ctx->dump_mpi); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + dst_print_vec(dst, + "sphincs+ encoded pubkey", + key.material.sphincsplus.pub.get_encoded(), + ctx->dump_mpi); + break; #endif default: dst_printf(dst, "unknown public key algorithm\n"); @@ -1984,6 +1999,11 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, case PGP_PKA_DILITHIUM5_BP384: /* TODO */ break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + /* TODO */ + break; #endif default: break; @@ -2129,6 +2149,11 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) case PGP_PKA_DILITHIUM5_BP384: /* TODO */ break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + /* TODO */ + break; #endif default: break; diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index b4c9b8a30..ac95d5481 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -693,6 +693,23 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) 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]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: { + uint8_t param; + if (!body.get(param)) { + RNP_LOG("failed to parse sphincs+ 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 sphincs+ 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: RNP_LOG("unknown pk alg : %d", (int) key.alg); @@ -850,6 +867,12 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) case PGP_PKA_DILITHIUM5_BP384: body.add(key.material.dilithium_exdsa.priv.get_encoded()); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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); @@ -1026,6 +1049,11 @@ forget_secret_key_fields(pgp_key_material_t *key) case PGP_PKA_DILITHIUM5_BP384: key->dilithium_exdsa.priv.secure_clear(); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + key->sphincsplus.priv.secure_clear(); + break; #endif default: RNP_LOG("unknown key algorithm: %d", (int) key->alg); @@ -1522,6 +1550,23 @@ pgp_key_pkt_t::parse(pgp_source_t &src) } material.dilithium_exdsa.pub = pgp_dilithium_exdsa_composite_public_key_t(tmpbuf, alg); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: { + uint8_t param; + if (!pkt.get(param)) { + RNP_LOG("failed to parse sphincs+ 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 sphincs+ 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); @@ -1695,6 +1740,12 @@ pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody) case PGP_PKA_DILITHIUM5_BP384: hbody.add(material.dilithium_exdsa.pub.get_encoded()); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + 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); diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index 825ae1f1d..684e31042 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1585,6 +1585,23 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const return false; } break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: { + uint8_t param; + if (!pkt.get(param)) { + RNP_LOG("failed to parse sphincs+ signature data"); + return false; + } + material.sphincsplus.param = (sphincsplus_parameter_t) param; + material.sphincsplus.sig.resize( + sphincsplus_signature_size(material.sphincsplus.param)); + if (!pkt.get(material.sphincsplus.sig.data(), material.sphincsplus.sig.size())) { + RNP_LOG("failed to parse sphincs+ signature data"); + return false; + } + break; + } #endif default: RNP_LOG("Unknown pk algorithm : %d", (int) palg); @@ -1687,6 +1704,12 @@ pgp_signature_t::write_material(const pgp_signature_material_t &material) case PGP_PKA_DILITHIUM5_BP384: pktbody.add(material.dilithium_exdsa.sig); break; + case PGP_PKA_SPHINCSPLUS_SHA2: + [[fallthrough]]; + case PGP_PKA_SPHINCSPLUS_SHAKE: + pktbody.add_byte((uint8_t) material.sphincsplus.param); + pktbody.add(material.sphincsplus.sig); + break; #endif default: RNP_LOG("Unknown pk algorithm : %d", (int) palg); diff --git a/src/rnp/fficli.cpp b/src/rnp/fficli.cpp index 0bb57eb1b..62ecd7012 100644 --- a/src/rnp/fficli.cpp +++ b/src/rnp/fficli.cpp @@ -1630,6 +1630,14 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) rnp_op_generate_set_v6_key(genkey); } #endif +#if defined(ENABLE_PQC) + if (cfg.has(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM) && + rnp_op_generate_set_sphincsplus_param( + genkey, cfg.get_cstr(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM))) { + ERR_MSG("Failed to set sphincsplus parameter."); + goto done; + } +#endif fprintf(rnp->userio_out, "Generating a new key...\n"); if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &primary)) { @@ -1676,6 +1684,14 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username) if (cfg.get_bool(CFG_KG_V6_KEY)) { rnp_op_generate_set_v6_key(genkey); } +#endif +#if defined(ENABLE_PQC) + if (cfg.has(CFG_KG_SUBKEY_SPHINCSPLUS_PARAM) && + rnp_op_generate_set_sphincsplus_param( + genkey, cfg.get_cstr(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM))) { + ERR_MSG("Failed to set sphincsplus parameter."); + goto done; + } #endif if (rnp_op_generate_execute(genkey) || rnp_op_generate_get_key(genkey, &subkey)) { ERR_MSG("Subkey generation failed."); diff --git a/src/rnp/rnpcfg.h b/src/rnp/rnpcfg.h index 9f891ba58..585ca174e 100644 --- a/src/rnp/rnpcfg.h +++ b/src/rnp/rnpcfg.h @@ -121,6 +121,10 @@ #define CFG_KG_PROT_ITERATIONS "kg-prot-iterations" #define CFG_KG_V6_KEY \ "kg-v6-key" /* represents a boolean property: non-empty string means 'true' */ +#define CFG_KG_PRIMARY_SPHINCSPLUS_PARAM \ + "kg-primary-sphincsplus-param" /* 128f, 128s, 192f, 192s, 256f, 256s */ +#define CFG_KG_SUBKEY_SPHINCSPLUS_PARAM \ + "kg-subkey-sphincsplus-param" /* 128f, 128s, 192f, 192s, 256f, 256s */ /* rnp CLI config : contains all the system-dependent and specified by the user configuration * options */ diff --git a/src/rnpkeys/tui.cpp b/src/rnpkeys/tui.cpp index 9b2725f6c..52e9e6939 100644 --- a/src/rnpkeys/tui.cpp +++ b/src/rnpkeys/tui.cpp @@ -231,11 +231,12 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) if (!check_attempts(attempts)) { return false; } - printf("Please select what kind of key you want:\n" - "\t(1) RSA (Encrypt or Sign)\n" - "\t(16) DSA + ElGamal\n" - "\t(17) DSA + RSA\n" // TODO: See #584 - "\t(19) ECDSA + ECDH\n" + printf( + "Please select what kind of key you want:\n" + "\t(1) RSA (Encrypt or Sign)\n" + "\t(16) DSA + ElGamal\n" + "\t(17) DSA + RSA\n" // TODO: See #584 + "\t(19) ECDSA + ECDH\n" #if defined(ENABLE_CRYPTO_REFRESH) "\t(21) EDDSA + ECDH (v6 key) \n" "\t(22) EDDSA + ECDH (v4 key) \n" @@ -251,6 +252,10 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) "\t(28) (Dilithium5 + ECDSA-NIST-P-384) + (Kyber1024 + ECDH-NIST-P-384)\n" "\t(29) (Dilithium3 + ECDSA-brainpoolP256r1) + (Kyber768 + ECDH-brainpoolP256r1)\n" "\t(30) (Dilithium5 + ECDSA-brainpoolP384r1) + (Kyber1024 + ECDH-brainpoolP384r1)\n" + "\t(31) SPHINCS+-SHA2-128f + (Kyber768 + X25519)\n" + "\t(32) SPHINCS+-SHAKE-128f + (Kyber768 + X25519)\n" + "\t(33) SPHINCS+-SHA2-256f + (Kyber1024 + ECDH-NIST-P-384)\n" + "\t(34) SPHINCS+-SHAKE-256f + (Kyber1024 + ECDH-NIST-P-384)\n" #endif "\t(99) SM2\n" "> "); @@ -354,6 +359,34 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_BP384); cfg.set_str(CFG_KG_V6_KEY, "true"); break; + case 31: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SPHINCSPLUS_SHA2); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_X25519); + cfg.set_str(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM, "128f"); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 32: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SPHINCSPLUS_SHAKE); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_256); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER768_X25519); + cfg.set_str(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM, "128f"); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 33: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SPHINCSPLUS_SHA2); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA512); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_P384); + cfg.set_str(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM, "256f"); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; + case 34: + cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SPHINCSPLUS_SHAKE); + cfg.set_str(CFG_KG_HASH, RNP_ALGNAME_SHA3_512); + cfg.set_str(CFG_KG_SUBKEY_ALG, RNP_ALGNAME_KYBER1024_P384); + cfg.set_str(CFG_KG_PRIMARY_SPHINCSPLUS_PARAM, "256f"); + cfg.set_str(CFG_KG_V6_KEY, "true"); + break; #endif case 99: { cfg.set_str(CFG_KG_PRIMARY_ALG, RNP_ALGNAME_SM2); diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 9162f339e..9664d38eb 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -683,6 +683,49 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) assert_rnp_failure(key2->pub.verify(&sig, hash_alg, message, sizeof(message))); } } + +TEST_F(rnp_tests, sphincsplus_signverify_success) +{ + uint8_t message[64]; + pgp_pubkey_alg_t algs[] = {PGP_PKA_SPHINCSPLUS_SHA2, PGP_PKA_SPHINCSPLUS_SHAKE}; + sphincsplus_parameter_t params[] = {sphincsplus_simple_128s, + sphincsplus_simple_128f, + sphincsplus_simple_192s, + sphincsplus_simple_192f, + sphincsplus_simple_256s, + sphincsplus_simple_256f}; + + for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { + for (size_t j = 0; j < ARRAY_SIZE(params); j++) { + // Generate test data. Mainly to make valgrind not to complain about uninitialized + // data + global_ctx.rng.get(message, sizeof(message)); + + pgp_sphincsplus_signature_t sig; + rnp_keygen_crypto_params_t key_desc; + key_desc.key_alg = algs[i]; + key_desc.sphincsplus.param = params[j]; + key_desc.ctx = &global_ctx; + + pgp_key_pkt_t seckey1; + pgp_key_pkt_t seckey2; + + 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))); + + // Fails because of different key used + assert_rnp_failure(key2->pub.verify(&sig, message, sizeof(message))); + } + } +} #endif // platforms known to not have a robust response can compile with diff --git a/src/tests/ffi.cpp b/src/tests/ffi.cpp index 3e5521a8e..9e40cd88d 100644 --- a/src/tests/ffi.cpp +++ b/src/tests/ffi.cpp @@ -3115,7 +3115,7 @@ TEST_F(rnp_tests, test_ffi_supported_features) crypto_refresh_opt = 2; // X25519 + ED25519 #endif #if defined(ENABLE_PQC) - pqc_opt = 10; // kyber+ecc and dilithium+ecc variants + pqc_opt = 12; // kyber+ecc and dilithium+ecc and sphincs+ variants #endif assert_true(check_features( RNP_FEATURE_PK_ALG, features, 6 + has_sm2 + pqc_opt + crypto_refresh_opt)); diff --git a/src/tests/pqc.cpp b/src/tests/pqc.cpp index abb608b07..0b779d497 100644 --- a/src/tests/pqc.cpp +++ b/src/tests/pqc.cpp @@ -30,6 +30,7 @@ #include "rnp_tests.h" #include #include "crypto/dilithium.h" +#include "crypto/sphincsplus.h" #include "crypto/kyber.h" TEST_F(rnp_tests, test_kyber_key_function) @@ -65,6 +66,33 @@ TEST_F(rnp_tests, test_dilithium_key_function) } } +TEST_F(rnp_tests, test_sphincsplus_key_function) +{ + sphincsplus_parameter_t params[] = {sphincsplus_simple_128s, + sphincsplus_simple_128f, + sphincsplus_simple_192s, + sphincsplus_simple_192f, + sphincsplus_simple_256s, + sphincsplus_simple_256f}; + sphincsplus_hash_func_t hash_funcs[] = {sphincsplus_sha256, sphinscplus_shake256}; + + for (sphincsplus_parameter_t param : params) { + for (sphincsplus_hash_func_t hash_func : hash_funcs) { + auto public_and_private_key = + sphincsplus_generate_keypair(&global_ctx.rng, param, hash_func); + + std::array msg{'H', 'e', 'l', 'l', 'o'}; + + pgp_sphincsplus_signature_t sig; + assert_rnp_success(public_and_private_key.second.sign( + &global_ctx.rng, &sig, msg.data(), msg.size())); + + assert_rnp_success( + public_and_private_key.first.verify(&sig, msg.data(), msg.size())); + } + } +} + TEST_F(rnp_tests, test_dilithium_exdsa_direct) { pgp_pubkey_alg_t algs[] = {PGP_PKA_DILITHIUM3_ED25519, From e42827a6dd5bd8b4ee7479aad2f591681f438e97 Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Tue, 1 Aug 2023 17:19:21 +0200 Subject: [PATCH 17/20] several fixes fix Botan deprecation in kyber code fix build system remove comments reverse ifdefs and config.h inclusion in rnp.h fix false positive in CodeQL --- include/rnp/rnp.h | 11 ----------- src/lib/crypto/kyber.cpp | 4 ++-- src/lib/rnp.cpp | 18 ++++++++++++------ src/librepgp/stream-write.cpp | 1 + src/tests/CMakeLists.txt | 7 +++++-- src/tests/ffi-enc.cpp | 4 ---- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index 51c6790df..5017bb10c 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -30,7 +30,6 @@ #include #include #include -#include "config.h" #if defined(__cplusplus) extern "C" { @@ -1177,7 +1176,6 @@ RNP_API rnp_result_t rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op); RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, const char * keyserver); -#if defined(ENABLE_CRYPTO_REFRESH) /** Set the generated key version to v6. * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any * time. @@ -1186,9 +1184,7 @@ RNP_API rnp_result_t rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, * @return RNP_SUCCESS or error code if failed. */ RNP_API rnp_result_t rnp_op_generate_set_v6_key(rnp_op_generate_t op); -#endif -#if defined(ENABLE_PQC) /** Set the SPHINCS+ parameter set * NOTE: This is an experimantal feature and this function can be replaced (or removed) at any * time. @@ -1204,7 +1200,6 @@ RNP_API rnp_result_t rnp_op_generate_set_v6_key(rnp_op_generate_t op); */ RNP_API rnp_result_t rnp_op_generate_set_sphincsplus_param(rnp_op_generate_t op, const char * param); -#endif /** Execute the prepared key or subkey generation operation. * Note: if you set protection algorithm, then you need to specify ffi password provider to @@ -3010,7 +3005,6 @@ RNP_API rnp_result_t rnp_op_encrypt_create(rnp_op_encrypt_t *op, */ RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_handle_t key); -#if defined(ENABLE_CRYPTO_REFRESH) /** * @brief Enables the creation of PKESK v6 (instead of v3) which results in the use of SEIPDv2. * The actually created version depends on the capabilities of the list of recipients. @@ -3021,7 +3015,6 @@ RNP_API rnp_result_t rnp_op_encrypt_add_recipient(rnp_op_encrypt_t op, rnp_key_h * @return RNP_SUCCESS or errorcode if failed. */ RNP_API rnp_result_t rnp_op_encrypt_enable_pkesk_v6(rnp_op_encrypt_t op); -#endif /** * @brief Add signature to encrypting context, so data will be encrypted and signed. @@ -3419,11 +3412,8 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_ECDH "ECDH" #define RNP_ALGNAME_ECDSA "ECDSA" #define RNP_ALGNAME_EDDSA "EDDSA" -#if defined(ENABLE_CRYPTO_REFRESH) #define RNP_ALGNAME_ED25519 "ED25519" #define RNP_ALGNAME_X25519 "X25519" -#endif -#if defined(ENABLE_PQC) #define RNP_ALGNAME_KYBER768_X25519 "KYBER768_X25519" #define RNP_ALGNAME_KYBER1024_X448 "KYBER1024_X448" #define RNP_ALGNAME_KYBER768_P256 "KYBER768_P256" @@ -3438,7 +3428,6 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_DILITHIUM5_BP384 "DILITHIUM5_BP384" #define RNP_ALGNAME_SPHINCSPLUS_SHA2 "SPHINCSPLUS_SHA2" #define RNP_ALGNAME_SPHINCSPLUS_SHAKE "SPHINCSPLUS_SHAKE" -#endif #define RNP_ALGNAME_IDEA "IDEA" #define RNP_ALGNAME_TRIPLEDES "TRIPLEDES" #define RNP_ALGNAME_CAST5 "CAST5" diff --git a/src/lib/crypto/kyber.cpp b/src/lib/crypto/kyber.cpp index 54845df1b..7b975f146 100644 --- a/src/lib/crypto/kyber.cpp +++ b/src/lib/crypto/kyber.cpp @@ -93,8 +93,8 @@ pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) // encryption of the payload data kem_enc.encrypt(encap_key, data_encryption_key, - key_share_size_from_kyber_param(kyber_mode_), - *rng->obj()); + *rng->obj(), + key_share_size_from_kyber_param(kyber_mode_)); kyber_encap_result_t result; result.ciphertext.insert( result.ciphertext.end(), encap_key.data(), encap_key.data() + encap_key.size()); diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 94a90df90..bfe811657 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -2575,19 +2575,21 @@ try { } FFI_GUARD -#if defined(ENABLE_CRYPTO_REFRESH) rnp_result_t rnp_op_encrypt_enable_pkesk_v6(rnp_op_encrypt_t op) try { +#if defined(ENABLE_CRYPTO_REFRESH) if (!op) { return RNP_ERROR_NULL_POINTER; } op->rnpctx.enable_pkesk_v6 = true; return RNP_SUCCESS; +#else + return RNP_ERROR_NOT_IMPLEMENTED; +#endif } FFI_GUARD -#endif rnp_result_t rnp_op_encrypt_add_signature(rnp_op_encrypt_t op, @@ -5688,23 +5690,25 @@ try { } FFI_GUARD -#if defined(ENABLE_CRYPTO_REFRESH) rnp_result_t rnp_op_generate_set_v6_key(rnp_op_generate_t op) try { +#if defined(ENABLE_CRYPTO_REFRESH) if (!op) { return RNP_ERROR_NULL_POINTER; } op->pgp_version = PGP_V6; return RNP_SUCCESS; +#else + return RNP_ERROR_NOT_IMPLEMENTED; +#endif } FFI_GUARD -#endif -#if defined(ENABLE_PQC) rnp_result_t rnp_op_generate_set_sphincsplus_param(rnp_op_generate_t op, const char *param_cstr) try { +#if defined(ENABLE_PQC) if (!op) { return RNP_ERROR_NULL_POINTER; } @@ -5730,9 +5734,11 @@ try { op->crypto.sphincsplus.param = param; return RNP_SUCCESS; +#else + return RNP_ERROR_NOT_IMPLEMENTED; +#endif } FFI_GUARD -#endif rnp_result_t rnp_op_generate_execute(rnp_op_generate_t op) diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index b49798478..9223681fc 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -120,6 +120,7 @@ typedef struct pgp_dest_encrypted_param_t { case rnp::AuthType::None: return false; } + throw rnp::rnp_exception(RNP_ERROR_GENERIC); }; #ifdef ENABLE_CRYPTO_REFRESH diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 69c2a399b..c4ba85611 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -134,7 +134,6 @@ set(RNP_TEST_SOURCES user-prefs.cpp utils-hex2bin.cpp utils-rnpcfg.cpp - pqc.cpp exdsa_ecdhkem.cpp issues/1030.cpp issues/1115.cpp @@ -153,7 +152,11 @@ set(RNP_TEST_SOURCES if(ENABLE_CRYPTO_REFRESH) list(APPEND RNP_TEST_SOURCES hkdf.cpp) -endif() +endif() +if(ENABLE_PQC) + list(APPEND RNP_TEST_SOURCES + pqc.cpp) +endif() add_executable(rnp_tests ${RNP_TEST_SOURCES}) diff --git a/src/tests/ffi-enc.cpp b/src/tests/ffi-enc.cpp index d69617286..b37cb689b 100644 --- a/src/tests/ffi-enc.cpp +++ b/src/tests/ffi-enc.cpp @@ -768,10 +768,6 @@ TEST_F(rnp_tests, test_ffi_encrypt_pk_with_v6_key) assert_true(import_all_keys(ffi, "data/test_v6_valid_data/transferable_seckey_v6.asc")); - // RNP_LOG_HEX("key id", ffi->secring->keys.front().keyid().data(), - // ffi->secring->keys.front().keyid().size()); RNP_LOG_HEX("key id", - // ffi->secring->keys.back().keyid().data(), ffi->secring->keys.back().keyid().size()); - std::vector ciphers = {"AES128", "AES192", "AES256"}; std::vector aead_modes = {"None", "EAX", "OCB"}; std::vector enable_pkeskv6_modes = {true, false}; From 89e91a3466ddc30f79e68f192cbfab8ec6832fea Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Mon, 28 Aug 2023 16:34:24 +0200 Subject: [PATCH 18/20] replace fallthrough statements --- src/lib/config.h.in | 7 ++ src/lib/crypto.cpp | 70 ++++++----- src/lib/crypto/dilithium_exdsa_composite.cpp | 8 +- src/lib/crypto/ec.cpp | 12 +- src/lib/crypto/ecdh.cpp | 12 +- src/lib/crypto/kyber_ecdh_composite.cpp | 8 +- src/lib/crypto/signatures.cpp | 26 ++--- src/lib/crypto/sphincsplus.cpp | 16 +-- src/lib/fingerprint.cpp | 2 +- src/lib/generate-key.cpp | 34 +++--- src/lib/pgp-key.cpp | 62 +++++----- src/lib/rnp.cpp | 101 ++++++++-------- src/librekey/rnp_key_store.cpp | 22 ++-- src/librepgp/stream-dump.cpp | 88 +++++++------- src/librepgp/stream-key.cpp | 116 +++++++++---------- src/librepgp/stream-packet.cpp | 20 ++-- src/librepgp/stream-parse.cpp | 20 ++-- src/librepgp/stream-sig.cpp | 44 ++++--- src/librepgp/stream-write.cpp | 10 +- src/rnp/rnp.cpp | 12 +- src/rnpkeys/main.cpp | 4 +- src/rnpkeys/tui.cpp | 2 +- 22 files changed, 342 insertions(+), 354 deletions(-) diff --git a/src/lib/config.h.in b/src/lib/config.h.in index 5a9396e34..0e938e9bc 100644 --- a/src/lib/config.h.in +++ b/src/lib/config.h.in @@ -73,3 +73,10 @@ ((defined(__clang__) && (__clang_major__ >= 4)) ) #define RNP_USE_STD_REGEX 1 #endif + +/* do not use the statement for old MSVC versions */ +#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) +# define FALLTHROUGH_STATEMENT [[fallthrough]]; +#else +# define FALLTHROUGH_STATEMENT +#endif \ No newline at end of file diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index 876ea117d..59126b69e 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -133,9 +133,7 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, seckey.material.ec.curve = crypto.ecc.curve; break; } -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; case PGP_PKA_ECDSA: case PGP_PKA_SM2: if (!curve_supported(crypto.ecc.curve)) { @@ -175,14 +173,14 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + 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)) { @@ -191,14 +189,14 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, } break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + 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)) { @@ -208,7 +206,7 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, } break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: if (pgp_sphincsplus_generate(&crypto.ctx->rng, &seckey.material.sphincsplus, @@ -267,29 +265,29 @@ key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return (key1->kyber_ecdh.pub == key2->kyber_ecdh.pub); case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: return (key1->dilithium_exdsa.pub == key2->dilithium_exdsa.pub); case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return (key1->sphincsplus.pub == key2->sphincsplus.pub); #endif @@ -348,29 +346,29 @@ validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return kyber_ecdh_validate_key(rng, &material->kyber_ecdh, material->secret); case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: return dilithium_exdsa_validate_key(rng, &material->dilithium_exdsa, material->secret); case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return sphincsplus_validate_key(rng, &material->sphincsplus, material->secret); #endif diff --git a/src/lib/crypto/dilithium_exdsa_composite.cpp b/src/lib/crypto/dilithium_exdsa_composite.cpp index 116d75972..cd2ed80ca 100644 --- a/src/lib/crypto/dilithium_exdsa_composite.cpp +++ b/src/lib/crypto/dilithium_exdsa_composite.cpp @@ -142,16 +142,14 @@ pgp_dilithium_exdsa_composite_key_t::pk_alg_to_dilithium_id(pgp_pubkey_alg_t pk_ { switch (pk_alg) { case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: return dilithium_L3; case PGP_PKA_DILITHIUM5_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - //[[fallthrough]]; - // case PGP_PKA_DILITHIUM5_ED448: return dilithium_L5; default: RNP_LOG("invalid PK alg given"); diff --git a/src/lib/crypto/ec.cpp b/src/lib/crypto/ec.cpp index ef9373507..8aca0a474 100644 --- a/src/lib/crypto/ec.cpp +++ b/src/lib/crypto/ec.cpp @@ -199,17 +199,17 @@ is_generic_prime_curve(pgp_curve_t curve) { switch (curve) { case PGP_CURVE_NIST_P_256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_NIST_P_384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_NIST_P_521: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_BP512: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_P256K1: return true; default: diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index 85a0b637b..31f078acc 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -412,17 +412,17 @@ exdsa_gen_keypair_native(rnp::RNG * rng, alg = PGP_PKA_EDDSA; break; case PGP_CURVE_NIST_P_256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_NIST_P_384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_NIST_P_521: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_BP512: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_CURVE_P256K1: alg = PGP_PKA_ECDSA; break; diff --git a/src/lib/crypto/kyber_ecdh_composite.cpp b/src/lib/crypto/kyber_ecdh_composite.cpp index 01ac337f9..b69556214 100644 --- a/src/lib/crypto/kyber_ecdh_composite.cpp +++ b/src/lib/crypto/kyber_ecdh_composite.cpp @@ -170,16 +170,14 @@ pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(pgp_pubkey_alg_t pk_alg) { switch (pk_alg) { case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: return kyber_768; case PGP_PKA_KYBER1024_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - //[[fallthrough]]; - // case PGP_PKA_KYBER1024_X448: return kyber_1024; default: RNP_LOG("invalid PK alg given"); diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index e4dcf9b13..8255ca683 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -196,20 +196,20 @@ signature_calculate(pgp_signature_t & sig, } #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + 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]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: ret = seckey.sphincsplus.priv.sign(&ctx.rng, &material.sphincsplus, hval, hlen); break; @@ -256,7 +256,7 @@ signature_validate(const pgp_signature_t & sig, bool hash_alg_valid = false; switch (key.alg) { case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: hash_alg_valid = key.sphincsplus.pub.validate_signature_hash_requirements(hash.alg()); break; @@ -339,20 +339,20 @@ signature_validate(const pgp_signature_t & sig, break; #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + 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]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: ret = key.sphincsplus.pub.verify(&material.sphincsplus, hval, hlen); break; diff --git a/src/lib/crypto/sphincsplus.cpp b/src/lib/crypto/sphincsplus.cpp index ea2122769..5589212e5 100644 --- a/src/lib/crypto/sphincsplus.cpp +++ b/src/lib/crypto/sphincsplus.cpp @@ -338,18 +338,18 @@ sphincsplus_hash_allowed(pgp_pubkey_alg_t pk_alg, case PGP_PKA_SPHINCSPLUS_SHA2: switch (sphincsplus_param) { case sphincsplus_simple_128s: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_128f: if (hash_alg != PGP_HASH_SHA256) { return false; } break; case sphincsplus_simple_192s: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_192f: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_256s: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_256f: if (hash_alg != PGP_HASH_SHA512) { return false; @@ -360,18 +360,18 @@ sphincsplus_hash_allowed(pgp_pubkey_alg_t pk_alg, case PGP_PKA_SPHINCSPLUS_SHAKE: switch (sphincsplus_param) { case sphincsplus_simple_128s: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_128f: if (hash_alg != PGP_HASH_SHA3_256) { return false; } break; case sphincsplus_simple_192s: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_192f: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_256s: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case sphincsplus_simple_256f: if (hash_alg != PGP_HASH_SHA3_512) { return false; diff --git a/src/lib/fingerprint.cpp b/src/lib/fingerprint.cpp index b6464ebb2..a1b002d49 100644 --- a/src/lib/fingerprint.cpp +++ b/src/lib/fingerprint.cpp @@ -60,7 +60,7 @@ pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key) switch (key.version) { #if defined(ENABLE_CRYPTO_REFRESH) case PGP_V6: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; #endif case PGP_V4: break; diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index 88e02e4d4..52481f971 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -282,29 +282,29 @@ get_numbits(const rnp_keygen_crypto_params_t *crypto) return crypto->elgamal.key_bitlen; #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return pgp_kyber_ecdh_composite_public_key_t::encoded_size(crypto->key_alg) * 8; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: return pgp_dilithium_exdsa_composite_public_key_t::encoded_size(crypto->key_alg) * 8; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return sphincsplus_pubkey_size(crypto->sphincsplus.param) * 8; #endif @@ -359,7 +359,7 @@ pgp_check_key_hash_requirements(rnp_keygen_crypto_params_t &crypto) { switch (crypto.key_alg) { case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: if (!sphincsplus_hash_allowed( crypto.key_alg, crypto.sphincsplus.param, crypto.hash_alg)) { @@ -367,14 +367,14 @@ pgp_check_key_hash_requirements(rnp_keygen_crypto_params_t &crypto) } break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: if (!dilithium_hash_allowed(crypto.hash_alg)) { return false; diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 58e62eef2..99f21ab97 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -209,30 +209,30 @@ pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg) #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return PGP_KF_ENCRYPT; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_AUTH); #endif @@ -2783,11 +2783,11 @@ pgp_key_material_t::curve() const { switch (alg) { case PGP_PKA_ECDH: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_ECDSA: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_EDDSA: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SM2: return ec.curve; #if defined(ENABLE_CRYPTO_REFRESH) @@ -2815,16 +2815,16 @@ pgp_key_material_t::bits() const case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: return 8 * mpi_bytes(&eg.y); case PGP_PKA_ECDH: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_ECDSA: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_EDDSA: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_X25519: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; #endif case PGP_PKA_SM2: { /* handle ecc cases */ @@ -2833,29 +2833,29 @@ pgp_key_material_t::bits() const } #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return 8 * kyber_ecdh.pub.get_encoded().size(); /* public key length */ case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: return 8 * dilithium_exdsa.pub.get_encoded().size(); /* public key length*/ case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return 8 * sphincsplus.pub.get_encoded().size(); /* public key length */ #endif diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index bfe811657..11ea7ec52 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -5266,29 +5266,29 @@ default_key_flags(pgp_pubkey_alg_t alg, bool subkey) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return PGP_KF_ENCRYPT; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return subkey ? PGP_KF_SIGN : pgp_key_flags_t(PGP_KF_SIGN | PGP_KF_CERTIFY); #endif @@ -7548,29 +7548,29 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return RNP_SUCCESS; /* TODO */ case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return RNP_SUCCESS; /* TODO */ #endif @@ -7607,14 +7607,14 @@ add_json_secret_mpis(json_object *jso, pgp_key_t *key) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return RNP_SUCCESS; /* TODO */ #endif @@ -7657,18 +7657,18 @@ add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) #endif #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return RNP_SUCCESS; /* TODO */ #endif @@ -7874,10 +7874,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } } - -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: case PGP_PKA_SM2: { @@ -7896,29 +7893,29 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: return RNP_SUCCESS; /* TODO */ case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: return RNP_SUCCESS; /* TODO */ #endif diff --git a/src/librekey/rnp_key_store.cpp b/src/librekey/rnp_key_store.cpp index 2af715349..0918d155c 100644 --- a/src/librekey/rnp_key_store.cpp +++ b/src/librekey/rnp_key_store.cpp @@ -749,31 +749,31 @@ rnp_key_store_get_key_grip(const pgp_key_material_t *key, pgp_key_grip_t &grip) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: hash->add(key->kyber_ecdh.pub.get_encoded()); break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: hash->add(key->dilithium_exdsa.pub.get_encoded()); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: hash->add(key->sphincsplus.pub.get_encoded()); break; diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index 30cd1ff02..644af5b61 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -828,20 +828,20 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t #endif #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: dst_print_vec( dst, "dilithium-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: dst_print_vec(dst, "sphincs+ sig", material.sphincsplus.sig, ctx->dump_mpi); break; @@ -950,14 +950,14 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: dst_print_vec(dst, "kyber-ecdh encoded pubkey", @@ -965,14 +965,14 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) ctx->dump_mpi); break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: dst_print_vec(dst, "dilithium-ecdsa/eddsa encodced pubkey", @@ -980,7 +980,7 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) ctx->dump_mpi); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: dst_print_vec(dst, "sphincs+ encoded pubkey", @@ -1161,14 +1161,14 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: dst_print_vec(dst, "kyber-ecdh composite ciphertext", @@ -1988,19 +1988,19 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, #endif #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: /* TODO */ break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: /* TODO */ break; @@ -2126,31 +2126,31 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: // TODO break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: /* TODO */ break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: /* TODO */ break; @@ -2292,14 +2292,14 @@ stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_obj #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: // TODO break; diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index ac95d5481..c3b180bbc 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -545,7 +545,7 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) if (key.version == PGP_V6) { break; /* checksum removed for v6 and usage byte zero */ } - [[fallthrough]]; + FALLTHROUGH_STATEMENT; #endif case PGP_S2KU_ENCRYPTED: { /* calculate and check sum16 of the cleartext */ @@ -658,14 +658,14 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + 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())) { @@ -676,14 +676,14 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) pgp_kyber_ecdh_composite_private_key_t(tmpbuf.data(), tmpbuf.size(), key.alg); break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + 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())) { @@ -694,7 +694,7 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) tmpbuf.data(), tmpbuf.size(), key.alg); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: { uint8_t param; if (!body.get(param)) { @@ -844,31 +844,31 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: body.add(key.material.kyber_ecdh.priv.get_encoded()); break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: body.add(key.material.dilithium_exdsa.priv.get_encoded()); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + 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()); @@ -1029,28 +1029,28 @@ forget_secret_key_fields(pgp_key_material_t *key) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: key->dilithium_exdsa.priv.secure_clear(); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: key->sphincsplus.priv.secure_clear(); break; @@ -1403,9 +1403,9 @@ pgp_key_pkt_t::parse(pgp_source_t &src) } switch (ver) { case PGP_V2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V3: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V4: break; #if defined(ENABLE_CRYPTO_REFRESH) @@ -1517,14 +1517,14 @@ pgp_key_pkt_t::parse(pgp_source_t &src) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + 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())) { @@ -1534,14 +1534,14 @@ pgp_key_pkt_t::parse(pgp_source_t &src) material.kyber_ecdh.pub = pgp_kyber_ecdh_composite_public_key_t(tmpbuf, alg); break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + 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())) { @@ -1551,7 +1551,7 @@ pgp_key_pkt_t::parse(pgp_source_t &src) material.dilithium_exdsa.pub = pgp_dilithium_exdsa_composite_public_key_t(tmpbuf, alg); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: { uint8_t param; if (!pkt.get(param)) { @@ -1717,31 +1717,31 @@ pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: hbody.add(material.kyber_ecdh.pub.get_encoded()); break; case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: hbody.add(material.dilithium_exdsa.pub.get_encoded()); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: hbody.add_byte((uint8_t) material.sphincsplus.pub.param()); hbody.add(material.sphincsplus.pub.get_encoded()); diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index b547ff012..7342a3268 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -1243,14 +1243,14 @@ pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) const #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: { uint8_t wrapped_key_len = 0; material.kyber_ecdh.composite_ciphertext.resize( @@ -1316,14 +1316,14 @@ pgp_pk_sesskey_t::write_material(const pgp_encrypted_material_t &material) #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: pktbody.add(material.kyber_ecdh.composite_ciphertext); pktbody.add_byte(static_cast(material.kyber_ecdh.wrapped_sesskey.size())); diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 4b924bc26..aed70530b 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1504,15 +1504,15 @@ do_enforce_aes_v3pkesk(pgp_pubkey_alg_t alg) switch (alg) { #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; #endif case PGP_PKA_X25519: return true; @@ -1644,14 +1644,14 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: { pgp_key_t key(*seckey, true); /* make public-key `pgp_key_t` object from seckey */ declen = decbuf.size(); diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index 684e31042..c256ef460 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -50,9 +50,9 @@ signature_hash_key(const pgp_key_pkt_t &key, rnp::Hash &hash) { switch (key.version) { case PGP_V2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V3: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V4: { uint8_t hdr[3] = {0x99, 0x00, 0x00}; if (key.hashed_data) { @@ -1443,13 +1443,13 @@ pgp_signature_t::parse(pgp_packet_body_t &pkt) rnp_result_t res; switch (ver) { case PGP_V2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V3: res = parse_v2v3(pkt); break; #if defined(ENABLE_CRYPTO_REFRESH) case PGP_V6: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; #endif case PGP_V4: res = parse_v4up(pkt); @@ -1539,9 +1539,7 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const if (version < PGP_V4) { RNP_LOG("Warning! v3 EdDSA signature."); } -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; case PGP_PKA_ECDSA: case PGP_PKA_SM2: case PGP_PKA_ECDH: @@ -1568,14 +1566,14 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const #endif #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: material.dilithium_exdsa.sig.resize( pgp_dilithium_exdsa_signature_t::composite_signature_size(palg)); @@ -1586,7 +1584,7 @@ pgp_signature_t::parse_material(pgp_signature_material_t &material) const } break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: { uint8_t param; if (!pkt.get(param)) { @@ -1620,9 +1618,9 @@ pgp_signature_t::write(pgp_dest_t &dst) const { switch (version) { case PGP_V2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V3: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V4: break; #if defined(ENABLE_CRYPTO_REFRESH) @@ -1693,19 +1691,19 @@ pgp_signature_t::write_material(const pgp_signature_material_t &material) #endif #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: - [[fallthrough]]; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: pktbody.add(material.dilithium_exdsa.sig); break; case PGP_PKA_SPHINCSPLUS_SHA2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: pktbody.add_byte((uint8_t) material.sphincsplus.param); pktbody.add(material.sphincsplus.sig); @@ -1731,9 +1729,9 @@ pgp_signature_t::fill_hashed_data() /* we don't have a need to write v2-v3 signatures */ switch (version) { case PGP_V2: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V3: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_V4: break; #if defined(ENABLE_CRYPTO_REFRESH) diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 9223681fc..acf122f9b 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -722,14 +722,14 @@ encrypted_add_recipient(pgp_write_handler_t *handler, #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: - [[fallthrough]]; - // TODO add case PGP_PKA_KYBER1024_X448: [[fallthrough]]; + FALLTHROUGH_STATEMENT; + // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_P256: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_P384: - [[fallthrough]]; + FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: - [[fallthrough]]; + 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); diff --git a/src/rnp/rnp.cpp b/src/rnp/rnp.cpp index 3dfcad852..a4b41f1ec 100644 --- a/src/rnp/rnp.cpp +++ b/src/rnp/rnp.cpp @@ -307,9 +307,7 @@ setcmd(rnp_cfg &cfg, int cmd, const char *arg) break; case CMD_CLEARSIGN: cfg.set_bool(CFG_CLEARTEXT, true); -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; case CMD_SIGN: cfg.set_bool(CFG_NEEDSSECKEY, true); cfg.set_bool(CFG_SIGN_NEEDED, true); @@ -326,9 +324,7 @@ setcmd(rnp_cfg &cfg, int cmd, const char *arg) case CMD_VERIFY: /* single verify will discard output, decrypt will not */ cfg.set_bool(CFG_NO_OUTPUT, true); -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; case CMD_VERIFY_CAT: newcmd = CMD_PROCESS; break; @@ -607,9 +603,7 @@ set_short_option(rnp_cfg &cfg, int ch, const char *arg) cfg.set_bool(CFG_KEYSTORE_DISABLED, true); break; case 'h': -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; default: return setcmd(cfg, CMD_HELP, optarg); } diff --git a/src/rnpkeys/main.cpp b/src/rnpkeys/main.cpp index 3dd088cc5..75e3efe54 100644 --- a/src/rnpkeys/main.cpp +++ b/src/rnpkeys/main.cpp @@ -52,9 +52,7 @@ get_short_cmd(int ch) case 'l': return CMD_LIST_KEYS; case 'h': -#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L) - [[fallthrough]]; -#endif + FALLTHROUGH_STATEMENT; default: return CMD_HELP; } diff --git a/src/rnpkeys/tui.cpp b/src/rnpkeys/tui.cpp index 52e9e6939..cd9724a75 100644 --- a/src/rnpkeys/tui.cpp +++ b/src/rnpkeys/tui.cpp @@ -311,7 +311,7 @@ rnpkeys_ask_generate_params(rnp_cfg &cfg, FILE *input_fp) #if defined(ENABLE_CRYPTO_REFRESH) case 21: { cfg.set_str(CFG_KG_V6_KEY, "true"); - [[fallthrough]]; + FALLTHROUGH_STATEMENT; } #endif case 22: { From c804badba4af355588a1780bbee65a6ee44a26f6 Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Mon, 18 Sep 2023 09:08:51 +0200 Subject: [PATCH 19/20] fixed API string for KMAC-256 to be compatible with official Botan master branch --- src/lib/crypto/kmac_botan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/crypto/kmac_botan.cpp b/src/lib/crypto/kmac_botan.cpp index f90eb05b1..161eecd0e 100644 --- a/src/lib/crypto/kmac_botan.cpp +++ b/src/lib/crypto/kmac_botan.cpp @@ -48,7 +48,7 @@ KMAC256_Botan::compute(const std::vector &ecc_key_share, const pgp_pubkey_alg_t alg_id, std::vector & out) { - auto kmac = Botan::MessageAuthenticationCode::create_or_throw("KMAC256(256)"); + auto kmac = Botan::MessageAuthenticationCode::create_or_throw("KMAC-256(256)"); /* the mapping between the KEM Combiner and the MAC interface is: * key <> domSeparation From 737c71fcbaaa92b2d9fe70745dc2c978eb3c00be Mon Sep 17 00:00:00 2001 From: Falko Strenzke Date: Thu, 21 Sep 2023 07:50:54 +0200 Subject: [PATCH 20/20] various fixes for v6 key operations fixed missing case in forget_secret_key_fields() --- src/lib/crypto/dilithium.cpp | 6 ++ src/lib/crypto/dilithium.h | 2 + src/lib/crypto/sphincsplus.cpp | 41 ++++++++++++- src/lib/crypto/sphincsplus.h | 3 + src/lib/pgp-key.cpp | 22 +++++++ src/librepgp/stream-key.cpp | 102 ++++++++++++++++++++++++--------- src/librepgp/stream-key.h | 4 +- src/librepgp/stream-sig.cpp | 4 ++ 8 files changed, 155 insertions(+), 29 deletions(-) diff --git a/src/lib/crypto/dilithium.cpp b/src/lib/crypto/dilithium.cpp index 2c0615185..bd7f112bd 100644 --- a/src/lib/crypto/dilithium.cpp +++ b/src/lib/crypto/dilithium.cpp @@ -128,4 +128,10 @@ dilithium_hash_allowed(pgp_hash_alg_t hash_alg) default: return false; } +} + +pgp_hash_alg_t +dilithium_default_hash_alg() +{ + return PGP_HASH_SHA3_256; } \ No newline at end of file diff --git a/src/lib/crypto/dilithium.h b/src/lib/crypto/dilithium.h index 678cf372a..18035ce0c 100644 --- a/src/lib/crypto/dilithium.h +++ b/src/lib/crypto/dilithium.h @@ -111,4 +111,6 @@ std::pair dilithium_gen bool dilithium_hash_allowed(pgp_hash_alg_t hash_alg); +pgp_hash_alg_t dilithium_default_hash_alg(); + #endif diff --git a/src/lib/crypto/sphincsplus.cpp b/src/lib/crypto/sphincsplus.cpp index 5589212e5..d948ddbed 100644 --- a/src/lib/crypto/sphincsplus.cpp +++ b/src/lib/crypto/sphincsplus.cpp @@ -383,4 +383,43 @@ sphincsplus_hash_allowed(pgp_pubkey_alg_t pk_alg, break; } return true; -} \ No newline at end of file +} + +pgp_hash_alg_t +sphincsplus_default_hash_alg(pgp_pubkey_alg_t pk_alg, + sphincsplus_parameter_t sphincsplus_param) +{ + switch (sphincsplus_param) { + case sphincsplus_simple_128s: + FALLTHROUGH_STATEMENT; + case sphincsplus_simple_128f: + switch (pk_alg) { + case PGP_PKA_SPHINCSPLUS_SHA2: + return PGP_HASH_SHA256; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return PGP_HASH_SHA3_256; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + case sphincsplus_simple_192s: + FALLTHROUGH_STATEMENT; + case sphincsplus_simple_192f: + FALLTHROUGH_STATEMENT; + case sphincsplus_simple_256s: + FALLTHROUGH_STATEMENT; + case sphincsplus_simple_256f: + switch (pk_alg) { + case PGP_PKA_SPHINCSPLUS_SHA2: + return PGP_HASH_SHA512; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return PGP_HASH_SHA3_512; + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + default: + RNP_LOG("invalid parameter given"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} diff --git a/src/lib/crypto/sphincsplus.h b/src/lib/crypto/sphincsplus.h index c709bb895..17d61c8e2 100644 --- a/src/lib/crypto/sphincsplus.h +++ b/src/lib/crypto/sphincsplus.h @@ -199,4 +199,7 @@ bool sphincsplus_hash_allowed(pgp_pubkey_alg_t pk_alg, sphincsplus_parameter_t sphincsplus_param, pgp_hash_alg_t hash_alg); +pgp_hash_alg_t sphincsplus_default_hash_alg(pgp_pubkey_alg_t pk_alg, + sphincsplus_parameter_t sphincsplus_param); + #endif \ No newline at end of file diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 99f21ab97..aadd1054a 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -520,6 +520,28 @@ find_suitable_key(pgp_op_t op, 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; } diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index c3b180bbc..7c9a5c4e2 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -788,6 +788,10 @@ decrypt_secret_key(pgp_key_pkt_t *key, const char *password) } ret = decrypt_secret_key_v3(&crypt, decdata.data(), key->sec_data, key->sec_len); break; +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_V6: + FALLTHROUGH_STATEMENT; +#endif case PGP_V4: pgp_cipher_cfb_decrypt(&crypt, decdata.data(), key->sec_data, key->sec_len); ret = RNP_SUCCESS; @@ -1037,6 +1041,9 @@ forget_secret_key_fields(pgp_key_material_t *key) 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; @@ -1317,6 +1324,54 @@ pgp_key_pkt_t::~pgp_key_pkt_t() free(sec_data); } +uint8_t +pgp_key_pkt_t::s2k_specifier_len(pgp_s2k_specifier_t specifier) +{ + switch (specifier) { + case PGP_S2KS_SIMPLE: + return 2; + case PGP_S2KS_SALTED: + return 10; + case PGP_S2KS_ITERATED_AND_SALTED: + return 11; + default: + RNP_LOG("invalid specifier"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + +void +pgp_key_pkt_t::make_s2k_params(pgp_packet_body_t &hbody) +{ + switch (sec_protection.s2k.usage) { + case PGP_S2KU_NONE: + break; + case PGP_S2KU_ENCRYPTED_AND_HASHED: + case PGP_S2KU_ENCRYPTED: { + hbody.add_byte(sec_protection.symm_alg); +#if defined(ENABLE_CRYPTO_REFRESH) + if (version == PGP_V6) { + // V6 packages contain length of the following field + hbody.add_byte(s2k_specifier_len(sec_protection.s2k.specifier)); + } +#endif + hbody.add(sec_protection.s2k); + if (sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL) { + size_t blsize = pgp_block_size(sec_protection.symm_alg); + if (!blsize) { + RNP_LOG("wrong block size"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } + hbody.add(sec_protection.iv, blsize); + } + break; + } + default: + RNP_LOG("wrong s2k usage"); + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } +} + void pgp_key_pkt_t::write(pgp_dest_t &dst) { @@ -1344,27 +1399,16 @@ pgp_key_pkt_t::write(pgp_dest_t &dst) } pktbody.add_byte(sec_protection.s2k.usage); - switch (sec_protection.s2k.usage) { - case PGP_S2KU_NONE: - break; - case PGP_S2KU_ENCRYPTED_AND_HASHED: - case PGP_S2KU_ENCRYPTED: { - pktbody.add_byte(sec_protection.symm_alg); - pktbody.add(sec_protection.s2k); - if (sec_protection.s2k.specifier != PGP_S2KS_EXPERIMENTAL) { - size_t blsize = pgp_block_size(sec_protection.symm_alg); - if (!blsize) { - RNP_LOG("wrong block size"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - pktbody.add(sec_protection.iv, blsize); - } - break; - } - default: - RNP_LOG("wrong s2k usage"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + pgp_packet_body_t s2k_params(tag); + make_s2k_params(s2k_params); +#if defined(ENABLE_CRYPTO_REFRESH) + if ((version == PGP_V6) && (sec_protection.s2k.usage != PGP_S2KU_NONE)) { + // V6 packages contain the count of the optional 1-byte parameters + pktbody.add_byte(s2k_params.size()); } +#endif + pktbody.add(s2k_params.data(), s2k_params.size()); + if (sec_len) { /* if key is stored on card, or exported via gpg --export-secret-subkeys, then * sec_data is empty */ @@ -1613,18 +1657,22 @@ pgp_key_pkt_t::parse(pgp_source_t &src) case PGP_S2KU_ENCRYPTED: case PGP_S2KU_ENCRYPTED_AND_HASHED: { /* we have s2k */ + uint8_t salg = 0; + if (!pkt.get(salg)) { + RNP_LOG("failed to read key protection (symmetric alg)"); + return RNP_ERROR_BAD_FORMAT; + } #if defined(ENABLE_CRYPTO_REFRESH) if (version == PGP_V6) { - // V6 packages contain the count of the optional 1-byte parameters - uint8_t s2k_params_count; - if (!pkt.get(s2k_params_count)) { - RNP_LOG("failed to read key protection"); + // V6 packages contain the length of the following field + uint8_t s2k_specifier_len; + if (!pkt.get(s2k_specifier_len)) { + RNP_LOG("failed to read key protection (s2k specifier length)"); } } #endif - uint8_t salg = 0; - if (!pkt.get(salg) || !pkt.get(sec_protection.s2k)) { - RNP_LOG("failed to read key protection"); + if (!pkt.get(sec_protection.s2k)) { + RNP_LOG("failed to read key protection (s2k)"); return RNP_ERROR_BAD_FORMAT; } sec_protection.symm_alg = (pgp_symm_alg_t) salg; diff --git a/src/librepgp/stream-key.h b/src/librepgp/stream-key.h index d34639bd3..8974a2318 100644 --- a/src/librepgp/stream-key.h +++ b/src/librepgp/stream-key.h @@ -72,7 +72,9 @@ typedef struct pgp_key_pkt_t { 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_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; /* userid/userattr with all the corresponding signatures */ diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index c256ef460..0b15fdfc8 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -771,7 +771,11 @@ pgp_signature_t::set_keyfp(const pgp_fingerprint_t &fp) pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, 1 + fp.length, true); subpkt.parsed = true; subpkt.hashed = true; +#if defined(ENABLE_CRYPTO_REFRESH) + subpkt.data[0] = (uint8_t) version; +#else subpkt.data[0] = 4; +#endif memcpy(subpkt.data + 1, fp.fingerprint, fp.length); subpkt.fields.issuer_fp.len = fp.length; subpkt.fields.issuer_fp.version = subpkt.data[0];