diff --git a/src/davetest/dave.cpp b/src/davetest/dave.cpp index b8574dd33e..07b1b8e66a 100644 --- a/src/davetest/dave.cpp +++ b/src/davetest/dave.cpp @@ -21,8 +21,58 @@ ************************************************************************************/ #include #include - +#include #include +#include + +#include "../../mlspp/lib/bytes/include/bytes/bytes.h" +#include "../../src/dpp/dave/array_view.h" +#include "../../src/dpp/dave/openssl_aead_cipher.h" +#include "../../src/dpp/dave/key_ratchet.h" +#include "../../src/dpp/dave/common.h" + +dpp::dave::EncryptionKey MakeStaticSenderKey(const std::string& userID); +dpp::dave::EncryptionKey MakeStaticSenderKey(uint64_t u64userID); + +class StaticKeyRatchet : public dpp::dave::IKeyRatchet { +public: + StaticKeyRatchet(const std::string& userId) noexcept; + ~StaticKeyRatchet() noexcept override = default; + + dpp::dave::EncryptionKey GetKey(dpp::dave::KeyGeneration generation) noexcept override; + void DeleteKey(dpp::dave::KeyGeneration generation) noexcept override; + +private: + uint64_t u64userID_; +}; + +dpp::dave::EncryptionKey MakeStaticSenderKey(const std::string& userID) +{ + auto u64userID = strtoull(userID.c_str(), nullptr, 10); + return MakeStaticSenderKey(u64userID); +} + +dpp::dave::EncryptionKey MakeStaticSenderKey(uint64_t u64userID) +{ + static_assert(dpp::dave::kAesGcm128KeyBytes == 2 * sizeof(u64userID)); + dpp::dave::EncryptionKey senderKey(dpp::dave::kAesGcm128KeyBytes); + const uint8_t* bytePtr = reinterpret_cast(&u64userID); + std::copy_n(bytePtr, sizeof(u64userID), senderKey.begin()); + std::copy_n(bytePtr, sizeof(u64userID), senderKey.begin() + sizeof(u64userID)); + return senderKey; +} + +StaticKeyRatchet::StaticKeyRatchet(const std::string& userId) noexcept + : u64userID_(strtoull(userId.c_str(), nullptr, 10)) { +} + +dpp::dave::EncryptionKey StaticKeyRatchet::GetKey(dpp::dave::KeyGeneration generation) noexcept +{ + return MakeStaticSenderKey(u64userID_); +} + +void StaticKeyRatchet::DeleteKey([[maybe_unused]] dpp::dave::KeyGeneration generation) noexcept { +} std::string get_testdata_dir() { char *env_var = getenv("TEST_DATA_DIR"); @@ -47,7 +97,138 @@ std::vector load_test_audio() { return testaudio; } +/*#define EXPECT_TRUE(expr) if (!(expr)) { std::cout << "Failed\n"; exit(1); } +#define EXPECT_FALSE(expr) if (expr) { std::cout << "Failed\n"; exit(1); } + +void encryptor_unit_test() { + constexpr size_t PLAINTEXT_SIZE = 1024; + auto plaintextBufferIn = std::vector(PLAINTEXT_SIZE, 0); + auto additionalDataBuffer = std::vector(PLAINTEXT_SIZE, 0); + auto plaintextBufferOut = std::vector(PLAINTEXT_SIZE, 0); + auto ciphertextBuffer = std::vector(PLAINTEXT_SIZE, 0); + auto nonceBuffer = std::vector(dpp::dave::kAesGcm128NonceBytes, 0); + auto tagBuffer = std::vector(dpp::dave::kAesGcm128TruncatedTagBytes, 0); + + auto plaintextIn = + dpp::dave::make_array_view(plaintextBufferIn.data(), plaintextBufferIn.size()); + auto additionalData = + dpp::dave::make_array_view(additionalDataBuffer.data(), additionalDataBuffer.size()); + auto plaintextOut = + dpp::dave::make_array_view(plaintextBufferOut.data(), plaintextBufferOut.size()); + auto ciphertextOut = dpp::dave::make_array_view(ciphertextBuffer.data(), ciphertextBuffer.size()); + auto ciphertextIn = + dpp::dave::make_array_view(ciphertextBuffer.data(), ciphertextBuffer.size()); + auto nonce = dpp::dave::make_array_view(nonceBuffer.data(), nonceBuffer.size()); + auto tagOut = dpp::dave::make_array_view(tagBuffer.data(), tagBuffer.size()); + auto tagIn = dpp::dave::make_array_view(tagBuffer.data(), tagBuffer.size()); + + dpp::dave::openssl_aead_cipher cryptor(MakeStaticSenderKey("12345678901234567890")); + + EXPECT_TRUE(cryptor.encrypt(ciphertextOut, plaintextIn, nonce, additionalData, tagOut)); + + // The ciphertext should not be the same as the plaintext + EXPECT_FALSE(memcmp(plaintextBufferIn.data(), ciphertextBuffer.data(), PLAINTEXT_SIZE) == 0); + + EXPECT_TRUE(cryptor.decrypt(plaintextOut, ciphertextIn, tagIn, nonce, additionalData)); + + // The plaintext should be the same as the original plaintext + EXPECT_TRUE(memcmp(plaintextBufferIn.data(), plaintextBufferOut.data(), PLAINTEXT_SIZE) == 0); + + plaintextBufferIn = std::vector(PLAINTEXT_SIZE, 0); + additionalDataBuffer = std::vector(PLAINTEXT_SIZE, 0); + plaintextBufferOut = std::vector(PLAINTEXT_SIZE, 0); + ciphertextBuffer = std::vector(PLAINTEXT_SIZE, 0); + nonceBuffer = std::vector(dpp::dave::kAesGcm128NonceBytes, 0); + tagBuffer = std::vector(dpp::dave::kAesGcm128TruncatedTagBytes, 0); + + plaintextIn = + dpp::dave::make_array_view(plaintextBufferIn.data(), plaintextBufferIn.size()); + auto additionalData1 = + dpp::dave::make_array_view(additionalDataBuffer.data(), additionalDataBuffer.size()); + plaintextOut = + dpp::dave::make_array_view(plaintextBufferOut.data(), plaintextBufferOut.size()); + ciphertextOut = dpp::dave::make_array_view(ciphertextBuffer.data(), ciphertextBuffer.size()); + ciphertextIn = + dpp::dave::make_array_view(ciphertextBuffer.data(), ciphertextBuffer.size()); + nonce = dpp::dave::make_array_view(nonceBuffer.data(), nonceBuffer.size()); + tagOut = dpp::dave::make_array_view(tagBuffer.data(), tagBuffer.size()); + tagIn = dpp::dave::make_array_view(tagBuffer.data(), tagBuffer.size()); + + dpp::dave::openssl_aead_cipher cryptor4(MakeStaticSenderKey("12345678901234567890")); + + EXPECT_TRUE(cryptor4.encrypt(ciphertextOut, plaintextIn, nonce, additionalData1, tagOut)); + + // We modify the additional data before decryption + additionalDataBuffer[0] = 1; + + EXPECT_FALSE(cryptor4.decrypt(plaintextOut, ciphertextIn, tagIn, nonce, additionalData1)); + + auto plaintextBuffer1 = std::vector(PLAINTEXT_SIZE, 0); + auto additionalDataBuffer1 = std::vector(PLAINTEXT_SIZE, 0); + auto plaintextBuffer2 = std::vector(PLAINTEXT_SIZE, 0); + auto additionalDataBuffer2 = std::vector(PLAINTEXT_SIZE, 0); + auto ciphertextBuffer1 = std::vector(PLAINTEXT_SIZE, 0); + auto ciphertextBuffer2 = std::vector(PLAINTEXT_SIZE, 0); + nonceBuffer = std::vector(dpp::dave::kAesGcm128NonceBytes, 0); + tagBuffer = std::vector(dpp::dave::kAesGcm128TruncatedTagBytes, 0); + + auto plaintext1 = + dpp::dave::make_array_view(plaintextBuffer1.data(), plaintextBuffer1.size()); + additionalData1 = + dpp::dave::make_array_view(additionalDataBuffer1.data(), additionalDataBuffer1.size()); + auto plaintext2 = + dpp::dave::make_array_view(plaintextBuffer2.data(), plaintextBuffer2.size()); + auto additionalData2 = + dpp::dave::make_array_view(additionalDataBuffer2.data(), additionalDataBuffer2.size()); + auto ciphertext1 = dpp::dave::make_array_view(ciphertextBuffer1.data(), ciphertextBuffer1.size()); + auto ciphertext2 = dpp::dave::make_array_view(ciphertextBuffer2.data(), ciphertextBuffer2.size()); + nonce = dpp::dave::make_array_view(nonceBuffer.data(), nonceBuffer.size()); + auto tag = dpp::dave::make_array_view(tagBuffer.data(), tagBuffer.size()); + + dpp::dave::openssl_aead_cipher cryptor1(MakeStaticSenderKey("12345678901234567890")); + dpp::dave::openssl_aead_cipher cryptor2(MakeStaticSenderKey("09876543210987654321")); + + EXPECT_TRUE(cryptor1.encrypt(ciphertext1, plaintext1, nonce, additionalData1, tag)); + EXPECT_TRUE(cryptor2.encrypt(ciphertext2, plaintext2, nonce, additionalData2, tag)); + + EXPECT_FALSE(memcmp(ciphertextBuffer1.data(), ciphertextBuffer2.data(), PLAINTEXT_SIZE) == 0); + + plaintextBuffer1 = std::vector(PLAINTEXT_SIZE, 0); + additionalDataBuffer1 = std::vector(PLAINTEXT_SIZE, 0); + plaintextBuffer2 = std::vector(PLAINTEXT_SIZE, 0); + additionalDataBuffer2 = std::vector(PLAINTEXT_SIZE, 0); + ciphertextBuffer1 = std::vector(PLAINTEXT_SIZE, 0); + ciphertextBuffer2 = std::vector(PLAINTEXT_SIZE, 0); + auto nonceBuffer1 = std::vector(dpp::dave::kAesGcm128NonceBytes, 0); + auto nonceBuffer2 = std::vector(dpp::dave::kAesGcm128NonceBytes, 1); + tagBuffer = std::vector(dpp::dave::kAesGcm128TruncatedTagBytes, 0); + + plaintext1 = + dpp::dave::make_array_view(plaintextBuffer1.data(), plaintextBuffer1.size()); + additionalData1 = + dpp::dave::make_array_view(additionalDataBuffer1.data(), additionalDataBuffer1.size()); + plaintext2 = + dpp::dave::make_array_view(plaintextBuffer2.data(), plaintextBuffer2.size()); + additionalData2 = + dpp::dave::make_array_view(additionalDataBuffer2.data(), additionalDataBuffer2.size()); + ciphertext1 = dpp::dave::make_array_view(ciphertextBuffer1.data(), ciphertextBuffer1.size()); + ciphertext2 = dpp::dave::make_array_view(ciphertextBuffer2.data(), ciphertextBuffer2.size()); + auto nonce1 = dpp::dave::make_array_view(nonceBuffer1.data(), nonceBuffer1.size()); + auto nonce2 = dpp::dave::make_array_view(nonceBuffer2.data(), nonceBuffer2.size()); + tag = dpp::dave::make_array_view(tagBuffer.data(), tagBuffer.size()); + + dpp::dave::openssl_aead_cipher cryptor3(MakeStaticSenderKey("12345678901234567890")); + + EXPECT_TRUE(cryptor3.encrypt(ciphertext1, plaintext1, nonce1, additionalData1, tag)); + EXPECT_TRUE(cryptor3.encrypt(ciphertext2, plaintext2, nonce2, additionalData2, tag)); + + EXPECT_FALSE(memcmp(ciphertextBuffer1.data(), ciphertextBuffer2.data(), PLAINTEXT_SIZE) == 0); +}*/ + int main() { + + //encryptor_unit_test(); + using namespace std::chrono_literals; char* t = getenv("DPP_UNIT_TEST_TOKEN"); if (t == nullptr || getenv("TEST_GUILD_ID") == nullptr || getenv("TEST_VC_ID") == nullptr) { @@ -66,6 +247,7 @@ int main() { std::vector testaudio = load_test_audio(); dave_test.on_voice_ready([&](const dpp::voice_ready_t & event) { + dave_test.log(dpp::ll_info, "Voice channel ready, sending audio..."); dpp::discord_voice_client* v = event.voice_client; if (v && v->is_ready()) { v->send_audio_raw((uint16_t*)testaudio.data(), testaudio.size()); @@ -76,7 +258,8 @@ int main() { dave_test.on_guild_create([&](const dpp::guild_create_t & event) { if (event.created->id == TEST_GUILD_ID) { dpp::discord_client* s = dave_test.get_shard(0); - s->connect_voice(TEST_GUILD_ID, TEST_VC_ID, false, false, true); + bool muted = false, deaf = false, enable_dave = true; + s->connect_voice(TEST_GUILD_ID, TEST_VC_ID, muted, deaf, enable_dave); } }); dave_test.start(false); diff --git a/src/dpp/dave/encryptor.cpp b/src/dpp/dave/encryptor.cpp index 301e299a9f..5124f6acfc 100755 --- a/src/dpp/dave/encryptor.cpp +++ b/src/dpp/dave/encryptor.cpp @@ -258,7 +258,7 @@ Codec Encryptor::CodecForSsrc(uint32_t ssrc) return existingCodecIt->second; } else { - return Codec::Unknown; + return Codec::Opus; } } diff --git a/src/dpp/dave/encryptor.h b/src/dpp/dave/encryptor.h index ddd889a53e..9a1bc2af04 100755 --- a/src/dpp/dave/encryptor.h +++ b/src/dpp/dave/encryptor.h @@ -76,15 +76,6 @@ class Encryptor { } ProtocolVersion GetProtocolVersion() const { return currentProtocolVersion_; } -private: - std::unique_ptr GetOrCreateFrameProcessor(); - void ReturnFrameProcessor(std::unique_ptr frameProcessor); - - using CryptorAndNonce = std::pair, TruncatedSyncNonce>; - CryptorAndNonce GetNextCryptorAndNonce(); - - void UpdateCurrentProtocolVersion(ProtocolVersion version); - enum ResultCode { Success, UninitializedContext, @@ -95,6 +86,15 @@ class Encryptor { TagAppendFailure }; +private: + std::unique_ptr GetOrCreateFrameProcessor(); + void ReturnFrameProcessor(std::unique_ptr frameProcessor); + + using CryptorAndNonce = std::pair, TruncatedSyncNonce>; + CryptorAndNonce GetNextCryptorAndNonce(); + + void UpdateCurrentProtocolVersion(ProtocolVersion version); + std::atomic_bool passthroughMode_{false}; std::mutex keyGenMutex_; diff --git a/src/dpp/dave/openssl_aead_cipher.cpp b/src/dpp/dave/openssl_aead_cipher.cpp index d629346e35..0e32b3681f 100755 --- a/src/dpp/dave/openssl_aead_cipher.cpp +++ b/src/dpp/dave/openssl_aead_cipher.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "common.h" #include "logger.h" diff --git a/src/dpp/voice/enabled/handle_frame.cpp b/src/dpp/voice/enabled/handle_frame.cpp index c98a7cfd39..71ea612d52 100644 --- a/src/dpp/voice/enabled/handle_frame.cpp +++ b/src/dpp/voice/enabled/handle_frame.cpp @@ -50,7 +50,7 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod mls_state->encryptor = std::make_unique(); mls_state->decryptors.clear(); } - break; + break; case voice_client_dave_mls_proposals: { log(ll_debug, "voice_client_dave_mls_proposals"); @@ -62,7 +62,7 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod this->write(std::string_view(reinterpret_cast(r.data()), r.size()), OP_BINARY); } } - break; + break; case voice_client_dave_announce_commit_transaction: { log(ll_debug, "voice_client_dave_announce_commit_transaction"); auto r = mls_state->dave_session->ProcessCommit(mls_state->cached_commit); @@ -82,8 +82,15 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod */ mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->GetLastEpochAuthenticator()); log(ll_debug, "E2EE Privacy Code: " + mls_state->privacy_code); + + if (!creator->on_voice_ready.empty()) { + voice_ready_t rdy(nullptr, data); + rdy.voice_client = this; + rdy.voice_channel_id = this->channel_id; + creator->on_voice_ready.call(rdy); + } } - break; + break; case voice_client_dave_mls_welcome: { this->mls_state->transition_id = dave_header->get_welcome_transition_id(); log(ll_debug, "voice_client_dave_mls_welcome with transition id " + std::to_string(this->mls_state->transition_id)); @@ -99,12 +106,19 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } mls_state->privacy_code = generate_displayable_code(mls_state->dave_session->GetLastEpochAuthenticator()); log(ll_debug, "E2EE Privacy Code: " + mls_state->privacy_code); + + if (!creator->on_voice_ready.empty()) { + voice_ready_t rdy(nullptr, data); + rdy.voice_client = this; + rdy.voice_channel_id = this->channel_id; + creator->on_voice_ready.call(rdy); + } } - break; + break; default: log(ll_debug, "Unexpected DAVE frame opcode"); log(dpp::ll_trace, "R: " + dpp::utility::debug_dump((uint8_t*)(data.data()), data.length())); - break; + break; } return true; @@ -136,30 +150,29 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod /* Ping acknowledgement */ case voice_opcode_connection_heartbeat_ack: /* These opcodes do not require a response or further action */ - break; + break; case voice_opcode_media_sink: case voice_client_flags: { } - break; + break; case voice_client_platform: { voice_client_platform_t vcp(nullptr, data); vcp.voice_client = this; vcp.user_id = snowflake_not_null(&j["d"], "user_id"); vcp.platform = static_cast(int8_not_null(&j["d"], "platform")); creator->on_voice_client_platform.call(vcp); - } - break; + break; case voice_opcode_multiple_clients_connect: { dave_mls_user_list = j["d"]["user_ids"]; log(ll_debug, "Number of clients in voice channel: " + std::to_string(dave_mls_user_list.size())); } - break; + break; case voice_client_dave_mls_invalid_commit_welcome: { this->mls_state->transition_id = j["d"]["transition_id"]; log(ll_debug, "voice_client_dave_mls_invalid_commit_welcome transition id " + std::to_string(this->mls_state->transition_id)); } - break; + break; case voice_client_dave_execute_transition: { log(ll_debug, "voice_client_dave_execute_transition"); this->mls_state->transition_id = j["d"]["transition_id"]; @@ -174,14 +187,14 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod }; this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); } - break; - /* "The protocol only uses this opcode to indicate when a downgrade to protocol version 0 is upcoming." */ + break; + /* "The protocol only uses this opcode to indicate when a downgrade to protocol version 0 is upcoming." */ case voice_client_dave_prepare_transition: { uint64_t transition_id = j["d"]["transition_id"]; uint64_t protocol_version = j["d"]["protocol_version"]; log(ll_debug, "voice_client_dave_prepare_transition version=" + std::to_string(protocol_version) + " for transition " + std::to_string(transition_id)); } - break; + break; case voice_client_dave_prepare_epoch: { uint64_t protocol_version = j["d"]["protocol_version"]; uint64_t epoch = j["d"]["epoch"]; @@ -191,8 +204,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod mls_state->dave_session->Init(dave::MaxSupportedProtocolVersion(), channel_id, creator->me.id.str(), mls_state->mls_key); } } - break; - /* Client Disconnect */ + break; + /* Client Disconnect */ case voice_opcode_client_disconnect: { if (j.find("d") != j.end() && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null()) { snowflake u_id = snowflake_not_null(&j["d"], "user_id"); @@ -211,10 +224,10 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } } } - break; - /* Speaking */ + break; + /* Speaking */ case voice_opcode_client_speaking: - /* Client Connect (doesn't seem to work) */ + /* Client Connect (doesn't seem to work) */ case voice_opcode_client_connect: { if (j.find("d") != j.end() && j["d"].find("user_id") != j["d"].end() && !j["d"]["user_id"].is_null() @@ -232,12 +245,12 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } } } - break; - /* Voice resume */ + break; + /* Voice resume */ case voice_opcode_connection_resumed: log(ll_debug, "Voice connection resumed"); - break; - /* Voice HELLO */ + break; + /* Voice HELLO */ case voice_opcode_connection_hello: { if (j.find("d") != j.end() && j["d"].find("heartbeat_interval") != j["d"].end() && !j["d"]["heartbeat_interval"].is_null()) { this->heartbeat_interval = j["d"]["heartbeat_interval"].get(); @@ -280,8 +293,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } this->connect_time = time(nullptr); } - break; - /* Session description */ + break; + /* Session description */ case voice_opcode_connection_description: { json &d = j["d"]; size_t ofs = 0; @@ -293,6 +306,9 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } has_secret_key = true; + /* Reset packet_nonce */ + packet_nonce = 1; + if (dave_version != dave_version_none) { if (j["d"]["dave_protocol_version"] != static_cast(dave_version)) { log(ll_error, "We requested DAVE E2EE but didn't receive it from the server, downgrading..."); @@ -313,21 +329,17 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } else { /* This is needed to start voice receiving and make sure that the start of sending isn't cut off */ send_silence(20); + /* Fire on_voice_ready */ + if (!creator->on_voice_ready.empty()) { + voice_ready_t rdy(nullptr, data); + rdy.voice_client = this; + rdy.voice_channel_id = this->channel_id; + creator->on_voice_ready.call(rdy); + } } - - /* Fire on_voice_ready */ - if (!creator->on_voice_ready.empty()) { - voice_ready_t rdy(nullptr, data); - rdy.voice_client = this; - rdy.voice_channel_id = this->channel_id; - creator->on_voice_ready.call(rdy); - } - - /* Reset packet_nonce */ - packet_nonce = 1; } - break; - /* Voice ready */ + break; + /* Voice ready */ case voice_opcode_connection_ready: { /* Video stream stuff comes in this frame too, but we can't use it (YET!) */ json &d = j["d"]; @@ -372,25 +384,25 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod } this->write(json({ - { "op", voice_opcode_connection_select_protocol }, - { "d", { - { "protocol", "udp" }, - { "data", { - { "address", discover_ip() }, - { "port", bound_port }, - { "mode", transport_encryption_protocol } - } - } - } - } - }).dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); + { "op", voice_opcode_connection_select_protocol }, + { "d", { + { "protocol", "udp" }, + { "data", { + { "address", discover_ip() }, + { "port", bound_port }, + { "mode", transport_encryption_protocol } + } + } + } + } + }).dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT); } } - break; + break; default: { log(ll_debug, "Unknown voice opcode " + std::to_string(op) + ": " + data); } - break; + break; } } return true; diff --git a/src/dpp/voice/enabled/opus.cpp b/src/dpp/voice/enabled/opus.cpp index 8e5c692da4..3964fd215b 100644 --- a/src/dpp/voice/enabled/opus.cpp +++ b/src/dpp/voice/enabled/opus.cpp @@ -26,6 +26,7 @@ #include #include +#include "../../dave/array_view.h" #include "../../dave/encryptor.h" #include "enabled.h" @@ -66,9 +67,7 @@ discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, opus_int32 encoded_audio_max_length = (opus_int32)length; std::vector encoded_audio(encoded_audio_max_length); size_t encoded_audio_length = encoded_audio_max_length; - encoded_audio_length = this->encode((uint8_t*)audio_data, length, encoded_audio.data(), encoded_audio_length); - send_audio_opus(encoded_audio.data(), encoded_audio_length); return *this; } @@ -125,7 +124,29 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet /* Append the 4 byte nonce to the resulting payload */ std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel)); - this->send(reinterpret_cast(payload.data()), payload.size(), duration); + if (this->is_end_to_end_encrypted()) { + + std::vector encrypted_buffer; + encrypted_buffer.resize(payload.size() * 2); + size_t out_size{0}; + + auto result = this->mls_state->encryptor->Encrypt( + dave::MediaType::Audio, + ssrc, + dave::make_array_view(payload.data(), payload.size()), + dave::make_array_view(encrypted_buffer), + &out_size + ); + if (result != dave::Encryptor::ResultCode::Success) { + log(ll_warning, "DAVE Encryption failure: " + std::to_string(result)); + } else { + std::cout << "In size: " << payload.size() << " enc: " << out_size << "\n"; + this->send(reinterpret_cast(encrypted_buffer.data()), out_size, duration); + } + } else { + this->send(reinterpret_cast(payload.data()), payload.size(), duration); + } + timestamp += frame_size; /* Increment for next packet */ diff --git a/src/dpp/voice/enabled/read_write.cpp b/src/dpp/voice/enabled/read_write.cpp index b4a5cec0c2..5cf85e96ff 100644 --- a/src/dpp/voice/enabled/read_write.cpp +++ b/src/dpp/voice/enabled/read_write.cpp @@ -56,7 +56,7 @@ void discord_voice_client::send(const char* packet, size_t len, uint64_t duratio } int discord_voice_client::udp_send(const char* data, size_t length) { - sockaddr_in servaddr; + sockaddr_in servaddr{}; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(this->port); diff --git a/testdata/Robot.pcm b/testdata/Robot.pcm index f9a7525d46..e7c167a754 100755 Binary files a/testdata/Robot.pcm and b/testdata/Robot.pcm differ