namespace Hazel.Dtls { /// /// DTLS version constants /// public enum ProtocolVersion : ushort { /// /// Use to obfuscate DTLS as regular UDP packets /// UDP = 0, /// /// DTLS 1.2 /// DTLS1_2 = 0xFEFD, } /// /// DTLS record content type /// public enum ContentType : byte { ChangeCipherSpec = 20, Alert = 21, Handshake = 22, ApplicationData = 23, } /// /// Encode/decode DTLS record header /// public struct Record { public ContentType ContentType; public ProtocolVersion ProtocolVersion; public ushort Epoch; public ulong SequenceNumber; public ushort Length; public const int Size = 13; /// /// Parse a DTLS record from wire format /// /// True if we successfully parse the record header. Otherwise false public static bool Parse(out Record record, ProtocolVersion? expectedProtocolVersion, ByteSpan span) { record = new Record(); if (span.Length < Size) { return false; } record.ContentType = (ContentType)span[0]; record.ProtocolVersion = (ProtocolVersion)span.ReadBigEndian16(1); record.Epoch = span.ReadBigEndian16(3); record.SequenceNumber = span.ReadBigEndian48(5); record.Length = span.ReadBigEndian16(11); if (expectedProtocolVersion.HasValue && record.ProtocolVersion != expectedProtocolVersion.Value) { return false; } return true; } /// /// Encode a DTLS record to wire format /// public void Encode(ByteSpan span) { span[0] = (byte)this.ContentType; span.WriteBigEndian16((ushort)this.ProtocolVersion, 1); span.WriteBigEndian16(this.Epoch, 3); span.WriteBigEndian48(this.SequenceNumber, 5); span.WriteBigEndian16(this.Length, 11); } } public struct ChangeCipherSpec { public const int Size = 1; enum Value : byte { ChangeCipherSpec = 1, } /// /// Parse a ChangeCipherSpec record from wire format /// /// /// True if we successfully parse the ChangeCipherSpec /// record. Otherwise, false. /// public static bool Parse(ByteSpan span) { if (span.Length != 1) { return false; } Value value = (Value)span[0]; if (value != Value.ChangeCipherSpec) { return false; } return true; } /// /// Encode a ChangeCipherSpec record to wire format /// public static void Encode(ByteSpan span) { span[0] = (byte)Value.ChangeCipherSpec; } } }