Skip to content

Commit

Permalink
document decryptor, encryptor, frame processor
Browse files Browse the repository at this point in the history
  • Loading branch information
braindigitalis committed Oct 6, 2024
1 parent dfc9275 commit 1a02080
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 22 deletions.
6 changes: 3 additions & 3 deletions src/dpp/dave/decryptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace dpp::dave {
constexpr auto kStatsInterval = 10s;

void decryptor::transition_to_key_ratchet(std::unique_ptr<key_ratchet_interface> keyRatchet,
Duration transitionExpiry)
duration transitionExpiry)
{
DISCORD_LOG(LS_INFO) << "Transitioning to new key ratchet: " << keyRatchet.get()
<< ", expiry: " << transitionExpiry.count();
Expand All @@ -52,7 +52,7 @@ void decryptor::transition_to_key_ratchet(std::unique_ptr<key_ratchet_interface>
}
}

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();
Expand Down Expand Up @@ -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_) {
Expand Down
100 changes: 94 additions & 6 deletions src/dpp/dave/decryptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -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<key_ratchet_interface> 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<const uint8_t> encryptedFrame,
array_view<uint8_t> 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<uint8_t> 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<inbound_frame_processor> get_or_create_frame_processor();

/**
* Return frame processor
* @param frameProcessor frame processor
*/
void return_frame_processor(std::unique_ptr<inbound_frame_processor> frameProcessor);

clock clock_;
Expand Down
4 changes: 2 additions & 2 deletions src/dpp/dave/encryptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const uint8_t> frame,
array_view<uint8_t> encryptedFrame,
Expand All @@ -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<int>(mediaType);
return 0;
return result_code::rc_encryption_failure;
}

if (passthroughMode_) {
Expand Down
145 changes: 134 additions & 11 deletions src/dpp/dave/encryptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<key_ratchet_interface> 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<const uint8_t> frame,
array_view<uint8_t> 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()>;
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<outbound_frame_processor> get_or_create_frame_processor();

/**
* @brief Return frame processor
* @param frameProcessor frame processor
*/
void return_frame_processor(std::unique_ptr<outbound_frame_processor> frameProcessor);

/**
* @brief Pair of cryptor and nonce pointers
*/
using cryptor_and_nonce = std::pair<std::shared_ptr<cipher_interface>, 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};
Expand Down
7 changes: 7 additions & 0 deletions src/dpp/dave/frame_processors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<range>;

uint8_t unencrypted_ranges_size(const ranges& unencryptedRanges);
Expand Down

0 comments on commit 1a02080

Please sign in to comment.