1414 * limitations under the License.
1515 */
1616
17- #include " frame_crypto_transformer.h"
17+ #include " api/crypto/ frame_crypto_transformer.h"
1818
1919#include < openssl/aes.h>
2020#include < openssl/err.h>
3535#include " common_video/h265/h265_common.h"
3636#include " modules/rtp_rtcp/source/rtp_format_h264.h"
3737#include " rtc_base/byte_buffer.h"
38+ #include " rtc_base/crypto_random.h"
3839#include " rtc_base/logging.h"
40+ #include " rtc_base/time_utils.h"
3941
4042enum class EncryptOrDecrypt { kEncrypt = 0 , kDecrypt };
4143
@@ -210,12 +212,16 @@ uint8_t get_unencrypted_bytes(webrtc::TransformableFrameInterface* frame,
210212 webrtc::H265::NaluType nalu_type =
211213 webrtc::H265::ParseNaluType (slice[0 ]);
212214 if (IsH265SliceNalu (nalu_type)) {
213- // H.265 has a 2-byte NALU header, so unencrypted bytes = offset + header size
214- unencrypted_bytes = index.payload_start_offset + webrtc::H265::kNaluHeaderSize ;
215+ // H.265 has a 2-byte NALU header, so unencrypted bytes = offset +
216+ // header size
217+ unencrypted_bytes =
218+ index.payload_start_offset + webrtc::H265::kNaluHeaderSize ;
215219 RTC_LOG (LS_INFO)
216- << " H265 NonParameterSetNalu::payload_size: " << index.payload_size
217- << " , nalu_type " << static_cast <int >(nalu_type) << " , NaluIndex [" << idx++
218- << " ] offset: " << index.payload_start_offset << " , unencrypted_bytes: " << unencrypted_bytes;
220+ << " H265 NonParameterSetNalu::payload_size: "
221+ << index.payload_size << " , nalu_type "
222+ << static_cast <int >(nalu_type) << " , NaluIndex [" << idx++
223+ << " ] offset: " << index.payload_start_offset
224+ << " , unencrypted_bytes: " << unencrypted_bytes;
219225 return unencrypted_bytes;
220226 }
221227 }
@@ -321,8 +327,8 @@ int AesEncryptDecrypt(EncryptOrDecrypt mode,
321327 RTC_LOG (LS_ERROR) << " Invalid AES-GCM key size." ;
322328 return ErrorUnexpected;
323329 }
324- return AesGcmEncryptDecrypt (
325- mode, raw_key, data, tag_length_bits / 8 , iv, additional_data, cipher, buffer);
330+ return AesGcmEncryptDecrypt (mode, raw_key, data, tag_length_bits / 8 , iv,
331+ additional_data, cipher, buffer);
326332 }
327333 default :
328334 RTC_LOG (LS_ERROR) << " Unsupported algorithm." ;
@@ -385,7 +391,8 @@ void FrameCryptorTransformer::Transform(
385391void FrameCryptorTransformer::encryptFrame (
386392 std::unique_ptr<webrtc::TransformableFrameInterface> frame) {
387393 bool enabled_cryption = false ;
388- webrtc::scoped_refptr<webrtc::TransformedFrameCallback> sink_callback = nullptr ;
394+ webrtc::scoped_refptr<webrtc::TransformedFrameCallback> sink_callback =
395+ nullptr ;
389396 {
390397 webrtc::MutexLock lock (&mutex_);
391398 enabled_cryption = enabled_cryption_;
@@ -410,7 +417,7 @@ void FrameCryptorTransformer::encryptFrame(
410417 if (data_in.size () == 0 || !enabled_cryption) {
411418 RTC_LOG (LS_WARNING) << " FrameCryptorTransformer::encryptFrame() "
412419 " data_in.size() == 0 || enabled_cryption == false" ;
413- if (key_provider_->options ().discard_frame_when_cryptor_not_ready ) {
420+ if (key_provider_->options ().discard_frame_when_cryptor_not_ready ) {
414421 return ;
415422 }
416423 sink_callback->OnTransformedFrame (std::move (frame));
@@ -498,7 +505,8 @@ void FrameCryptorTransformer::encryptFrame(
498505void FrameCryptorTransformer::decryptFrame (
499506 std::unique_ptr<webrtc::TransformableFrameInterface> frame) {
500507 bool enabled_cryption = false ;
501- webrtc::scoped_refptr<webrtc::TransformedFrameCallback> sink_callback = nullptr ;
508+ webrtc::scoped_refptr<webrtc::TransformedFrameCallback> sink_callback =
509+ nullptr ;
502510 {
503511 webrtc::MutexLock lock (&mutex_);
504512 enabled_cryption = enabled_cryption_;
@@ -524,7 +532,7 @@ void FrameCryptorTransformer::decryptFrame(
524532 if (data_in.size () == 0 || !enabled_cryption) {
525533 RTC_LOG (LS_WARNING) << " FrameCryptorTransformer::decryptFrame() "
526534 " data_in.size() == 0 || enabled_cryption == false" ;
527- if (key_provider_->options ().discard_frame_when_cryptor_not_ready ) {
535+ if (key_provider_->options ().discard_frame_when_cryptor_not_ready ) {
528536 return ;
529537 }
530538
@@ -585,8 +593,8 @@ void FrameCryptorTransformer::decryptFrame(
585593 ? key_provider_->GetSharedKey (participant_id_)
586594 : key_provider_->GetKey (participant_id_);
587595
588- if (0 > key_index || key_index >= key_provider_->options ().key_ring_size || key_handler == nullptr ||
589- key_handler->GetKeySet (key_index) == nullptr ) {
596+ if (0 > key_index || key_index >= key_provider_->options ().key_ring_size ||
597+ key_handler == nullptr || key_handler ->GetKeySet (key_index) == nullptr ) {
590598 RTC_LOG (LS_INFO) << " FrameCryptorTransformer::decryptFrame() no keys, or "
591599 " key_index["
592600 << key_index << " ] out of range for participant "
@@ -621,7 +629,8 @@ void FrameCryptorTransformer::decryptFrame(
621629 encrypted_buffer.SetData (
622630 H264::ParseRbsp (encrypted_buffer.data (), encrypted_buffer.size ()));
623631 } else if (FrameIsH265 (frame.get (), type_) &&
624- NeedsRbspUnescaping (encrypted_buffer.data (), encrypted_buffer.size ())) {
632+ NeedsRbspUnescaping (encrypted_buffer.data (),
633+ encrypted_buffer.size ())) {
625634 encrypted_buffer.SetData (
626635 H265::ParseRbsp (encrypted_buffer.data (), encrypted_buffer.size ()));
627636 }
@@ -728,8 +737,7 @@ void FrameCryptorTransformer::onFrameCryptionStateChanged(
728737rtc::Buffer FrameCryptorTransformer::makeIv (uint32_t ssrc, uint32_t timestamp) {
729738 uint32_t send_count = 0 ;
730739 if (send_counts_.find (ssrc) == send_counts_.end ()) {
731- srand ((unsigned )time (NULL ));
732- send_counts_[ssrc] = floor (rand () * 0xFFFF );
740+ send_counts_[ssrc] = floor (CreateRandomNonZeroId () * 0xFFFF );
733741 } else {
734742 send_count = send_counts_[ssrc];
735743 }
@@ -753,4 +761,156 @@ uint8_t FrameCryptorTransformer::getIvSize() {
753761 }
754762}
755763
764+ DataPacketCryptor::DataPacketCryptor (
765+ FrameCryptorTransformer::Algorithm algorithm,
766+ webrtc::scoped_refptr<KeyProvider> key_provider)
767+ : algorithm_(algorithm), key_provider_(key_provider) {
768+ RTC_DCHECK (key_provider_ != nullptr );
769+ }
770+
771+ DataPacketCryptor::~DataPacketCryptor () {}
772+
773+ RTCErrorOr<webrtc::scoped_refptr<EncryptedPacket>> DataPacketCryptor::Encrypt (
774+ const std::string participant_id,
775+ int key_index,
776+ const std::vector<uint8_t >& data) {
777+ auto key_handler = key_provider_->options ().shared_key
778+ ? key_provider_->GetSharedKey (participant_id)
779+ : key_provider_->GetKey (participant_id);
780+
781+ if (key_handler == nullptr || key_handler->GetKeySet (key_index) == nullptr ) {
782+ RTC_LOG (LS_INFO) << " DataPacketCryptor::Encrypt() no keys, or "
783+ " key_index["
784+ << key_index << " ] out of range for participant "
785+ << participant_id;
786+ return RTCError (RTCErrorType::INVALID_PARAMETER,
787+ " DataPacketCryptor::Encrypt() no keys, or key_index[" +
788+ std::to_string (key_index) +
789+ " ] out of range for participant " + participant_id);
790+ }
791+
792+ auto key_set = key_handler->GetKeySet (key_index);
793+ auto timestamp = Timestamp::Millis (rtc::TimeMillis ())
794+ .ms (); // use current time millis as timestamp
795+ auto iv = makeIv (timestamp); // for data packets, ssrc is always 0
796+
797+ std::vector<uint8_t > buffer;
798+ rtc::Buffer payload (data.data (), data.size ());
799+ auto frame_header = rtc::Buffer (0 ); // no frame header for data packets
800+ if (AesEncryptDecrypt (EncryptOrDecrypt::kEncrypt , algorithm_,
801+ key_set->encryption_key , iv, frame_header, payload,
802+ &buffer) == Success) {
803+ webrtc::scoped_refptr<EncryptedPacket> encryptedPacket =
804+ webrtc::make_ref_counted<EncryptedPacket>(
805+ buffer, std::vector<uint8_t >(iv.begin (), iv.end ()), key_index);
806+ return encryptedPacket;
807+ }
808+
809+ return RTCError (RTCErrorType::INTERNAL_ERROR,
810+ " DataPacketCryptor::Encrypt() failed" );
811+ }
812+
813+ RTCErrorOr<std::vector<uint8_t >> DataPacketCryptor::Decrypt (
814+ const std::string participant_id,
815+ const webrtc::scoped_refptr<EncryptedPacket> encryptedPacket) {
816+ auto key_handler = key_provider_->options ().shared_key
817+ ? key_provider_->GetSharedKey (participant_id)
818+ : key_provider_->GetKey (participant_id);
819+ int key_index = encryptedPacket->key_index ;
820+ if (key_handler == nullptr || key_handler->GetKeySet (key_index) == nullptr ) {
821+ RTC_LOG (LS_INFO) << " DataPacketCryptor::Decrypt() no keys, or "
822+ " key_index["
823+ << key_index << " ] out of range for participant "
824+ << participant_id;
825+ return RTCError (RTCErrorType::INVALID_PARAMETER,
826+ " DataPacketCryptor::Decrypt() no keys, or key_index[" +
827+ std::to_string (key_index) +
828+ " ] out of range for participant " + participant_id);
829+ }
830+
831+ std::vector<uint8_t > buffer;
832+ rtc::Buffer encrypted_payload (encryptedPacket->data .data (),
833+ encryptedPacket->data .size ());
834+ rtc::Buffer iv (encryptedPacket->iv .data (), encryptedPacket->iv .size ());
835+ auto frame_header = rtc::Buffer (0 ); // no frame header for data packets
836+
837+ auto key_set = key_handler->GetKeySet (key_index);
838+ auto initialKeyMaterial = key_set->material ;
839+ bool decryption_success = false ;
840+
841+ if (AesEncryptDecrypt (EncryptOrDecrypt::kDecrypt , algorithm_,
842+ key_set->encryption_key , iv, frame_header,
843+ encrypted_payload, &buffer) == Success) {
844+ decryption_success = true ;
845+ } else {
846+ RTC_LOG (LS_WARNING) << " DataPacketCryptor::Decrypt() failed with key_index "
847+ << static_cast <int >(key_index);
848+ webrtc::scoped_refptr<ParticipantKeyHandler::KeySet> ratcheted_key_set;
849+ auto currentKeyMaterial = key_set->material ;
850+ int ratchet_count = 0 ;
851+ if (key_provider_->options ().ratchet_window_size > 0 ) {
852+ while (ratchet_count < key_provider_->options ().ratchet_window_size ) {
853+ ratchet_count++;
854+
855+ RTC_LOG (LS_INFO) << " ratcheting key attempt " << ratchet_count << " of "
856+ << key_provider_->options ().ratchet_window_size ;
857+
858+ auto new_material = key_handler->RatchetKeyMaterial (currentKeyMaterial);
859+ ratcheted_key_set = key_handler->DeriveKeys (
860+ new_material, key_provider_->options ().ratchet_salt , 128 );
861+
862+ if (AesEncryptDecrypt (EncryptOrDecrypt::kDecrypt , algorithm_,
863+ ratcheted_key_set->encryption_key , iv,
864+ frame_header, encrypted_payload,
865+ &buffer) == Success) {
866+ RTC_LOG (LS_INFO) << " DataPacketCryptor::Decrypt() successfully "
867+ " ratcheted to key_index="
868+ << static_cast <int >(key_index);
869+ decryption_success = true ;
870+ // success, so we set the new key
871+ key_handler->SetKeyFromMaterial (new_material, key_index);
872+ key_handler->SetHasValidKey ();
873+ break ;
874+ }
875+ // for the next ratchet attempt
876+ currentKeyMaterial = new_material;
877+ }
878+
879+ /* Since the key it is first send and only afterwards actually used for
880+ encrypting, there were situations when the decrypting failed due to the
881+ fact that the received frame was not encrypted yet and ratcheting, of
882+ course, did not solve the problem. So if we fail RATCHET_WINDOW_SIZE
883+ times, we come back to the initial key.
884+ */
885+ if (!decryption_success ||
886+ ratchet_count >= key_provider_->options ().ratchet_window_size ) {
887+ key_handler->SetKeyFromMaterial (initialKeyMaterial, key_index);
888+ }
889+ }
890+ }
891+
892+ if (decryption_success) {
893+ return buffer;
894+ }
895+
896+ return RTCError (RTCErrorType::INTERNAL_ERROR,
897+ " DataPacketCryptor::Decrypt() failed" );
898+ }
899+
900+ rtc::Buffer DataPacketCryptor::makeIv (uint32_t timestamp) {
901+ if (send_count_ == 0 ) {
902+ send_count_ = floor (CreateRandomNonZeroId () * 0xFFFF );
903+ }
904+ rtc::ByteBufferWriter buf;
905+ uint32_t random_u32 = CreateRandomId ();
906+ buf.WriteUInt32 (random_u32);
907+ buf.WriteUInt32 (timestamp);
908+ buf.WriteUInt32 (timestamp - (send_count_ % 0xFFFF ));
909+ send_count_ += 1 ;
910+
911+ RTC_CHECK_EQ (buf.Length (), 12 );
912+
913+ return rtc::Buffer (buf.Data (), buf.Length ());
914+ }
915+
756916} // namespace webrtc
0 commit comments