From dfc9275e55dcd80c1841bab7dd8abd8134328c21 Mon Sep 17 00:00:00 2001 From: Craig Edwards Date: Sun, 6 Oct 2024 11:59:26 +0000 Subject: [PATCH] docs: docblock comments --- .cspell.json | 4 +- src/dpp/dave/clock.h | 33 ++++++++++++- src/dpp/dave/codec_utils.h | 52 +++++++++++++++++++++ src/dpp/dave/common.h | 80 +++++++++++++++++++++++++++----- src/dpp/dave/cryptor_manager.h | 85 ++++++++++++++++++++++++++++++++-- src/dpp/dave/decryptor.h | 3 ++ 6 files changed, 241 insertions(+), 16 deletions(-) diff --git a/.cspell.json b/.cspell.json index 592a8c2c39..e8ef129aca 100644 --- a/.cspell.json +++ b/.cspell.json @@ -144,7 +144,9 @@ "moai", "xbps", "chacha20", - "chacha" + "chacha", + "nullopt", + "chrono" ], "flagWords": [ "hte" diff --git a/src/dpp/dave/clock.h b/src/dpp/dave/clock.h index 743fd79ef4..9a6114e6ce 100755 --- a/src/dpp/dave/clock.h +++ b/src/dpp/dave/clock.h @@ -28,19 +28,50 @@ namespace dpp::dave { +/** + * @brief An interface for a wrapper around chrono clocks + */ class clock_interface { public: + /** + * @brief chrono steady clock + */ using base_clock = std::chrono::steady_clock; + + /** + * @brief time point on a steady clock + */ using time_point = base_clock::time_point; + + /** + * @brief duration on a steady clock + */ using clock_duration = base_clock::duration; + /** + * @brief Default destructor + */ virtual ~clock_interface() = default; + + /** + * @brief Get current time + * @return current time + */ virtual time_point now() const = 0; }; +/** + * @brief Chrono clock class + */ class clock : public clock_interface { public: - time_point now() const override { return base_clock::now(); } + /** + * Get current time + * @return current time + */ + time_point now() const override { + return base_clock::now(); + } }; } // namespace dpp::dave diff --git a/src/dpp/dave/codec_utils.h b/src/dpp/dave/codec_utils.h index ea517c35e0..3ef2d6b97d 100755 --- a/src/dpp/dave/codec_utils.h +++ b/src/dpp/dave/codec_utils.h @@ -28,15 +28,67 @@ #include "frame_processors.h" #include "array_view.h" +/** + * @brief Functions for processing specific frame types. + * Different types of audio/video frames have different rules for what parts of it + * must remain unencrypted to allow for routing and processing further up the chain. + */ namespace dpp::dave::codec_utils { +/** + * process opus audio frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ bool process_frame_opus(outbound_frame_processor & processor, array_view frame); + +/** + * process VP8 video frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ bool process_frame_vp8(outbound_frame_processor & processor, array_view frame); + +/** + * process VP9 video frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ bool process_frame_vp9(outbound_frame_processor & processor, array_view frame); + +/** + * process H264 video frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ bool process_frame_h264(outbound_frame_processor & processor, array_view frame); + +/** + * process opus frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ bool process_frame_h265(outbound_frame_processor & processor, array_view frame); + +/** + * process opus frame + * @param processor outbound frame processor + * @param frame frame bytes + * @return true if frame could be processed + */ bool process_frame_av1(outbound_frame_processor & processor, array_view frame); +/** + * Check if encrypted frame is valid + * @param processor outbound frame processor + * @param frame frame to validate + * @return true if frame could be validated + */ bool validate_encrypted_frame(outbound_frame_processor& processor, array_view frame); } // namespace dpp::dave::codec_utils diff --git a/src/dpp/dave/common.h b/src/dpp/dave/common.h index f5c16e8953..62efe5bb60 100755 --- a/src/dpp/dave/common.h +++ b/src/dpp/dave/common.h @@ -35,38 +35,85 @@ #include "version.h" namespace mlspp::bytes_ns { + /** + * @brief bytes type + */ struct bytes; }; namespace dpp::dave { +/** + * @brief Unencrypted frame header size + */ using unencrypted_frame_header_size = uint16_t; + +/** + * @brief Truncated sync nonce + */ using truncated_sync_nonce = uint32_t; + +/** + * @brief Magic marker + */ using magic_marker = uint16_t; + +/** + * @brief Encryption key + */ using encryption_key = ::mlspp::bytes_ns::bytes; + +/** + * @brief Transition ID + */ using transition_id = uint16_t; + +/** + * @brief Supplemental bytes size + */ using supplemental_bytes_size = uint8_t; +/** + * @brief Media frame types + */ enum media_type : uint8_t { media_audio, media_video }; + + +/** + * @brief Media codec types + */ enum codec : uint8_t { cd_unknown, cd_opus, cd_vp8, cd_vp9, cd_h264, cd_h265, cd_av1 }; -// Returned in std::variant when a message is hard-rejected and should trigger a reset +/** + * @brief Returned in std::variant when a message is hard-rejected and should trigger a reset + */ struct failed_t {}; -// Returned in std::variant when a message is soft-rejected and should not trigger a reset +/** + * @brief Returned in std::variant when a message is soft-rejected and should not trigger a reset + */ struct ignored_t {}; -// Map of ID-key pairs. -// In ProcessCommit, this lists IDs whose keys have been added, changed, or removed; -// an empty value value means a key was removed. +/** + * @briefMap of ID-key pairs. + * In process_commit, this lists IDs whose keys have been added, changed, or removed; + * an empty value value means a key was removed. + */ using roster_map = std::map>; -// Return type for functions producing RosterMap or hard or soft failures +/** + * @brief Return type for functions producing RosterMap or hard or soft failures + */ using roster_variant = std::variant; +/** + * @brief Magic marker ID + */ constexpr magic_marker MARKER_BYTES = 0xFAFA; -// Layout constants +/** + * Layout constants + */ constexpr size_t AES_GCM_128_KEY_BYTES = 16; constexpr size_t AES_GCM_128_NONCE_BYTES = 12; constexpr size_t AES_GCM_128_TRUNCATED_SYNC_NONCE_BYTES = 4; @@ -77,11 +124,15 @@ constexpr size_t RATCHET_GENERATION_SHIFT_BITS = 8 * (AES_GCM_128_TRUNCATED_SYNC constexpr size_t SUPPLEMENTAL_BYTES = AES_GCM_127_TRUNCATED_TAG_BYTES + sizeof(supplemental_bytes_size) + sizeof(magic_marker); constexpr size_t TRANSFORM_PADDING_BYTES = 64; -// Timing constants +/** + * Timing constants + */ constexpr auto DEFAULT_TRANSITION_EXPIRY = std::chrono::seconds(10); constexpr auto CIPHER_EXPIRY = std::chrono::seconds(10); -// Behavior constants +/** + * Behavior constants + */ constexpr auto INIT_TRANSITION_ID = 0; constexpr auto DISABLED_VERSION = 0; constexpr auto MAX_GENERATION_GAP = 250; @@ -91,13 +142,20 @@ constexpr auto MAX_FRAMES_PER_SECOND = 50 + 2 * 60; // 50 audio frames + 2 * 60f constexpr std::array OPUS_SILENCE_PACKET = {0xF8, 0xFF, 0xFE}; // Utility routine for variant return types + +/** + * @brief Utility to get variant return types wrapped in an optional + * @tparam T type to get from variant + * @tparam V type for the optional + * @param variant variant to get from + * @return value retrieved or nullopt if not found + */ template inline std::optional get_optional(V&& variant) { if (auto map = std::get_if(&variant)) { if constexpr (std::is_rvalue_reference_v) { return std::move(*map); - } - else { + } else { return *map; } } diff --git a/src/dpp/dave/cryptor_manager.h b/src/dpp/dave/cryptor_manager.h index 18d779cfcd..ce969669fe 100755 --- a/src/dpp/dave/cryptor_manager.h +++ b/src/dpp/dave/cryptor_manager.h @@ -36,33 +36,112 @@ namespace dpp::dave { +/** + * @brief Compute wrapped generation for key + * @param oldest oldest key generation + * @param generation key generation + * @return wrapped computed generation + */ key_generation compute_wrapped_generation(key_generation oldest, key_generation generation); +/** + * @brief A big nonce (64 bits) + */ using big_nonce = uint64_t; + +/** + * @brief Compute wrapped big nonce + * @param generation generation + * @param nonce truncated sync nonce + * @return big nonce (64 bits) + */ big_nonce compute_wrapped_big_nonce(key_generation generation, truncated_sync_nonce nonce); +/** + * @brief A manager to handle whichever cipher is best for the current version of DAVE + * + * his will currently instantiate an AES 128 GCM AEAD cipher. + */ class aead_cipher_manager { public: + /** + * @brief Chrono time point + */ using time_point = typename clock_interface::time_point; + /** + * @brief Constructor + * @param clock chrono clock + * @param keyRatchet key ratchet for cipher + */ aead_cipher_manager(const clock_interface& clock, std::unique_ptr keyRatchet); - void update_expiry(time_point expiry) { ratchetExpiry_ = expiry; } - bool is_expired() const { return clock_.now() > ratchetExpiry_; } - + /** + * @brief Update cipher expiry + * @param expiry expiry time + */ + void update_expiry(time_point expiry) { + ratchetExpiry_ = expiry; + } + + /** + * @brief True if cipher has expired + * @return true if expired + */ + bool is_expired() const { + return clock_.now() > ratchetExpiry_; + } + + /** + * @brief True if nonce can be processed for generation + * @param generation key generation + * @param nonce nonce/IV + * @return true if can be processed + */ bool can_process_nonce(key_generation generation, truncated_sync_nonce nonce) const; + + /** + * Compute wrapped generation for key + * @param generation key generation + * @return key generation + */ key_generation compute_wrapped_generation(key_generation generation); cipher_interface* get_cipher(key_generation generation); + + /** + * @brief Updates the expiry time for all old ciphers + * @param generation key generation + * @param nonce nonce/IV + */ void report_cipher_success(key_generation generation, truncated_sync_nonce nonce); private: + /** + * @brief Cipher with an expiry date/time + */ struct expiring_cipher { + /** + * @brief Cipher + */ std::unique_ptr cryptor; + + /** + * @brief Expiry time + */ time_point expiry; }; + /** + * Create a cipher with an expiry time + * @param generation key generation + * @return expiring cipher + */ expiring_cipher make_expiring_cipher(key_generation generation); + + /** + * @brief Clean up old expired ciphers + */ void cleanup_expired_ciphers(); const clock_interface& clock_; diff --git a/src/dpp/dave/decryptor.h b/src/dpp/dave/decryptor.h index 8786a695cf..8977ea9f18 100755 --- a/src/dpp/dave/decryptor.h +++ b/src/dpp/dave/decryptor.h @@ -51,6 +51,9 @@ struct decryption_stats { uint64_t decrypt_attempts = 0; }; +/** + * @brief Decryptor, decrypts encrypted frames + */ class decryptor { public: using Duration = std::chrono::seconds;