0%

Airplay握手流程(二)

fairplay

fairplay是苹果的流传输协议。在建立连接前,进行四次握手

  • 第一次握手(发送方发出)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    POST /fp-setup RTSP/1.0
    X-Apple-ET: 32
    Content-Length: 16
    Content-Type: application/octet-stream
    CSeq: 4
    DACP-ID: 1FF65A04A9252F60
    Active-Remote: 2814835199
    User-Agent: AirPlay/409.16

    // 报文
    FPLY»

    // 报文16进制
    0100 xx xx xx xx 46 50 4c 59 03 01 01 00 00 00 00 04
    0110 02 00 02 bb
    报文的第5个字节表明他的fairplay版本version,此例是0x03;第15个字节表明模式mode,此例是0x02
  • 第二次握手(接收端回应)
    接收端判断fairplay版本是否一致,不一致忽略,握手失败
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    RTSP/1.0 200 OK
    CSeq: 4
    Server: AirTunes/220.68
    Content-Type: application/octet-stream
    Content-Length: 142

    // 报文
    FPLYÁi£Rîí5±ÝXÖOÁQëS½
    C6Íhö8ÿj[R·ú²¶TÇD!¢ÇþØ=·ª×Ñpcâ¤WUY¯üv4}@CXäûä,©ÞÜ^²£ª=.ÍYçîç 6)ò*ýsSݹÜnVøPÎ

    // 报文16进制
    00b0 xx xx xx xx 46 50 4c 59 03 01 02 00 00 00 00 82
    00c0 02 02 c1 69 a3 52 ee ed 35 b1 8c dd 9c 58 d6 4f
    00d0 16 c1 51 9a 89 eb 53 17 bd 0d 43 36 cd 68 f6 38
    00e0 ff 9d 01 6a 5b 52 b7 fa 92 16 b2 b6 54 82 c7 84
    00f0 44 11 81 21 a2 c7 fe d8 3d b7 11 9e 91 82 aa d7
    0100 d1 8c 70 63 e2 a4 57 55 59 10 af 9e 0e fc 76 34
    0110 7d 16 40 43 80 7f 58 1e e4 fb e4 2c a9 de dc 1b
    0120 5e b2 a3 aa 3d 2e cd 59 e7 ee e7 0b 36 29 f2 2a
    0130 fd 16 1d 87 73 53 dd b9 9a dc 8e 07 00 6e 56 f8
    0140 50 ce
    版本合理之后,根据模式返回对应的142字节数据,代码如下:
    1
    2
    3
    4
    5
    6
    char reply_message[4][142] = {{0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x00,0x0f,0x9f,0x3f,0x9e,0x0a,0x25,0x21,0xdb,0xdf,0x31,0x2a,0xb2,0xbf,0xb2,0x9e,0x8d,0x23,0x2b,0x63,0x76,0xa8,0xc8,0x18,0x70,0x1d,0x22,0xae,0x93,0xd8,0x27,0x37,0xfe,0xaf,0x9d,0xb4,0xfd,0xf4,0x1c,0x2d,0xba,0x9d,0x1f,0x49,0xca,0xaa,0xbf,0x65,0x91,0xac,0x1f,0x7b,0xc6,0xf7,0xe0,0x66,0x3d,0x21,0xaf,0xe0,0x15,0x65,0x95,0x3e,0xab,0x81,0xf4,0x18,0xce,0xed,0x09,0x5a,0xdb,0x7c,0x3d,0x0e,0x25,0x49,0x09,0xa7,0x98,0x31,0xd4,0x9c,0x39,0x82,0x97,0x34,0x34,0xfa,0xcb,0x42,0xc6,0x3a,0x1c,0xd9,0x11,0xa6,0xfe,0x94,0x1a,0x8a,0x6d,0x4a,0x74,0x3b,0x46,0xc3,0xa7,0x64,0x9e,0x44,0xc7,0x89,0x55,0xe4,0x9d,0x81,0x55,0x00,0x95,0x49,0xc4,0xe2,0xf7,0xa3,0xf6,0xd5,0xba},
    {0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x01,0xcf,0x32,0xa2,0x57,0x14,0xb2,0x52,0x4f,0x8a,0xa0,0xad,0x7a,0xf1,0x64,0xe3,0x7b,0xcf,0x44,0x24,0xe2,0x00,0x04,0x7e,0xfc,0x0a,0xd6,0x7a,0xfc,0xd9,0x5d,0xed,0x1c,0x27,0x30,0xbb,0x59,0x1b,0x96,0x2e,0xd6,0x3a,0x9c,0x4d,0xed,0x88,0xba,0x8f,0xc7,0x8d,0xe6,0x4d,0x91,0xcc,0xfd,0x5c,0x7b,0x56,0xda,0x88,0xe3,0x1f,0x5c,0xce,0xaf,0xc7,0x43,0x19,0x95,0xa0,0x16,0x65,0xa5,0x4e,0x19,0x39,0xd2,0x5b,0x94,0xdb,0x64,0xb9,0xe4,0x5d,0x8d,0x06,0x3e,0x1e,0x6a,0xf0,0x7e,0x96,0x56,0x16,0x2b,0x0e,0xfa,0x40,0x42,0x75,0xea,0x5a,0x44,0xd9,0x59,0x1c,0x72,0x56,0xb9,0xfb,0xe6,0x51,0x38,0x98,0xb8,0x02,0x27,0x72,0x19,0x88,0x57,0x16,0x50,0x94,0x2a,0xd9,0x46,0x68,0x8a},
    {0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x02,0xc1,0x69,0xa3,0x52,0xee,0xed,0x35,0xb1,0x8c,0xdd,0x9c,0x58,0xd6,0x4f,0x16,0xc1,0x51,0x9a,0x89,0xeb,0x53,0x17,0xbd,0x0d,0x43,0x36,0xcd,0x68,0xf6,0x38,0xff,0x9d,0x01,0x6a,0x5b,0x52,0xb7,0xfa,0x92,0x16,0xb2,0xb6,0x54,0x82,0xc7,0x84,0x44,0x11,0x81,0x21,0xa2,0xc7,0xfe,0xd8,0x3d,0xb7,0x11,0x9e,0x91,0x82,0xaa,0xd7,0xd1,0x8c,0x70,0x63,0xe2,0xa4,0x57,0x55,0x59,0x10,0xaf,0x9e,0x0e,0xfc,0x76,0x34,0x7d,0x16,0x40,0x43,0x80,0x7f,0x58,0x1e,0xe4,0xfb,0xe4,0x2c,0xa9,0xde,0xdc,0x1b,0x5e,0xb2,0xa3,0xaa,0x3d,0x2e,0xcd,0x59,0xe7,0xee,0xe7,0x0b,0x36,0x29,0xf2,0x2a,0xfd,0x16,0x1d,0x87,0x73,0x53,0xdd,0xb9,0x9a,0xdc,0x8e,0x07,0x00,0x6e,0x56,0xf8,0x50,0xce},
    {0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x03,0x90,0x01,0xe1,0x72,0x7e,0x0f,0x57,0xf9,0xf5,0x88,0x0d,0xb1,0x04,0xa6,0x25,0x7a,0x23,0xf5,0xcf,0xff,0x1a,0xbb,0xe1,0xe9,0x30,0x45,0x25,0x1a,0xfb,0x97,0xeb,0x9f,0xc0,0x01,0x1e,0xbe,0x0f,0x3a,0x81,0xdf,0x5b,0x69,0x1d,0x76,0xac,0xb2,0xf7,0xa5,0xc7,0x08,0xe3,0xd3,0x28,0xf5,0x6b,0xb3,0x9d,0xbd,0xe5,0xf2,0x9c,0x8a,0x17,0xf4,0x81,0x48,0x7e,0x3a,0xe8,0x63,0xc6,0x78,0x32,0x54,0x22,0xe6,0xf7,0x8e,0x16,0x6d,0x18,0xaa,0x7f,0xd6,0x36,0x25,0x8b,0xce,0x28,0x72,0x6f,0x66,0x1f,0x73,0x88,0x93,0xce,0x44,0x31,0x1e,0x4b,0xe6,0xc0,0x53,0x51,0x93,0xe5,0xef,0x72,0xe8,0x68,0x62,0x33,0x72,0x9c,0x22,0x7d,0x82,0x0c,0x99,0x94,0x45,0xd8,0x92,0x46,0xc8,0xc3,0x59}};

    // 分别对应模式0-3
    模式之间的区别、数据包表示的内容,还需要进一步学习
  • 第三次握手(发送方发出)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    POST /fp-setup RTSP/1.0
    X-Apple-ET: 32
    Content-Length: 164
    Content-Type: application/octet-stream
    CSeq: 5
    DACP-ID: 1FF65A04A9252F60
    Active-Remote: 2814835199
    User-Agent: AirPlay/409.16

    // 报文16进制(txt报文跟md格式换行符冲突了..)
    0100 xx xx xx xx xx 46 50 4c 59 03 01 03 00 00 00 00
    0110 98 02 8f 1a 9c ef f8 33 ec eb 40 f8 2e d4 bd 27
    0120 e1 10 fa d1 05 c5 57 d0 d6 e6 61 83 c2 18 0e 29
    0130 e7 c0 e2 1a 83 11 0b 82 a7 b4 90 1b db 13 4b 89
    0140 92 ff 4e 27 ba 32 30 a4 55 8d d2 64 4c fd 7f 98
    0150 85 fc f1 90 2f 2a f6 91 70 e1 17 89 be 4f 3f 57
    0160 27 07 6c ea bb 8f 0d 27 cf 51 db f0 8e 89 78 e9
    0170 b9 55 6a 6a 38 f1 56 85 d6 73 92 b7 46 8a 46 5d
    0180 21 81 59 d3 b9 6f 3e 7e ab a3 2c 2d e2 62 28 66
    0190 1d 10 f7 13 bf 4b 50 ab bc 39 a1 fe 46 29 a4 da
    01a0 49 18 81 8e 3f a0 fc 5c 83
    内容是fairplay加密密钥keymsg,长度固定164字节
  • 第四次握手(接收方回应)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    RTSP/1.0 200 OK
    CSeq: 5
    Server: AirTunes/220.68
    Content-Type: application/octet-stream
    Content-Length: 32

    FPLYKP«¼9¡þF)¤ÚI? ü\

    // 报文16进制
    00b0 xx xx xx 46 50 4c 59 03 01 04 00 00 00 00 14 4b
    00c0 50 ab bc 39 a1 fe 46 29 a4 da 49 18 81 8e 3f a0
    00d0 fc 5c 83
    报文的前12个字节是固定的
    1
    char fp_header[] = {0x46, 0x50, 0x4c, 0x59, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14};
    后20个字节,实际上是第三次握手报文的末尾20个字节

