注:以下为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");
  } }

dtls_srtp学习笔记的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  3. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  4. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  5. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  6. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  7. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  8. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

  9. DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记

    今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...

随机推荐

  1. SpringMVC源码情操陶冶-DispatcherServlet类简析(一)

    阅读源码有利于陶冶情操,此文承接前文SpringMVC源码情操陶冶-DispatcherServlet父类简析 注意:springmvc初始化其他内容,其对应的配置文件已被加载至beanFactory ...

  2. 洛谷 [P2486] 染色

    树剖+线段树维护连续相同区间个数 注意什么时候长度要减一 #include <iostream> #include <cstdio> #include <cstdlib& ...

  3. 济南清北学堂游记 Day 0.

    (摄于千佛山山顶,济南城区风光) 看似稳得一比,实则慌如老狗= = 我可能是报到最早的且实力最弱的一只. 早晨六点二十被从床上拉起来,然后在火车站附近匆忙吃了点东西就坐火车去济南了. 路途不算远,大概 ...

  4. CentOS安装编译Lua

    Lua介绍 Lua 是一个小巧的脚本语言.是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Robert ...

  5. Java并发(一)——线程安全的容器(上)

    Java中线程安全的容器主要包括两类: Vector.Hashtable,以及封装器类Collections.synchronizedList和Collections.synchronizedMap: ...

  6. Promise对象的简单用法

    要了解一个东西,首先要从,它是什么.用来做什么以及怎么取用它这三个方面来了解. 首先,promise是什么? 我们来参考一下MDN对它的定义: Promise 对象用于一个异步操作的最终完成(或失败) ...

  7. shell 脚本中执行SQL语句 -e "..."

    /usr/local/mysql/bin/mysql -uroot -p123456 -e " use faygo source faygo.sql select * from devqui ...

  8. 940D Alena And The Heater

    传送门 题目大意 给出两个长度为N的数组A,B,以及一种计算规律: 若t[i]=1,需满足t[i-1]=t[i-2]=t[i-3]=t[i-4]=0,以及max{A[i],A[i-1],A[i-2], ...

  9. POJ 1018 Communication System(贪心)

    Description We have received an order from Pizoor Communications Inc. for a special communication sy ...

  10. CEF小白人系列1-认识CEF

    手头上有个项目需要做浏览器的相关功能,评估了几个嵌入式方案最后选定CEF作为开发基础. 在入坑新技术的时候第一选择是去官网学习,这是一个非常好的习惯. CEF官网(请科学上网) https://bit ...