XOR-MAPPED-ADDRESS
- IP真實(shí)IP地址 XOR magic cookie (2112a442)
- PORT,真實(shí)端口 XOR magic cookie (2112a442) 前2字節(jié)
MESSAGE-INTEGRITY
anwser
a=ice-ufrag:SDZV
a=ice-pwd:n31QqnImNpUctZbD+1ZwLZBF
offer
a=ice-ufrag:o2lH
a=ice-pwd:E+LjzA6PVnYpSwqCl6mG01
SDP 有關(guān)STUN認(rèn)證的參數(shù)。
- 上面的是local的,下面的是remote的。
- 本機(jī)發(fā)送到遠(yuǎn)端需要使用remote的desc。
下圖所示

size為:96
header size為:20
message size為:76
原始:
00 01 00 4c 21 12 a4 42 53 56 79 33 73 54 53 6f
2b 7a 45 67 00 06 00 09 6f 32 6c 48 3a 53 44 5a
56 00 00 00 c0 57 00 04 00 03 00 0a 80 29 00 08
76 17 87 96 ae 1e 0c f1 00 24 00 04 6e 7e 1e ff
00 08 00 14 53 1c 5d 34 b1 3b 2f b4 a0 3e fe 55
92 de 93 a8 72 6f 76 eb 80 28 00 04 4d 10 60 2d
去除 MESSAGE-INTEGRITY 之下的 Attributes之后,
message size應(yīng)該是68
size - header size - other attr size
96-20-8=68
下面標(biāo)粗的部分(這里的message size跟實(shí)際長度并不匹配)
去除之后的應(yīng)該是
00 01 00 44 21 12 a4 42 53 56 79 33 73 54 53 6f
2b 7a 45 67 00 06 00 09 6f 32 6c 48 3a 53 44 5a
56 00 00 00 c0 57 00 04 00 03 00 0a 80 29 00 08
76 17 87 96 ae 1e 0c f1 00 24 00 04 6e 7e 1e ff
hmac-sha1計(jì)算結(jié)果
https://www.liavaag.org/English/SHA-Generator/HMAC

