diff --git a/src/dpp/dave/decryptor.cpp b/src/dpp/dave/decryptor.cpp index abfd8c5381..3371124f43 100755 --- a/src/dpp/dave/decryptor.cpp +++ b/src/dpp/dave/decryptor.cpp @@ -39,7 +39,7 @@ namespace dpp::dave { constexpr auto kStatsInterval = 10s; void decryptor::transition_to_key_ratchet(std::unique_ptr keyRatchet, - Duration transitionExpiry) + duration transitionExpiry) { DISCORD_LOG(LS_INFO) << "Transitioning to new key ratchet: " << keyRatchet.get() << ", expiry: " << transitionExpiry.count(); @@ -52,7 +52,7 @@ void decryptor::transition_to_key_ratchet(std::unique_ptr } } -void decryptor::transition_to_passthrough_mode(bool passthroughMode, Duration transitionExpiry) +void decryptor::transition_to_passthrough_mode(bool passthroughMode, duration transitionExpiry) { if (passthroughMode) { allowPassThroughUntil_ = time_point::max(); @@ -207,7 +207,7 @@ size_t decryptor::get_max_plaintext_byte_size(media_type mediaType, size_t encry return encryptedFrameSize; } -void decryptor::update_cryptor_manager_expiry(Duration expiry) +void decryptor::update_cryptor_manager_expiry(duration expiry) { auto maxExpiryTime = clock_.now() + expiry; for (auto& cryptorManager : cryptorManagers_) { diff --git a/src/dpp/dave/decryptor.h b/src/dpp/dave/decryptor.h index 8977ea9f18..3a31d58fd7 100755 --- a/src/dpp/dave/decryptor.h +++ b/src/dpp/dave/decryptor.h @@ -43,11 +43,29 @@ namespace dpp::dave { class key_ratchet_interface; +/** + * @brief Decryption stats + */ struct decryption_stats { + /** + * @brief Number of passthroughs + */ uint64_t passthroughs = 0; + /** + * @brief Number of decryption successes + */ uint64_t decrypt_success = 0; + /** + * @brief Number of decryption failures + */ uint64_t decrypt_failure = 0; + /** + * @brief Total encryption duration + */ uint64_t decrypt_duration = 0; + /** + * @brief Number of decryption attempts + */ uint64_t decrypt_attempts = 0; }; @@ -56,32 +74,102 @@ struct decryption_stats { */ class decryptor { public: - using Duration = std::chrono::seconds; - + /** + * @brief Chrono duration + */ + using duration = std::chrono::seconds; + + /** + * @brief Set a new key ratchet for a decryptor. These are derived during welcome/commit + * of the session. Once you have a key ratchet, you can derive the key, and decrypt that + * user's audio/video. + * + * @param keyRatchet Key ratchet + * @param transitionExpiry Transition expiry. Old keys last this long before being withdrawn + * in preference of this new one. + */ void transition_to_key_ratchet(std::unique_ptr keyRatchet, - Duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + + /** + * @brief Transition to passthrough mode + * + * Passthrough mode occurs when a non-DAVE user connects to the VC. + * + * @param passthroughMode True to enable passthrough mode + * @param transitionExpiry Expiry for the transition + */ void transition_to_passthrough_mode(bool passthroughMode, - Duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); - + duration transitionExpiry = DEFAULT_TRANSITION_EXPIRY); + + /** + * Decrypt a frame + * + * @param mediaType type of media, audio or video + * @param encryptedFrame encrypted frame bytes + * @param frame plaintext output + * @return size of decrypted frame, or 0 if failure + */ size_t decrypt(media_type mediaType, array_view encryptedFrame, array_view frame); + /** + * @brief Get maximum possible decrypted size of frame from an encrypted frame + * @param mediaType type of media + * @param encryptedFrameSize encrypted frame size + * @return size of plaintext buffer required + */ size_t get_max_plaintext_byte_size(media_type mediaType, size_t encryptedFrameSize); + + /** + * Get decryption stats + * @param mediaType media type, audio or video + * @return decryption stats + */ decryption_stats get_stats(media_type mediaType) const { return stats_[mediaType]; } private: + /** + * @brief Chrono time point + */ using time_point = clock_interface::time_point; + /** + * @brief Decryption implementation + * + * @param cipher_manager cipher manager + * @param mediaType media time, audio or video + * @param encryptedFrame encrypted frame data + * @param frame decrypted frame data + * @return True if decryption succeeded + */ bool decrypt_impl(aead_cipher_manager& cipher_manager, media_type mediaType, inbound_frame_processor& encryptedFrame, array_view frame); - void update_cryptor_manager_expiry(Duration expiry); + /** + * @brief Update expiry for an instance of the manager + * @param expiry expiry duration + */ + void update_cryptor_manager_expiry(duration expiry); + + /** + * @brief Clean up expired cryptor managers + */ void cleanup_expired_cryptor_managers(); + /** + * @brief Get frame procesor, or create a new one + * @return frame processor + */ std::unique_ptr get_or_create_frame_processor(); + + /** + * Return frame processor + * @param frameProcessor frame processor + */ void return_frame_processor(std::unique_ptr frameProcessor); clock clock_; diff --git a/src/dpp/dave/encryptor.cpp b/src/dpp/dave/encryptor.cpp index ce923b31ed..de5ffee028 100755 --- a/src/dpp/dave/encryptor.cpp +++ b/src/dpp/dave/encryptor.cpp @@ -56,7 +56,7 @@ void encryptor::set_passthrough_mode(bool passthroughMode) update_current_protocol_version(passthroughMode ? 0 : max_protocol_version()); } -int encryptor::encrypt(media_type mediaType, +encryptor::result_code encryptor::encrypt(media_type mediaType, uint32_t ssrc, array_view frame, array_view encryptedFrame, @@ -65,7 +65,7 @@ int encryptor::encrypt(media_type mediaType, if (mediaType != media_audio && mediaType != media_video) { DISCORD_LOG(LS_WARNING) << "encrypt failed, invalid media type: " << static_cast(mediaType); - return 0; + return result_code::rc_encryption_failure; } if (passthroughMode_) { diff --git a/src/dpp/dave/encryptor.h b/src/dpp/dave/encryptor.h index 98f572ab71..1b2b8c798f 100755 --- a/src/dpp/dave/encryptor.h +++ b/src/dpp/dave/encryptor.h @@ -40,54 +40,177 @@ namespace dpp::dave { +/** + * @brief Encryption stats + */ struct encryption_stats { + /** + * @brief Number of passthrough packets + */ uint64_t passthroughs = 0; + /** + * @brief Number of encryption successes + */ uint64_t encrypt_success = 0; + /** + * @brief Number of encryption failures + */ uint64_t encrypt_failure = 0; + /** + * @brief Duration encrypted + */ uint64_t encrypt_duration = 0; + /** + * @brief Number of encryption atempts + */ uint64_t encrypt_attempts = 0; + /** + * @brief Maximum attempts at encryption + */ uint64_t encrypt_max_attempts = 0; }; class encryptor { public: + /** + * @brief Return codes for encryptor::encrypt + */ + enum result_code : uint8_t { + /** + * @brief Successful encryption + */ + rc_success, + /** + * @brief Encryption failure + */ + rc_encryption_failure, + }; + + /** + * @brief Set key ratchet for encryptor, this should be the bot's ratchet. + * @param keyRatchet Bot's key ratchet + */ void set_key_ratchet(std::unique_ptr keyRatchet); + + /** + * @brief Set encryption to passthrough mode + * @param passthroughMode true to enable passthrough mode, false to disable + */ void set_passthrough_mode(bool passthroughMode); - bool has_key_ratchet() const { return keyRatchet_ != nullptr; } - bool is_passthrough_mode() const { return passthroughMode_; } + /** + * @brief True if key ratchet assigned + * @return key ratchet is assigned + */ + bool has_key_ratchet() const { + return keyRatchet_ != nullptr; + } + /** + * @brief True if is in passthrough mode + * @return is in passthrough mode + */ + bool is_passthrough_mode() const { + return passthroughMode_; + } + + /** + * @brief Assign SSRC to codec + * @note This is unused - all SSRC are assumed to be OPUS for bots at present. + * @param ssrc RTP SSRC + * @param codecType Codec type + */ void assign_ssrc_to_codec(uint32_t ssrc, codec codecType); + + /** + * @brief Get codec for RTP SSRC + * @note This is unused - all SSRC are assumed to be OPUS for bots at present. + * @param ssrc RTP SSRC + * @return always returns OPUS as bots can only send/receive audio at present + */ codec codec_for_ssrc(uint32_t ssrc); - int encrypt(media_type mediaType, + /** + * @brief Encrypt plaintext opus frames + * @param mediaType media type, should always be audio + * @param ssrc RTP SSRC + * @param frame Frame plaintext + * @param encryptedFrame Encrypted frame + * @param bytesWritten Number of bytes written to the encrypted buffer + * @return Status code for encryption + */ + encryptor::result_code encrypt(media_type mediaType, uint32_t ssrc, array_view frame, array_view encryptedFrame, size_t* bytesWritten); + /** + * @brief Get maximum possible ciphertext size for a plaintext buffer + * @param mediaType media type, should always be audio for bots + * @param frameSize frame size of plaintext buffer + * @return size of ciphertext buffer to allocate + */ size_t get_max_ciphertext_byte_size(media_type mediaType, size_t frameSize); - encryption_stats get_stats(media_type mediaType) const { return stats_[mediaType]; } + /** + * @brief Get encryption stats + * @param mediaType media type + * @return encryption stats + */ + encryption_stats get_stats(media_type mediaType) const { + return stats_[mediaType]; + } + + /** + * @brief Protocol version changed callback + */ using protocol_version_changed_callback = std::function; - void set_protocol_version_changed_callback(protocol_version_changed_callback callback) - { + + /** + * @brief Set protocol version changed callback + * @param callback Callback to set + */ + void set_protocol_version_changed_callback(protocol_version_changed_callback callback) { protocolVersionChangedCallback_ = std::move(callback); } - protocol_version get_protocol_version() const { return currentProtocolVersion_; } - enum result_code : uint8_t { - rc_success, - rc_encryption_failure, - }; + /** + * @brief Get protocol version + * @return protocol version + */ + protocol_version get_protocol_version() const { + return currentProtocolVersion_; + } private: + /** + * @brief Get the current frame processor or create a new one + * @return Frame processor + */ std::unique_ptr get_or_create_frame_processor(); + + /** + * @brief Return frame processor + * @param frameProcessor frame processor + */ void return_frame_processor(std::unique_ptr frameProcessor); + /** + * @brief Pair of cryptor and nonce pointers + */ using cryptor_and_nonce = std::pair, truncated_sync_nonce>; + + /** + * @brief Get cryptor and nonce + * @return cryptor and nonce + */ cryptor_and_nonce get_next_cryptor_and_nonce(); + /** + * @brief Change protocol version + * @param version new protocol version + */ void update_current_protocol_version(protocol_version version); std::atomic_bool passthroughMode_{false}; diff --git a/src/dpp/dave/frame_processors.h b/src/dpp/dave/frame_processors.h index 534caaa18b..79fe0ddcf2 100755 --- a/src/dpp/dave/frame_processors.h +++ b/src/dpp/dave/frame_processors.h @@ -33,10 +33,17 @@ namespace dpp::dave { +/** + * @brief Range inside a frame + */ struct range { size_t offset; size_t size; }; + +/** + * @brief Vector of ranges in a frame + */ using ranges = std::vector; uint8_t unencrypted_ranges_size(const ranges& unencryptedRanges);