WebRTC SRTP解密

Posted

技术标签:

【中文标题】WebRTC SRTP解密【英文标题】:WebRTC SRTP decryption 【发布时间】:2014-03-27 15:25:32 【问题描述】:

我正在尝试构建一个SRTPRTP 流转换器,但我在从我正在创建的WebRTC peerconnection 获取Master Key 时遇到问题。

据我了解,使用DES exchange,密钥是通过SDP 交换并显示在a=crypto 字段中。所以,这种情况看起来很简单(如果我错了,请纠正我),但最终没有用,因为WebRTC 标准化现在要求不应使用 DES(现在只有Chrome 支持它,它可能会在未来)。

对于DTLS,SDP 中有指纹字段,这是 certificate desired 的哈希值以供将来交换使用吗?[编辑:阅读后,我认为那不是案例]我会认为,在了解指纹以及解析交换中的 DTLS 数据包的能力的情况下,我应该能够抓住Master Key 来解码 SRTP 流,但是我碰壁了,因为我没有知道在哪里寻找,甚至 100% 确定是否可行。

因此,简而言之,解码在Chrome 中使用WebRTC PeerConnectionFireFox(可能通过使用从SDP 交换收集的信息进行数据包嗅探)?[编辑:令人沮丧的是,似乎无法访问密钥的私有部分(又名主密钥)......请如果我错了,请纠正]

【问题讨论】:

相关:Can I specify my own encryption key in DTLS-SRTP encryption 我认为目前唯一的选择是使用原生 API 而不是主流浏览器实现 借助接受答案的库支持,您最终能否将 SRTP 转换为 RTP(未加密)?我也对这种实现我的 WebRTC SFU 的方法感兴趣,但不知道从哪里开始。问了几个关于赏金的问题,但没有运气。看看你能不能帮忙:How to use libsrtp or similar library to decrypt/encrypt the WebRTC data stream? 和 How to integrate part of WebRTC... 如果有任何 SRTP 到 RTP 的库,那么很想使用它。谢谢。 【参考方案1】:

这是一些使用 openssl 和 libsrtp 原生 api 的代码

#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 * 2 + SRTP_MASTER_KEY_SALT_LEN * 2];
  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 = 0;

  /*
   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,
                                    0, 
                                    PJ_FALSE);

  memcpy(&client_write_key[0], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
  offset += SRTP_MASTER_KEY_KEY_LEN;
  memcpy(&server_write_key[0], &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(0);
  
  policy.s-s-rc.value = 0;
  policy.next = NULL;

  /* Init transmit direction */
  policy.s-s-rc.type = s-s-rc_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.s-s-rc.type = s-s-rc_any_inbound;  
  policy.key = server_write_key;    

  err = srtp_create(&dtls->srtp_ctx_tx, &policy);
  if (err != err_status_ok) 
    printf("not working\n");
   


【讨论】:

老兄,喜欢它!这是特定项目的一部分吗? 坦克,bwtrent!它是 CrystalVu SDK (integrit.com/products/240-crystalvu-video-conferencing-sdk) 的一部分,提供与 sipml5 (sipml5.org) 的互操作性【参考方案2】:

我找到了“SSL_export_keying_material” 它可以从 SSL 机制中获取密钥(在 DTLS 握手之后)并将其用于 SRTP。

我不是专家,像你一样碰壁……

【讨论】:

【参考方案3】:

尚不清楚这是否是您的情况,但请注意,仅作为被动观察者无法从(即:unencrypt)SRTP 访问音频/视频 - 这就是传输加密的全部意义所在。

协议(DTLS-SRTP)的工作原理大致如下:

每个浏览器都有一个唯一的密钥对,通常在安装时生成 每一方的fingerprint of the public part of the keypair 都包含在 SDP、offer 和 answer 中。 两端通过ordinary DTLS handshake 协商 DTLS 连接,从而派生一种会话密钥,用于保护 (DTLS) 连接 The derived session key is used as the SRTP key

如果您无权访问密钥对的至少一个私有部分,则根本无法解密连接。如果端点选择在握手时使用Diffie-Hellman key exchange,则被动攻击者将无法获得派生密钥,即使可以访问两个私钥。此属性称为forward secrecy。

访问 SRTP 内容的唯一可靠方法是自己进行握手、实施活动 MITM(更改 SDP 上的指纹)或从浏览器获取私钥并限制 DH 密钥交换(AFAIK 是根本不可能)

【讨论】:

以上是关于WebRTC SRTP解密的主要内容,如果未能解决你的问题,请参考以下文章

WebRTC 传输安全机制:深入显出 SRTP 协议

Android IOS WebRTC 音视频开发总结(六二)-- 大数据解密国外实时通讯行业开发现状

详解 WebRTC 传输安全机制:一文读懂 DTLS 协议

详解 WebRTC 传输安全机制:一文读懂 DTLS 协议

WebRTC 有多少个通道以及使用了哪些传输?

技术分享| Sip与WebRTC互通-SRProxy开源库讲解