diff --git a/.gitignore b/.gitignore index 8202b82014..2a4acfebb7 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,9 @@ /xcodebuild /.vscode !webrtc/* +/tmp.patch +/out-release +/out-debug +/node_modules +/libwebrtc +/args.txt diff --git a/api/crypto/frame_crypto_transformer.cc b/api/crypto/frame_crypto_transformer.cc index 318b10cc31..323a7c53fc 100644 --- a/api/crypto/frame_crypto_transformer.cc +++ b/api/crypto/frame_crypto_transformer.cc @@ -82,6 +82,16 @@ const EVP_CIPHER* GetAesCbcAlgorithmFromKeySize(size_t key_size_bytes) { } } +std::string to_uint8_list(const uint8_t* data, int len) { + std::stringstream ss; + ss << "["; + for (int i = 0; i < len; i++) { + ss << static_cast(data[i]) << ","; + } + ss << "]"; + return ss.str(); +} + std::string to_hex(const uint8_t* data, int len) { std::stringstream ss; ss << std::uppercase << std::hex << std::setfill('0'); @@ -140,6 +150,31 @@ uint8_t get_unencrypted_bytes(webrtc::TransformableFrameInterface* frame, return unencrypted_bytes; } +int DerivePBKDF2KeyFromRawKey(const std::vector raw_key, + const std::vector& salt, + unsigned int optional_length_bits, + std::vector* derived_key) { + size_t key_size_bytes = optional_length_bits / 8; + derived_key->resize(key_size_bytes); + + if (PKCS5_PBKDF2_HMAC((const char*)raw_key.data(), raw_key.size(), + salt.data(), salt.size(), 100000, EVP_sha256(), + key_size_bytes, derived_key->data()) != 1) { + RTC_LOG(LS_ERROR) << "Failed to derive AES key from password."; + return ErrorUnexpected; + } + + RTC_LOG(LS_INFO) << "raw_key " + << to_uint8_list(raw_key.data(), raw_key.size()) << " len " + << raw_key.size() << " slat << " + << to_uint8_list(salt.data(), salt.size()) << " len " + << salt.size() << "\n derived_key " + << to_uint8_list(derived_key->data(), derived_key->size()) + << " len " << derived_key->size(); + + return Success; +} + int AesGcmEncryptDecrypt(EncryptOrDecrypt mode, const std::vector raw_key, const rtc::ArrayView data, @@ -255,12 +290,12 @@ FrameCryptorTransformer::FrameCryptorTransformer( const std::string participant_id, MediaType type, Algorithm algorithm, - rtc::scoped_refptr key_manager) + rtc::scoped_refptr key_provider) : participant_id_(participant_id), type_(type), algorithm_(algorithm), - key_manager_(key_manager) { - RTC_DCHECK(key_manager_ != nullptr); + key_provider_(key_provider) { + RTC_DCHECK(key_provider_ != nullptr); } void FrameCryptorTransformer::Transform( @@ -304,10 +339,11 @@ void FrameCryptorTransformer::encryptFrame( if (sink_callback == nullptr) { RTC_LOG(LS_WARNING) << "FrameCryptorTransformer::encryptFrame() sink_callback is NULL"; - if (last_enc_error_ != FrameCryptionError::kInternalError) { - last_enc_error_ = FrameCryptionError::kInternalError; + if (last_enc_error_ != FrameCryptionState::kInternalError) { + last_enc_error_ = FrameCryptionState::kInternalError; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_enc_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_enc_error_); } return; } @@ -318,21 +354,22 @@ void FrameCryptorTransformer::encryptFrame( return; } - auto keys = key_manager_->keys(participant_id_); - if (keys.size() == 0 || key_index_ >= (int)keys.size()) { + auto key_handler = key_provider_->GetKey(participant_id_); + if (key_handler == nullptr || key_handler->GetKeySet(key_index_) == nullptr) { RTC_LOG(LS_INFO) << "FrameCryptorTransformer::encryptFrame() no keys, or " "key_index[" << key_index_ << "] out of range for participant " << participant_id_; - if (keys.size() && last_enc_error_ != FrameCryptionError::kMissingKey) { - last_enc_error_ = FrameCryptionError::kMissingKey; + if (last_enc_error_ != FrameCryptionState::kMissingKey) { + last_enc_error_ = FrameCryptionState::kMissingKey; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_enc_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_enc_error_); } return; } - std::vector aes_key = keys[key_index_]; + auto key_set = key_handler->GetKeySet(key_index_); uint8_t unencrypted_bytes = get_unencrypted_bytes(frame.get(), type_); rtc::Buffer frameHeader(unencrypted_bytes); @@ -351,8 +388,9 @@ void FrameCryptorTransformer::encryptFrame( } std::vector buffer; - if (AesEncryptDecrypt(EncryptOrDecrypt::kEncrypt, algorithm_, aes_key, iv, - frameHeader, payload, &buffer) == Success) { + if (AesEncryptDecrypt(EncryptOrDecrypt::kEncrypt, algorithm_, + key_set->encryption_key, iv, frameHeader, payload, + &buffer) == Success) { rtc::Buffer encrypted_payload(buffer.data(), buffer.size()); rtc::Buffer data_out; data_out.AppendData(frameHeader); @@ -370,19 +408,23 @@ void FrameCryptorTransformer::encryptFrame( << static_cast(iv.size()) << " unencrypted_bytes=" << static_cast(unencrypted_bytes) << " keyIndex=" << static_cast(key_index_) - << " aesKey=" << to_hex(aes_key.data(), aes_key.size()) + << " aesKey=" + << to_hex(key_set->encryption_key.data(), + key_set->encryption_key.size()) << " iv=" << to_hex(iv.data(), iv.size()); - if (last_enc_error_ != FrameCryptionError::kOk) { - last_enc_error_ = FrameCryptionError::kOk; + if (last_enc_error_ != FrameCryptionState::kOk) { + last_enc_error_ = FrameCryptionState::kOk; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_enc_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_enc_error_); } sink_callback->OnTransformedFrame(std::move(frame)); } else { - if (last_enc_error_ != FrameCryptionError::kEncryptionFailed) { - last_enc_error_ = FrameCryptionError::kEncryptionFailed; + if (last_enc_error_ != FrameCryptionState::kEncryptionFailed) { + last_enc_error_ = FrameCryptionState::kEncryptionFailed; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_enc_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_enc_error_); } RTC_LOG(LS_ERROR) << "FrameCryptorTransformer::encryptFrame() failed"; } @@ -405,19 +447,53 @@ void FrameCryptorTransformer::decryptFrame( if (sink_callback == nullptr) { RTC_LOG(LS_WARNING) << "FrameCryptorTransformer::decryptFrame() sink_callback is NULL"; - if (last_dec_error_ != FrameCryptionError::kInternalError) { - last_dec_error_ = FrameCryptionError::kInternalError; + if (last_dec_error_ != FrameCryptionState::kInternalError) { + last_dec_error_ = FrameCryptionState::kInternalError; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_dec_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_dec_error_); } return; } rtc::ArrayView date_in = frame->GetData(); + if (date_in.size() == 0 || !enabled_cryption) { sink_callback->OnTransformedFrame(std::move(frame)); return; } + + auto uncrypted_magic_bytes = key_provider_->options().uncrypted_magic_bytes; + if (uncrypted_magic_bytes.size() > 0 && + date_in.size() >= uncrypted_magic_bytes.size() + 1) { + auto tmp = date_in.subview(date_in.size() - (uncrypted_magic_bytes.size() + 1), + uncrypted_magic_bytes.size()); + + + + if (uncrypted_magic_bytes == std::vector(tmp.begin(), tmp.end())) { + + RTC_CHECK_EQ(tmp.size(), uncrypted_magic_bytes.size()); + auto frame_type = date_in.subview(date_in.size() - 1, 1); + RTC_CHECK_EQ(frame_type.size(), 1); + + RTC_LOG(LS_INFO) << "FrameCryptorTransformer::uncrypted_magic_bytes( type " + << frame_type[0] << ", tmp " + << to_hex(tmp.data(), tmp.size()) << ", magic bytes " + << to_hex(uncrypted_magic_bytes.data(), + uncrypted_magic_bytes.size()) + << ")"; + + // magic bytes detected, this is a non-encrypted frame, skip frame decryption. + rtc::Buffer data_out; + data_out.AppendData( + date_in.subview(0, date_in.size() - uncrypted_magic_bytes.size() - 1)); + frame->SetData(data_out); + sink_callback->OnTransformedFrame(std::move(frame)); + return; + } + } + uint8_t unencrypted_bytes = get_unencrypted_bytes(frame.get(), type_); @@ -432,32 +508,36 @@ void FrameCryptorTransformer::decryptFrame( uint8_t ivLength = frameTrailer[0]; uint8_t key_index = frameTrailer[1]; - if(ivLength != getIvSize()) { + if (ivLength != getIvSize()) { RTC_LOG(LS_ERROR) << "FrameCryptorTransformer::decryptFrame() ivLength[" << static_cast(ivLength) << "] != getIvSize()[" << static_cast(getIvSize()) << "]"; - if (last_dec_error_ != FrameCryptionError::kDecryptionFailed) { - last_dec_error_ = FrameCryptionError::kDecryptionFailed; + if (last_dec_error_ != FrameCryptionState::kDecryptionFailed) { + last_dec_error_ = FrameCryptionState::kDecryptionFailed; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_dec_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_dec_error_); } return; } - auto keys = key_manager_->keys(participant_id_); - if (keys.size() == 0 || key_index >= (int)keys.size()) { + auto key_handler = key_provider_->GetKey(participant_id_); + if (key_index >= KEYRING_SIZE || key_handler == nullptr || + key_handler->GetKeySet(key_index) == nullptr) { RTC_LOG(LS_INFO) << "FrameCryptorTransformer::decryptFrame() no keys, or " "key_index[" << key_index_ << "] out of range for participant " << participant_id_; - if (last_dec_error_ != FrameCryptionError::kMissingKey) { - last_dec_error_ = FrameCryptionError::kMissingKey; + if (last_dec_error_ != FrameCryptionState::kMissingKey) { + last_dec_error_ = FrameCryptionState::kMissingKey; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_dec_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_dec_error_); } return; } - std::vector aes_key = keys[key_index]; + + auto key_set = key_handler->GetKeySet(key_index); rtc::Buffer iv = rtc::Buffer(ivLength); for (size_t i = 0; i < ivLength; i++) { @@ -470,35 +550,92 @@ void FrameCryptorTransformer::decryptFrame( encrypted_payload[i - unencrypted_bytes] = date_in[i]; } std::vector buffer; - if (AesEncryptDecrypt(EncryptOrDecrypt::kDecrypt, algorithm_, aes_key, iv, - frameHeader, encrypted_payload, &buffer) == Success) { - rtc::Buffer payload(buffer.data(), buffer.size()); - rtc::Buffer data_out; - data_out.AppendData(frameHeader); - data_out.AppendData(payload); - frame->SetData(data_out); - RTC_LOG(LS_INFO) << "FrameCryptorTransformer::decryptFrame() ivLength=" - << static_cast(ivLength) << " unencrypted_bytes=" - << static_cast(unencrypted_bytes) - << " keyIndex=" << static_cast(key_index_) - << " aesKey=" << to_hex(aes_key.data(), aes_key.size()) - << " iv=" << to_hex(iv.data(), iv.size()); + int ratchet_count = 0; + auto initialKeyMaterial = key_set->material; + bool decryption_success = false; + if (AesEncryptDecrypt(EncryptOrDecrypt::kDecrypt, algorithm_, + key_set->encryption_key, iv, frameHeader, + encrypted_payload, &buffer) == Success) { + decryption_success = true; + } else { + RTC_LOG(LS_ERROR) << "FrameCryptorTransformer::decryptFrame() failed"; + std::shared_ptr ratchetedKeySet; + auto currentKeyMaterial = key_set->material; + if (key_handler->options().ratchet_window_size > 0) { + while (ratchet_count < key_handler->options().ratchet_window_size) { + ratchet_count++; + + RTC_LOG(LS_INFO) << "ratcheting key attempt " << ratchet_count << " of " + << key_handler->options().ratchet_window_size; + + auto newMaterial = key_handler->RatchetKeyMaterial(currentKeyMaterial); + ratchetedKeySet = key_handler->DeriveKeys(newMaterial, key_handler->options().ratchet_salt, 128); + + if (AesEncryptDecrypt(EncryptOrDecrypt::kDecrypt, algorithm_, + ratchetedKeySet->encryption_key, iv, frameHeader, + encrypted_payload, &buffer) == Success) { + RTC_LOG(LS_INFO) << "FrameCryptorTransformer::decryptFrame() " + "ratcheted to keyIndex=" + << static_cast(key_index); + decryption_success = true; + // success, so we set the new key + key_handler->SetKeyFromMaterial(newMaterial, key_index); + if (last_dec_error_ != FrameCryptionState::kKeyRatcheted) { + last_dec_error_ = FrameCryptionState::kKeyRatcheted; + if (observer_) + observer_->OnFrameCryptionStateChanged(participant_id_, + last_dec_error_); + } + break; + } + // for the next ratchet attempt + currentKeyMaterial = newMaterial; + } - if (last_dec_error_ != FrameCryptionError::kOk) { - last_dec_error_ = FrameCryptionError::kOk; - if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_dec_error_); + /* Since the key it is first send and only afterwards actually used for + encrypting, there were situations when the decrypting failed due to the + fact that the received frame was not encrypted yet and ratcheting, of + course, did not solve the problem. So if we fail RATCHET_WINDOW_SIZE + times, we come back to the initial key. + */ + if (!decryption_success || + ratchet_count >= key_handler->options().ratchet_window_size) { + key_handler->SetKeyFromMaterial(initialKeyMaterial, key_index); + } } - sink_callback->OnTransformedFrame(std::move(frame)); - } else { - if (last_dec_error_ != FrameCryptionError::kDecryptionFailed) { - last_dec_error_ = FrameCryptionError::kDecryptionFailed; + } + + if (!decryption_success) { + if (last_dec_error_ != FrameCryptionState::kDecryptionFailed) { + last_dec_error_ = FrameCryptionState::kDecryptionFailed; if (observer_) - observer_->OnFrameCryptionError(participant_id_, last_dec_error_); + observer_->OnFrameCryptionStateChanged(participant_id_, + last_dec_error_); } - RTC_LOG(LS_ERROR) << "FrameCryptorTransformer::decryptFrame() failed"; + return; + } + + rtc::Buffer payload(buffer.data(), buffer.size()); + rtc::Buffer data_out; + data_out.AppendData(frameHeader); + data_out.AppendData(payload); + frame->SetData(data_out); + + RTC_LOG(LS_INFO) << "FrameCryptorTransformer::decryptFrame() ivLength=" + << static_cast(ivLength) << " unencrypted_bytes=" + << static_cast(unencrypted_bytes) + << " keyIndex=" << static_cast(key_index_) << " aesKey=" + << to_hex(key_set->encryption_key.data(), + key_set->encryption_key.size()) + << " iv=" << to_hex(iv.data(), iv.size()); + + if (last_dec_error_ != FrameCryptionState::kOk) { + last_dec_error_ = FrameCryptionState::kOk; + if (observer_) + observer_->OnFrameCryptionStateChanged(participant_id_, last_dec_error_); } + sink_callback->OnTransformedFrame(std::move(frame)); } rtc::Buffer FrameCryptorTransformer::makeIv(uint32_t ssrc, uint32_t timestamp) { diff --git a/api/crypto/frame_crypto_transformer.h b/api/crypto/frame_crypto_transformer.h index 68af609bbf..ebb5e004fc 100644 --- a/api/crypto/frame_crypto_transformer.h +++ b/api/crypto/frame_crypto_transformer.h @@ -17,39 +17,209 @@ #ifndef WEBRTC_FRAME_CRYPTOR_TRANSFORMER_H_ #define WEBRTC_FRAME_CRYPTOR_TRANSFORMER_H_ +#include + #include "api/frame_transformer_interface.h" #include "rtc_base/buffer.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/system/rtc_export.h" #include "rtc_base/thread.h" +int DerivePBKDF2KeyFromRawKey(const std::vector raw_key, + const std::vector& salt, + unsigned int optional_length_bits, + std::vector* derived_key); + namespace webrtc { -class KeyManager : public rtc::RefCountInterface { +const size_t KEYRING_SIZE = 16; + +struct KeyProviderOptions { + bool shared_key; + std::vector ratchet_salt; + std::vector uncrypted_magic_bytes; + int ratchet_window_size; + KeyProviderOptions() : shared_key(false), ratchet_window_size(0) {} + KeyProviderOptions(KeyProviderOptions& copy) + : shared_key(copy.shared_key), + ratchet_salt(copy.ratchet_salt), + uncrypted_magic_bytes(copy.uncrypted_magic_bytes), + ratchet_window_size(copy.ratchet_window_size) {} +}; + +class ParticipantKeyHandler { + public: + struct KeySet { + std::vector material; + std::vector encryption_key; + KeySet(std::vector material, std::vector encryptionKey) + : material(material), encryption_key(encryptionKey) {} + }; + + public: + ParticipantKeyHandler(KeyProviderOptions options) : options_(options) { + cryptoKeyRing_.resize(KEYRING_SIZE); + } + + virtual ~ParticipantKeyHandler() = default; + + virtual std::vector RatchetKey(int keyIndex) { + auto currentMaterial = GetKeySet(keyIndex)->material; + std::vector newMaterial; + if (DerivePBKDF2KeyFromRawKey(currentMaterial, options_.ratchet_salt, 256, + &newMaterial) != 0) { + return std::vector(); + } + SetKeyFromMaterial(newMaterial, + keyIndex != -1 ? keyIndex : currentKeyIndex); + return newMaterial; + } + + virtual std::shared_ptr GetKeySet(int keyIndex) { + return cryptoKeyRing_[keyIndex != -1 ? keyIndex : currentKeyIndex]; + } + + virtual void SetKeyFromMaterial(std::vector password, int keyIndex) { + if (keyIndex >= 0) { + currentKeyIndex = keyIndex % cryptoKeyRing_.size(); + } + cryptoKeyRing_[currentKeyIndex] = + DeriveKeys(password, options_.ratchet_salt, 128); + } + + virtual KeyProviderOptions& options() { return options_; } + + std::shared_ptr DeriveKeys(std::vector password, + std::vector ratchet_salt, + unsigned int optional_length_bits) { + std::vector derived_key; + if (DerivePBKDF2KeyFromRawKey(password, ratchet_salt, optional_length_bits, + &derived_key) == 0) { + return std::make_shared(password, derived_key); + } + return nullptr; + } + + std::vector RatchetKeyMaterial( + std::vector currentMaterial) { + std::vector newMaterial; + if (DerivePBKDF2KeyFromRawKey(currentMaterial, options_.ratchet_salt, 256, + &newMaterial) != 0) { + return std::vector(); + } + return newMaterial; + } + + private: + int currentKeyIndex = 0; + KeyProviderOptions options_; + std::vector> cryptoKeyRing_; +}; + +class KeyProvider : public rtc::RefCountInterface { public: enum { kRawKeySize = 32 }; public: - virtual const std::vector> keys( + virtual const std::shared_ptr GetKey( const std::string participant_id) const = 0; + virtual bool SetKey(const std::string participant_id, + int index, + std::vector key) = 0; + + virtual const std::vector RatchetKey( + const std::string participant_id, + int key_index) = 0; + + virtual const std::vector ExportKey(const std::string participant_id, + int key_index) const = 0; + + virtual KeyProviderOptions& options() = 0; + protected: - virtual ~KeyManager() {} + virtual ~KeyProvider() {} }; -enum FrameCryptionError { +class DefaultKeyProviderImpl : public KeyProvider { + public: + DefaultKeyProviderImpl(KeyProviderOptions options) : options_(options) {} + ~DefaultKeyProviderImpl() override = default; + + /// Set the key at the given index. + bool SetKey(const std::string participant_id, + int index, + std::vector key) override { + webrtc::MutexLock lock(&mutex_); + + if (keys_.find(participant_id) == keys_.end()) { + keys_[participant_id] = std::make_shared(options_); + } + + auto keyHandler = keys_[participant_id]; + keyHandler->SetKeyFromMaterial(key, index); + + return true; + } + + const std::shared_ptr GetKey( + const std::string participant_id) const override { + webrtc::MutexLock lock(&mutex_); + if (keys_.find(participant_id) == keys_.end()) { + return nullptr; + } + + return keys_.find(participant_id)->second; + } + + const std::vector RatchetKey(const std::string participant_id, + int key_index) override { + webrtc::MutexLock lock(&mutex_); + if (keys_.find(participant_id) == keys_.end()) { + return std::vector(); + } + + return keys_[participant_id]->RatchetKey(key_index); + } + + const std::vector ExportKey(const std::string participant_id, + int key_index) const override { + webrtc::MutexLock lock(&mutex_); + if (keys_.find(participant_id) == keys_.end()) { + return std::vector(); + } + + auto keySet = GetKey(participant_id); + + if (!keySet) { + return std::vector(); + } + + return keySet->GetKeySet(key_index)->material; + } + + KeyProviderOptions& options() override { return options_; } + + private: + mutable webrtc::Mutex mutex_; + KeyProviderOptions options_; + std::unordered_map> keys_; +}; + +enum FrameCryptionState { kNew = 0, kOk, kEncryptionFailed, kDecryptionFailed, kMissingKey, + kKeyRatcheted, kInternalError, }; class FrameCryptorTransformerObserver { public: - virtual void OnFrameCryptionError(const std::string participant_id, - FrameCryptionError error) = 0; + virtual void OnFrameCryptionStateChanged(const std::string participant_id, + FrameCryptionState error) = 0; protected: virtual ~FrameCryptorTransformerObserver() {} @@ -71,7 +241,7 @@ class RTC_EXPORT FrameCryptorTransformer explicit FrameCryptorTransformer(const std::string participant_id, MediaType type, Algorithm algorithm, - rtc::scoped_refptr key_manager); + rtc::scoped_refptr key_provider); virtual void SetFrameCryptorTransformerObserver( FrameCryptorTransformerObserver* observer) { @@ -85,6 +255,7 @@ class RTC_EXPORT FrameCryptorTransformer } virtual int key_index() const { return key_index_; }; + virtual void SetEnabled(bool enabled) { webrtc::MutexLock lock(&mutex_); enabled_cryption_ = enabled; @@ -140,11 +311,11 @@ class RTC_EXPORT FrameCryptorTransformer sink_callbacks_; int key_index_ = 0; std::map sendCounts_; - rtc::scoped_refptr key_manager_; + rtc::scoped_refptr key_provider_; FrameCryptorTransformerObserver* observer_ = nullptr; std::unique_ptr thread_; - FrameCryptionError last_enc_error_ = FrameCryptionError::kNew; - FrameCryptionError last_dec_error_ = FrameCryptionError::kNew; + FrameCryptionState last_enc_error_ = FrameCryptionState::kNew; + FrameCryptionState last_dec_error_ = FrameCryptionState::kNew; }; } // namespace webrtc diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 3d3741025a..252d92e81a 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -1020,9 +1020,9 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCFrameCryptor+Private.h", "objc/api/peerconnection/RTCFrameCryptor.h", "objc/api/peerconnection/RTCFrameCryptor.mm", - "objc/api/peerconnection/RTCFrameCryptorKeyManager+Private.h", - "objc/api/peerconnection/RTCFrameCryptorKeyManager.h", - "objc/api/peerconnection/RTCFrameCryptorKeyManager.mm", + "objc/api/peerconnection/RTCFrameCryptorKeyProvider+Private.h", + "objc/api/peerconnection/RTCFrameCryptorKeyProvider.h", + "objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm", "objc/api/peerconnection/RTCIceCandidate+Private.h", "objc/api/peerconnection/RTCIceCandidate.h", "objc/api/peerconnection/RTCIceCandidate.mm", @@ -1381,7 +1381,7 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCDataChannel.h", "objc/api/peerconnection/RTCDataChannelConfiguration.h", "objc/api/peerconnection/RTCFrameCryptor.h", - "objc/api/peerconnection/RTCFrameCryptorKeyManager.h", + "objc/api/peerconnection/RTCFrameCryptorKeyProvider.h", "objc/api/peerconnection/RTCFieldTrials.h", "objc/api/peerconnection/RTCIceCandidate.h", "objc/api/peerconnection/RTCIceCandidateErrorEvent.h", @@ -1506,7 +1506,7 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCDataChannelConfiguration.h", "objc/api/peerconnection/RTCDtmfSender.h", "objc/api/peerconnection/RTCFrameCryptor.h", - "objc/api/peerconnection/RTCFrameCryptorKeyManager.h", + "objc/api/peerconnection/RTCFrameCryptorKeyProvider.h", "objc/api/peerconnection/RTCFieldTrials.h", "objc/api/peerconnection/RTCIceCandidate.h", "objc/api/peerconnection/RTCIceCandidateErrorEvent.h", diff --git a/sdk/android/BUILD.gn b/sdk/android/BUILD.gn index 0c761f0943..8fe98cb2b0 100644 --- a/sdk/android/BUILD.gn +++ b/sdk/android/BUILD.gn @@ -290,7 +290,7 @@ if (is_android) { "api/org/webrtc/FrameCryptor.java", "api/org/webrtc/FrameCryptorAlgorithm.java", "api/org/webrtc/FrameCryptorFactory.java", - "api/org/webrtc/FrameCryptorKeyManager.java", + "api/org/webrtc/FrameCryptorKeyProvider.java", "api/org/webrtc/RtpCapabilities.java", "api/org/webrtc/RtpParameters.java", "api/org/webrtc/RtpReceiver.java", @@ -742,8 +742,8 @@ if (current_os == "linux" || is_android) { "src/jni/pc/dtmf_sender.cc", "src/jni/pc/frame_cryptor.cc", "src/jni/pc/frame_cryptor.h", - "src/jni/pc/frame_cryptor_key_manager.cc", - "src/jni/pc/frame_cryptor_key_manager.h", + "src/jni/pc/frame_cryptor_key_provider.cc", + "src/jni/pc/frame_cryptor_key_provider.h", "src/jni/pc/ice_candidate.cc", "src/jni/pc/ice_candidate.h", "src/jni/pc/media_constraints.cc", @@ -1425,7 +1425,7 @@ if (current_os == "linux" || is_android) { "api/org/webrtc/DtmfSender.java", "api/org/webrtc/FrameCryptor.java", "api/org/webrtc/FrameCryptorFactory.java", - "api/org/webrtc/FrameCryptorKeyManager.java", + "api/org/webrtc/FrameCryptorKeyProvider.java", "api/org/webrtc/IceCandidate.java", "api/org/webrtc/IceCandidateErrorEvent.java", "api/org/webrtc/MediaConstraints.java", diff --git a/sdk/android/api/org/webrtc/FrameCryptor.java b/sdk/android/api/org/webrtc/FrameCryptor.java index f7ccd8fb86..d633e05005 100644 --- a/sdk/android/api/org/webrtc/FrameCryptor.java +++ b/sdk/android/api/org/webrtc/FrameCryptor.java @@ -19,24 +19,24 @@ import androidx.annotation.Nullable; public class FrameCryptor { - - public enum FrameCryptorErrorState { + public enum FrameCryptionState { NEW, OK, ENCRYPTIONFAILED, DECRYPTIONFAILED, MISSINGKEY, + KEYRATCHETED, INTERNALERROR; - @CalledByNative("FrameCryptorErrorState") - static FrameCryptorErrorState fromNativeIndex(int nativeIndex) { + @CalledByNative("FrameCryptionState") + static FrameCryptionState fromNativeIndex(int nativeIndex) { return values()[nativeIndex]; } } public static interface Observer { @CalledByNative("Observer") - void onFrameCryptorErrorState(String participantId, FrameCryptorErrorState newState); + void onFrameCryptionStateChanged(String participantId, FrameCryptionState newState); } private long nativeFrameCryptor; @@ -74,23 +74,23 @@ public void setKeyIndex(int index) { public void dispose() { checkFrameCryptorExists(); + nativeUnSetObserver(nativeFrameCryptor); JniCommon.nativeReleaseRef(nativeFrameCryptor); nativeFrameCryptor = 0; - if(observerPtr != 0) { + if (observerPtr != 0) { JniCommon.nativeReleaseRef(observerPtr); observerPtr = 0; } - nativeUnSetObserver(nativeFrameCryptor); } public void setObserver(@Nullable Observer observer) { checkFrameCryptorExists(); long newPtr = nativeSetObserver(nativeFrameCryptor, observer); - if(observerPtr != 0) { + if (observerPtr != 0) { JniCommon.nativeReleaseRef(observerPtr); observerPtr = 0; } - newPtr= observerPtr; + newPtr = observerPtr; } private void checkFrameCryptorExists() { diff --git a/sdk/android/api/org/webrtc/FrameCryptorFactory.java b/sdk/android/api/org/webrtc/FrameCryptorFactory.java index 59f4bafdfd..74df6a5b29 100644 --- a/sdk/android/api/org/webrtc/FrameCryptorFactory.java +++ b/sdk/android/api/org/webrtc/FrameCryptorFactory.java @@ -17,26 +17,28 @@ package org.webrtc; public class FrameCryptorFactory { - public static FrameCryptorKeyManager createFrameCryptorKeyManager() { - return nativeCreateFrameCryptorKeyManager(); + public static FrameCryptorKeyProvider createFrameCryptorKeyProvider( + boolean sharedKey, byte[] ratchetSalt, int ratchetWindowSize, byte[] uncryptedMagicBytes) { + return nativeCreateFrameCryptorKeyProvider(sharedKey, ratchetSalt, ratchetWindowSize, uncryptedMagicBytes); } public static FrameCryptor createFrameCryptorForRtpSender(RtpSender rtpSender, - String participantId, FrameCryptorAlgorithm algorithm, FrameCryptorKeyManager keyManager) { + String participantId, FrameCryptorAlgorithm algorithm, FrameCryptorKeyProvider keyProvider) { return nativeCreateFrameCryptorForRtpSender(rtpSender.getNativeRtpSender(), participantId, - algorithm.ordinal(), keyManager.getNativeKeyManager()); + algorithm.ordinal(), keyProvider.getNativeKeyProvider()); } public static FrameCryptor createFrameCryptorForRtpReceiver(RtpReceiver rtpReceiver, - String participantId, FrameCryptorAlgorithm algorithm, FrameCryptorKeyManager keyManager) { + String participantId, FrameCryptorAlgorithm algorithm, FrameCryptorKeyProvider keyProvider) { return nativeCreateFrameCryptorForRtpReceiver(rtpReceiver.getNativeRtpReceiver(), participantId, - algorithm.ordinal(), keyManager.getNativeKeyManager()); + algorithm.ordinal(), keyProvider.getNativeKeyProvider()); } private static native FrameCryptor nativeCreateFrameCryptorForRtpSender( - long rtpSender, String participantId, int algorithm, long nativeFrameCryptorKeyManager); + long rtpSender, String participantId, int algorithm, long nativeFrameCryptorKeyProvider); private static native FrameCryptor nativeCreateFrameCryptorForRtpReceiver( - long rtpReceiver, String participantId, int algorithm, long nativeFrameCryptorKeyManager); + long rtpReceiver, String participantId, int algorithm, long nativeFrameCryptorKeyProvider); - private static native FrameCryptorKeyManager nativeCreateFrameCryptorKeyManager(); + private static native FrameCryptorKeyProvider nativeCreateFrameCryptorKeyProvider( + boolean sharedKey, byte[] ratchetSalt, int ratchetWindowSize, byte[] uncryptedMagicBytes); } diff --git a/sdk/android/api/org/webrtc/FrameCryptorKeyManager.java b/sdk/android/api/org/webrtc/FrameCryptorKeyManager.java deleted file mode 100644 index a899136904..0000000000 --- a/sdk/android/api/org/webrtc/FrameCryptorKeyManager.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2022 LiveKit - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.webrtc; - -import java.util.ArrayList; - -public class FrameCryptorKeyManager { - private long nativeKeyManager; - - @CalledByNative - public FrameCryptorKeyManager(long nativeKeyManager) { - this.nativeKeyManager = nativeKeyManager; - } - - public long getNativeKeyManager() { - return nativeKeyManager; - } - - public boolean setKey(String participantId, int index, byte[] key) { - return nativeSetKey(nativeKeyManager, participantId, index, key); - } - - public boolean setKeys(String participantId, ArrayList keys) { - return nativeSetKeys(nativeKeyManager, participantId, keys); - } - - public ArrayList getKeys(String participantId) { - return nativeGetKeys(nativeKeyManager, participantId); - } - - public void dispose() { - checkKeyManagerExists(); - JniCommon.nativeReleaseRef(nativeKeyManager); - nativeKeyManager = 0; - } - - private void checkKeyManagerExists() { - if (nativeKeyManager == 0) { - throw new IllegalStateException("FrameCryptorKeyManager has been disposed."); - } - } - - private static native long createNativeKeyManager(); - private static native boolean nativeSetKey( - long keyManagerPointer, String participantId, int index, byte[] key); - private static native boolean nativeSetKeys( - long keyManagerPointer, String participantId, ArrayList keys); - private static native ArrayList nativeGetKeys( - long keyManagerPointer, String participantId); -} \ No newline at end of file diff --git a/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java b/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java new file mode 100644 index 0000000000..1c89eac55b --- /dev/null +++ b/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java @@ -0,0 +1,66 @@ +/* + * Copyright 2022 LiveKit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.webrtc; + +import java.util.ArrayList; + +public class FrameCryptorKeyProvider { + private long nativeKeyProvider; + + @CalledByNative + public FrameCryptorKeyProvider(long nativeKeyProvider) { + this.nativeKeyProvider = nativeKeyProvider; + } + + public long getNativeKeyProvider() { + return nativeKeyProvider; + } + + public boolean setKey(String participantId, int index, byte[] key) { + checkKeyProviderExists(); + return nativeSetKey(nativeKeyProvider, participantId, index, key); + } + + public byte[] ratchetKey(String participantId, int index) { + checkKeyProviderExists(); + return nativeRatchetKey(nativeKeyProvider, participantId, index); + } + + public byte[] exportKey(String participantId, int index) { + checkKeyProviderExists(); + return nativeExportKey(nativeKeyProvider, participantId, index); + } + + public void dispose() { + checkKeyProviderExists(); + JniCommon.nativeReleaseRef(nativeKeyProvider); + nativeKeyProvider = 0; + } + + private void checkKeyProviderExists() { + if (nativeKeyProvider == 0) { + throw new IllegalStateException("FrameCryptorKeyProvider has been disposed."); + } + } + + private static native boolean nativeSetKey( + long keyProviderPointer, String participantId, int index, byte[] key); + private static native byte[] nativeRatchetKey( + long keyProviderPointer, String participantId, int index); + private static native byte[] nativeExportKey( + long keyProviderPointer, String participantId, int index); +} \ No newline at end of file diff --git a/sdk/android/src/jni/pc/frame_cryptor.cc b/sdk/android/src/jni/pc/frame_cryptor.cc index 570e6a4e4b..d02f0c62da 100644 --- a/sdk/android/src/jni/pc/frame_cryptor.cc +++ b/sdk/android/src/jni/pc/frame_cryptor.cc @@ -22,7 +22,7 @@ #include "sdk/android/generated_peerconnection_jni/FrameCryptor_jni.h" #include "sdk/android/native_api/jni/java_types.h" #include "sdk/android/src/jni/jni_helpers.h" -#include "sdk/android/src/jni/pc/frame_cryptor_key_manager.h" +#include "sdk/android/src/jni/pc/frame_cryptor_key_provider.h" namespace webrtc { namespace jni { @@ -34,13 +34,13 @@ FrameCryptorObserverJni::FrameCryptorObserverJni( FrameCryptorObserverJni::~FrameCryptorObserverJni() {} -void FrameCryptorObserverJni::OnFrameCryptionError( +void FrameCryptorObserverJni::OnFrameCryptionStateChanged( const std::string participant_id, - FrameCryptionError new_state) { + FrameCryptionState new_state) { JNIEnv* env = AttachCurrentThreadIfNeeded(); - Java_Observer_onFrameCryptorErrorState( + Java_Observer_onFrameCryptionStateChanged( env, j_observer_global_, NativeToJavaString(env, participant_id), - Java_FrameCryptorErrorState_fromNativeIndex(env, new_state)); + Java_FrameCryptionState_fromNativeIndex(env, new_state)); } ScopedJavaLocalRef NativeToJavaFrameCryptor( @@ -84,19 +84,20 @@ static jlong JNI_FrameCryptor_SetObserver( JNIEnv* jni, jlong j_frame_cryptor_pointer, const JavaParamRef& j_observer) { - auto observer = rtc::make_ref_counted(jni, j_observer); + auto observer = + rtc::make_ref_counted(jni, j_observer); observer->AddRef(); reinterpret_cast(j_frame_cryptor_pointer) ->SetFrameCryptorTransformerObserver(observer.get()); - return jlongFromPointer(observer.get()); + return jlongFromPointer(observer.get()); } static void JNI_FrameCryptor_UnSetObserver(JNIEnv* jni, - jlong j_frame_cryptor_pointer) { - reinterpret_cast(j_frame_cryptor_pointer)->SetFrameCryptorTransformerObserver(nullptr); + jlong j_frame_cryptor_pointer) { + reinterpret_cast(j_frame_cryptor_pointer) + ->SetFrameCryptorTransformerObserver(nullptr); } - webrtc::FrameCryptorTransformer::Algorithm AlgorithmFromIndex(int index) { switch (index) { case 0: @@ -114,8 +115,9 @@ JNI_FrameCryptorFactory_CreateFrameCryptorForRtpReceiver( jlong j_rtp_receiver_pointer, const base::android::JavaParamRef& participantId, jint j_algorithm_index, - jlong j_key_manager) { - auto keyManager = reinterpret_cast(j_key_manager); + jlong j_key_provider) { + auto keyProvider = + reinterpret_cast(j_key_provider); auto participant_id = JavaToStdString(env, participantId); auto rtpReceiver = reinterpret_cast(j_rtp_receiver_pointer); @@ -127,7 +129,7 @@ JNI_FrameCryptorFactory_CreateFrameCryptorForRtpReceiver( rtc::scoped_refptr( new webrtc::FrameCryptorTransformer( participant_id, mediaType, AlgorithmFromIndex(j_algorithm_index), - rtc::scoped_refptr(keyManager))); + rtc::scoped_refptr(keyProvider))); rtpReceiver->SetDepacketizerToDecoderFrameTransformer( frame_crypto_transformer); @@ -142,8 +144,9 @@ JNI_FrameCryptorFactory_CreateFrameCryptorForRtpSender( jlong j_rtp_sender_pointer, const base::android::JavaParamRef& participantId, jint j_algorithm_index, - jlong j_key_manager) { - auto keyManager = reinterpret_cast(j_key_manager); + jlong j_key_provider) { + auto keyProvider = + reinterpret_cast(j_key_provider); auto rtpSender = reinterpret_cast(j_rtp_sender_pointer); auto participant_id = JavaToStdString(env, participantId); auto mediaType = @@ -154,7 +157,7 @@ JNI_FrameCryptorFactory_CreateFrameCryptorForRtpSender( rtc::scoped_refptr( new webrtc::FrameCryptorTransformer( participant_id, mediaType, AlgorithmFromIndex(j_algorithm_index), - rtc::scoped_refptr(keyManager))); + rtc::scoped_refptr(keyProvider))); rtpSender->SetEncoderToPacketizerFrameTransformer(frame_crypto_transformer); frame_crypto_transformer->SetEnabled(false); @@ -163,9 +166,24 @@ JNI_FrameCryptorFactory_CreateFrameCryptorForRtpSender( } static base::android::ScopedJavaLocalRef -JNI_FrameCryptorFactory_CreateFrameCryptorKeyManager(JNIEnv* env) { - return NativeToJavaFrameCryptorKeyManager( - env, rtc::make_ref_counted()); +JNI_FrameCryptorFactory_CreateFrameCryptorKeyProvider( + JNIEnv* env, + jboolean j_shared, + const base::android::JavaParamRef& j_ratchetSalt, + jint j_ratchetWindowSize, + const base::android::JavaParamRef& j_uncryptedMagicBytes) { + auto ratchetSalt = JavaToNativeByteArray(env, j_ratchetSalt); + KeyProviderOptions options; + options.ratchet_salt = + std::vector(ratchetSalt.begin(), ratchetSalt.end()); + options.ratchet_window_size = j_ratchetWindowSize; + + auto uncryptedMagicBytes = JavaToNativeByteArray(env, j_uncryptedMagicBytes); + options.uncrypted_magic_bytes = + std::vector(uncryptedMagicBytes.begin(), uncryptedMagicBytes.end()); + options.shared_key = j_shared; + return NativeToJavaFrameCryptorKeyProvider( + env, rtc::make_ref_counted(options)); } } // namespace jni diff --git a/sdk/android/src/jni/pc/frame_cryptor.h b/sdk/android/src/jni/pc/frame_cryptor.h index 14f87d00d9..66645bb33c 100644 --- a/sdk/android/src/jni/pc/frame_cryptor.h +++ b/sdk/android/src/jni/pc/frame_cryptor.h @@ -29,14 +29,15 @@ ScopedJavaLocalRef NativeToJavaFrameCryptor( JNIEnv* env, rtc::scoped_refptr cryptor); -class FrameCryptorObserverJni : public FrameCryptorTransformerObserver, public rtc::RefCountInterface { +class FrameCryptorObserverJni : public FrameCryptorTransformerObserver, + public rtc::RefCountInterface { public: FrameCryptorObserverJni(JNIEnv* jni, const JavaRef& j_observer); ~FrameCryptorObserverJni() override; protected: - void OnFrameCryptionError(const std::string participant_id, - FrameCryptionError error) override; + void OnFrameCryptionStateChanged(const std::string participant_id, + FrameCryptionState state) override; private: const ScopedJavaGlobalRef j_observer_global_; diff --git a/sdk/android/src/jni/pc/frame_cryptor_key_manager.cc b/sdk/android/src/jni/pc/frame_cryptor_key_manager.cc deleted file mode 100644 index a86c27ef7d..0000000000 --- a/sdk/android/src/jni/pc/frame_cryptor_key_manager.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2022 LiveKit - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "sdk/android/src/jni/pc/frame_cryptor_key_manager.h" - -#include "sdk/android/generated_peerconnection_jni/FrameCryptorKeyManager_jni.h" -#include "sdk/android/native_api/jni/java_types.h" -#include "sdk/android/src/jni/jni_helpers.h" - -namespace webrtc { -namespace jni { - -ScopedJavaLocalRef NativeToJavaFrameCryptorKeyManager( - JNIEnv* env, - rtc::scoped_refptr key_manager) { - if (!key_manager) - return nullptr; - // Sender is now owned by the Java object, and will be freed from - // FrameCryptorKeyManager.dispose(). - return Java_FrameCryptorKeyManager_Constructor( - env, jlongFromPointer(key_manager.release())); -} - -static jboolean JNI_FrameCryptorKeyManager_SetKey( - JNIEnv* jni, - jlong j_key_manager, - const base::android::JavaParamRef& participantId, - jint j_index, - const base::android::JavaParamRef& j_key) { - auto key = JavaToNativeByteArray(jni, j_key); - auto participant_id = JavaToStdString(jni, participantId); - return reinterpret_cast(j_key_manager) - ->SetKey(participant_id, j_index, - std::vector(key.begin(), key.end())); -} - -static jboolean JNI_FrameCryptorKeyManager_SetKeys( - JNIEnv* env, - jlong keyManagerPointer, - const base::android::JavaParamRef& participantId, - const base::android::JavaParamRef& keys) { - auto participant_id = JavaToStdString(env, participantId); - auto key_manager = - reinterpret_cast(keyManagerPointer); - auto keys_size = env->GetArrayLength((jobjectArray)keys.obj()); - std::vector> keys_vector; - for (int i = 0; i < keys_size; i++) { - auto key = JavaToNativeByteArray( - env, base::android::JavaParamRef( - env, (jbyteArray)env->GetObjectArrayElement( - (jobjectArray)keys.obj(), i))); - keys_vector.push_back(std::vector(key.begin(), key.end())); - } - return key_manager->SetKeys(participant_id, keys_vector); -} - -static ScopedJavaLocalRef JNI_FrameCryptorKeyManager_GetKeys( - JNIEnv* jni, - jlong j_key_manager, - const base::android::JavaParamRef& participantId) { - auto participant_id = JavaToStdString(jni, participantId); - auto keys = reinterpret_cast(j_key_manager) - ->keys(participant_id); - JavaListBuilder j_keys(jni); - for (size_t i = 0; i < keys.size(); i++) { - auto uint8Key = keys[i]; - std::vector int8tKey = - std::vector(uint8Key.begin(), uint8Key.end()); - auto j_key = NativeToJavaByteArray(jni, rtc::ArrayView(int8tKey)); - j_keys.add(j_key); - } - return j_keys.java_list(); -} - -} // namespace jni -} // namespace webrtc diff --git a/sdk/android/src/jni/pc/frame_cryptor_key_manager.h b/sdk/android/src/jni/pc/frame_cryptor_key_manager.h deleted file mode 100644 index 9a6e59470c..0000000000 --- a/sdk/android/src/jni/pc/frame_cryptor_key_manager.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2022 LiveKit - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SDK_ANDROID_SRC_JNI_PC_FRAME_CRYPTOR_KEY_MANAGER_H_ -#define SDK_ANDROID_SRC_JNI_PC_FRAME_CRYPTOR_KEY_MANAGER_H_ - -#include - -#include "api/crypto/frame_crypto_transformer.h" -#include "sdk/android/native_api/jni/scoped_java_ref.h" - -namespace webrtc { -namespace jni { - -class DefaultKeyManagerImpl : public webrtc::KeyManager { - public: - DefaultKeyManagerImpl() = default; - ~DefaultKeyManagerImpl() override = default; - - /// Set the key at the given index. - bool SetKey(const std::string participant_id, - int index, - std::vector key) { - webrtc::MutexLock lock(&mutex_); - - if (keys_.find(participant_id) == keys_.end()) { - keys_[participant_id] = std::vector>(); - } - - if (index + 1 > (int)keys_[participant_id].size()) { - keys_[participant_id].resize(index + 1); - } - - keys_[participant_id][index] = key; - return true; - } - - /// Set the keys. - bool SetKeys(const std::string participant_id, - std::vector> keys) { - webrtc::MutexLock lock(&mutex_); - keys_[participant_id] = keys; - return true; - } - - const std::vector> keys( - const std::string participant_id) const override { - webrtc::MutexLock lock(&mutex_); - if (keys_.find(participant_id) == keys_.end()) { - return std::vector>(); - } - - return keys_.find(participant_id)->second; - } - - private: - mutable webrtc::Mutex mutex_; - std::map>> keys_; -}; - -ScopedJavaLocalRef NativeToJavaFrameCryptorKeyManager( - JNIEnv* env, - rtc::scoped_refptr cryptor); - -} // namespace jni -} // namespace webrtc - -#endif // SDK_ANDROID_SRC_JNI_PC_FRAME_CRYPTOR_KEY_MANAGER_H_ diff --git a/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc b/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc new file mode 100644 index 0000000000..2732693c0f --- /dev/null +++ b/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc @@ -0,0 +1,79 @@ +/* + * Copyright 2022 LiveKit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "sdk/android/src/jni/pc/frame_cryptor_key_provider.h" + +#include "sdk/android/generated_peerconnection_jni/FrameCryptorKeyProvider_jni.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/src/jni/jni_helpers.h" + +namespace webrtc { +namespace jni { + +ScopedJavaLocalRef NativeToJavaFrameCryptorKeyProvider( + JNIEnv* env, + rtc::scoped_refptr key_provider) { + if (!key_provider) + return nullptr; + // Sender is now owned by the Java object, and will be freed from + // FrameCryptorKeyProvider.dispose(). + return Java_FrameCryptorKeyProvider_Constructor( + env, jlongFromPointer(key_provider.release())); +} + +static jboolean JNI_FrameCryptorKeyProvider_SetKey( + JNIEnv* jni, + jlong j_key_provider, + const base::android::JavaParamRef& participantId, + jint j_index, + const base::android::JavaParamRef& j_key) { + auto key = JavaToNativeByteArray(jni, j_key); + auto participant_id = JavaToStdString(jni, participantId); + return reinterpret_cast(j_key_provider) + ->SetKey(participant_id, j_index, + std::vector(key.begin(), key.end())); +} + +static base::android::ScopedJavaLocalRef +JNI_FrameCryptorKeyProvider_RatchetKey( + JNIEnv* env, + jlong keyProviderPointer, + const base::android::JavaParamRef& participantId, + jint j_index) { + auto participant_id = JavaToStdString(env, participantId); + auto key_provider = + reinterpret_cast(keyProviderPointer); + auto newKey = key_provider->RatchetKey(participant_id, j_index); + std::vector int8tKey = + std::vector(newKey.begin(), newKey.end()); + return NativeToJavaByteArray(env, rtc::ArrayView(int8tKey)); +} + +static base::android::ScopedJavaLocalRef +JNI_FrameCryptorKeyProvider_ExportKey( + JNIEnv* env, + jlong keyProviderPointer, + const base::android::JavaParamRef& participantId, + jint j_index) { + auto participant_id = JavaToStdString(env, participantId); + auto key_provider = + reinterpret_cast(keyProviderPointer); + auto key = key_provider->ExportKey(participant_id, j_index); + std::vector int8tKey = std::vector(key.begin(), key.end()); + return NativeToJavaByteArray(env, rtc::ArrayView(int8tKey)); +} + +} // namespace jni +} // namespace webrtc diff --git a/sdk/android/src/jni/pc/frame_cryptor_key_provider.h b/sdk/android/src/jni/pc/frame_cryptor_key_provider.h new file mode 100644 index 0000000000..8832a83035 --- /dev/null +++ b/sdk/android/src/jni/pc/frame_cryptor_key_provider.h @@ -0,0 +1,35 @@ +/* + * Copyright 2022 LiveKit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SDK_ANDROID_SRC_JNI_PC_FRAME_CRYPTOR_KEY_PROVIDER_H_ +#define SDK_ANDROID_SRC_JNI_PC_FRAME_CRYPTOR_KEY_PROVIDER_H_ + +#include + +#include "api/crypto/frame_crypto_transformer.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +namespace webrtc { +namespace jni { + +ScopedJavaLocalRef NativeToJavaFrameCryptorKeyProvider( + JNIEnv* env, + rtc::scoped_refptr cryptor); + +} // namespace jni +} // namespace webrtc + +#endif // SDK_ANDROID_SRC_JNI_PC_FRAME_CRYPTOR_KEY_PROVIDER_H_ diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptor+Private.h b/sdk/objc/api/peerconnection/RTCFrameCryptor+Private.h index 6fa9a01369..86e6fdff8c 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptor+Private.h +++ b/sdk/objc/api/peerconnection/RTCFrameCryptor+Private.h @@ -16,15 +16,15 @@ #import "RTCFrameCryptor.h" -#include "api/crypto/frame_crypto_transformer.h" #include +#include "api/crypto/frame_crypto_transformer.h" NS_ASSUME_NONNULL_BEGIN @interface RTC_OBJC_TYPE (RTCFrameCryptor) () -@end + @end namespace webrtc { @@ -33,13 +33,13 @@ class RTCFrameCryptorDelegateAdapter : public FrameCryptorTransformerObserver { RTCFrameCryptorDelegateAdapter(RTC_OBJC_TYPE(RTCFrameCryptor) * frameCryptor); ~RTCFrameCryptorDelegateAdapter() override; - void OnFrameCryptionError(const std::string participant_id, - FrameCryptionError error) override; + void OnFrameCryptionStateChanged(const std::string participant_id, + FrameCryptionState state) override; private: __weak RTC_OBJC_TYPE(RTCFrameCryptor) * frame_cryptor_; }; -} +} // namespace webrtc NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptor.h b/sdk/objc/api/peerconnection/RTCFrameCryptor.h index 8496a33412..6712ca3688 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptor.h +++ b/sdk/objc/api/peerconnection/RTCFrameCryptor.h @@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN @class RTC_OBJC_TYPE(RTCRtpSender); @class RTC_OBJC_TYPE(RTCRtpReceiver); -@class RTC_OBJC_TYPE(RTCFrameCryptorKeyManager); +@class RTC_OBJC_TYPE(RTCFrameCryptorKeyProvider); @class RTC_OBJC_TYPE(RTCFrameCryptor); typedef NS_ENUM(NSUInteger, RTCCyrptorAlgorithm) { @@ -30,13 +30,14 @@ typedef NS_ENUM(NSUInteger, RTCCyrptorAlgorithm) { RTCCyrptorAlgorithmAesCbc, }; -typedef NS_ENUM(NSInteger, RTCFrameCryptorErrorState) { - RTCFrameCryptorErrorStateNew = 0, - RTCFrameCryptorErrorStateOk, - RTCFrameCryptorErrorStateEncryptionFailed, - RTCFrameCryptorErrorStateDecryptionFailed, - RTCFrameCryptorErrorStateMissingKey, - RTCFrameCryptorErrorStateInternalError, +typedef NS_ENUM(NSInteger, FrameCryptionState) { + FrameCryptionStateNew = 0, + FrameCryptionStateOk, + FrameCryptionStateEncryptionFailed, + FrameCryptionStateDecryptionFailed, + FrameCryptionStateMissingKey, + FrameCryptionStateKeyRatcheted, + FrameCryptionStateInternalError, }; RTC_OBJC_EXPORT @@ -45,7 +46,7 @@ RTC_OBJC_EXPORT /** Called when the RTCFrameCryptor got errors. */ - (void)frameCryptor : (RTC_OBJC_TYPE(RTCFrameCryptor) *)frameCryptor didStateChangeWithParticipantId - : (NSString *)participantId withState : (RTCFrameCryptorErrorState)stateChanged; + : (NSString *)participantId withState : (FrameCryptionState)stateChanged; @end RTC_OBJC_EXPORT @@ -62,12 +63,12 @@ RTC_OBJC_EXPORT - (instancetype)initWithRtpSender:(RTC_OBJC_TYPE(RTCRtpSender) *)sender participantId:(NSString *)participantId algorithm:(RTCCyrptorAlgorithm)algorithm - keyManager:(RTC_OBJC_TYPE(RTCFrameCryptorKeyManager) *)keyManager; + keyProvider:(RTC_OBJC_TYPE(RTCFrameCryptorKeyProvider) *)keyProvider; - (instancetype)initWithRtpReceiver:(RTC_OBJC_TYPE(RTCRtpReceiver) *)receiver participantId:(NSString *)participantId algorithm:(RTCCyrptorAlgorithm)algorithm - keyManager:(RTC_OBJC_TYPE(RTCFrameCryptorKeyManager) *)keyManager; + keyProvider:(RTC_OBJC_TYPE(RTCFrameCryptorKeyProvider) *)keyProvider; @end diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptor.mm b/sdk/objc/api/peerconnection/RTCFrameCryptor.mm index 6ceca441ce..312331f72d 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptor.mm +++ b/sdk/objc/api/peerconnection/RTCFrameCryptor.mm @@ -15,7 +15,7 @@ */ #import "RTCFrameCryptor+Private.h" -#import "RTCFrameCryptorKeyManager+Private.h" +#import "RTCFrameCryptorKeyProvider+Private.h" #import "RTCRtpReceiver+Private.h" #import "RTCRtpSender+Private.h" @@ -44,40 +44,45 @@ kMissingKey, kInternalError, */ -void RTCFrameCryptorDelegateAdapter::OnFrameCryptionError(const std::string participant_id, - FrameCryptionError error) { +void RTCFrameCryptorDelegateAdapter::OnFrameCryptionStateChanged(const std::string participant_id, + FrameCryptionState state) { RTC_OBJC_TYPE(RTCFrameCryptor) *frameCryptor = frame_cryptor_; if (frameCryptor.delegate) { - switch (error) { - case FrameCryptionError::kNew: + switch (state) { + case FrameCryptionState::kNew: [frameCryptor.delegate frameCryptor:frameCryptor didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] - withState:RTCFrameCryptorErrorStateNew]; + withState:FrameCryptionStateNew]; break; - case FrameCryptionError::kOk: + case FrameCryptionState::kOk: [frameCryptor.delegate frameCryptor:frameCryptor didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] - withState:RTCFrameCryptorErrorStateOk]; + withState:FrameCryptionStateOk]; break; - case FrameCryptionError::kEncryptionFailed: + case FrameCryptionState::kEncryptionFailed: [frameCryptor.delegate frameCryptor:frameCryptor didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] - withState:RTCFrameCryptorErrorStateEncryptionFailed]; + withState:FrameCryptionStateEncryptionFailed]; break; - case FrameCryptionError::kDecryptionFailed: + case FrameCryptionState::kDecryptionFailed: [frameCryptor.delegate frameCryptor:frameCryptor didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] - withState:RTCFrameCryptorErrorStateDecryptionFailed]; + withState:FrameCryptionStateDecryptionFailed]; break; - case FrameCryptionError::kMissingKey: + case FrameCryptionState::kMissingKey: [frameCryptor.delegate frameCryptor:frameCryptor didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] - withState:RTCFrameCryptorErrorStateMissingKey]; + withState:FrameCryptionStateMissingKey]; break; - case FrameCryptionError::kInternalError: + case FrameCryptionState::kKeyRatcheted: [frameCryptor.delegate frameCryptor:frameCryptor didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] - withState:RTCFrameCryptorErrorStateInternalError]; + withState:FrameCryptionStateKeyRatcheted]; + break; + case FrameCryptionState::kInternalError: + [frameCryptor.delegate frameCryptor:frameCryptor + didStateChangeWithParticipantId:[NSString stringForStdString:participant_id] + withState:FrameCryptionStateInternalError]; break; } } @@ -109,7 +114,7 @@ @implementation RTC_OBJC_TYPE (RTCFrameCryptor) { - (instancetype)initWithRtpSender:(RTC_OBJC_TYPE(RTCRtpSender) *)sender participantId:(NSString *)participantId algorithm:(RTCCyrptorAlgorithm)algorithm - keyManager:(RTC_OBJC_TYPE(RTCFrameCryptorKeyManager) *)keyManager { + keyProvider:(RTC_OBJC_TYPE(RTCFrameCryptorKeyProvider) *)keyProvider { if (self = [super init]) { _observer.reset(new webrtc::RTCFrameCryptorDelegateAdapter(self)); _participantId = participantId; @@ -121,7 +126,7 @@ - (instancetype)initWithRtpSender:(RTC_OBJC_TYPE(RTCRtpSender) *)sender new webrtc::FrameCryptorTransformer([participantId stdString], mediaType, [self algorithmFromEnum:algorithm], - keyManager.nativeKeyManager)); + keyProvider.nativeKeyProvider)); rtpSender->SetEncoderToPacketizerFrameTransformer(frame_crypto_transformer_); frame_crypto_transformer_->SetEnabled(false); @@ -133,7 +138,7 @@ - (instancetype)initWithRtpSender:(RTC_OBJC_TYPE(RTCRtpSender) *)sender - (instancetype)initWithRtpReceiver:(RTC_OBJC_TYPE(RTCRtpReceiver) *)receiver participantId:(NSString *)participantId algorithm:(RTCCyrptorAlgorithm)algorithm - keyManager:(RTC_OBJC_TYPE(RTCFrameCryptorKeyManager) *)keyManager { + keyProvider:(RTC_OBJC_TYPE(RTCFrameCryptorKeyProvider) *)keyProvider { if (self = [super init]) { _observer.reset(new webrtc::RTCFrameCryptorDelegateAdapter(self)); _participantId = participantId; @@ -145,7 +150,7 @@ - (instancetype)initWithRtpReceiver:(RTC_OBJC_TYPE(RTCRtpReceiver) *)receiver new webrtc::FrameCryptorTransformer([participantId stdString], mediaType, [self algorithmFromEnum:algorithm], - keyManager.nativeKeyManager)); + keyProvider.nativeKeyProvider)); rtpReceiver->SetDepacketizerToDecoderFrameTransformer(frame_crypto_transformer_); frame_crypto_transformer_->SetEnabled(false); diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager.mm b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager.mm deleted file mode 100644 index ab3ffc3e7c..0000000000 --- a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager.mm +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2022 LiveKit - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "RTCFrameCryptorKeyManager+Private.h" - -#include -#include - -#import "base/RTCLogging.h" -#import "helpers/NSString+StdString.h" - -class DefaultKeyManagerImpl : public webrtc::KeyManager { - public: - DefaultKeyManagerImpl() = default; - ~DefaultKeyManagerImpl() override = default; - - /// Set the key at the given index. - bool SetKey(const std::string participant_id, int index, std::vector key) { - webrtc::MutexLock lock(&mutex_); - - if (keys_.find(participant_id) == keys_.end()) { - keys_[participant_id] = std::vector>(); - } - - if (index + 1 > (int)keys_[participant_id].size()) { - keys_[participant_id].resize(index + 1); - } - keys_[participant_id][index] = key; - return true; - } - - /// Set the keys. - bool SetKeys(const std::string participant_id, std::vector> keys) { - webrtc::MutexLock lock(&mutex_); - keys_[participant_id] = keys; - return true; - } - - const std::vector> keys(const std::string participant_id) const override { - webrtc::MutexLock lock(&mutex_); - if (keys_.find(participant_id) == keys_.end()) { - return std::vector>(); - } - - return keys_.find(participant_id)->second; - } - - private: - mutable webrtc::Mutex mutex_; - std::unordered_map>> keys_; -}; - -@implementation RTC_OBJC_TYPE (RTCFrameCryptorKeyManager) { - rtc::scoped_refptr _nativeKeyManager; -} - -- (rtc::scoped_refptr)nativeKeyManager { - return _nativeKeyManager; -} - -- (instancetype)init { - if (self = [super init]) { - _nativeKeyManager = rtc::make_ref_counted(); - } - return self; -} - -- (void)setKey:(NSData *)key withIndex:(int)index forParticipant:(NSString *)participantId { - _nativeKeyManager->SetKey( - [participantId stdString], - index, - std::vector((const uint8_t *)key.bytes, ((const uint8_t *)key.bytes) + key.length)); -} - -- (void)setKeys:(NSArray *)keys forParticipant:(NSString *)participantId { - std::vector> nativeKeys; - for (NSData *key in keys) { - nativeKeys.push_back(std::vector((const uint8_t *)key.bytes, - ((const uint8_t *)key.bytes) + key.length)); - } - _nativeKeyManager->SetKeys([participantId stdString], nativeKeys); -} - -- (NSArray *)getKeys:(NSString *)participantId { - std::vector> nativeKeys = - _nativeKeyManager->keys([participantId stdString]); - NSMutableArray *keys = [NSMutableArray array]; - for (std::vector key : nativeKeys) { - [keys addObject:[NSData dataWithBytes:key.data() length:key.size()]]; - } - return keys; -} - -@end diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager+Private.h b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider+Private.h similarity index 86% rename from sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager+Private.h rename to sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider+Private.h index 3b31f633cb..eb7c83e2e7 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager+Private.h +++ b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider+Private.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#import "RTCFrameCryptorKeyManager.h" +#import "RTCFrameCryptorKeyProvider.h" -#include "rtc_base/ref_count.h" #include "api/crypto/frame_crypto_transformer.h" +#include "rtc_base/ref_count.h" NS_ASSUME_NONNULL_BEGIN -@interface RTC_OBJC_TYPE (RTCFrameCryptorKeyManager) +@interface RTC_OBJC_TYPE (RTCFrameCryptorKeyProvider) () - @property(nonatomic, readonly) rtc::scoped_refptr nativeKeyManager; + @property(nonatomic, readonly) rtc::scoped_refptr nativeKeyProvider; @end diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager.h b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h similarity index 65% rename from sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager.h rename to sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h index 7dd3162906..276b2e730c 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyManager.h +++ b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h @@ -21,15 +21,18 @@ NS_ASSUME_NONNULL_BEGIN RTC_OBJC_EXPORT -@interface RTC_OBJC_TYPE (RTCFrameCryptorKeyManager) : NSObject +@interface RTC_OBJC_TYPE (RTCFrameCryptorKeyProvider) : NSObject - (void)setKey:(NSData *)key withIndex:(int)index forParticipant:(NSString *)participantId; -- (void)setKeys:(NSArray *)keys forParticipant:(NSString *)participantId; +- (NSData *)ratchetKey:(NSString *)participantId withIndex:(int)index; -- (NSArray *) getKeys:(NSString *)participantId; +- (NSData *)exportKey:(NSString *)participantId withIndex:(int)index; -- (instancetype)init; +- (instancetype)initWithRatchetSalt:(NSData *)salt + ratchetWindowSize:(int)windowSize + sharedKeyMode:(BOOL)sharedKey + uncryptedMagicBytes:(nullable NSData *)uncryptedMagicBytes; @end diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm new file mode 100644 index 0000000000..c27e18975b --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm @@ -0,0 +1,69 @@ +/* + * Copyright 2022 LiveKit + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "RTCFrameCryptorKeyProvider+Private.h" + +#include +#include "api/crypto/frame_crypto_transformer.h" + +#import "base/RTCLogging.h" +#import "helpers/NSString+StdString.h" + +@implementation RTC_OBJC_TYPE (RTCFrameCryptorKeyProvider) { + rtc::scoped_refptr _nativeKeyProvider; +} + +- (rtc::scoped_refptr)nativeKeyProvider { + return _nativeKeyProvider; +} + +- (instancetype)initWithRatchetSalt:(NSData *)salt + ratchetWindowSize:(int)windowSize + sharedKeyMode:(BOOL)sharedKey + uncryptedMagicBytes:(NSData *)uncryptedMagicBytes { + if (self = [super init]) { + webrtc::KeyProviderOptions options; + options.ratchet_salt = std::vector((const uint8_t *)salt.bytes, + ((const uint8_t *)salt.bytes) + salt.length); + options.ratchet_window_size = windowSize; + options.shared_key = sharedKey; + if(uncryptedMagicBytes != nil) { + options.uncrypted_magic_bytes = std::vector((const uint8_t *)uncryptedMagicBytes.bytes, + ((const uint8_t *)uncryptedMagicBytes.bytes) + uncryptedMagicBytes.length); + } + _nativeKeyProvider = rtc::make_ref_counted(options); + } + return self; +} + +- (void)setKey:(NSData *)key withIndex:(int)index forParticipant:(NSString *)participantId { + _nativeKeyProvider->SetKey( + [participantId stdString], + index, + std::vector((const uint8_t *)key.bytes, ((const uint8_t *)key.bytes) + key.length)); +} + +- (NSData *)ratchetKey:(NSString *)participantId withIndex:(int)index { + std::vector nativeKey = _nativeKeyProvider->RatchetKey([participantId stdString], index); + return [NSData dataWithBytes:nativeKey.data() length:nativeKey.size()]; +} + +- (NSData *)exportKey:(NSString *)participantId withIndex:(int)index { + std::vector nativeKey = _nativeKeyProvider->ExportKey([participantId stdString], index); + return [NSData dataWithBytes:nativeKey.data() length:nativeKey.size()]; +} + +@end