public void CalculateProperly() { var username = "******"; var password = "******"; var realm = "twilio.com"; var message = new byte[] { 0x00, 0x03, 0x00, 0x90, 0x21, 0x12, 0xa4, 0x42, 0xf5, 0xdb, 0xe7, 0xc1, 0x2a, 0x74, 0xbe, 0xf9, 0x8b, 0x16, 0x56, 0x3e, 0x00, 0x19, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x04, 0x00, 0x00, 0x03, 0x09, 0x00, 0x06, 0x00, 0x40, 0x61, 0x65, 0x30, 0x36, 0x33, 0x33, 0x63, 0x64, 0x35, 0x38, 0x62, 0x61, 0x30, 0x39, 0x37, 0x61, 0x31, 0x31, 0x36, 0x37, 0x63, 0x36, 0x64, 0x32, 0x63, 0x63, 0x34, 0x65, 0x32, 0x33, 0x36, 0x64, 0x62, 0x35, 0x32, 0x32, 0x35, 0x36, 0x61, 0x34, 0x30, 0x64, 0x35, 0x36, 0x35, 0x66, 0x31, 0x31, 0x65, 0x64, 0x66, 0x37, 0x36, 0x63, 0x30, 0x32, 0x64, 0x31, 0x33, 0x64, 0x62, 0x39, 0x33, 0x63, 0x00, 0x15, 0x00, 0x10, 0x37, 0x35, 0x64, 0x34, 0x35, 0x34, 0x31, 0x39, 0x63, 0x33, 0x39, 0x33, 0x34, 0x33, 0x66, 0x65, 0x00, 0x14, 0x00, 0x0a, 0x74, 0x77, 0x69, 0x6c, 0x69, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00, }; MessageIntegrity attr = MessageIntegrity.Calculate(username, password, realm, message); Assert.Equal( new byte[] { 0x77, 0xe8, 0xcf, 0x30, 0x9e, 0x85, 0x6c, 0x22, 0x72, 0x53, 0xa3, 0xb7, 0xe0, 0x35, 0x7c, 0xc2, 0x30, 0xfc, 0xbc, 0xf4, }, attr.Value ); }
public byte[] Encode(IStunContext ctx) { bool useMessageIntegrity = !string.IsNullOrEmpty(ctx?.Username) && !string.IsNullOrEmpty(ctx?.Password) && !string.IsNullOrEmpty(ctx?.Realm); var c = (ushort)Class; var m = (ushort)Method; int type = (m & 0x0f80) << 2 | (m & 0x0070) << 1 | (m & 0x000f) << 0 | (c & 0x2) << 7 | (c & 0x1) << 4; using (var ms = new MemoryStream()) { List <Attribute> attrs = Attributes.ToList(); if (!string.IsNullOrEmpty(ctx?.Username)) { attrs.Add(new Username(ctx.Username)); } if (ctx?.Nonce != null) { attrs.Add(new Attributes.Nonce(ctx.Nonce)); } if (!string.IsNullOrEmpty(ctx?.Realm)) { attrs.Add(new Realm(ctx.Realm)); } byte[] encodedAttrs; using (var ams = new MemoryStream()) { foreach (Attribute attr in attrs) { byte[] asBytes = attr.ToByteArray(TransactionId); ams.Write(asBytes, 0, asBytes.Length); } encodedAttrs = ams.ToArray(); } // 8 bytes for Fingerprint var messageLength = (ushort)(encodedAttrs.Length + FingerprintBytes); if (useMessageIntegrity) { messageLength += MessageIntegrityBytes; } ms.Write(((ushort)type).ToBytes(), 0, 2); ms.Write(messageLength.ToBytes(), 0, 2); ms.Write(MagicCookie, 0, MagicCookie.Length); ms.Write(TransactionId, 0, TransactionId.Length); ms.Write(encodedAttrs, 0, encodedAttrs.Length); if (useMessageIntegrity) { var lengthWithoutFingerprint = (ushort)(messageLength - FingerprintBytes); byte[] toCalc = ms.ToArray(); lengthWithoutFingerprint.ToBytes().CopyTo(toCalc, 2); MessageIntegrity mi = MessageIntegrity.Calculate( ctx?.Username, ctx?.Password, ctx?.Realm, toCalc); ms.Write(mi.ToByteArray(), 0, MessageIntegrityBytes); } Fingerprint fingerprint = Fingerprint.FromMessage( ms.ToArray() ); ms.Write(fingerprint.ToByteArray(), 0, FingerprintBytes); return(ms.ToArray()); } }