Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/srtp/srtcp.c b/src/srtp/srtcp.c
new file mode 100644
index 0000000..d677898
--- /dev/null
+++ b/src/srtp/srtcp.c
@@ -0,0 +1,254 @@
+/**
+ * @file srtcp.c  Secure Real-time Transport Control Protocol (SRTCP)
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_list.h>
+#include <re_hmac.h>
+#include <re_sha.h>
+#include <re_aes.h>
+#include <re_net.h>
+#include <re_srtp.h>
+#include "srtp.h"
+
+
+static int get_rtcp_ssrc(uint32_t *ssrc, struct mbuf *mb)
+{
+	if (mbuf_get_left(mb) < 8)
+		return EBADMSG;
+
+	mbuf_advance(mb, 4);
+	*ssrc = ntohl(mbuf_read_u32(mb));
+
+	return 0;
+}
+
+
+int srtcp_encrypt(struct srtp *srtp, struct mbuf *mb)
+{
+	struct srtp_stream *strm;
+	struct comp *rtcp;
+	uint32_t ssrc;
+	size_t start;
+	uint32_t ep = 0;
+	int err;
+
+	if (!srtp || !mb)
+		return EINVAL;
+
+	rtcp = &srtp->rtcp;
+	start = mb->pos;
+
+	err = get_rtcp_ssrc(&ssrc, mb);
+	if (err)
+		return err;
+
+	err = stream_get(&strm, srtp, ssrc);
+	if (err)
+		return err;
+
+	strm->rtcp_index = (strm->rtcp_index+1) & 0x7fffffff;
+
+	if (rtcp->aes && rtcp->mode == AES_MODE_CTR) {
+		union vect128 iv;
+		uint8_t *p = mbuf_buf(mb);
+
+		srtp_iv_calc(&iv, &rtcp->k_s, ssrc, strm->rtcp_index);
+
+		aes_set_iv(rtcp->aes, iv.u8);
+		err = aes_encr(rtcp->aes, p, p, mbuf_get_left(mb));
+		if (err)
+			return err;
+
+		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;
+	err = mbuf_write_u32(mb, htonl(ep<<31 | strm->rtcp_index));
+	if (err)
+		return err;
+
+	if (rtcp->hmac) {
+		uint8_t tag[SHA_DIGEST_LENGTH];
+
+		mb->pos = start;
+
+		err = hmac_digest(rtcp->hmac, tag, sizeof(tag),
+				  mbuf_buf(mb), mbuf_get_left(mb));
+		if (err)
+			return err;
+
+		mb->pos = mb->end;
+
+		err = mbuf_write_mem(mb, tag, rtcp->tag_len);
+		if (err)
+			return err;
+	}
+
+	mb->pos = start;
+
+	return 0;
+}
+
+
+int srtcp_decrypt(struct srtp *srtp, struct mbuf *mb)
+{
+	size_t start, eix_start, pld_start;
+	struct srtp_stream *strm;
+	struct comp *rtcp;
+	uint32_t v, ix;
+	uint32_t ssrc;
+	bool ep;
+	int err;
+
+	if (!srtp || !mb)
+		return EINVAL;
+
+	rtcp = &srtp->rtcp;
+	start = mb->pos;
+
+	err = get_rtcp_ssrc(&ssrc, mb);
+	if (err)
+		return err;
+
+	err = stream_get(&strm, srtp, ssrc);
+	if (err)
+		return err;
+
+	pld_start = mb->pos;
+
+	if (mbuf_get_left(mb) < (4 + rtcp->tag_len))
+		return EBADMSG;
+
+	/* Read out E-Bit, SRTCP-index and Authentication Tag */
+	eix_start = mb->end - (4 + rtcp->tag_len);
+	mb->pos = eix_start;
+	v = ntohl(mbuf_read_u32(mb));
+
+	ep = (v >> 31) & 1;
+	ix = v & 0x7fffffff;
+
+	if (rtcp->hmac) {
+		uint8_t tag[SHA_DIGEST_LENGTH], tag_pkt[SHA_DIGEST_LENGTH];
+		const size_t tag_start = mb->pos;
+
+		err = mbuf_read_mem(mb, tag_pkt, rtcp->tag_len);
+		if (err)
+			return err;
+
+		mb->pos = start;
+		mb->end = tag_start;
+
+		err = hmac_digest(rtcp->hmac, tag, sizeof(tag),
+				  mbuf_buf(mb), mbuf_get_left(mb));
+		if (err)
+			return err;
+
+		if (0 != memcmp(tag, tag_pkt, rtcp->tag_len))
+			return EAUTH;
+
+		/*
+		 * SRTCP replay protection is as defined in Section 3.3.2,
+		 * but using the SRTCP index as the index i and a separate
+		 * Replay List that is specific to SRTCP.
+		 */
+		if (!srtp_replay_check(&strm->replay_rtcp, ix))
+			return EALREADY;
+	}
+
+	mb->end = eix_start;
+
+	if (rtcp->aes && ep && rtcp->mode == AES_MODE_CTR) {
+		union vect128 iv;
+		uint8_t *p;
+
+		mb->pos = pld_start;
+		p = mbuf_buf(mb);
+
+		srtp_iv_calc(&iv, &rtcp->k_s, ssrc, ix);
+
+		aes_set_iv(rtcp->aes, iv.u8);
+		err = aes_decr(rtcp->aes, p, p, mbuf_get_left(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;
+
+	return 0;
+}