DTLS, DTLS-SRTP, SRTP/SRTCP client and server written in C#.
$ dotnet add package SharpSRTPDTLS, DTLS-SRTP and SRTP/SRTCP client and server written in C#.
Implements the following RFCs:
Currently implemented SRTP Crypto Suites are:
Currently implemented DTLS-SRTP protection profiles are:
SharpSRTP is not thread-safe. If multiple threads need to access the same SRTP context, proper synchronization mechanisms must be implemented by the user.
The current DTLS implementation is based upon BouncyCastle and supports DTLS 1.2 only.
Start with generating the TLS certificate. Self-signed RSA SHA256 certificate can be generated as follows:
bool isRSA = true;
var rsaCertificate = DtlsCertificateUtils.GenerateCertificate("DTLS", DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddDays(30), isRSA);Create the DTLS server and subscribe the OnHandshakeCompleted event to get notified when a client connects:
DtlsServer server = new DtlsServer(rsaCertificate.Certificate, rsaCertificate.PrivateKey, SignatureAlgorithm.rsa, HashAlgorithm.sha256);
server.OnHandshakeCompleted += (sender, e) =>
{
...
};Create the DTLS transport. Here we will use UDP on localhost, port 8888:
UdpDatagramTransport udpServerTransport = new UdpDatagramTransport("127.0.0.1:8888", null);Wait for the client and perform DTLS handshake:
bool isShutdown = false;
while(!isShutdown)
{
DtlsTransport dtlsTransport = server.DoHandshake(
out string error,
udpServerTransport,
() =>
{
return udpServerTransport.RemoteEndPoint.ToString();
},
(remoteEndpoint) =>
{
return new UdpDatagramTransport(null, remoteEndpoint);
});
var session = Task.Run(() =>
{
...
});
}Receive data from the client:
byte[] buffer = new byte[dtlsTransport.GetReceiveLimit()];
int receivedLength = dtlsTransport.Receive(buffer, 0, buffer.Length, 100);Send data to the client:
dtlsTransport.Send(buffer, 0, buffer.Length);To modify the offered crypto suites for the DTLS handshake, simply override GetSupportedCipherSuites and return a different set of crypto suites. To support a different version of DTLS, override GetSupportedVersions and return a different version. Note that as of January 2026, BouncyCastle still does not support DTLS 1.3.
Start with creating the TLS certificate. Certificate type of the client must match the certificate type on the server, meaning if the server uses RSA certificate, the client has to use RSA certificate as well:
var rsaCertificate = DtlsCertificateUtils.GenerateCertificate("DTLS", DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddDays(30), true);Create the DTLS client:
DtlsClient client = new DtlsClient(null, rsaCertificate.certificate, rsaCertificate.key, SignatureAlgorithm.rsa, HashAlgorithm.sha256);Optionally, you can let the client auto-generate the matching certificate:
DtlsClient client = new DtlsClient();Subscribe for OnHandshakeCompleted:
client.OnHandshakeCompleted += (sender, e) =>
{
...
};Create the DTLS transport. Here we will use UDP on localhost, port 8888:
UdpDatagramTransport udpServerTransport = new UdpDatagramTransport(null, "127.0.0.1:8888");Connect the client:
DtlsTransport dtlsTransport = client.DoHandshake(out string error, udpClientTransport);Receive data to the server:
dtlsTransport.Send(buffer, 0, buffer.Length);Receive data from the server:
byte[] buffer = new byte[dtlsTransport.GetReceiveLimit()];
int receivedLength = dtlsTransport.Receive(buffer, 0, buffer.Length, 100);Close the transport:
dtlsTransport.Close();SRTP implementation is designed to take RTP/RTCP and convert it to SRTP/SRTCP while maintaining the SRTP context. RTP/RTSP server and clients are out of the scope of this library, but for a fully working example based upon SharpRTSP please refer to the examples.
Generate a random SRTP master key for AES_CM_128_HMAC_SHA1_80 on the server:
string cryptoSuite = SrtpCryptoSuites.AES_CM_128_HMAC_SHA1_80;
byte[] MKI = null;
SrtpKeys keys = SrtpProtocol.CreateMasterKeys(cryptoSuite, MKI);Obtain the generated master key + master salt to send it to the client:
byte[] masterKeySalt = keys.MasterKeySalt;Create a new SRTP context using those keys:
SrtpSessionContext context = SrtpProtocol.CreateSrtpSessionContext(keys);Create a new SRTP context using existing keys from the server:
string cryptoSuite = SrtpCryptoSuites.AES_CM_128_HMAC_SHA1_80;
byte[] masterKeySalt = ...
byte[] MKI = null;
SrtpKeys keys = SrtpProtocol.CreateMasterKeys(cryptoSuite, MKI, masterKeySalt);
SrtpSessionContext context = SrtpProtocol.CreateSrtpSessionContext(keys);To encrypt RTP and create SRTP:
byte[] rtp = ...
byte[] rtpBuffer = new byte[context.CalculateRequiredSrtpPayloadLength(rtp.Length)];
Buffer.BlockCopy(rtp, 0, rtpBuffer, 0, rtp.Length);
context.ProtectRtp(rtpBuffer, rtp.Length, out int length);
byte[] srtp = rtpBuffer.Take(length).ToArray();To decrypt SRTP and create RTP:
byte[] srtp = ...
context.UnprotectRtp(srtp, srtp.Length, out int length);
byte[] rtp = srtp.Take(length).ToArray();To encrypt RTCP and create SRTCP:
byte[] rtcp = ...
byte[] rtcpBuffer = new byte[context.CalculateRequiredSrtcpPayloadLength(rtcp.Length)];
Buffer.BlockCopy(rtcp, 0, rtcpBuffer, 0, rtcp.Length];
context.ProtectRtcp(rtcpBuffer, rtcp.Length, out int length);
byte[] srtcp = rtcpBuffer.Take(length).ToArray();To decrypt SRTCP and create RTCP:
byte[] srtcp = ...
context.UnprotectRtcp(srtcp, srtcp.Length, out int length);
byte[] rtcp = srtcp.Take(length).ToArray();SRTP samples can be found in the SharpRealtimeStreaming repo.
DTLS-SRTP uses a modified DTLS client/server with the "use_srtp" extension to negotiate the SRTP encryption parameters and derive the corresponding SRTP keys.
First generate the TLS certificate, this time it will be ECDsa:
bool isRSA = false;
var ecdsaCertificate = DtlsCertificateUtils.GenerateCertificate("WebRTC", DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddDays(30), isRSA);Create the DTLS-SRTP server:
var server = new DtlsSrtpServer(ecdsaCertificate.Certificate, ecdsaCertificate.PrivateKey, SignatureAlgorithm.ecdsa, HashAlgorithm.sha256);Subscribe for OnSessionStarted:
server.OnSessionStarted += (sender, e) =>
{
var context = e.Context;
var clientTransport = e.ClientDatagramTransport;
...
};Create the DTLS transport. Here we will use UDP on localhost, port 8888:
UdpDatagramTransport udpServerTransport = new UdpDatagramTransport("127.0.0.1:8888", null);Wait for the client and perform DTLS handshake:
bool isShutdown = false;
while(!isShutdown)
{
DtlsTransport dtlsTransport = server.DoHandshake(
out string error,
udpServerTransport,
() =>
{
return udpServerTransport.RemoteEndPoint.ToString();
},
(remoteEndpoint) =>
{
return new UdpDatagramTransport(null, remoteEndpoint);
});
}After the OnSessionStarted event is executed, you can use the Context to protect/unprotect data and clientTransport to send/receive SRTP.
Generate the TLS certificate, this time it will be ECDsa:
bool isRSA = false;
var ecdsaCertificate = DtlsCertificateUtils.GenerateCertificate("WebRTC", DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddDays(30), isRSA);Create the DTLS-SRTP client:
var client = new DtlsSrtpClient(ecdsaCertificate.Certificate, ecdsaCertificate.PrivateKey, SignatureAlgorithm.ecdsa, HashAlgorithm.sha256)Subscribe for OnSessionStarted:
client.OnSessionStarted += (sender, e) =>
{
var context = e.Context;
var clientTransport = e.ClientDatagramTransport;
...
};Create the DTLS transport. Here we will use UDP on localhost, port 8888:
UdpDatagramTransport udpServerTransport = new UdpDatagramTransport(null, "127.0.0.1:8888");Connect the client:
DtlsTransport dtlsTransport = client.DoHandshake(out string error, udpClientTransport);After the OnSessionStarted event is executed, you can use the Context to protect/unprotect data and clientTransport to send/receive SRTP.