Browse Source

implement srtp decryption

git.mgm/mediaproxy-ng/github/master
Richard Fuchs 13 years ago
parent
commit
2b61b12c71
4 changed files with 128 additions and 29 deletions
  1. +17
    -0
      daemon/call.c
  2. +8
    -5
      daemon/crypto.c
  3. +12
    -3
      daemon/crypto.h
  4. +91
    -21
      daemon/rtp.c

+ 17
- 0
daemon/call.c View File

@ -229,6 +229,12 @@ static int call_avp2savp_rtp(str *s, struct streamrelay *r) {
static int call_avp2savp_rtcp(str *s, struct streamrelay *r) {
return 0;
}
static int call_savp2avp_rtp(str *s, struct streamrelay *r) {
return rtp_savp2avp(s, &r->peer.crypto.in);
}
static int call_savp2avp_rtcp(str *s, struct streamrelay *r) {
return 0;
}
static stream_handler determine_handler(struct streamrelay *in) {
@ -254,6 +260,17 @@ static stream_handler determine_handler(struct streamrelay *in) {
abort();
}
case PROTO_RTP_SAVP:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:
case PROTO_RTP_AVPF:
return in->rtcp ? call_savp2avp_rtcp
: call_savp2avp_rtp;
default:
abort();
}
case PROTO_RTP_AVPF:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:


+ 8
- 5
daemon/crypto.c View File

@ -11,7 +11,7 @@
static int aes_cm_encrypt_rtp(struct crypto_context *, struct rtp_header *, str *, u_int64_t);
static int hmac_sha1_rtp(struct crypto_context *, char *out, str *in);
static int hmac_sha1_rtp(struct crypto_context *, char *out, str *in, u_int64_t);
/* all lengths are in bits, some code assumes everything to be multiples of 8 */
const struct crypto_suite crypto_suites[] = {
@ -31,6 +31,7 @@ const struct crypto_suite crypto_suites[] = {
.srtp_auth_key_len = 160,
.srtcp_auth_key_len = 160,
.encrypt_rtp = aes_cm_encrypt_rtp,
.decrypt_rtp = aes_cm_encrypt_rtp,
.hash_rtp = hmac_sha1_rtp,
},
{
@ -49,6 +50,7 @@ const struct crypto_suite crypto_suites[] = {
.srtp_auth_key_len = 160,
.srtcp_auth_key_len = 160,
.encrypt_rtp = aes_cm_encrypt_rtp,
.decrypt_rtp = aes_cm_encrypt_rtp,
.hash_rtp = hmac_sha1_rtp,
},
{
@ -216,19 +218,20 @@ static int aes_cm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, st
}
/* rfc 3711, sections 4.2 and 4.2.1 */
static int hmac_sha1_rtp(struct crypto_context *c, char *out, str *in) {
static int hmac_sha1_rtp(struct crypto_context *c, char *out, str *in, u_int64_t index) {
unsigned char hmac[20];
HMAC_CTX hc;
u_int32_t roc;
HMAC_Init(&hc, c->session_auth_key, c->crypto_suite->srtp_auth_key_len, EVP_sha1());
HMAC_Init(&hc, c->session_auth_key, c->crypto_suite->srtp_auth_key_len / 8, EVP_sha1());
HMAC_Update(&hc, (unsigned char *) in->s, in->len);
roc = htonl(c->roc);
roc = htonl((index & 0xffffffff0000ULL) >> 16);
HMAC_Update(&hc, (unsigned char *) &roc, sizeof(roc));
HMAC_Final(&hc, hmac, NULL);
HMAC_CTX_cleanup(&hc);
memcpy(out, hmac, c->crypto_suite->srtp_auth_tag);
assert(sizeof(hmac) >= c->crypto_suite->srtp_auth_tag / 8);
memcpy(out, hmac, c->crypto_suite->srtp_auth_tag / 8);
return 0;
}

+ 12
- 3
daemon/crypto.h View File

@ -28,7 +28,7 @@ struct crypto_context;
struct rtp_header;
typedef int (*crypto_func)(struct crypto_context *, struct rtp_header *, str *, u_int64_t);
typedef int (*hash_func)(struct crypto_context *, char *out, str *in);
typedef int (*hash_func)(struct crypto_context *, char *out, str *in, u_int64_t);
struct crypto_suite {
const char *name;
@ -47,7 +47,8 @@ struct crypto_suite {
srtcp_lifetime;
enum cipher cipher;
enum mac mac;
crypto_func encrypt_rtp;
crypto_func encrypt_rtp,
decrypt_rtp;
hash_func hash_rtp;
};
@ -61,7 +62,7 @@ struct crypto_context {
/* from rfc 3711 */
u_int32_t roc;
u_int16_t s_l;
u_int64_t s_l;
/* XXX replay list */
u_int64_t num_packets;
/* <from, to>? */
@ -97,6 +98,14 @@ static inline int crypto_encrypt_rtp(struct crypto_context *c, struct rtp_header
return c->crypto_suite->encrypt_rtp(c, rtp, payload, index);
}
static inline int crypto_decrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,
str *payload, u_int64_t index)
{
if (!c || !c->crypto_suite)
return -1;
return c->crypto_suite->decrypt_rtp(c, rtp, payload, index);
}


+ 91
- 21
daemon/rtp.c View File

@ -32,42 +32,41 @@ static inline int check_session_key(struct crypto_context *c) {
return 0;
}
/* XXX some error handling/logging here */
int rtp_avp2savp(str *s, struct crypto_context *c) {
static int rtp_payload(str *p, str *s) {
struct rtp_header *rtp;
str payload, to_auth;
struct rtp_extension *ext;
u_int16_t seq;
u_int64_t index, s_l_index;
long long int diff;
char *pl_end;
u_int32_t mki_part;
if (s->len < sizeof(*rtp))
return -1;
if (check_session_key(c))
return -1;
rtp = (void *) s->s;
if ((rtp->v_p_x_cc & 0xc0) != 0x80) /* version 2 */
return -1;
payload = *s;
*p = *s;
/* fixed header */
str_shift(&payload, sizeof(*rtp));
str_shift(p, sizeof(*rtp));
/* csrc list */
if (str_shift(&payload, (rtp->v_p_x_cc & 0xf) * 4))
if (str_shift(p, (rtp->v_p_x_cc & 0xf) * 4))
return -1;
if ((rtp->v_p_x_cc & 0x10)) {
/* extension */
if (payload.len < sizeof(*ext))
if (p->len < sizeof(*ext))
return -1;
ext = (void *) payload.s;
if (str_shift(&payload, 4 + ntohs(ext->length) * 4))
ext = (void *) p->s;
if (str_shift(p, 4 + ntohs(ext->length) * 4))
return -1;
}
return 0;
}
static u_int64_t packet_index(struct crypto_context *c, struct rtp_header *rtp) {
u_int16_t seq;
u_int64_t index;
long long int diff;
seq = ntohs(rtp->seq_num);
/* rfc 3711 section 3.3.1 */
if (G_UNLIKELY(!c->s_l))
@ -75,11 +74,10 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
/* rfc 3711 appendix A, modified, and sections 3.3 and 3.3.1 */
index = ((u_int64_t) c->roc << 16) | seq;
s_l_index = ((u_int64_t) c->roc << 16) | c->s_l;
diff = index - s_l_index;
diff = index - c->s_l;
if (diff >= 0) {
if (diff < 0x8000)
;
c->s_l = index;
else if (index >= 0x10000)
index -= 0x10000;
}
@ -89,9 +87,30 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
else {
index += 0x10000;
c->roc++;
c->s_l = index;
}
}
return index;
}
/* rfc 3711, section 3.3 */
/* XXX some error handling/logging here */
int rtp_avp2savp(str *s, struct crypto_context *c) {
struct rtp_header *rtp;
str payload, to_auth;
u_int64_t index;
char *pl_end;
u_int32_t mki_part;
if (rtp_payload(&payload, s))
return -1;
if (check_session_key(c))
return -1;
rtp = (void *) s->s;
index = packet_index(c, rtp);
/* rfc 3711 section 3.1 */
if (crypto_encrypt_rtp(c, rtp, &payload, index))
@ -123,8 +142,8 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
}
if (c->crypto_suite->srtp_auth_tag) {
c->crypto_suite->hash_rtp(c, pl_end, &to_auth);
pl_end += c->crypto_suite->srtp_auth_tag;
c->crypto_suite->hash_rtp(c, pl_end, &to_auth, index);
pl_end += c->crypto_suite->srtp_auth_tag / 8;
}
s->len = pl_end - s->s;
@ -132,8 +151,59 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
return 0;
}
/* rfc 3711, section 3.3 */
int rtp_savp2avp(str *s, struct crypto_context *c) {
struct rtp_header *rtp;
u_int64_t index;
str payload, mki, to_auth;
char hmac[20], *auth_tag = NULL;
int i;
if (rtp_payload(&payload, s))
return -1;
if (check_session_key(c))
return -1;
rtp = (void *) s->s;
index = packet_index(c, rtp);
/* rfc 3711 section 3.1 */
to_auth = *s;
if (c->crypto_suite->srtp_auth_tag) {
i = c->crypto_suite->srtp_auth_tag / 8;
assert(sizeof(hmac) >= i);
if (payload.len < i)
return -1;
auth_tag = payload.s + payload.len - i;
payload.len -= i;
to_auth.len -= i;
}
if (c->mki_len) {
if (payload.len < c->mki_len)
return -1;
str_init_len(&mki, payload.s - c->mki_len, c->mki_len);
payload.len -= c->mki_len;
to_auth.len -= c->mki_len;
/* ignoring the mki for now */
}
if (c->crypto_suite->srtp_auth_tag) {
c->crypto_suite->hash_rtp(c, hmac, &to_auth, index);
if (memcmp(hmac, auth_tag, c->crypto_suite->srtp_auth_tag / 8))
return -1;
}
if (crypto_decrypt_rtp(c, rtp, &payload, index))
return -1;
*s = to_auth;
return 0;
}

Loading…
Cancel
Save