WebRTC筆記2-STUN算法

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。

下圖所示


屏幕快照 2017-02-20 19.45.26.png

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

屏幕快照 2017-02-20 20.19.37.png

代碼

// 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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 12,351評論 6 13
  • 春秋時齊國大將田單功高蓋世,當(dāng)時他面臨著燕國大軍,敵強(qiáng)我弱,形勢十分危急,他先后利用反間計(jì),將對手將領(lǐng)替換。再用火...
    明月清風(fēng)舟閱讀 836評論 0 1
  • 更新標(biāo)題【體驗(yàn)內(nèi)測】更新標(biāo)題 更新內(nèi)容【1-修復(fù)Bug龔玥菲通過個人發(fā)廣告發(fā)的凍成狗一個個方法方法太多 \n2-...
    strlly閱讀 361評論 0 1
  • 蘭亭集序作為王右任群聚眾賢,醉后之作,其行書筆法,氣韻乃是典范,可惜無真跡遺存至今,現(xiàn)存版本只是當(dāng)時唐太宗皇帝令大...
    小亦吾廬閱讀 375評論 0 0
  • 若所有的流浪都是因?yàn)槲?我如何能不愛你風(fēng)霜的面容 若世間的悲苦 你都已為我嘗盡 我如何能不愛你憔悴的心 他們說 你...
    露珠拾遺閱讀 224評論 0 0

友情鏈接更多精彩內(nèi)容