Rtmp協議複雜握手(handshake)詳解

2021-10-03 11:49:25 字數 3712 閱讀 7705

先從wireshark抓包中直觀的認識握手到底長什麼樣子吧

格式:c0:乙個位元組0x03,

c1:timestamp(4bytes)+ version(4bytes)+ (複雜二進位制串)1526bytes

version(4bytes):至於這個version具體是多少因客戶端的不同也是不同。在srs中給的是

version = [0x80, 0x00, 0x07, 0x02] // c1[4-7]

version = [0x04, 0x05, 0x00, 0x01] // s1[4-7]

我也是按srs中給的使用的。

注意:在抓包分析中fms用的digest-key模式(schema1),從各大文章中分析得出的貌似fms僅支援schema1模式

下後面詳細講解複雜二進位制串的構成與演算法

格式:s0:乙個位元組0x03,

s1:timestamp(4bytes)+ version(4bytes)+ (複雜二進位制串)1526bytes

s2:timestamp(4bytes)+ timestamp2(4bytes)+ (複雜二進位制串)1526bytes

s1結構與c1結構完全相同,s2中只是把version換成了timestamp2。

本人在實現rtmp服務的過程中發現,不論是srs還是crtmpserver這個version都不同,個人嘗試只要不是0都是可以的。

s1的時間戳作為伺服器我用的當前時間戳,不管事fms還是srs生成的s1時間戳分析出來都是乙個以前的時間戳甚至是一八幾幾年的時間,我也是很無語。有大神知道這個邏輯請指教。

格式:c2:timestamp(4bytes)+ timestamp2(4bytes)+ (複雜二進位制串)1526bytes

s1結構與s2結構完全相同。

注意:在c2、s2**現的時間戳的計算,如下:

time(4個位元組): 這個字段必須包含終端在s1 (給 c2) 或者 c1 (給 s2) 發的 timestamp。

time2 (4個位元組):這個字段必須包含終端先前發出資料報 (s1 或者 c1) timestamp。

//1c、s1結構 key:764bytes 

random data:(offset)bytes

key data:(128bytes) --可以秘鑰

random data(764-offset-128-4)bytes

offset:4bytes(大端對應在0-764的正整數)

找到offset那四個位元組分別轉換成數字相加,因為這個是隨機數有可能超過了key的所有長度所有需要取餘數。這個取餘的數就是764位元組的整體長度- 128位元組的key秘鑰-4位元組的自身長度。具體演算法如下:

var keymaxoffsetsize = 764 - 128 - 4;  //632

int keyoffset;

switch (schemal)

這個就是128位元組長度的二進位制串,rtmp伺服器在收到c1的key秘鑰後,會生成s1的秘鑰key。在官方及其各大部落格中介紹的都是openssl中的乙個加密演算法傳入c1的key秘鑰從而得到共享秘鑰,把這個共享秘鑰作為s1的key秘鑰:

在srs中是這樣使用的:

bignum* ppk = null;

if ((ppk = bn_bin2bn((const unsigned char*)ppkey, ppkey_size, 0)) == null)

但是:在c#中很難去實現這個演算法,後來我發現如果把c1的秘鑰key直接當做s1秘鑰key發給客戶端也是可以的。

digest是通過秘鑰算出來的乙個32位元組的二進位制串(注意:我這裡寫的是秘鑰,而不是秘鑰key)。

在求digest的過程中用到幾個秘鑰,如下:

public static byte fmskey = new byte; // 68

public static byte fpkey = new byte ; // 62 

其中還設計到乙個演算法:hmacsha256演算法,如下:

/// /// hmacsha256演算法,返回的結果始終是32位

///

/// 加密的鍵,可以是任何資料

/// 取key資料的長度

/// 待加密的內容

/// 返回base64編碼字串

public static byte hmacsha256(byte key, int keysize, byte content)

}

另乙個內容就是在計算digest所使用的輸入引數,該引數是整個1536位元組取出36位元組digest部分所剩餘部分,在此命名為joinedarray,joinedarray結構圖如下

s1 digest演算法如下:

獲取到digest的offset,然後求出joinedarray

var digest = hmacsha256(fmskey, 36, joinedarray);

注意:c1的schema模式要與s1的模式相同,所以在生成s1的時候要先求出c1的模式(一般是schem1)與key秘鑰。c1的驗證公式為:

if (convert.tobase64string(hmacsha256(fpkey, 30, joinedarray)) == convert.tobase64string(c1.digest))

c2、s2結構 1536bytes

其實c2、s2就是把digest放到最後那32位元組上。

c2、s2digest演算法如下:

第一步:計算乙個臨時key,var temp_key = hmacsha256(fmskey, 68, c1.digest);

第二部:計算joinedarray

第三部:使用臨時kye計算digest,var digest = hmacsha256(temp_key, 32, joinedarray);

RTMP協議詳解 (一) 握手

rtmp協議介紹 包結構 握手在rtmp連線建立後,服務端與客戶端需要通過3次交換報文完成握手.握手其他的協議不同,是由三個靜態大小的塊,而不是可變大小的塊組成的,客戶端與伺服器傳送相同的三個chunk,客戶端傳送c0,c1,c2 chunk,服務端傳送s0,s1,s2 chunk.傳送順序 握手開...

RTMP協議概述

rtmp協議概述 介紹 rtmp協議就像乙個用來裝資料報的容器,這些資料可以是amf格式的資料,也可以是flv中的視 音訊資料.乙個單一的連線可以通過不同的通道傳輸多路網路流.這些通道中的包都是按照固定大小的包傳輸的.網路連線 connection copy to clipboard code va...

RTMP協議分析

rtmp協議封包 由乙個包頭和乙個包體組成,包頭可以是4種長度的任意一種 12,8,4,1 byte s 完整的rtmp包頭應該是12bytes,包含了時間戳,amfsize,amftype,streamid資訊,8位元組的包頭只紀錄了時間戳,amfsize,amftype,其他位元組的包頭紀錄資訊...