
正文
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
#define SRTP_MASTER_KEY_KEY_LEN 16
#define SRTP_MASTER_KEY_SALT_LEN 14
static void dtls_srtp_init( struct transport_dtls *dtls )
{ /*
When SRTP mode is in effect, different keys are used for ordinary
DTLS record protection and SRTP packet protection. These keys are
generated using a TLS exporter [RFC5705] to generate 2 * (SRTPSecurityParams.master_key_len +
SRTPSecurityParams.master_salt_len) bytes of data which are assigned as shown below. The per-association context value
is empty. client_write_SRTP_master_key[SRTPSecurityParams.master_key_len];
server_write_SRTP_master_key[SRTPSecurityParams.master_key_len];
client_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len];
server_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len];
*/
int code;
err_status_t err;
srtp_policy_t policy;
char dtls_buffer[SRTP_MASTER_KEY_KEY_LEN * + SRTP_MASTER_KEY_SALT_LEN * ];
char client_write_key[SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN];
char server_write_key[SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN];
size_t offset = ; /*
The exporter label for this usage is "EXTRACTOR-dtls_srtp". (The
"EXTRACTOR" prefix is for historical compatibility.)
RFC 5764 4.2. Key Derivation
*/
const char * label = "EXTRACTOR-dtls_srtp"; SRTP_PROTECTION_PROFILE * srtp_profile= SSL_get_selected_srtp_profile( dtls->ssl ); /* SSL_export_keying_material exports a value derived from the master secret,
* as specified in RFC 5705. It writes |olen| bytes to |out| given a label and
* optional context. (Since a zero length context is allowed, the |use_context|
* flag controls whether a context is included.)
*
* It returns 1 on success and zero otherwise.
*/
code = SSL_export_keying_material(dtls->ssl,
dtls_buffer,
sizeof(dtls_buffer),
label,
strlen( label),
NULL,
,
PJ_FALSE); memcpy(&client_write_key[], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
offset += SRTP_MASTER_KEY_KEY_LEN;
memcpy(&server_write_key[], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
offset += SRTP_MASTER_KEY_KEY_LEN;
memcpy(&client_write_key[SRTP_MASTER_KEY_KEY_LEN], &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN);
offset += SRTP_MASTER_KEY_SALT_LEN;
memcpy(&server_write_key[SRTP_MASTER_KEY_KEY_LEN], &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN); switch( srtp_profile->id )
{
case SRTP_AES128_CM_SHA1_80:
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
break;
case SRTP_AES128_CM_SHA1_32:
crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // rtp is 32,
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // rtcp still 80
break;
default:
assert();
}
policy.ssrc.value = ;
policy.next = NULL; /* Init transmit direction */
policy.ssrc.type = ssrc_any_outbound;
policy.key = client_write_key; err = srtp_create(&dtls->srtp_ctx_rx, &policy);
if (err != err_status_ok) {
printf("not working\n");
} /* Init receive direction */
policy.ssrc.type = ssrc_any_inbound;
policy.key = server_write_key; err = srtp_create(&dtls->srtp_ctx_tx, &policy);
if (err != err_status_ok) {
printf("not working\n");
} }







