From 87977caac70dfc3ff5fc0e94c8ab76e20940767c Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Sat, 9 Sep 2023 08:56:07 +0800 Subject: [PATCH] add failure tolerance for framecryptor. (#91) * add failure tolerance for framecryptor. * add failureTolerance for android/objc. * fix: make H264's unencrypted_bytes consistent with js-sdk. * add SetSifTrailer. --- api/crypto/frame_crypto_transformer.cc | 12 +++---- api/crypto/frame_crypto_transformer.h | 35 +++++++++++++++---- .../api/org/webrtc/FrameCryptorFactory.java | 6 ++-- .../org/webrtc/FrameCryptorKeyProvider.java | 7 ++++ sdk/android/src/jni/pc/frame_cryptor.cc | 4 ++- .../src/jni/pc/frame_cryptor_key_provider.cc | 9 +++++ .../RTCFrameCryptorKeyProvider.h | 8 +++++ .../RTCFrameCryptorKeyProvider.mm | 19 ++++++++++ 8 files changed, 84 insertions(+), 16 deletions(-) diff --git a/api/crypto/frame_crypto_transformer.cc b/api/crypto/frame_crypto_transformer.cc index 9d8ee44c9e..9ef356ce0f 100644 --- a/api/crypto/frame_crypto_transformer.cc +++ b/api/crypto/frame_crypto_transformer.cc @@ -136,7 +136,7 @@ uint8_t get_unencrypted_bytes(webrtc::TransformableFrameInterface* frame, << "NonParameterSetNalu::payload_size: " << index.payload_size << ", nalu_type " << nalu_type << ", NaluIndex [" << idx++ << "] offset: " << index.payload_start_offset; - break; + return unencrypted_bytes; default: break; } @@ -219,7 +219,7 @@ int AesGcmEncryptDecrypt(EncryptOrDecrypt mode, } if (!ok) { - RTC_LOG(LS_ERROR) << "Failed to perform AES-GCM operation."; + RTC_LOG(LS_WARNING) << "Failed to perform AES-GCM operation."; return OperationError; } @@ -510,7 +510,7 @@ void FrameCryptorTransformer::decryptFrame( uint8_t key_index = frame_trailer[1]; if (ivLength != getIvSize()) { - RTC_LOG(LS_ERROR) << "FrameCryptorTransformer::decryptFrame() ivLength[" + RTC_LOG(LS_WARNING) << "FrameCryptorTransformer::decryptFrame() ivLength[" << static_cast(ivLength) << "] != getIvSize()[" << static_cast(getIvSize()) << "]"; if (last_dec_error_ != FrameCryptionState::kDecryptionFailed) { @@ -569,7 +569,7 @@ void FrameCryptorTransformer::decryptFrame( encrypted_payload, &buffer) == Success) { decryption_success = true; } else { - RTC_LOG(LS_ERROR) << "FrameCryptorTransformer::decryptFrame() failed"; + RTC_LOG(LS_WARNING) << "FrameCryptorTransformer::decryptFrame() failed"; std::shared_ptr ratcheted_key_set; auto currentKeyMaterial = key_set->material; if (key_provider_->options().ratchet_window_size > 0) { @@ -593,7 +593,7 @@ void FrameCryptorTransformer::decryptFrame( decryption_success = true; // success, so we set the new key key_handler->SetKeyFromMaterial(new_material, key_index); - key_handler->SetHasValidKey(true); + key_handler->SetHasValidKey(); if (last_dec_error_ != FrameCryptionState::kKeyRatcheted) { last_dec_error_ = FrameCryptionState::kKeyRatcheted; if (observer_) @@ -622,7 +622,7 @@ void FrameCryptorTransformer::decryptFrame( if (!decryption_success) { if (last_dec_error_ != FrameCryptionState::kDecryptionFailed) { last_dec_error_ = FrameCryptionState::kDecryptionFailed; - key_handler->SetHasValidKey(false); + key_handler->DecryptionFailure(); if (observer_) observer_->OnFrameCryptionStateChanged(participant_id_, last_dec_error_); diff --git a/api/crypto/frame_crypto_transformer.h b/api/crypto/frame_crypto_transformer.h index bd245729cf..c3042b2021 100644 --- a/api/crypto/frame_crypto_transformer.h +++ b/api/crypto/frame_crypto_transformer.h @@ -41,12 +41,14 @@ struct KeyProviderOptions { std::vector ratchet_salt; std::vector uncrypted_magic_bytes; int ratchet_window_size; - KeyProviderOptions() : shared_key(false), ratchet_window_size(0) {} + int failure_tolerance; + KeyProviderOptions() : shared_key(false), ratchet_window_size(0), failure_tolerance(-1) {} 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) {} + ratchet_window_size(copy.ratchet_window_size), + failure_tolerance(copy.failure_tolerance) {} }; class KeyProvider : public rtc::RefCountInterface { @@ -74,6 +76,8 @@ class KeyProvider : public rtc::RefCountInterface { virtual const std::vector ExportKey(const std::string participant_id, int key_index) const = 0; + virtual void SetSifTrailer(const std::vector trailer) = 0; + virtual KeyProviderOptions& options() = 0; protected: @@ -116,7 +120,7 @@ class ParticipantKeyHandler { } SetKeyFromMaterial(new_material, key_index != -1 ? key_index : current_key_index_); - SetHasValidKey(true); + SetHasValidKey(); return new_material; } @@ -127,7 +131,7 @@ class ParticipantKeyHandler { virtual void SetKey(std::vector password, int key_index) { SetKeyFromMaterial(password, key_index); - SetHasValidKey(true); + SetHasValidKey(); } std::vector RatchetKeyMaterial( @@ -156,9 +160,10 @@ class ParticipantKeyHandler { return has_valid_key_; } - void SetHasValidKey(bool has_valid_key) { + void SetHasValidKey() { webrtc::MutexLock lock(&mutex_); - has_valid_key_ = has_valid_key; + decryption_failure_count_ = 0; + has_valid_key_ = true; } void SetKeyFromMaterial(std::vector password, int key_index) { @@ -170,8 +175,21 @@ class ParticipantKeyHandler { DeriveKeys(password, key_provider_->options().ratchet_salt, 128); } + void DecryptionFailure() { + webrtc::MutexLock lock(&mutex_); + if (key_provider_->options().failure_tolerance < 0) { + return; + } + decryption_failure_count_ += 1; + + if (decryption_failure_count_ > key_provider_->options().failure_tolerance) { + has_valid_key_ = false; + } + } + private: bool has_valid_key_ = false; + int decryption_failure_count_ = 0; mutable webrtc::Mutex mutex_; int current_key_index_ = 0; KeyProvider* key_provider_; @@ -296,6 +314,11 @@ class DefaultKeyProviderImpl : public KeyProvider { return std::vector(); } + void SetSifTrailer(const std::vector trailer) override { + webrtc::MutexLock lock(&mutex_); + options_.uncrypted_magic_bytes = trailer; + } + KeyProviderOptions& options() override { return options_; } private: diff --git a/sdk/android/api/org/webrtc/FrameCryptorFactory.java b/sdk/android/api/org/webrtc/FrameCryptorFactory.java index 74df6a5b29..b70f61cc6b 100644 --- a/sdk/android/api/org/webrtc/FrameCryptorFactory.java +++ b/sdk/android/api/org/webrtc/FrameCryptorFactory.java @@ -18,8 +18,8 @@ public class FrameCryptorFactory { public static FrameCryptorKeyProvider createFrameCryptorKeyProvider( - boolean sharedKey, byte[] ratchetSalt, int ratchetWindowSize, byte[] uncryptedMagicBytes) { - return nativeCreateFrameCryptorKeyProvider(sharedKey, ratchetSalt, ratchetWindowSize, uncryptedMagicBytes); + boolean sharedKey, byte[] ratchetSalt, int ratchetWindowSize, byte[] uncryptedMagicBytes, int failureTolerance) { + return nativeCreateFrameCryptorKeyProvider(sharedKey, ratchetSalt, ratchetWindowSize, uncryptedMagicBytes, failureTolerance); } public static FrameCryptor createFrameCryptorForRtpSender(RtpSender rtpSender, @@ -40,5 +40,5 @@ private static native FrameCryptor nativeCreateFrameCryptorForRtpReceiver( long rtpReceiver, String participantId, int algorithm, long nativeFrameCryptorKeyProvider); private static native FrameCryptorKeyProvider nativeCreateFrameCryptorKeyProvider( - boolean sharedKey, byte[] ratchetSalt, int ratchetWindowSize, byte[] uncryptedMagicBytes); + boolean sharedKey, byte[] ratchetSalt, int ratchetWindowSize, byte[] uncryptedMagicBytes, int failureTolerance); } diff --git a/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java b/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java index af2e3ff651..6ab0cdddf5 100644 --- a/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java +++ b/sdk/android/api/org/webrtc/FrameCryptorKeyProvider.java @@ -60,6 +60,11 @@ public byte[] exportKey(String participantId, int index) { return nativeExportKey(nativeKeyProvider, participantId, index); } + public void setSifTrailer(byte[] sifTrailer) { + checkKeyProviderExists(); + nativeSetSifTrailer(nativeKeyProvider, sifTrailer); + } + public void dispose() { checkKeyProviderExists(); JniCommon.nativeReleaseRef(nativeKeyProvider); @@ -83,4 +88,6 @@ private static native byte[] nativeRatchetKey( long keyProviderPointer, String participantId, int index); private static native byte[] nativeExportKey( long keyProviderPointer, String participantId, int index); + private static native void nativeSetSifTrailer( + long keyProviderPointer, byte[] sifTrailer); } \ 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 d02f0c62da..6c36ece9ee 100644 --- a/sdk/android/src/jni/pc/frame_cryptor.cc +++ b/sdk/android/src/jni/pc/frame_cryptor.cc @@ -171,7 +171,8 @@ JNI_FrameCryptorFactory_CreateFrameCryptorKeyProvider( jboolean j_shared, const base::android::JavaParamRef& j_ratchetSalt, jint j_ratchetWindowSize, - const base::android::JavaParamRef& j_uncryptedMagicBytes) { + const base::android::JavaParamRef& j_uncryptedMagicBytes, + jint j_failureTolerance) { auto ratchetSalt = JavaToNativeByteArray(env, j_ratchetSalt); KeyProviderOptions options; options.ratchet_salt = @@ -182,6 +183,7 @@ JNI_FrameCryptorFactory_CreateFrameCryptorKeyProvider( options.uncrypted_magic_bytes = std::vector(uncryptedMagicBytes.begin(), uncryptedMagicBytes.end()); options.shared_key = j_shared; + options.failure_tolerance = j_failureTolerance; return NativeToJavaFrameCryptorKeyProvider( env, rtc::make_ref_counted(options)); } diff --git a/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc b/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc index 2665bdc9ab..e41d16ed91 100644 --- a/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc +++ b/sdk/android/src/jni/pc/frame_cryptor_key_provider.cc @@ -110,5 +110,14 @@ JNI_FrameCryptorKeyProvider_ExportKey( return NativeToJavaByteArray(env, rtc::ArrayView(int8tKey)); } +static void JNI_FrameCryptorKeyProvider_SetSifTrailer( + JNIEnv* jni, + jlong j_key_provider, + const base::android::JavaParamRef& j_trailer) { + auto trailer = JavaToNativeByteArray(jni, j_trailer); + reinterpret_cast(j_key_provider) + ->SetSifTrailer(std::vector(trailer.begin(), trailer.end())); +} + } // namespace jni } // namespace webrtc diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h index 0122a31444..b10cf8c4b2 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h +++ b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.h @@ -35,11 +35,19 @@ RTC_OBJC_EXPORT - (NSData *)exportKey:(NSString *)participantId withIndex:(int)index; +- (void)setSifTrailer:(NSData *)trailer; + - (instancetype)initWithRatchetSalt:(NSData *)salt ratchetWindowSize:(int)windowSize sharedKeyMode:(BOOL)sharedKey uncryptedMagicBytes:(nullable NSData *)uncryptedMagicBytes; +- (instancetype)initWithRatchetSalt:(NSData *)salt + ratchetWindowSize:(int)windowSize + sharedKeyMode:(BOOL)sharedKey + uncryptedMagicBytes:(nullable NSData *)uncryptedMagicBytes + failureTolerance:(int)failureTolerance; + @end NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm index 218a3fafb0..1596b98016 100644 --- a/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm +++ b/sdk/objc/api/peerconnection/RTCFrameCryptorKeyProvider.mm @@ -34,12 +34,25 @@ - (instancetype)initWithRatchetSalt:(NSData *)salt ratchetWindowSize:(int)windowSize sharedKeyMode:(BOOL)sharedKey uncryptedMagicBytes:(NSData *)uncryptedMagicBytes { + return [self initWithRatchetSalt:salt + ratchetWindowSize:windowSize + sharedKeyMode:sharedKey + uncryptedMagicBytes:uncryptedMagicBytes + failureTolerance:-1]; +} + +- (instancetype)initWithRatchetSalt:(NSData *)salt + ratchetWindowSize:(int)windowSize + sharedKeyMode:(BOOL)sharedKey + uncryptedMagicBytes:(nullable NSData *)uncryptedMagicBytes + failureTolerance:(int)failureTolerance { 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; + options.failure_tolerance = failureTolerance; if(uncryptedMagicBytes != nil) { options.uncrypted_magic_bytes = std::vector((const uint8_t *)uncryptedMagicBytes.bytes, ((const uint8_t *)uncryptedMagicBytes.bytes) + uncryptedMagicBytes.length); @@ -82,4 +95,10 @@ - (NSData *)exportKey:(NSString *)participantId withIndex:(int)index { return [NSData dataWithBytes:nativeKey.data() length:nativeKey.size()]; } +- (void)setSifTrailer:(NSData *)trailer { + _nativeKeyProvider->SetSifTrailer( + std::vector((const uint8_t *)trailer.bytes, + ((const uint8_t *)trailer.bytes) + trailer.length)); +} + @end