1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
namespace Hazel.Dtls
{
/// <summary>
/// DTLS version constants
/// </summary>
public enum ProtocolVersion : ushort
{
/// <summary>
/// Use to obfuscate DTLS as regular UDP packets
/// </summary>
UDP = 0,
/// <summary>
/// DTLS 1.2
/// </summary>
DTLS1_2 = 0xFEFD,
}
/// <summary>
/// DTLS record content type
/// </summary>
public enum ContentType : byte
{
ChangeCipherSpec = 20,
Alert = 21,
Handshake = 22,
ApplicationData = 23,
}
/// <summary>
/// Encode/decode DTLS record header
/// </summary>
public struct Record
{
public ContentType ContentType;
public ProtocolVersion ProtocolVersion;
public ushort Epoch;
public ulong SequenceNumber;
public ushort Length;
public const int Size = 13;
/// <summary>
/// Parse a DTLS record from wire format
/// </summary>
/// <returns>True if we successfully parse the record header. Otherwise false</returns>
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;
}
/// <summary>
/// Encode a DTLS record to wire format
/// </summary>
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,
}
/// <summary>
/// Parse a ChangeCipherSpec record from wire format
/// </summary>
/// <returns>
/// True if we successfully parse the ChangeCipherSpec
/// record. Otherwise, false.
/// </returns>
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;
}
/// <summary>
/// Encode a ChangeCipherSpec record to wire format
/// </summary>
public static void Encode(ByteSpan span)
{
span[0] = (byte)Value.ChangeCipherSpec;
}
}
}
|