/// <summary> /// Add the MESSAGE-INTEGRITY attribute to the message. /// This should be fired just before a call to StunClient.SendMessage as it needs existing /// attribute to be computed. But these attributes MUST be added before the MESSAGE-ATTRIBUTE /// except for FINGERPRINT attribute which MUST be added at the end of the StunMessage /// and also used in the MESSAGE-INTEGRITY computation /// </summary> /// <param name="password">The password used to authenticate the StunMessage</param> /// <param name="useLongTermCredentials">True if this StunMessage should authenticate using longterm credentials</param> public void AddMessageIntegrity(String password, Boolean useLongTermCredentials) { password = new SASLprep().Prepare(password); byte[] hmacSha1Key; if (useLongTermCredentials) { if (this.Stun.Username == null) throw new ArgumentException("USERNAME attribute is mandatory for long-term credentials MESSAGE-INTEGRITY creation", "this.Username"); if (this.Stun.Realm == null) throw new ArgumentException("REALM attribute is mandatory for long-term credentials MESSAGE-INTEGRITY creation", "this.Realm"); using (MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider()) { String valueToHashMD5 = String.Format(CultureInfo.CurrentCulture, "{0}:{1}:{2}", this.Stun.Username.ValueString, this.Stun.Realm.ValueString, password); hmacSha1Key = md5.ComputeHash(StunMessage.Encoder.GetBytes(valueToHashMD5)); } } else { hmacSha1Key = StunMessage.Encoder.GetBytes(password); } StunAttribute messageIntegrity = new StunAttribute(StunAttributeType.MessageIntegrity, this.ComputeHMAC(hmacSha1Key)); this.SetAttribute(messageIntegrity); }
/// <summary> /// Constructs a new StunAttribute /// </summary> /// <param name="type">The type of this StunAttribute</param> /// <param name="typeBytes">The value of the type of this StunAttribute in bytes</param> /// <param name="value">The value of this StunAttribute</param> public StunAttribute(StunAttributeType type, byte[] typeBytes, byte[] value) { if (typeBytes == null) throw new ArgumentNullException("value", "Cannot be null"); if (value == null) throw new ArgumentNullException("value", "Cannot be null"); switch (type) { case StunAttributeType.Software: case StunAttributeType.Realm: case StunAttributeType.Nonce: case StunAttributeType.ErrorCode: if (value.Length > 763) throw new ArgumentOutOfRangeException("value", "Cannot be greater than 763 bytes for the given type as described in RFC 5389"); break; case StunAttributeType.Username: if (value.Length > 513) throw new ArgumentOutOfRangeException("value", "Cannot be greater than 513 bytes for the given type as described in RFC 5389"); break; } switch (type) { case StunAttributeType.Realm: case StunAttributeType.Username: String saslPrepValue = new SASLprep().Prepare(StunMessage.Encoder.GetString(value)); value = StunMessage.Encoder.GetBytes(saslPrepValue); break; } this.TypeBytes = typeBytes; this.Type = type; this.Value = value; }