代碼
// Verifies a STUN message has a valid MESSAGE-INTEGRITY attribute, using the
// procedure outlined in RFC 5389, section 15.4.
bool StunMessage::ValidateMessageIntegrity(const char* data, size_t size,
const std::string& password) {
// Verifying the size of the message.
if ((size % 4) != 0) {
return false;
}
// Getting the message length from the STUN header.
uint16 msg_length = talk_base::GetBE16(&data[2]);
if (size != (msg_length + kStunHeaderSize)) {
return false;
}
// Finding Message Integrity attribute in stun message.
size_t current_pos = kStunHeaderSize;
bool has_message_integrity_attr = false;
while (current_pos < size) {
uint16 attr_type, attr_length;
// Getting attribute type and length.
attr_type = talk_base::GetBE16(&data[current_pos]);
attr_length = talk_base::GetBE16(&data[current_pos + sizeof(attr_type)]);
// If M-I, sanity check it, and break out.
if (attr_type == STUN_ATTR_MESSAGE_INTEGRITY) {
if (attr_length != kStunMessageIntegritySize ||
current_pos + attr_length > size) {
return false;
}
has_message_integrity_attr = true;
break;
}
// Otherwise, skip to the next attribute.
current_pos += sizeof(attr_type) + sizeof(attr_length) + attr_length;
if ((attr_length % 4) != 0) {
current_pos += (4 - (attr_length % 4));
}
}
if (!has_message_integrity_attr) {
return false;
}
// Getting length of the message to calculate Message Integrity.
size_t mi_pos = current_pos;
talk_base::scoped_ptr<char[]> temp_data(new char[current_pos]);
memcpy(temp_data.get(), data, current_pos);
if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
// Stun message has other attributes after message integrity.
// Adjust the length parameter in stun message to calculate HMAC.
size_t extra_offset = size -
(mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize);
size_t new_adjusted_len = size - extra_offset - kStunHeaderSize;
// Writing new length of the STUN message @ Message Length in temp buffer.
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |0 0| STUN Message Type | Message Length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
talk_base::SetBE16(temp_data.get() + 2,
static_cast<uint16>(new_adjusted_len));
}
char hmac[kStunMessageIntegritySize];
size_t ret = talk_base::ComputeHmac(talk_base::DIGEST_SHA_1,
password.c_str(), password.size(),
temp_data.get(), mi_pos,
hmac, sizeof(hmac));
ASSERT(ret == sizeof(hmac));
if (ret != sizeof(hmac))
return false;
// Comparing the calculated HMAC with the one present in the message.
return (std::memcmp(data + current_pos + kStunAttributeHeaderSize,
hmac, sizeof(hmac)) == 0);
}
FINGERPRINT
按照協(xié)議描述當(dāng)MESSAGE-INTEGRITY存在時,F(xiàn)INGERPRINT必須存在。
FINGERPRINT的算法:
- FINGERPRINT上面的所有部分進(jìn)行CRC-32運(yùn)算,然后XOR 0x5354554E
- The FINGERPRINT attribute MAY be present in all STUN messages. The value of the attribute is computed as the CRC-32 of the STUN message up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with the 32-bit value 0x5354554e (the XOR helps in cases where an application packet is also using CRC-32 in it). The 32-bit CRC is the one defined in ITU V.42 [ITU.V42.2002], which has a generator polynomial of x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1. When present, the FINGERPRINT attribute MUST be the last attribute in the message, and thus will appear after MESSAGE-INTEGRITY.
00 01 00 4c 21 12 a4 42 35 48 65 4d 6c 49 4d 39
41 43 66 38 00 06 00 09 49 53 4b 77 3a 39 75 32
71 00 00 00 c0 57 00 04 00 01 00 0a 80 2a 00 08
18 d2 67 dd 44 ca 9c c9 00 24 00 04 6e 7e 1e fe
00 08 00 14 a2 d7 12 3a e5 77 82 5e 03 4e cc 2a
34 80 33 55 c3 e0 4a d7 80 28 00 04 fc ea f7 45
去掉后面8字節(jié)
00 01 00 4c 21 12 a4 42 35 48 65 4d 6c 49 4d 39
41 43 66 38 00 06 00 09 49 53 4b 77 3a 39 75 32
71 00 00 00 c0 57 00 04 00 01 00 0a 80 2a 00 08
18 d2 67 dd 44 ca 9c c9 00 24 00 04 6e 7e 1e fe
00 08 00 14 a2 d7 12 3a e5 77 82 5e 03 4e cc 2a
34 80 33 55 c3 e0 4a d7
進(jìn)行crc-32運(yùn)算 選HEX
https://www.lammertbies.nl/comm/info/crc-calculation.html
0xAFBEA20B ^ 0x5354554E
http://xor.pw/
結(jié)果
0xfceaf745。對應(yīng)FINGERPRINT的值
貼代碼
// Verifies a message is in fact a STUN message, by performing the checks
// outlined in RFC 5389, section 7.3, including the FINGERPRINT check detailed
// in section 15.5.
bool StunMessage::ValidateFingerprint(const char* data, size_t size) {
// Check the message length.
size_t fingerprint_attr_size =
kStunAttributeHeaderSize + StunUInt32Attribute::SIZE;
if (size % 4 != 0 || size < kStunHeaderSize + fingerprint_attr_size)
return false;
// Skip the rest if the magic cookie isn't present.
const char* magic_cookie =
data + kStunTransactionIdOffset - kStunMagicCookieLength;
if (talk_base::GetBE32(magic_cookie) != kStunMagicCookie)
return false;
// Check the fingerprint type and length.
const char* fingerprint_attr_data = data + size - fingerprint_attr_size;
if (talk_base::GetBE16(fingerprint_attr_data) != STUN_ATTR_FINGERPRINT ||
talk_base::GetBE16(fingerprint_attr_data + sizeof(uint16)) !=
StunUInt32Attribute::SIZE)
return false;
// Check the fingerprint value.
uint32 fingerprint =
talk_base::GetBE32(fingerprint_attr_data + kStunAttributeHeaderSize);
return ((fingerprint ^ STUN_FINGERPRINT_XOR_VALUE) ==
talk_base::ComputeCrc32(data, size - fingerprint_attr_size));
}
const uint32 STUN_FINGERPRINT_XOR_VALUE = 0x5354554E;
bool StunMessage::AddFingerprint() {
// Add the attribute with a dummy value. Since this is a known attribute,
// it can't fail.
StunUInt32Attribute* fingerprint_attr =
new StunUInt32Attribute(STUN_ATTR_FINGERPRINT, 0);
VERIFY(AddAttribute(fingerprint_attr));
// Calculate the CRC-32 for the message and insert it.
talk_base::ByteBuffer buf;
if (!Write(&buf))
return false;
int msg_len_for_crc32 = static_cast<int>(
buf.Length() - kStunAttributeHeaderSize - fingerprint_attr->length());
uint32 c = talk_base::ComputeCrc32(buf.Data(), msg_len_for_crc32);
// Insert the correct CRC-32, XORed with a constant, into the attribute.
fingerprint_attr->SetValue(c ^ STUN_FINGERPRINT_XOR_VALUE);
return true;
}