Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/DtlsSrtpClientSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,50 @@
client.OnSessionStarted += (sender, e) =>
{
isSrtpSessionRunning = true;
socket.ReceiveTimeout = 1000;
socket.ReceiveTimeout = 1000;

var context = e.Context;
var srtpSession = Task.Run(async () =>
{
var protectionProfile = context.DecodeRtpContext.ProtectionProfile;
Console.WriteLine($"SRTP cipher: {protectionProfile.Cipher}, auth: {protectionProfile.Auth}");

byte[] receiveBuffer = new byte[2048];
int timeoutCounter = 0;

while (!isShutdown)
{
int receivedLen = 0;
int receivedLen = 0;
try
{
receivedLen = socket.Receive(receiveBuffer);
timeoutCounter = 0;
}
catch (SocketException ex)
{
if(ex.SocketErrorCode == SocketError.TimedOut)
if (ex.SocketErrorCode == SocketError.TimedOut)
{
timeoutCounter++;
}
}

if (receivedLen != 0)
{
Console.WriteLine($"SRTP: {Convert.ToHexString(receiveBuffer.Take(receivedLen).ToArray())}");

if (context.UnprotectRtp(receiveBuffer, receivedLen, out int length) == 0)
try
{
var length = context.UnprotectRtp(receiveBuffer, receiveBuffer);
byte[] rtp = receiveBuffer.Take(length).ToArray();
Console.WriteLine($"RTP: {Convert.ToHexString(rtp)}");
}
catch (System.Security.Cryptography.CryptographicException ex)
{
Console.WriteLine($"SRTP error: {ex.HResult}");
}
}

if(timeoutCounter > 30)
if (timeoutCounter > 30)
{
isSrtpSessionRunning = false;
break;
Expand All @@ -74,7 +79,7 @@
{
Console.WriteLine($"DTLS connected");

while(isSrtpSessionRunning)
while (isSrtpSessionRunning)
{
Thread.Sleep(1000);
}
Expand Down
7 changes: 6 additions & 1 deletion src/DtlsSrtpServerSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,17 @@
Buffer.BlockCopy(rtpPacket, 0, rtpBuffer, 0, rtpPacket.Length);

Console.WriteLine($"RTP: {Convert.ToHexString(rtpPacket)}");
if (context.ProtectRtp(rtpBuffer, rtpPacket.Length, out int length) == 0)
try
{
var length = context.ProtectRtp(rtpBuffer, rtpBuffer);
byte[] srtp = rtpBuffer.Take(length).ToArray();
Console.WriteLine($"SRTP: {Convert.ToHexString(srtp)}");
listenSocket.SendTo(srtp, remoteEndpoint);
}
catch (System.Security.Cryptography.CryptographicException ex)
{
Console.WriteLine($"SRTP error: {ex.HResult}");
}

sequenceNumber++;
Thread.Sleep(1000);
Expand Down
52 changes: 52 additions & 0 deletions src/SharpSRTP.Tests/Convert.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#if !NET5_0_OR_GREATER
using System;

namespace SharpSRTP.Tests
{
internal static partial class Convert
{
internal static byte[] FromHexString(string s)
{
if (s == null) throw new ArgumentNullException(nameof(s));
if ((s.Length & 1) != 0) throw new FormatException("Hex string must have even length.");

int len = s.Length >> 1;
var bytes = new byte[len];
for (int i = 0, bi = 0; bi < len; i += 2, bi++)
{
int hi = ParseNibble(s[i]);
int lo = ParseNibble(s[i + 1]);
bytes[bi] = (byte)((hi << 4) | lo);
}
return bytes;
}

internal static string ToHexString(ReadOnlySpan<byte> bytes)
{
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
char[] c = new char[bytes.Length * 2];
int ci = 0;
for (int i = 0; i < bytes.Length; i++)
{
byte b = bytes[i];
c[ci++] = NibbleToHex((b >> 4) & 0xF);
c[ci++] = NibbleToHex(b & 0xF);
}
return new string(c);
}

private static int ParseNibble(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
throw new FormatException("Invalid hex character.");
}

private static char NibbleToHex(int value)
{
return (char)(value < 10 ? ('0' + value) : ('A' + (value - 10)));
}
}
}
#endif
2 changes: 1 addition & 1 deletion src/SharpSRTP.Tests/SharpSRTP.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFrameworks>net462;net8.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
Expand Down
56 changes: 44 additions & 12 deletions src/SharpSRTP.Tests/TestProtectUnprotect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,65 @@
using SharpSRTP.SRTP;
using System;
using System.Data;
using System.Linq;

namespace SharpSRTP.Tests
{
[TestClass]
public class TestProtectUnprotect
{
[DataRow("n7z9GgmnJ4Bc2hC0prEf8KFCKv8EyG+4WrUOg7oi", "80e1000103cb6bc84218a6a3001006c801123318f6882d06086141a9c44dfbfb7e9f1cf997eb257b77c732bcf779ae750b6493aff001815dcfc814a4fb96089153b0becc4e091f2632584ee88fc01701a0dc5111f3d7b201b0a5496972275d00e503d921370ecbdebc5ac4e54572e59ca65c29ce246b438659df04633d5d0452da1b9ce729670a616b4f5050df2c7de897ca16f5762d6df93da0134d6c3d2fedb178be2fbbfa3c702673c231d5af4f1c9b2fa791a19ef3a23aee2325dc633f19ebde33f0eeec8351cfa62bbbf9339d6b7e322ba3bb5e1d31a3956475cf450984d4a274d2583d1b80e0", "80e1000103cb6bc84218a6a3cf77c0bc864411afc82ac978b1087b699bf51892b46152bcf95963dbc69f7efbb776c79a0daa3e2e7ae8a3ceda005fb29b068d099d0b0a103ae0bc9ae62b55c0c8dca25583478377f2bb310f0371a2ada32a119e96a84c796b9376a093409e21a7b16bafedbc4fffadabe5f770e895ec36b8de959819aac706aba8788ba9da2fd3f58bd43796fd51124e92117d98575cc82d302741a8be3c9234bafeb42d2c52ebd9e6edfcb1e7e01fb40131758c9d1181525b1c02e35cc34b46e0aaf1df4dc931036aaf4f9044b47058d22008395596e8000b4a7def6aa97a989e76f0c88ba939313459373a6f")]
public static System.Collections.Generic.IEnumerable<object[]> Test_Srtp_Protect_Unprotect_TestData()
{
var masterKeySalt = "n7z9GgmnJ4Bc2hC0prEf8KFCKv8EyG+4WrUOg7oi";
var rtp = "80e1000103cb6bc84218a6a3001006c801123318f6882d06086141a9c44dfbfb7e9f1cf997eb257b77c732bcf779ae750b6493aff001815dcfc814a4fb96089153b0becc4e091f2632584ee88fc01701a0dc5111f3d7b201b0a5496972275d00e503d921370ecbdebc5ac4e54572e59ca65c29ce246b438659df04633d5d0452da1b9ce729670a616b4f5050df2c7de897ca16f5762d6df93da0134d6c3d2fedb178be2fbbfa3c702673c231d5af4f1c9b2fa791a19ef3a23aee2325dc633f19ebde33f0eeec8351cfa62bbbf9339d6b7e322ba3bb5e1d31a3956475cf450984d4a274d2583d1b80e0";
var srtp = "80e1000103cb6bc84218a6a3cf77c0bc864411afc82ac978b1087b699bf51892b46152bcf95963dbc69f7efbb776c79a0daa3e2e7ae8a3ceda005fb29b068d099d0b0a103ae0bc9ae62b55c0c8dca25583478377f2bb310f0371a2ada32a119e96a84c796b9376a093409e21a7b16bafedbc4fffadabe5f770e895ec36b8de959819aac706aba8788ba9da2fd3f58bd43796fd51124e92117d98575cc82d302741a8be3c9234bafeb42d2c52ebd9e6edfcb1e7e01fb40131758c9d1181525b1c02e35cc34b46e0aaf1df4dc931036aaf4f9044b47058d22008395596e8000b4a7def6aa97a989e76f0c88ba939313459373a6f";

yield return new object[] { masterKeySalt, rtp, srtp, true };
yield return new object[] { masterKeySalt, rtp, srtp, false };
}

[DynamicData(nameof(Test_Srtp_Protect_Unprotect_TestData))]
[TestMethod]
public void Test_Srtp_Protect_Unprotect(string masterKeySalt, string rtp, string srtp)
public void Test_Srtp_Protect_Unprotect(string masterKeySalt, string rtp, string srtp, bool useSharedBuffer)
{
byte[] masterKeySaltBytes = Convert.FromBase64String(masterKeySalt);
byte[] masterKeySaltBytes = System.Convert.FromBase64String(masterKeySalt);
byte[] rtpBytes = Convert.FromHexString(rtp);
byte[] srtpBytes = rtpBytes.Concat(new byte[10]).ToArray();
byte[] srtpProtectedBytes = new byte[rtpBytes.Length + 10];
ReadOnlySpan<byte> srtpUnprotectedBytes;

if (useSharedBuffer)
{
srtpUnprotectedBytes = srtpProtectedBytes.AsSpan(0, rtpBytes.Length);
rtpBytes.AsSpan().CopyTo(srtpProtectedBytes);
}
else
{
srtpUnprotectedBytes = rtpBytes;
}

byte[] MKI = null;
var keys = SrtpProtocol.CreateMasterKeys(SrtpCryptoSuites.AES_CM_128_HMAC_SHA1_80, MKI, masterKeySaltBytes);
var context = SrtpProtocol.CreateSrtpSessionContext(keys);
int ret = context.ProtectRtp(srtpBytes, rtpBytes.Length, out int len);

string srtpString = Convert.ToHexString(srtpBytes.Take(len).ToArray()).ToLowerInvariant();
Assert.AreEqual(srtp, srtpString);

context.UnprotectRtp(srtpBytes, srtpBytes.Length, out int olen);
int len = context.ProtectRtp(srtpProtectedBytes.AsSpan(), srtpUnprotectedBytes);
var expectedSrtpBytes = Convert.FromHexString(srtp);
var actualSrtpBytes = srtpProtectedBytes.AsSpan(0, len).ToArray();
Assert.IsTrue(expectedSrtpBytes.SequenceEqual(actualSrtpBytes),
$"SRTP protect mismatch.\nExpected: {BitConverter.ToString(expectedSrtpBytes)}\nActual: {BitConverter.ToString(actualSrtpBytes)}");

string rtpString = Convert.ToHexString(srtpBytes.Take(olen).ToArray()).ToLowerInvariant();
Assert.AreEqual(rtp, rtpString);
var decodeContext = SrtpProtocol.CreateSrtpSessionContext(keys);
Span<byte> srtpUnprotectedOut;
if (useSharedBuffer)
{
srtpUnprotectedOut = srtpProtectedBytes;
}
else
{
srtpUnprotectedOut = new byte[srtpProtectedBytes.Length];
}
int olen = decodeContext.UnprotectRtp(srtpUnprotectedOut, srtpProtectedBytes.AsSpan(0, len));
var actualUnprotected = srtpUnprotectedOut.Slice(0, olen).ToArray();
Assert.IsTrue(rtpBytes.SequenceEqual(actualUnprotected),
$"SRTP unprotect mismatch.\nExpected: {BitConverter.ToString(rtpBytes)}\nActual: {BitConverter.ToString(actualUnprotected)}");
}
}
}
Loading