rtmfp协议中的加解密原理

转载自:http://bbs.baofengcloud.com/home.php?mod=space&uid=30&do=blog&quickforward=1&id=5

1.加解密原理

1.1.原理
     在DH密码系统中,p和g是公开的,发起者和接收者两端的p和g必须相同。特殊地,g等于2,p是一个1024位长的数字。发起者生成一个随机的1024位长的私有数字(x1),以此创建1024位长的DH公开数(y1)。
      y1 = g ^ x1 % p
     当目标接收到这条消息后。它会生成一个新的1024位随机数作为DH私有数(x2),和1024位的DH公开数(y2)。
      y2 = g ^ x2 % p
     发起者和反馈者要相互交换y1和y2,然后两端分别计算shared-secret,两端算出的结果应该是一样的。
      shared-secret = y1 ^ x2 % p = y2 ^ x1 % p
      除了shared-secret,发起者和反馈者两端还需要交换各自的initiator-nonce和responder-nonce,然后就可以计算出各自的加解密秘钥。
      decode key = HMAC-SHA256(shared-secret, HMAC-SHA256(responder nonce, initiator nonce))
      encode key = HMAC-SHA256(shared-secret, HMAC-SHA256(initiator nonce, responder nonce))

      cumulus使用的公开数p。
unsigned char p[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
1.2.握手阶段加解密
     handshake阶段,使用默认的sessionid=0,默认的加解密秘钥“Adobe Systems 02”。四部握手的加解密都要使用这个秘钥,但是第四部的时候要使用iikeying协议中获取到的sessionid。
1.3.秘钥交换
     秘钥交换指的是交换公开数y1,y2,initiator-nonce和responder-nonce。客户端与服务器端秘钥交换,客户端之间秘钥交换有些区别。certificate和nonce中存放的数据结构都是OPTION。
     客户端与服务器端秘钥交换时,y1存放在IIKeying的certificate中,后128字节,y2存放在RIIKeying的nonce中,后128字节。
     客户端之间秘钥交换时,y1存放在IIKeying的certificate中,后128字节,y2存放在RIHello的certificate中,后128字节。

2.与服务器交互
2.1.四步握手
2.1.1.IHello
     略。
2.1.2.RIHello
     certificate无用。
2.1.3.IIKeying
     certificate中只有一个option,结构为0x81,0x02,0x1d,0x02 + 128B随机数(y1)。
     nonce中包含多个option,结构为0x02,0x1d,0x02,0x41,0x0e + 64B随机数 + 0x03,0x1a,0x02,x0a,0x02,0x1e,0x02。
2.1.4.RIIKeying
     nonce中包含多个option,结构为0x03,0x1a,0x00,0x00,0x02,0x1e,0x00,0x41,0x0e + 128B随机数(y2)+ 0x03,0x1a,0x00,0x00,0x02,0x1e,x00。

2.2.建立会话

2.2.1.connect命令
发送包结构
0x80 + flowid + seqnum + fsn + option(0x050,x00,0x54,0x43,0x04 ,x00 ) + 5B(0x14,0x00,0x00,0x00,0x00) + amf
Name:                  no-name., STRING:   connect
Name:                  no-name., NUMBER:   1.00
Name:                       app, STRING:
Name:                  flashVer, STRING:   WIN 11,1,102,55
Name:                    swfUrl, UNDEFINED
Name:                     tcUrl, STRING:   rtmfp://192.168.200.39
Name:                      fpad, BOOLEAN:  FALSE
Name:              capabilities, NUMBER:   235.00
Name:               audioCodecs, NUMBER:   3575.00
Name:               videoCodecs, NUMBER:   252.00
Name:             videoFunction, NUMBER:   1.00
Name:                   pageUrl, UNDEFINED
Name:            objectEncoding, NUMBER:   3.00
返回包结构
0x80 + flowid + seqnum + fsn + option(0x050,x00,0x54,0x43,0x04 ,x00;0x02,0x0a,0x02 ) + 5B(0x14,0x00,0x00,0x00,0x00) + amf
Name:                  no-name., STRING:   _result
Name:                  no-name., NUMBER:   1.00
Name:                  no-name., NULL
Name:                     level, STRING:   status
Name:                      code, STRING:   NetConnection.Connect.Success
Name:               description, STRING:   Connection succeeded
Name:            objectEncoding, NUMBER:   3.00

2.2.2.setpeerinfo命令
发送包结构
0x00 + flowid + seqnum + fsn  + 5B(0x11,0x00,0x00,0x00,0x00 ,0x00 ) + amf
Name:           no-name., STRING:   setPeerInfo
Name:           no-name., NUMBER:   0.00
Name:           no-name., STRING:   192.168.202.91:1935
返回包结构
0x00 + flowid + seqnum + fsn  + 7B( 0x0 4, 0x0 0, 0x0 0, 0x0 0, 0x0 0, 0x0 0, 0x 29 ) + 4B(server keepalive) + 4B(peer keepalive)

2.3.如果加入group
     略

完整流程


3.客户端间交互
3.1四部握手
3.1.1.IHello
     略。
3.1.2.FIHello
      fihello命令中只有一个initiator地址,但是server可能会观察到initiator多个地址,如redirect中flag=1的地址。如果responder不回应initiator,则server回定时重发fihello命令,其中包含的地址会以轮询的方式变化,第一个fihello中的地址为flag=2的地址。
3.1.3.Redirect
      redirect命令中包含多个地址,每个地址前面有个flag,flag=2的地址是客户端自己上报的(准确地址),flag=1的地址为服务器观察到的(可能不准确),我们最好使用flag=2的地址。
flag 2, ip 192.168.202.91, port 58716
flag 1, ip 192.168.66.1, port 58716
flag 1, ip 192.168.108.1, port 58716
flag 1, ip 192.168.202.91, port 58716
3.1.4.RHello
      certificate中只有一个option,结构为0x81,0x02,0x1d,0x02 + 128B随机数(y2)。
3.1.5.IIKeying
      certificate中只有一个option,结构为0x81,0x02,0x1d,0x02 + 128B随机数(y1)。
      nonce中包含多个option,结构为0x02,0x1d,0x02,0x41,0x0e + 64B随机数 + 0x03,0x1a,0x02,x0a,0x02,0x1e,0x02。
3.1.6.RIIKeying
      nonce中包含多个option,结构为0x03,0x1a,0x00,0x00,0x02,0x1e,0x00,0x41,0x0e + 64B随机数。
3.2会话建立过程
     两个peer之间需要建立两个连接(4个数据流),分别为initiator到responder的连接和responder到initiator的连接,连接的建立过程是相同的,都是由play命令开始的。注意这里的连接值的是NetStream连接,而不是NetConnection连接。NetConnection的连接在整个点播过程中只有1个,而NetStream的连接每两个客户端之间就有2个。一次连接的交互过程如下所示。

play数据包
0x80 + flowid + seqnum + fsn  + option(0x050,x00,0x54,0x43,0x04 ,x05 )  + 6B(0x11,4B随机 ,0x00 ) + amf
Name:                  no-name., STRING:        play
Name:                  no-name., NUMBER:        0.00
Name:                  no-name., STRING:         data-stream(数据流名字,应用程序觉定)

play确认包
      play后面会跟随两个一样的确认包(除了时间戳略有差异),其实一个确认包就够了。

     下面的四个chunk有可能是一次性收到的,第一个chunk是0x10,后面三个是0x11,也有可能是分多次收到的。
|RtmpSampleAccess包(这个包可以忽略)
0x80 + flowid + seqnum + fsn + option(0x050,x00,0x54,0x43,0x04 ,x02;0x02,0x0a,0x02 ) + 6B(0x0f,0x00,0x00,0x00,0x00 ,0x00 ) + amf
Name:                  no-name., STRING:   |RtmpSampleAccess
Name:                  no-name., BOOLEAN:  FALSE
Name:                  no-name., BOOLEAN:  FALSE

11B包(这个包可以忽略)
0x00 +   11B
观察到的值:0x04,0xc6,0x0c,0xbe,0x16,0x00,0x00,0x00,0x00,0x00,0x02
观察到的值:0x04,0xc6,0x17,0xb6,0x7c,0x00,0x00,0x00,0x00,0x00,0x02

NetStream.Play.Reset包
0x00  + 6B(0x11,0x00,0x00,0x00,0x00 ,0x00 ) + amf
Name:                  no-name., STRING:   onStatus
Name:                  no-name., NUMBER:   0.00
Name:                  level, STRING:   status
Name:                  code, STRING:   NetStream.Play.Reset
Name:                  description, STRING:   Playing and resetting data-stream

NetStream.Play.Start包
0x00  + 6B(0x11,0x00,0x00,0x00,0x00 ,0x00 ) + amf
Name:                  no-name., STRING:   onStatus
Name:                  no-name., NUMBER:   0.00
Name:                  level, STRING:   status
Name:                  code, STRING:   NetStream.Play.Start
Name:                  description, STRING:   Started playing data-stream

NetStream确认包
     两个一样的确认包。

整个交互流程可以简化为


3.3.流关联方法
     每一个连接建立的过程中需要创建2个数据流。play命令中会带一个flow1,后面跟着的确认包表示flow1建立完成。NetStream命令中会带一个flow2,后面跟着的确认包表示flow2建立完成。我们还需要让flow1和flow2相互关联,方法是在NetStream的OPTION中设置。OPTION有两种,如下所示。
     第一个OPTION表示数据流的元信息,具体含义不明。例如:0x050,x00,0x54,0x43,0x04,x05。

     第二个OPTION表示当前数据包使用的流与flowID相关联,三个字段都是VLU格式。

     在play命令中会带第一种OPTION,NetStream命令中两种OPTION都带,第一个OPTION直接使用play中的OPTION,第二个OPTION中的flowID填写play带过来的flowID,表示两个flow相互关联。


3.4.数据发送
     当两边的双向数据流建立完毕后,就可以正式发送数据了,接收端收到的数据与发送端有关系。
     发送端调用: sendStream.send("__data", args),第一个参数是要求接收端实现的回调函数名,接收端必须实现这个函数来处理后面跟着的数据。发送端发送的内容就是args字符串。
     接收端收到的数据如下:
0x00 + flowid + seqnum + fsn +  6B(0x0 f,0x00,0x00,0x9b,0x70,0x00 ) + amf + 6B(0x 11,0x09,0x03,0x01,0x06,0x07 ) + 内容

4.部分细节描述
4.1.消息重发
     所有用0x10消息扩展的协议都必须由0x51确认,否则就必须走重发流程。
     举例:4步握手之后,client会发送由0x10扩展的connect命令,如果server不返回0x51确认,则client会一直重发connect,大约发送了15次,才宣告连接失败。如果server这时候返回了0x51则client就不会重发connect命令了,这时候client会等待server发送connectresult命令,一直等下去。

4.2.handshake过程中重发包
     在handshake过程中,initiator给responder发送0x30,0x38,如果responder没有返回包,则会重发,重发间隔类似一个等差数列。responder向initiator发送0x70,如果这时候没有收到后续包不需要重发,重发都是由initiator触发的。

4.3.rtmfp域名访问方式
     用rtmfp协议访问域名时,flash会向该域名下所有服务器发送ihello协议,服务器返回rhello协议,flash先收到哪个rhello协议就使用那一台服务器。

4.4.redirect与fihello协议
     redirect协议会返回多个打孔被动方地址,fihello只返回打孔主动方一个地址。redirect协议的sessionid=0,fihello的sessionid为客户端与服务器建立的id。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值