public static STUNMessage ParseSTUNMessage(byte[] buffer, int bufferLength) { if (buffer != null && buffer.Length > 0 && buffer.Length >= bufferLength) { STUNMessage stunMessage = new STUNMessage(); stunMessage.Header = STUNHeader.ParseSTUNHeader(buffer); if (stunMessage.Header.MessageLength > 0) { stunMessage.Attributes = STUNAttribute.ParseMessageAttributes(buffer, STUNHeader.STUN_HEADER_LENGTH, bufferLength); } return(stunMessage); } return(null); }
public static STUNMessage ParseSTUNMessage(byte[] buffer, int bufferLength) { if (buffer != null && buffer.Length > 0 && buffer.Length >= bufferLength) { STUNMessage stunMessage = new STUNMessage(); stunMessage._receivedBuffer = buffer.Take(bufferLength).ToArray(); stunMessage.Header = STUNHeader.ParseSTUNHeader(buffer); if (stunMessage.Header.MessageLength > 0) { stunMessage.Attributes = STUNAttribute.ParseMessageAttributes(buffer, STUNHeader.STUN_HEADER_LENGTH, bufferLength); } if (stunMessage.Attributes.Count > 0 && stunMessage.Attributes.Last().AttributeType == STUNAttributeTypesEnum.FingerPrint) { // Check fingerprint. var fingerprintAttribute = stunMessage.Attributes.Last(); var input = buffer.Take(buffer.Length - STUNAttribute.STUNATTRIBUTE_HEADER_LENGTH - FINGERPRINT_ATTRIBUTE_CRC32_LENGTH).ToArray(); uint crc = Crc32.Compute(input) ^ FINGERPRINT_XOR; byte[] fingerPrint = (BitConverter.IsLittleEndian) ? BitConverter.GetBytes(NetConvert.DoReverseEndian(crc)) : BitConverter.GetBytes(crc); //logger.LogDebug($"STUNMessage supplied fingerprint attribute: {fingerprintAttribute.Value.HexStr()}."); //logger.LogDebug($"STUNMessage calculated fingerprint attribute: {fingerPrint.HexStr()}."); if (fingerprintAttribute.Value.HexStr() == fingerPrint.HexStr()) { stunMessage.isFingerprintValid = true; } } return(stunMessage); } return(null); }
public static List <STUNAttribute> ParseMessageAttributes(byte[] buffer, int startIndex, int endIndex) { if (buffer != null && buffer.Length > startIndex && buffer.Length >= endIndex) { List <STUNAttribute> attributes = new List <STUNAttribute>(); int startAttIndex = startIndex; while (startAttIndex < endIndex) { UInt16 stunAttributeType = BitConverter.ToUInt16(buffer, startAttIndex); UInt16 stunAttributeLength = BitConverter.ToUInt16(buffer, startAttIndex + 2); byte[] stunAttributeValue = null; if (BitConverter.IsLittleEndian) { stunAttributeType = NetConvert.DoReverseEndian(stunAttributeType); stunAttributeLength = NetConvert.DoReverseEndian(stunAttributeLength); } if (stunAttributeLength > 0) { if (stunAttributeLength + startIndex + 4 > endIndex) { logger.LogWarning( "The attribute length on a STUN parameter was greater than the available number of bytes."); } else { stunAttributeValue = new byte[stunAttributeLength]; Buffer.BlockCopy(buffer, startAttIndex + 4, stunAttributeValue, 0, stunAttributeLength); } } STUNAttributeTypesEnum attributeType = STUNAttributeTypes.GetSTUNAttributeTypeForId(stunAttributeType); STUNAttribute attribute = null; if (attributeType == STUNAttributeTypesEnum.ChangeRequest) { attribute = new STUNChangeRequestAttribute(stunAttributeValue); } else if (attributeType == STUNAttributeTypesEnum.MappedAddress) { attribute = new STUNAddressAttribute(stunAttributeValue); } else if (attributeType == STUNAttributeTypesEnum.ErrorCode) { attribute = new STUNErrorCodeAttribute(stunAttributeValue); } else if (attributeType == STUNAttributeTypesEnum.XORMappedAddress || attributeType == STUNAttributeTypesEnum.XORPeerAddress || attributeType == STUNAttributeTypesEnum.XORRelayedAddress) { attribute = new STUNXORAddressAttribute(attributeType, stunAttributeValue); } else { attribute = new STUNAttribute(attributeType, stunAttributeValue); } attributes.Add(attribute); // Attributes start on 32 bit word boundaries so where an attribute length is not a multiple of 4 it gets padded. int padding = (stunAttributeLength % 4 != 0) ? 4 - (stunAttributeLength % 4) : 0; startAttIndex = startAttIndex + 4 + stunAttributeLength + padding; } return(attributes); } else { return(null); } }
public static List<STUNAttribute> ParseMessageAttributes(byte[] buffer, int startIndex, int endIndex) { if (buffer != null && buffer.Length > startIndex && buffer.Length >= endIndex) { List<STUNAttribute> attributes = new List<STUNAttribute>(); int startAttIndex = startIndex; while (startAttIndex < endIndex) { UInt16 stunAttributeType = BitConverter.ToUInt16(buffer, startAttIndex); UInt16 stunAttributeLength = BitConverter.ToUInt16(buffer, startAttIndex + 2); byte[] stunAttributeValue = null; if (BitConverter.IsLittleEndian) { stunAttributeType = Utility.ReverseEndian(stunAttributeType); stunAttributeLength = Utility.ReverseEndian(stunAttributeLength); } if (stunAttributeLength > 0) { if (stunAttributeType == (int)STUNAttributeTypesEnum.Username && stunAttributeLength > buffer.Length - startIndex - 4) { // Received some STUN messages where the username is shorter than the claimed length. int realLength = buffer.Length - startIndex - 4; stunAttributeValue = new byte[realLength]; Buffer.BlockCopy(buffer, startIndex + 4, stunAttributeValue, 0, realLength); } else { stunAttributeValue = new byte[stunAttributeLength]; Buffer.BlockCopy(buffer, startIndex + 4, stunAttributeValue, 0, stunAttributeLength); } } STUNAttributeTypesEnum attributeType = STUNAttributeTypes.GetSTUNAttributeTypeForId(stunAttributeType); STUNAttribute attribute = null; if (attributeType == STUNAttributeTypesEnum.ChangeRequest) { attribute = new STUNChangeRequestAttribute(stunAttributeValue); } else if (attributeType == STUNAttributeTypesEnum.MappedAddress) { attribute = new STUNAddressAttribute(stunAttributeValue); } else { attribute = new STUNAttribute(attributeType, stunAttributeLength, stunAttributeValue); } attributes.Add(attribute); startAttIndex = startAttIndex + 4 + stunAttributeLength; } return attributes; } else { return null; } }
public byte[] ToByteBuffer(byte[] messageIntegrityKey, bool addFingerprint) { UInt16 attributesLength = 0; foreach (STUNAttribute attribute in Attributes) { attributesLength += Convert.ToUInt16(STUNAttribute.STUNATTRIBUTE_HEADER_LENGTH + attribute.PaddedLength); } if (messageIntegrityKey != null) { attributesLength += STUNAttribute.STUNATTRIBUTE_HEADER_LENGTH + MESSAGE_INTEGRITY_ATTRIBUTE_HMAC_LENGTH; } int messageLength = STUNHeader.STUN_HEADER_LENGTH + attributesLength; byte[] buffer = new byte[messageLength]; if (BitConverter.IsLittleEndian) { Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian((UInt16)Header.MessageType)), 0, buffer, 0, 2); Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(attributesLength)), 0, buffer, 2, 2); Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(STUNHeader.MAGIC_COOKIE)), 0, buffer, 4, 4); } else { Buffer.BlockCopy(BitConverter.GetBytes((UInt16)Header.MessageType), 0, buffer, 0, 2); Buffer.BlockCopy(BitConverter.GetBytes(attributesLength), 0, buffer, 2, 2); Buffer.BlockCopy(BitConverter.GetBytes(STUNHeader.MAGIC_COOKIE), 0, buffer, 4, 4); } Buffer.BlockCopy(Header.TransactionId, 0, buffer, 8, STUNHeader.TRANSACTION_ID_LENGTH); int attributeIndex = 20; foreach (STUNAttribute attr in Attributes) { attributeIndex += attr.ToByteBuffer(buffer, attributeIndex); } //logger.LogDebug($"Pre HMAC STUN message: {ByteBufferInfo.HexStr(buffer, attributeIndex)}"); if (messageIntegrityKey != null) { var integrityAttibtue = new STUNAttribute(STUNAttributeTypesEnum.MessageIntegrity, new byte[MESSAGE_INTEGRITY_ATTRIBUTE_HMAC_LENGTH]); HMACSHA1 hmacSHA = new HMACSHA1(messageIntegrityKey, true); byte[] hmac = hmacSHA.ComputeHash(buffer, 0, attributeIndex); integrityAttibtue.Value = hmac; attributeIndex += integrityAttibtue.ToByteBuffer(buffer, attributeIndex); } if (addFingerprint) { // The fingerprint attribute length has not been included in the length in the STUN header so adjust it now. attributesLength += STUNAttribute.STUNATTRIBUTE_HEADER_LENGTH + FINGERPRINT_ATTRIBUTE_CRC32_LENGTH; messageLength += STUNAttribute.STUNATTRIBUTE_HEADER_LENGTH + FINGERPRINT_ATTRIBUTE_CRC32_LENGTH; if (BitConverter.IsLittleEndian) { Buffer.BlockCopy(BitConverter.GetBytes(NetConvert.DoReverseEndian(attributesLength)), 0, buffer, 2, 2); } else { Buffer.BlockCopy(BitConverter.GetBytes(attributesLength), 0, buffer, 2, 2); } var fingerprintAttribute = new STUNAttribute(STUNAttributeTypesEnum.FingerPrint, new byte[FINGERPRINT_ATTRIBUTE_CRC32_LENGTH]); uint crc = Crc32.Compute(buffer) ^ FINGERPRINT_XOR; byte[] fingerPrint = (BitConverter.IsLittleEndian) ? BitConverter.GetBytes(NetConvert.DoReverseEndian(crc)) : BitConverter.GetBytes(crc); fingerprintAttribute.Value = fingerPrint; Array.Resize(ref buffer, messageLength); fingerprintAttribute.ToByteBuffer(buffer, attributeIndex); } return(buffer); }
public static List <STUNAttribute> ParseMessageAttributes(byte[] buffer, int startIndex, int endIndex) { if (buffer != null && buffer.Length > startIndex && buffer.Length >= endIndex) { List <STUNAttribute> attributes = new List <STUNAttribute>(); int startAttIndex = startIndex; while (startAttIndex < endIndex) { UInt16 stunAttributeType = BitConverter.ToUInt16(buffer, startAttIndex); UInt16 stunAttributeLength = BitConverter.ToUInt16(buffer, startAttIndex + 2); byte[] stunAttributeValue = null; if (BitConverter.IsLittleEndian) { stunAttributeType = Utility.ReverseEndian(stunAttributeType); stunAttributeLength = Utility.ReverseEndian(stunAttributeLength); } if (stunAttributeLength > 0) { if (stunAttributeType == (int)STUNAttributeTypesEnum.Username && stunAttributeLength > buffer.Length - startIndex - 4) { // Received some STUN messages where the username is shorter than the claimed length. int realLength = buffer.Length - startIndex - 4; stunAttributeValue = new byte[realLength]; Buffer.BlockCopy(buffer, startIndex + 4, stunAttributeValue, 0, realLength); } else { stunAttributeValue = new byte[stunAttributeLength]; Buffer.BlockCopy(buffer, startIndex + 4, stunAttributeValue, 0, stunAttributeLength); } } STUNAttributeTypesEnum attributeType = STUNAttributeTypes.GetSTUNAttributeTypeForId(stunAttributeType); STUNAttribute attribute = null; if (attributeType == STUNAttributeTypesEnum.ChangeRequest) { attribute = new STUNChangeRequestAttribute(stunAttributeValue); } else if (attributeType == STUNAttributeTypesEnum.MappedAddress) { attribute = new STUNAddressAttribute(stunAttributeValue); } else { attribute = new STUNAttribute(attributeType, stunAttributeLength, stunAttributeValue); } attributes.Add(attribute); startAttIndex = startAttIndex + 4 + stunAttributeLength; } return(attributes); } else { return(null); } }