Skip to content

Conversation

@jimm98y
Copy link
Contributor

@jimm98y jimm98y commented Jan 4, 2026

To remove the AGPL-derived code, I implemented a new DTLS-SRTP layer based upon BouncyCastle DTLS samples and the RFCs. More info here: https://github.com/jimm98y/SharpSRTP

This PR wires up the new implementation into the current code base. The only modification when compared to SharpSRTP are the namespaces which have been adjusted to match sipsorcery and the logging was wired up to sipsorcery's logging mechanism.

I have unit tests for all the implemented RFCs in my repo and it should be easy to sync any changes/bugfixes in the future. I tested some of the WebRTC samples that I was able to run on ARM64 and I also tested the new implementation on https://github.com/jimm98y/SharpRTSPtoWebRTC.

This new DTLS-SRTP implementation also fixes the RSA TLS certificate sipsorcery was using in WebRTC, now it's using ECDsa by default. By default I also disabled DTLS 1.0, leaving only DTLS 1.2 available. DTLS 1.0 can be enabled using overrides. DTLS 1.3 currently cannot be supported because BouncyCastle does not support it yet.

This PR should also resolve AES-GCM AEAD support #871.

@sipsorcery
Copy link
Member

Fair dues for taking this on! The AGPL code does cause a few people problems.

I'm doing some testing with the various WebRTC examples and will add comments for any issues I find (first one immediately below).

What's your plan for the SharpSRTP package? It would seem more efficient for this project to use a separate nuget package rather than mirroring the code. If you did want to stop maintaining the package at some point it would be easy enough to bring the code into this repo as this PR does.

@sipsorcery
Copy link
Member

Using this PR with the WebRTC Get Started example results in an exception almost immediately after the media streams are started. My guess would be it's caused by two media stream (audio and video) attempting to use the same encryption context.

08:37:29 DBG] Peer connection state change to connected.
[08:37:29 DBG] Starting RTCP session for a623e39b-99db-4354-b2f6-87124ad65626.
[08:37:29 DBG] Starting RTCP session for 534c6962-c5bb-4205-a8d4-4171a6d036b2.
Unhandled exception. System.InvalidOperationException: GCM cipher cannot be reused for encryption
   at Org.BouncyCastle.Crypto.Modes.GcmBlockCipher.CheckStatus()
   at Org.BouncyCastle.Crypto.Modes.GcmBlockCipher.ProcessBytes(ReadOnlySpan`1 input, Span`1 output)
   at Org.BouncyCastle.Crypto.Modes.GcmBlockCipher.ProcessBytes(Byte[] input, Int32 inOff, Int32 len, Byte[] output, Int32 outOff)
   at SIPSorcery.Net.SharpSRTP.SRTP.Encryption.AEAD.Encrypt(IAeadBlockCipher engine, Byte[] payload, Int32 offset, Int32 length, Byte[] iv, Byte[] K_e, Int32 N_tag, Byte[] associatedData) in c:\dev\sipsorcery\src\net\DtlsSrtp\Lib\SRTP\Encryption\AEAD.cs:line 43
   at SIPSorcery.Net.SharpSRTP.SRTP.SrtpContext.ProtectRtp(Byte[] payload, Int32 length, Int32& outputBufferLength) in c:\dev\sipsorcery\src\net\DtlsSrtp\Lib\SRTP\SrtpContext.cs:line 469
   at SIPSorcery.Net.SharpSRTP.SRTP.SrtpSessionContext.ProtectRtp(Byte[] payload, Int32 length, Int32& outputBufferLength) in c:\dev\sipsorcery\src\net\DtlsSrtp\Lib\SRTP\SrtpSessionContext.cs:line 46
...

@jimm98y
Copy link
Contributor Author

jimm98y commented Jan 10, 2026

"What's your plan for the SharpSRTP package?"
I have a one or two pet projects that depend upon it (I was using sipsorcery's SRTP until now), so my plan is to maintain it as long as I have the time. I thought it might be better to include the code in the PR in order to not introduce another dependency, especially not one that is currently not stable enough and might have some API breaking changes in the future that would require me to test for and provide backwards compatibility. This means version 0.1.x will not be 100% API-compatible with 0.0.x. If you are OK with taking the dependency, I can modify the PR to use the nuget instead.

"My guess would be it's caused by two media stream (audio and video) attempting to use the same encryption context."
You are right, that's the most probable cause of the exception. I could not try all the WebRTC examples, because the nugets seem to require native code and there is currently no support for ARM64, resulting in immediate crashes with BadImageFormatException on my machine. I will try to switch to x86/x64 and see if I can make the samples work.

As for the locking, the original implementation had locking implemented inside SRTP contexts. I wanted to avoid locking entirely, which means now the caller is responsible for locking. Ideally, you'd have 1:1 mapping in between contexts/threads, avoiding locking entirely.

Edit: The issue should be fixed. I added locking when RTP/RTCP multiplexing is being used and the rtpChannel is shared among multiple media streams.

@sipsorcery
Copy link
Member

"What's your plan for the SharpSRTP package?" I have a one or two pet projects that depend upon it (I was using sipsorcery's SRTP until now), so my plan is to maintain it as long as I have the time. I thought it might be better to include the code in the PR in order to not introduce another dependency, especially not one that is currently not stable enough and might have some API breaking changes in the future that would require me to test for and provide backwards compatibility. This means version 0.1.x will not be 100% API-compatible with 0.0.x. If you are OK with taking the dependency, I can modify the PR to use the nuget instead.

Ok, if the public API is likely to be evolving quickly it may be better to use the original approach in this PR and duplicate the code in this repo.

Edit: The issue should be fixed. I added locking when RTP/RTCP multiplexing is being used and the rtpChannel is shared among multiple media streams.

It's working for me now. I do always get a single message of a decrypt failure as per below with teh WebRTCGetStarted exanple. It only seems to happen once, It doesn't occur on the master branch,

[17:19:35 WRN] SRTCP unprotect failed for audio track, result -4.

@jimm98y
Copy link
Contributor Author

jimm98y commented Jan 10, 2026

-4 is the replay protection failing, so it is likely the MediaTrack trying to decrypt the same RTCP message for the second time. I presume this is the result of multiplexing re-using the same channel for multiple tracks.

Yes, in this case it seems to be a problem of my current implementation as per RFC 3711:

In addition, there can be cases (see Sections 8 and 9.1) where
several SRTP streams within a given RTP session, identified by their
synchronization source (SSRCs, which is part of the RTP header),
share most of the crypto context parameters (including possibly
master and session keys). In such cases, just as in the normal
SRTP/SRTCP parameter sharing above, separate replay lists and packet
counters for each stream (SSRC) MUST still be maintained. Also,
separate SRTP indices MUST then be maintained.

--------SRTCP Unprotect 38583594: 81c90007000000018b3147129ba0ec92ad0b6836ed95c6f27ede8a9a879482fdf3b794d912c7b98cfd8ab9f12b993de280000001
--------SRTCP Unprotect 38583594: 81c9000700000001ea35c655331ef3d3152d5b8af8d56a697ded95e7826856a9306a42ab97ebcda6d70461dab80427b380000002
--------SRTCP Unprotect 38583594 failed: 81c90007fa17fa1795779e3aa93daa7ada9da5f8a19697355e8f2166cbe16754091a6f5c4c232a37c7117ffda34e586980000001

RTCP indexes for both video/audio start from 1 and they only differ in SSRC, yet in this case they are sharing the same SrtpContext.

Edit: Should be fixed now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants