int srtp_derive(uint8_t *out, size_t out_len, uint8_t label, const uint8_t *master_key, size_t key_bytes, const uint8_t *master_salt, size_t salt_bytes) { uint8_t x[AES_BLOCK_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; static const uint8_t null[AES_BLOCK_SIZE * 2]; struct aes *aes; int err; if (!out || !master_key || !master_salt) return EINVAL; if (out_len > sizeof(null) || salt_bytes > sizeof(x)) return EINVAL; 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; err = aes_encr(aes, out, null, out_len); mem_deref(aes); return err; }
int srtp_encrypt(struct srtp *srtp, struct mbuf *mb) { struct srtp_stream *strm; struct rtp_header hdr; struct comp *comp; size_t start; uint64_t ix; int err; if (!srtp || !mb) return EINVAL; comp = &srtp->rtp; start = mb->pos; err = rtp_hdr_decode(&hdr, mb); if (err) return err; err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq); if (err) return err; /* Roll-Over Counter (ROC) */ if (seq_diff(strm->s_l, hdr.seq) <= -32768) { strm->roc++; strm->s_l = 0; } ix = 65536ULL * strm->roc + hdr.seq; if (comp->aes) { union vect128 iv; uint8_t *p = mbuf_buf(mb); srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix); aes_set_iv(comp->aes, iv.u8); err = aes_encr(comp->aes, p, p, mbuf_get_left(mb)); if (err) return err; } if (comp->hmac) { const size_t tag_start = mb->end; uint8_t tag[SHA_DIGEST_LENGTH]; mb->pos = tag_start; err = mbuf_write_u32(mb, htonl(strm->roc)); if (err) return err; mb->pos = start; err = hmac_digest(comp->hmac, tag, sizeof(tag), mbuf_buf(mb), mbuf_get_left(mb)); if (err) return err; mb->pos = mb->end = tag_start; err = mbuf_write_mem(mb, tag, comp->tag_len); if (err) return err; } if (hdr.seq > strm->s_l) strm->s_l = hdr.seq; mb->pos = start; return 0; }