/** * @file src/crypto.h * @brief Declarations for cryptography functions. */ #pragma once // standard includes #include // lib includes #include #include #include #include #include #include // local includes #include "utility.h" namespace crypto { struct creds_t { std::string x509; std::string pkey; }; void md_ctx_destroy(EVP_MD_CTX *); using sha256_t = std::array; using aes_t = std::vector; using x509_t = util::safe_ptr; using x509_store_t = util::safe_ptr; using x509_store_ctx_t = util::safe_ptr; using cipher_ctx_t = util::safe_ptr; using md_ctx_t = util::safe_ptr; using bio_t = util::safe_ptr; using pkey_t = util::safe_ptr; using pkey_ctx_t = util::safe_ptr; using bignum_t = util::safe_ptr; /** * @brief The permissions of a client. */ enum class PERM: uint32_t { _reserved = 1, _input = _reserved << 8, // Input permission group input_controller = _input << 0, // Allow controller input input_touch = _input << 1, // Allow touch input input_pen = _input << 2, // Allow pen input input_mouse = _input << 3, // Allow mouse input input_kbd = _input << 4, // Allow keyboard input _all_inputs = input_controller | input_touch | input_pen | input_mouse | input_kbd, _operation = _input << 8, // Operation permission group clipboard_set = _operation << 0, // Allow set clipboard from client clipboard_read = _operation << 1, // Allow read clipboard from host file_upload = _operation << 2, // Allow upload files to host file_dwnload = _operation << 3, // Allow download files from host server_cmd = _operation << 4, // Allow execute server cmd _all_opeiations = clipboard_set | clipboard_read | file_upload | file_dwnload | server_cmd, _action = _operation << 8, // Action permission group list = _action << 0, // Allow list apps view = _action << 1, // Allow view streams launch = _action << 2, // Allow launch apps _allow_view = view | launch, // If no view permission is granted, disconnect the device upon permission update _all_actions = list | view | launch, _default = view | list, // Default permissions for new clients _no = 0, // No permissions are granted _all = _all_inputs | _all_opeiations | _all_actions, // All current permissions }; inline constexpr PERM operator&(PERM x, PERM y) { return static_cast(static_cast(x) & static_cast(y)); } inline constexpr bool operator!(PERM p) { return static_cast(p) == 0; } struct command_entry_t { std::string cmd; bool elevated; // Serialize method using nlohmann::json static inline nlohmann::json serialize(const command_entry_t& entry) { nlohmann::json node; node["cmd"] = entry.cmd; node["elevated"] = entry.elevated; return node; } }; struct named_cert_t { std::string name; std::string uuid; std::string cert; std::string display_mode; std::list do_cmds; std::list undo_cmds; PERM perm; }; using p_named_cert_t = std::shared_ptr; /** * @brief Hashes the given plaintext using SHA-256. * @param plaintext * @return The SHA-256 hash of the plaintext. */ sha256_t hash(const std::string_view &plaintext); aes_t gen_aes_key(const std::array &salt, const std::string_view &pin); x509_t x509(const std::string_view &x); pkey_t pkey(const std::string_view &k); std::string pem(x509_t &x509); std::string pem(pkey_t &pkey); std::vector sign256(const pkey_t &pkey, const std::string_view &data); bool verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature); creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits); std::string_view signature(const x509_t &x); std::string rand(std::size_t bytes); std::string rand_alphabet(std::size_t bytes, const std::string_view &alphabet = std::string_view {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!%&()=-"}); class cert_chain_t { public: KITTY_DECL_CONSTR(cert_chain_t) void add(p_named_cert_t& named_cert_p); void clear(); const char *verify(x509_t::element_type *cert, p_named_cert_t& named_cert_out); private: std::vector> _certs; x509_store_ctx_t _cert_ctx; }; namespace cipher { constexpr std::size_t tag_size = 16; constexpr std::size_t round_to_pkcs7_padded(std::size_t size) { return ((size + 15) / 16) * 16; } class cipher_t { public: cipher_ctx_t decrypt_ctx; cipher_ctx_t encrypt_ctx; aes_t key; bool padding; }; class ecb_t: public cipher_t { public: ecb_t() = default; ecb_t(ecb_t &&) noexcept = default; ecb_t &operator=(ecb_t &&) noexcept = default; ecb_t(const aes_t &key, bool padding = true); int encrypt(const std::string_view &plaintext, std::vector &cipher); int decrypt(const std::string_view &cipher, std::vector &plaintext); }; class gcm_t: public cipher_t { public: gcm_t() = default; gcm_t(gcm_t &&) noexcept = default; gcm_t &operator=(gcm_t &&) noexcept = default; gcm_t(const crypto::aes_t &key, bool padding = true); /** * @brief Encrypts the plaintext using AES GCM mode. * @param plaintext The plaintext data to be encrypted. * @param tag The buffer where the GCM tag will be written. * @param ciphertext The buffer where the resulting ciphertext will be written. * @param iv The initialization vector to be used for the encryption. * @return The total length of the ciphertext and GCM tag. Returns -1 in case of an error. */ int encrypt(const std::string_view &plaintext, std::uint8_t *tag, std::uint8_t *ciphertext, aes_t *iv); /** * @brief Encrypts the plaintext using AES GCM mode. * length of cipher must be at least: round_to_pkcs7_padded(plaintext.size()) + crypto::cipher::tag_size * @param plaintext The plaintext data to be encrypted. * @param tagged_cipher The buffer where the resulting ciphertext and GCM tag will be written. * @param iv The initialization vector to be used for the encryption. * @return The total length of the ciphertext and GCM tag written into tagged_cipher. Returns -1 in case of an error. */ int encrypt(const std::string_view &plaintext, std::uint8_t *tagged_cipher, aes_t *iv); int decrypt(const std::string_view &cipher, std::vector &plaintext, aes_t *iv); }; class cbc_t: public cipher_t { public: cbc_t() = default; cbc_t(cbc_t &&) noexcept = default; cbc_t &operator=(cbc_t &&) noexcept = default; cbc_t(const crypto::aes_t &key, bool padding = true); /** * @brief Encrypts the plaintext using AES CBC mode. * length of cipher must be at least: round_to_pkcs7_padded(plaintext.size()) * @param plaintext The plaintext data to be encrypted. * @param cipher The buffer where the resulting ciphertext will be written. * @param iv The initialization vector to be used for the encryption. * @return The total length of the ciphertext written into cipher. Returns -1 in case of an error. */ int encrypt(const std::string_view &plaintext, std::uint8_t *cipher, aes_t *iv); }; } // namespace cipher } // namespace crypto