parent
66ae090ea6
commit
25dfb8ccf7
8 changed files with 220 additions and 16 deletions
|
@ -198,6 +198,7 @@ legend:
|
|||
* [RFC 6455](https://tools.ietf.org/html/rfc6455) - The WebSocket Protocol
|
||||
* [RFC 7159](https://tools.ietf.org/html/rfc7159) - JavaScript Object Notation (JSON)
|
||||
* [RFC 7350](https://tools.ietf.org/html/rfc7350) - DTLS as Transport for STUN
|
||||
* [RFC 7714](https://tools.ietf.org/html/rfc7714) - AES-GCM Authenticated Encryption in SRTP
|
||||
|
||||
|
||||
## Supported platforms
|
||||
|
|
|
@ -10,6 +10,8 @@ enum srtp_suite {
|
|||
SRTP_AES_CM_128_HMAC_SHA1_80,
|
||||
SRTP_AES_256_CM_HMAC_SHA1_32,
|
||||
SRTP_AES_256_CM_HMAC_SHA1_80,
|
||||
SRTP_AES_128_GCM,
|
||||
SRTP_AES_256_GCM,
|
||||
};
|
||||
|
||||
enum srtp_flags {
|
||||
|
|
|
@ -59,6 +59,7 @@ int srtp_derive(uint8_t *out, size_t out_len, uint8_t label,
|
|||
memcpy(x, master_salt, salt_bytes);
|
||||
x[7] ^= label;
|
||||
|
||||
/* NOTE: Counter Mode is used for both CTR and GCM */
|
||||
err = aes_alloc(&aes, AES_MODE_CTR, master_key, key_bytes*8, x);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -86,6 +87,24 @@ void srtp_iv_calc(union vect128 *iv, const union vect128 *k_s,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* NOTE: The IV for AES-GCM is 12 bytes
|
||||
*/
|
||||
void srtp_iv_calc_gcm(union vect128 *iv, const union vect128 *k_s,
|
||||
uint32_t ssrc, uint64_t ix)
|
||||
{
|
||||
if (!iv || !k_s)
|
||||
return;
|
||||
|
||||
iv->u16[0] = k_s->u16[0];
|
||||
iv->u16[1] = k_s->u16[1] ^ htons(ssrc >> 16);
|
||||
iv->u16[2] = k_s->u16[2] ^ htons(ssrc & 0xffff);
|
||||
iv->u16[3] = k_s->u16[3] ^ htons((ix >> 32) & 0xffff);
|
||||
iv->u16[4] = k_s->u16[4] ^ htons((ix >> 16) & 0xffff);
|
||||
iv->u16[5] = k_s->u16[5] ^ htons(ix & 0xffff);
|
||||
}
|
||||
|
||||
|
||||
const char *srtp_suite_name(enum srtp_suite suite)
|
||||
{
|
||||
switch (suite) {
|
||||
|
@ -94,6 +113,8 @@ const char *srtp_suite_name(enum srtp_suite suite)
|
|||
case SRTP_AES_CM_128_HMAC_SHA1_80: return "AES_CM_128_HMAC_SHA1_80";
|
||||
case SRTP_AES_256_CM_HMAC_SHA1_32: return "AES_256_CM_HMAC_SHA1_32";
|
||||
case SRTP_AES_256_CM_HMAC_SHA1_80: return "AES_256_CM_HMAC_SHA1_80";
|
||||
case SRTP_AES_128_GCM: return "AEAD_AES_128_GCM";
|
||||
case SRTP_AES_256_GCM: return "AEAD_AES_256_GCM";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <re_types.h>
|
||||
#include <re_mbuf.h>
|
||||
#include <re_list.h>
|
||||
#include <re_aes.h>
|
||||
#include <re_srtp.h>
|
||||
#include "srtp.h"
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ int srtcp_encrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
|
||||
strm->rtcp_index = (strm->rtcp_index+1) & 0x7fffffff;
|
||||
|
||||
if (rtcp->aes) {
|
||||
if (rtcp->aes && rtcp->mode == AES_MODE_CTR) {
|
||||
union vect128 iv;
|
||||
uint8_t *p = mbuf_buf(mb);
|
||||
|
||||
|
@ -66,6 +66,40 @@ int srtcp_encrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
|
||||
ep = 1;
|
||||
}
|
||||
else if (rtcp->aes && rtcp->mode == AES_MODE_GCM) {
|
||||
|
||||
union vect128 iv;
|
||||
uint8_t *p = mbuf_buf(mb);
|
||||
uint8_t tag[GCM_TAGLEN];
|
||||
const uint32_t ix_be = htonl(1<<31 | strm->rtcp_index);
|
||||
|
||||
srtp_iv_calc_gcm(&iv, &rtcp->k_s, ssrc, strm->rtcp_index);
|
||||
|
||||
aes_set_iv(rtcp->aes, iv.u8);
|
||||
|
||||
/* The RTCP Header and Index is Associated Data */
|
||||
err = aes_encr(rtcp->aes, NULL, &mb->buf[start],
|
||||
mb->pos - start);
|
||||
err |= aes_encr(rtcp->aes, NULL,
|
||||
(void *)&ix_be, sizeof(ix_be));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aes_encr(rtcp->aes, p, p, mbuf_get_left(mb));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aes_get_authtag(rtcp->aes, tag, sizeof(tag));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mb->pos = mb->end;
|
||||
err = mbuf_write_mem(mb, tag, sizeof(tag));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ep = 1;
|
||||
}
|
||||
|
||||
/* append E-bit and SRTCP-index */
|
||||
mb->pos = mb->end;
|
||||
|
@ -163,7 +197,7 @@ int srtcp_decrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
|
||||
mb->end = eix_start;
|
||||
|
||||
if (rtcp->aes && ep) {
|
||||
if (rtcp->aes && ep && rtcp->mode == AES_MODE_CTR) {
|
||||
union vect128 iv;
|
||||
uint8_t *p;
|
||||
|
||||
|
@ -177,6 +211,42 @@ int srtcp_decrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
if (err)
|
||||
return err;
|
||||
}
|
||||
else if (rtcp->aes && ep && rtcp->mode == AES_MODE_GCM) {
|
||||
|
||||
union vect128 iv;
|
||||
size_t tag_start;
|
||||
uint8_t *p;
|
||||
|
||||
srtp_iv_calc_gcm(&iv, &rtcp->k_s, ssrc, ix);
|
||||
|
||||
aes_set_iv(rtcp->aes, iv.u8);
|
||||
|
||||
/* The RTP Header is Associated Data */
|
||||
err = aes_decr(rtcp->aes, NULL, &mb->buf[start],
|
||||
pld_start - start);
|
||||
err |= aes_decr(rtcp->aes, NULL, &mb->buf[eix_start], 4);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mb->pos = pld_start;
|
||||
p = mbuf_buf(mb);
|
||||
|
||||
if (mbuf_get_left(mb) < GCM_TAGLEN)
|
||||
return EBADMSG;
|
||||
|
||||
tag_start = mb->end - GCM_TAGLEN;
|
||||
|
||||
err = aes_decr(rtcp->aes, p, p, tag_start - pld_start);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aes_authenticate(rtcp->aes, &mb->buf[tag_start],
|
||||
GCM_TAGLEN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mb->end = tag_start;
|
||||
}
|
||||
|
||||
mb->pos = start;
|
||||
|
||||
|
|
129
src/srtp/srtp.c
129
src/srtp/srtp.c
|
@ -33,7 +33,8 @@ static inline int seq_diff(uint16_t x, uint16_t y)
|
|||
static int comp_init(struct comp *c, unsigned offs,
|
||||
const uint8_t *key, size_t key_b,
|
||||
const uint8_t *s, size_t s_b,
|
||||
size_t tag_len, bool encrypted)
|
||||
size_t tag_len, bool encrypted, bool hash,
|
||||
enum aes_mode mode)
|
||||
{
|
||||
uint8_t k_e[MAX_KEYLEN], k_a[SHA_DIGEST_LENGTH];
|
||||
int err = 0;
|
||||
|
@ -45,6 +46,7 @@ static int comp_init(struct comp *c, unsigned offs,
|
|||
return EINVAL;
|
||||
|
||||
c->tag_len = tag_len;
|
||||
c->mode = mode;
|
||||
|
||||
err |= srtp_derive(k_e, key_b, 0x00+offs, key, key_b, s, s_b);
|
||||
err |= srtp_derive(k_a, sizeof(k_a), 0x01+offs, key, key_b, s, s_b);
|
||||
|
@ -53,14 +55,16 @@ static int comp_init(struct comp *c, unsigned offs,
|
|||
return err;
|
||||
|
||||
if (encrypted) {
|
||||
err = aes_alloc(&c->aes, AES_MODE_CTR, k_e, key_b*8, NULL);
|
||||
err = aes_alloc(&c->aes, mode, k_e, key_b*8, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = hmac_create(&c->hmac, HMAC_HASH_SHA1, k_a, sizeof(k_a));
|
||||
if (err)
|
||||
return err;
|
||||
if (hash) {
|
||||
err = hmac_create(&c->hmac, HMAC_HASH_SHA1, k_a, sizeof(k_a));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -84,7 +88,9 @@ int srtp_alloc(struct srtp **srtpp, enum srtp_suite suite,
|
|||
{
|
||||
struct srtp *srtp;
|
||||
const uint8_t *master_salt;
|
||||
size_t cipher_bytes, auth_bytes;
|
||||
size_t cipher_bytes, salt_bytes, auth_bytes;
|
||||
enum aes_mode mode;
|
||||
bool hash;
|
||||
int err = 0;
|
||||
|
||||
if (!srtpp || !key)
|
||||
|
@ -93,30 +99,58 @@ int srtp_alloc(struct srtp **srtpp, enum srtp_suite suite,
|
|||
switch (suite) {
|
||||
|
||||
case SRTP_AES_CM_128_HMAC_SHA1_80:
|
||||
mode = AES_MODE_CTR;
|
||||
cipher_bytes = 16;
|
||||
salt_bytes = 14;
|
||||
auth_bytes = 10;
|
||||
hash = true;
|
||||
break;
|
||||
|
||||
case SRTP_AES_CM_128_HMAC_SHA1_32:
|
||||
mode = AES_MODE_CTR;
|
||||
cipher_bytes = 16;
|
||||
salt_bytes = 14;
|
||||
auth_bytes = 4;
|
||||
hash = true;
|
||||
break;
|
||||
|
||||
case SRTP_AES_256_CM_HMAC_SHA1_80:
|
||||
mode = AES_MODE_CTR;
|
||||
cipher_bytes = 32;
|
||||
salt_bytes = 14;
|
||||
auth_bytes = 10;
|
||||
hash = true;
|
||||
break;
|
||||
|
||||
case SRTP_AES_256_CM_HMAC_SHA1_32:
|
||||
mode = AES_MODE_CTR;
|
||||
cipher_bytes = 32;
|
||||
salt_bytes = 14;
|
||||
auth_bytes = 4;
|
||||
hash = true;
|
||||
break;
|
||||
|
||||
case SRTP_AES_128_GCM:
|
||||
mode = AES_MODE_GCM;
|
||||
cipher_bytes = 16;
|
||||
salt_bytes = 12;
|
||||
auth_bytes = 0;
|
||||
hash = false;
|
||||
break;
|
||||
|
||||
case SRTP_AES_256_GCM:
|
||||
mode = AES_MODE_GCM;
|
||||
cipher_bytes = 32;
|
||||
salt_bytes = 12;
|
||||
auth_bytes = 0;
|
||||
hash = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ENOTSUP;
|
||||
};
|
||||
|
||||
if ((cipher_bytes + SRTP_SALT_SIZE) != key_bytes)
|
||||
if ((cipher_bytes + salt_bytes) != key_bytes)
|
||||
return EINVAL;
|
||||
|
||||
master_salt = &key[cipher_bytes];
|
||||
|
@ -126,10 +160,11 @@ int srtp_alloc(struct srtp **srtpp, enum srtp_suite suite,
|
|||
return ENOMEM;
|
||||
|
||||
err |= comp_init(&srtp->rtp, 0, key, cipher_bytes,
|
||||
master_salt, SRTP_SALT_SIZE, auth_bytes, true);
|
||||
master_salt, salt_bytes, auth_bytes,
|
||||
true, hash, mode);
|
||||
err |= comp_init(&srtp->rtcp, 3, key, cipher_bytes,
|
||||
master_salt, SRTP_SALT_SIZE, auth_bytes,
|
||||
!(flags & SRTP_UNENCRYPTED_SRTCP));
|
||||
master_salt, salt_bytes, auth_bytes,
|
||||
!(flags & SRTP_UNENCRYPTED_SRTCP), hash, mode);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -175,7 +210,7 @@ int srtp_encrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
|
||||
ix = 65536ULL * strm->roc + hdr.seq;
|
||||
|
||||
if (comp->aes) {
|
||||
if (comp->aes && comp->mode == AES_MODE_CTR) {
|
||||
union vect128 iv;
|
||||
uint8_t *p = mbuf_buf(mb);
|
||||
|
||||
|
@ -186,6 +221,34 @@ int srtp_encrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
if (err)
|
||||
return err;
|
||||
}
|
||||
else if (comp->aes && comp->mode == AES_MODE_GCM) {
|
||||
union vect128 iv;
|
||||
uint8_t *p = mbuf_buf(mb);
|
||||
uint8_t tag[GCM_TAGLEN];
|
||||
|
||||
srtp_iv_calc_gcm(&iv, &comp->k_s, strm->ssrc, ix);
|
||||
|
||||
aes_set_iv(comp->aes, iv.u8);
|
||||
|
||||
/* The RTP Header is Associated Data */
|
||||
err = aes_encr(comp->aes, NULL, &mb->buf[start],
|
||||
mb->pos - start);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aes_encr(comp->aes, p, p, mbuf_get_left(mb));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aes_get_authtag(comp->aes, tag, sizeof(tag));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mb->pos = mb->end;
|
||||
err = mbuf_write_mem(mb, tag, sizeof(tag));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (comp->hmac) {
|
||||
const size_t tag_start = mb->end;
|
||||
|
@ -303,7 +366,7 @@ int srtp_decrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
return EALREADY;
|
||||
}
|
||||
|
||||
if (comp->aes) {
|
||||
if (comp->aes && comp->mode == AES_MODE_CTR) {
|
||||
|
||||
union vect128 iv;
|
||||
uint8_t *p = mbuf_buf(mb);
|
||||
|
@ -315,6 +378,48 @@ int srtp_decrypt(struct srtp *srtp, struct mbuf *mb)
|
|||
if (err)
|
||||
return err;
|
||||
}
|
||||
else if (comp->aes && comp->mode == AES_MODE_GCM) {
|
||||
|
||||
union vect128 iv;
|
||||
uint8_t *p = mbuf_buf(mb);
|
||||
size_t tag_start;
|
||||
|
||||
srtp_iv_calc_gcm(&iv, &comp->k_s, strm->ssrc, ix);
|
||||
|
||||
aes_set_iv(comp->aes, iv.u8);
|
||||
|
||||
/* The RTP Header is Associated Data */
|
||||
err = aes_decr(comp->aes, NULL, &mb->buf[start],
|
||||
mb->pos - start);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (mbuf_get_left(mb) < GCM_TAGLEN)
|
||||
return EBADMSG;
|
||||
|
||||
tag_start = mb->end - GCM_TAGLEN;
|
||||
|
||||
err = aes_decr(comp->aes, p, p, tag_start - mb->pos);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aes_authenticate(comp->aes, &mb->buf[tag_start],
|
||||
GCM_TAGLEN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mb->end = tag_start;
|
||||
|
||||
/*
|
||||
* 3.3.2. Replay Protection
|
||||
*
|
||||
* Secure replay protection is only possible when
|
||||
* integrity protection is present.
|
||||
*/
|
||||
if (!srtp_replay_check(&strm->replay_rtp, ix))
|
||||
return EALREADY;
|
||||
|
||||
}
|
||||
|
||||
if (hdr.seq > strm->s_l)
|
||||
strm->s_l = hdr.seq;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
|
||||
enum {
|
||||
SRTP_SALT_SIZE = 14
|
||||
GCM_TAGLEN = 16, /**< GCM taglength in bytes */
|
||||
};
|
||||
|
||||
|
||||
|
@ -40,9 +40,10 @@ struct srtp_stream {
|
|||
struct srtp {
|
||||
struct comp {
|
||||
struct aes *aes; /**< AES Context */
|
||||
enum aes_mode mode; /**< AES encryption mode */
|
||||
struct hmac *hmac; /**< HMAC Context */
|
||||
union vect128 k_s; /**< Derived salting key (14 bytes) */
|
||||
size_t tag_len; /**< Authentication tag length [bytes] */
|
||||
size_t tag_len; /**< CTR Auth. tag length [bytes] */
|
||||
} rtp, rtcp;
|
||||
|
||||
struct list streaml; /**< SRTP-streams (struct srtp_stream) */
|
||||
|
@ -59,6 +60,8 @@ int srtp_derive(uint8_t *out, size_t out_len, uint8_t label,
|
|||
const uint8_t *master_salt, size_t salt_bytes);
|
||||
void srtp_iv_calc(union vect128 *iv, const union vect128 *k_s,
|
||||
uint32_t ssrc, uint64_t ix);
|
||||
void srtp_iv_calc_gcm(union vect128 *iv, const union vect128 *k_s,
|
||||
uint32_t ssrc, uint64_t ix);
|
||||
uint64_t srtp_get_index(uint32_t roc, uint16_t s_l, uint16_t seq);
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <re_mem.h>
|
||||
#include <re_mbuf.h>
|
||||
#include <re_list.h>
|
||||
#include <re_aes.h>
|
||||
#include <re_srtp.h>
|
||||
#include "srtp.h"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue