先從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,其他位元組的包頭紀錄資訊...