fairplay总结

协议内容还需要进一步学习。但是从目前几次握手来看,两边主要是检查fairplay版本以及商量模式,并最终确定一个164字节的密钥用于以后的加解密处理

SETUP 1

发送端传输

fairplay认证成功后,发送端会发送SETUP包

SETUP包在整个airplay建立连接过程中会由发送端发送最多三次,现在是第一次

1
2
3
4
5
6
7
8
9
10
11
12
SETUP rtsp://192.168.137.1/10555496157292350542 RTSP/1.0
Content-Length: 529
Content-Type: application/x-apple-binary-plist
CSeq: 6
DACP-ID: 1FF65A04A9252F60
Active-Remote: 2814835199
User-Agent: AirPlay/409.16

bplist00ß

RetSeiv^timingProtocol[sessionUUIDVosName^osBuildVersion]sourceVersionZtimingPort_isScreenMirroringSessionYosVersionTekeyXdeviceIDUmodelTnameZmacAddress OnþôTûÝNîqÒ¿\%iýSNTP_$927CA7D4-6369-4C4E-BB1F-B098F51192B5YiPhone OSU17B84V409.16Õ T13.2OHFPLY< ¡4»píFÁµÂûmýÒEb3¯xú )6ÚZ`²&ò/s{VêÁ÷Ú´ ¦_10:30:25:B1:D7:4BWiPad7,5jrainv iPad_10:30:25:A6:E6:B8),0?KRaoz¤³¸ÃÅØÜ
#n³

SETUP包采用的是bplist格式传输,解析后大概如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>et</key>
<integer>32</integer>
<key>eiv</key> // aes初向量
<data>
GSgNHeRh+6vF1GfGcxMbFg==
</data>
<key>timingProtocol</key> // 时间同步协议类型
<string>NTP</string>
<key>sessionUUID</key> // 会话uuid
<string>FC871575-191F-434C-9CAC-56AC500AAB3A</string>
<key>osName</key> // os
<string>iPhone OS</string>
<key>osBuildVersion</key> // os版本
<string>17B84</string>
<key>sourceVersion</key>
<string>409.16</string>
<key>timingPort</key> // 时间同步端口
<integer>49234</integer>
<key>isScreenMirroringSession</key> // 是否镜像会话
<true/>
<key>osVersion</key> // os版本
<string>13.2</string>
<key>ekey</key> // aes密钥密文
<data>
RlBMWQECAQAAAAA8AAAAAPSn9omnrwyvkQ3dQ2zlYhcAAAAQ3U7aEmD/w57Bd760J6nq
lPr1kfslMSn4sNDywSEHZzLndoYH
</data>
<key>deviceID</key>
<string>10:30:25:B1:D7:4B</string>
<key>model</key>
<string>iPad7,5</string>
<key>name</key> // 设备名称
<string>rain的 iPad</string>
<key>macAddress</key> // mac地址
<string>10:30:25:A6:E6:B8</string>
</dict>
</plist>
  • eiv
    16字节数据,作为aes加密的初向量
  • ekey
    72字节数据,内容是被fairplay加密后的aes密钥
  • timing_port
    时间同步端口
  • name
    设备显示名字
  • deviceId
    设备ID,注意不是mac地址

rtp初始化

SETUP 1包主要初始化了raop协议的

  • ip
    支持ipv4以及ipv6
  • 设备名称
  • DeviceId
  • 时间同步协议远端端口
  • 音频缓冲区
    • 创建aac解码器
    • 初始化加密环境
      其中eiv可以直接使用,但是ekey是密文。下面是得到aes密钥的流程
      1. `ekey`通过[fairplay](#fairplay)解密获取16位密文`fairplay_ekey`
      2. 初始化sha512上下文
      3. sha512摘要`fairplay_ekey`
      4. sha512摘要`ecdh_secret`
      5. 使用sha512签名的64位数据作为aes加密密钥`aeskey`
  • 视频缓冲区
    • 初步初始化加密环境
      SETUP 1阶段初始化只是记录16位fairplay_ekey以及ecdh_secret,后续加密在SETUP 2完成

接收端回应

回应一个空包

1
2
3
4
5
6
7
8
GET /info RTSP/1.0
X-Apple-ProtocolVersion: 1
CSeq: 7
DACP-ID: 1FF65A04A9252F60
Active-Remote: 2814835199
User-Agent: AirPlay/409.16


SETUP 1总结

SETUP 1阶段实际上是发送端单方面的数据传输,接收端根据报文初始化rtp协议。其中音频环境已完成,镜像环境未完成。

其中音频加密协议主要使用aes加密算法,其中初向量来自包中eiv数据,密钥的获取需要经过fairplay解密、pair流程的ecdh密钥、sha512签名运算获得