dtls_srtp學習筆記


注:以下為rfc5764的學習筆記,不保證完全正確。

DTLS-SRTP是DTLS的一個擴展,將SRTP加解密與DTLS的key交換和會話管理相結合。從SRTP的角度看,是為其提供一種新的key協商管理的方法;從DTLS的角度看,是為應用數據提供一個新的數據格式(SRTP/SRTCP)。

1,應用層數據加解密是由SRTP完成的,要求必須是RTP/RTCP的格式。
2,DTLS的握手過程是為SRTP加解密過程協商使用哪種profile和密鑰。
3,除了應用數據加密為SRTP格式,其他record-layer的報文仍為普通的DTLS格式(比如TLS control message)
4,當發送SRTP格式的應用層數據時,需要直接跳過DTLS加密層,將SRTP數據包透傳到下層的數據傳輸層做發送。

由於密鑰和加密參數是在DTLS握手過程中協商得到的,而此過程是保密的,因而相比常規的方式(比如在通過SDP消息交互來協商)更為安全。在發起DTLS握手之前,需要先設置use-srtp擴展。

接收端使用 DTLS-SRTP
自DTLS下層的傳輸層收到報文之后,需要根據包頭特征手動區分做demultiplexing,一般可以如下進行
檢查第一個報文的第一個字節
1,是[0, 1]時,表示可能是STUN報文
2,是[128, 191]時,表示可能時RTP(SRTP)報文
3,是[20, 63]時,表示可能是DTLS record layer報文
其他的類別請根據實際情況做區分處理

DTLS握手成功之后,需要導出key material,然后從中分離出server/client端用於SRTP對稱加密的密鑰。key material中對應SRTP的密鑰,構成如下

client_master_key server_master_key client_salt server_salt

其中 master_key 和 salt 的長度是根據最終協商的 SRTP 的profile來確定的,具體可查 RFC3711 SRTP

key material導出的規范見 RFC5705 Keying Material Exporters for TLS

webrtc中對此代碼實現見,webrtc/pc/channel.cc中 BaseChannel::SetupDtlsSrtp_n() 函數

Code Sample using DTLS-SRTP

 1 #define SRTP_MASTER_KEY_KEY_LEN 16
 2 #define SRTP_MASTER_KEY_SALT_LEN 14
 3 static void dtls_srtp_init( struct transport_dtls *dtls )
 4 {
 5 
 6 /*
 7   When SRTP mode is in effect, different keys are used for ordinary
 8    DTLS record protection and SRTP packet protection.  These keys are
 9    generated using a TLS exporter [RFC5705] to generate
10 
11    2 * (SRTPSecurityParams.master_key_len +
12         SRTPSecurityParams.master_salt_len) bytes of data
13 
14    which are assigned as shown below.  The per-association context value
15    is empty.
16 
17    client_write_SRTP_master_key[SRTPSecurityParams.master_key_len];
18    server_write_SRTP_master_key[SRTPSecurityParams.master_key_len];
19    client_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len];
20    server_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len];
21 */
22   int code;
23   err_status_t     err;
24   srtp_policy_t policy;
25   char dtls_buffer[SRTP_MASTER_KEY_KEY_LEN * 2 + SRTP_MASTER_KEY_SALT_LEN * 2];
26   char client_write_key[SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN];
27   char server_write_key[SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN];
28   size_t offset = 0;
29 
30   /*
31    The exporter label for this usage is "EXTRACTOR-dtls_srtp".  (The
32    "EXTRACTOR" prefix is for historical compatibility.)
33    RFC 5764 4.2.  Key Derivation
34   */
35   const char * label = "EXTRACTOR-dtls_srtp";
36 
37   SRTP_PROTECTION_PROFILE * srtp_profile= SSL_get_selected_srtp_profile( dtls->ssl );
38 
39 /* SSL_export_keying_material exports a value derived from the master secret,
40 * as specified in RFC 5705. It writes |olen| bytes to |out| given a label and
41 * optional context. (Since a zero length context is allowed, the |use_context|
42 * flag controls whether a context is included.)
43 *
44 * It returns 1 on success and zero otherwise.
45 */
46   code = SSL_export_keying_material(dtls->ssl, 
47                                     dtls_buffer, 
48                                     sizeof(dtls_buffer),
49                                     label, 
50                                     strlen( label),
51                                     NULL,
52                                     0, 
53                                     PJ_FALSE);
54 
55   memcpy(&client_write_key[0], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
56   offset += SRTP_MASTER_KEY_KEY_LEN;
57   memcpy(&server_write_key[0], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
58   offset += SRTP_MASTER_KEY_KEY_LEN;
59   memcpy(&client_write_key[SRTP_MASTER_KEY_KEY_LEN], &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN);
60   offset += SRTP_MASTER_KEY_SALT_LEN;
61   memcpy(&server_write_key[SRTP_MASTER_KEY_KEY_LEN], &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN); 
62 
63   switch( srtp_profile->id )
64   {
65   case SRTP_AES128_CM_SHA1_80:
66     crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
67     crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
68     break;
69   case SRTP_AES128_CM_SHA1_32:
70     crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);   // rtp is 32,
71     crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);  // rtcp still 80
72     break;
73   default:
74     assert(0);
75   }
76   policy.ssrc.value = 0;
77   policy.next = NULL;
78 
79   /* Init transmit direction */
80   policy.ssrc.type = ssrc_any_outbound;  
81   policy.key = client_write_key;    
82 
83   err = srtp_create(&dtls->srtp_ctx_rx, &policy);
84   if (err != err_status_ok) {
85     printf("not working\n");
86   } 
87 
88   /* Init receive direction */
89   policy.ssrc.type = ssrc_any_inbound;  
90   policy.key = server_write_key;    
91 
92   err = srtp_create(&dtls->srtp_ctx_tx, &policy);
93   if (err != err_status_ok) {
94     printf("not working\n");
95   } 
96 
97 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM