AirPlay 鏡像協(xié)議-下(交換秘鑰與傳輸)

AirPlay 鏡像協(xié)議-上(發(fā)現(xiàn))
可以用來運行和調(diào)試的源碼

目標(biāo)

當(dāng)點擊iPhone上的屏幕鏡像設(shè)備后,屏幕鏡像設(shè)備是如何收到鏡像圖像的

在iPhone上點擊屏幕鏡像之后,iPhone發(fā)起了13次請求,每次請求都是一次rtsp協(xié)議,rtsp協(xié)議可以看做是一種特別的http協(xié)議,只不過http協(xié)議請求和返回的第一行常規(guī)的HTTP/1.1修改成了RTSP/1.0
這13次請求分別如下

1. /info

iPhone沒有發(fā)送什么信息過來,只有一個請求,這是屏幕鏡像設(shè)備需要準(zhǔn)備比較多的數(shù)據(jù),形成一個字典,字典里面可能包含信息對,也可能包含字典,還可以包含字典,并把數(shù)據(jù)保存為plist二進(jìn)制形式發(fā)送給手機,例如根字典數(shù)據(jù)如下

                NSDictionary r_node = new NSDictionary();
                r_node["txtAirPlay"] = new NSData(AirPlayServer_mdns.bytesProperties);
                r_node["features"] =new NSNumber((UInt64)0x1E << 32 | 0x5A7FFFF7);
                r_node["audioFormats"] = audio_formats_node;
                r_node["pi"] = new NSString("2e388006-13ba-4041-9a67-25dd4a43d536");
                r_node["vv"] = new NSNumber(2);
                r_node["statusFlags"] = new NSNumber(68);
                r_node["keepAliveLowPower"] = new NSNumber(1);
                r_node["sourceVersion"] = new NSString("220.68");
                r_node["pk"] = new NSData(HexStringToBytes("b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7"));
                r_node["keepAliveSendStatsAsBody"] = new NSNumber(1);
                r_node["deviceID"] = new NSString("58:55:CA:1A:E2:88");
                r_node["name"] = new NSString("My AirPlay Device");
                r_node["model"] = new NSString("AppleTV2,1");
                r_node["macAddress"] = new NSString("58:55:CA:1A:E2:88");
                
                NSArray audio_formats_node = new NSArray();

                NSDictionary audio_format_0_node = new NSDictionary();
                audio_format_0_node["type"] = new NSNumber(100);
                ...
                audio_formats_node.Add(audio_format_0_node);

                NSDictionary audio_format_1_node = new NSDictionary();
                audio_format_1_node["type"] = new NSNumber(101);
                ...
                audio_formats_node.Add(audio_format_1_node);

                

                NSArray audio_latencies_node = new NSArray();
                NSDictionary audio_latencies_0_node = new NSDictionary();
                audio_latencies_0_node["outputLatencyMicros"] = new NSNumber(0);
                ...
                audio_latencies_node.Add(audio_latencies_0_node);

                NSDictionary audio_latencies_1_node = new NSDictionary();
                audio_latencies_1_node["outputLatencyMicros"] = new NSNumber(0);
                ...
                audio_latencies_node.Add(audio_latencies_1_node);
                r_node["audioLatencies"] = audio_latencies_1_node;




                NSArray displays_node = new NSArray();
                NSDictionary displays_0_node = new NSDictionary();
                displays_0_node["uuid"] = new NSString("e0ff8a27-6738-3d56-8a16-cc53aacee925");
                displays_0_node["widthPhysical"] = new NSNumber(0);
                displays_0_node["heightPhysical"] = new NSNumber(0);
                ...
                displays_node.Add(displays_0_node);

                r_node["displays"] = displays_node;

上述數(shù)據(jù)中,r_node["txtAirPlay"]比較特別,它是文章AirPlay 鏡像協(xié)議-上(發(fā)現(xiàn))中的字典信息,而且格式比較特別,舉例如下
假如有配對信息a->b,和cd->ef, 那么數(shù)據(jù)AirPlayServer_mdns.bytesProperties內(nèi)容為
{0x3, 'a', '=', 'b', 0x5, 'c', 'd', '=', 'e', 'f'},可以看到配對信息用等號=相連,配對信息前面有一字節(jié)的信息表明該組信息的長度,所以限制了配對信息長度不可以大于255,

在返回給iPhone的RTSP信息中,HEADER部分增加信息表明返回的是二進(jìn)制形式的plist文件
response.AddHeader("Content-Type", "application/x-apple-binary-plist");

2. /pair-setup

該請求,iPhone沒有攜帶重要的信息,鏡像設(shè)備發(fā)送一個ed25519的public key到iPhone,發(fā)送內(nèi)容作為RTSP的Body部分,該ed25519秘鑰對可以在使用的時候才生成

3&4. /pair-verify

這兩次請求是非常關(guān)鍵的,首先iPhone發(fā)送了自己的加密信息中的公鑰部分,也包含簽名需要的信息,然后鏡像設(shè)備進(jìn)行了簽名,并把簽名結(jié)果返回給iPhone,如果iPhone驗證了簽名成功,則把再次簽名的結(jié)果發(fā)送給鏡像設(shè)備來驗證,如果鏡像設(shè)備驗證成功,說明雙方都得到了對方身份已確認(rèn),稍微詳細(xì)點的信息可以看散列與加密算法的幾處實際應(yīng)用場景中的場景4:AirPlay協(xié)議

5&6. /fp-setup

兩次請求,body部分都帶有數(shù)據(jù),分別調(diào)用fairplay函數(shù)的setup和handshake,返回這兩個函數(shù)的返回值即可

7. SETUP

iPhone請求第二次,iPhone發(fā)給鏡像設(shè)備key,該key經(jīng)過步驟5和6初始化之后的fairplay解碼成一個aes加密算的aeskey,未來傳輸?shù)囊曨l編碼會用aeskey可以來加密,鏡像設(shè)備準(zhǔn)備好事件反饋端口和時間對齊端口發(fā)送給iPhone

8. GET /info RTSP/1.0

iPhone再次請求和1一樣的數(shù)據(jù),鏡像設(shè)備和1返回一樣的內(nèi)容

9. GET_PARAMETER

iPHone查詢鏡像設(shè)備的一些信息,目前在body播放只有如下內(nèi)容"volume\r\n", 鏡像設(shè)備可以返回給iPhone的body部分為"volume:0.0\r\n"

10. RECORD

iPhone發(fā)送Record命令,鏡像設(shè)備返回的RTSP Header中增加一條記錄,body為空
response.AddHeader("Audio-Latency", request.GetHeader("2205"));

11. SETUP

iPhone請求第二次setup,鏡像設(shè)備準(zhǔn)備好新的tcp服務(wù)器,準(zhǔn)備接收數(shù)據(jù),端口任意,并返回給iPhone

12. SET_PARAMETER

iPhone發(fā)送音量或者進(jìn)度條信息,可以不用處理,返回RTSP 200

13. /feedback

iPhone會不間斷發(fā)送/feedback,里面包含時間信息,可以不用處理,返回RTSP 200

這時,在步驟11中準(zhǔn)備的新tcp服務(wù)器,可以開始收到經(jīng)過步驟7中的提供的秘鑰進(jìn)行aes加密的視頻數(shù)據(jù)了。

音頻數(shù)據(jù)依然會通過roap.tcp.local來傳輸,所以現(xiàn)在收到的數(shù)據(jù)不包含音頻數(shù)據(jù)。

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

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

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