|
|
|
|
@ -3,6 +3,7 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
|
#include <openssl/hmac.h>
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
|
|
#include "str.h"
|
|
|
|
|
#include "aux.h"
|
|
|
|
|
@ -23,6 +24,8 @@ static int hmac_sha1_rtp(struct crypto_context *, char *out, str *in, u_int64_t)
|
|
|
|
|
static int hmac_sha1_rtcp(struct crypto_context *, char *out, str *in);
|
|
|
|
|
static int aes_f8_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, u_int64_t idx);
|
|
|
|
|
static int aes_f8_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, u_int64_t idx);
|
|
|
|
|
static int aes_session_key_init(struct crypto_context *c);
|
|
|
|
|
static int aes_session_key_cleanup(struct crypto_context *c);
|
|
|
|
|
|
|
|
|
|
/* all lengths are in bits, some code assumes everything to be multiples of 8 */
|
|
|
|
|
const struct crypto_suite crypto_suites[] = {
|
|
|
|
|
@ -47,6 +50,8 @@ const struct crypto_suite crypto_suites[] = {
|
|
|
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
|
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
|
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
|
|
|
.session_key_init = aes_session_key_init,
|
|
|
|
|
.session_key_cleanup = aes_session_key_cleanup,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "AES_CM_128_HMAC_SHA1_32",
|
|
|
|
|
@ -125,8 +130,7 @@ const struct crypto_suite *crypto_find_suite(const str *s) {
|
|
|
|
|
|
|
|
|
|
/* rfc 3711 section 4.1 and 4.1.1
|
|
|
|
|
* "in" and "out" MAY point to the same buffer */
|
|
|
|
|
static void aes_ctr_128(char *out, str *in, char *key, char *iv) {
|
|
|
|
|
EVP_CIPHER_CTX ecc;
|
|
|
|
|
static void aes_ctr_128(char *out, str *in, EVP_CIPHER_CTX *ecc, char *iv) {
|
|
|
|
|
unsigned char ivx[16];
|
|
|
|
|
unsigned char key_block[16];
|
|
|
|
|
unsigned char *p, *q;
|
|
|
|
|
@ -134,19 +138,17 @@ static void aes_ctr_128(char *out, str *in, char *key, char *iv) {
|
|
|
|
|
int outlen, i;
|
|
|
|
|
u_int64_t *pi, *qi, *ki;
|
|
|
|
|
|
|
|
|
|
if (!ecc)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
memcpy(ivx, iv, 16);
|
|
|
|
|
pi = (void *) in->s;
|
|
|
|
|
qi = (void *) out;
|
|
|
|
|
ki = (void *) key_block;
|
|
|
|
|
left = in->len;
|
|
|
|
|
|
|
|
|
|
/* XXX do this only once per thread or maybe once per stream/key? */
|
|
|
|
|
EVP_CIPHER_CTX_init(&ecc);
|
|
|
|
|
|
|
|
|
|
EVP_EncryptInit_ex(&ecc, EVP_aes_128_ecb(), NULL, (unsigned char *) key, NULL);
|
|
|
|
|
|
|
|
|
|
while (left) {
|
|
|
|
|
EVP_EncryptUpdate(&ecc, key_block, &outlen, ivx, 16);
|
|
|
|
|
EVP_EncryptUpdate(ecc, key_block, &outlen, ivx, 16);
|
|
|
|
|
assert(outlen == 16);
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY(left < 16)) {
|
|
|
|
|
@ -173,10 +175,19 @@ static void aes_ctr_128(char *out, str *in, char *key, char *iv) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EVP_EncryptFinal_ex(&ecc, key_block, &outlen);
|
|
|
|
|
static void aes_ctr_128_no_ctx(char *out, str *in, char *key, char *iv) {
|
|
|
|
|
EVP_CIPHER_CTX ctx;
|
|
|
|
|
unsigned char block[16];
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
EVP_CIPHER_CTX_cleanup(&ecc);
|
|
|
|
|
EVP_CIPHER_CTX_init(&ctx);
|
|
|
|
|
EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, (unsigned char *) key, NULL);
|
|
|
|
|
aes_ctr_128(out, in, &ctx, iv);
|
|
|
|
|
EVP_EncryptFinal_ex(&ctx, block, &len);
|
|
|
|
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* rfc 3711 section 4.3.1 and 4.3.3
|
|
|
|
|
@ -197,7 +208,7 @@ static void prf_n(str *out, char *key, char *x) {
|
|
|
|
|
/* iv[14] = iv[15] = 0; := x << 16 */
|
|
|
|
|
ZERO(in); /* outputs the key stream */
|
|
|
|
|
str_init_len(&in_s, in, out->len >= 16 ? 32 : 16);
|
|
|
|
|
aes_ctr_128(o, &in_s, key, iv);
|
|
|
|
|
aes_ctr_128_no_ctx(o, &in_s, key, iv);
|
|
|
|
|
|
|
|
|
|
memcpy(out->s, o, out->len);
|
|
|
|
|
}
|
|
|
|
|
@ -263,7 +274,7 @@ static int aes_cm_encrypt(struct crypto_context *c, u_int32_t ssrc, str *s, u_in
|
|
|
|
|
ivi[2] ^= idxh;
|
|
|
|
|
ivi[3] ^= idxl;
|
|
|
|
|
|
|
|
|
|
aes_ctr_128(s->s, s, c->session_key, (char *) iv);
|
|
|
|
|
aes_ctr_128(s->s, s, c->session_key_ctx, (char *) iv);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -423,3 +434,27 @@ static int hmac_sha1_rtcp(struct crypto_context *c, char *out, str *in) {
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int aes_session_key_init(struct crypto_context *c) {
|
|
|
|
|
aes_session_key_cleanup(c);
|
|
|
|
|
c->session_key_ctx = g_slice_alloc(sizeof(EVP_CIPHER_CTX));
|
|
|
|
|
EVP_CIPHER_CTX_init(c->session_key_ctx);
|
|
|
|
|
EVP_EncryptInit_ex(c->session_key_ctx, EVP_aes_128_ecb(), NULL,
|
|
|
|
|
(unsigned char *) c->session_key, NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int aes_session_key_cleanup(struct crypto_context *c) {
|
|
|
|
|
unsigned char block[16];
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
if (!c->session_key_ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
EVP_EncryptFinal_ex(c->session_key_ctx, block, &len);
|
|
|
|
|
EVP_CIPHER_CTX_cleanup(c->session_key_ctx);
|
|
|
|
|
g_slice_free1(sizeof(EVP_CIPHER_CTX), c->session_key_ctx);
|
|
|
|
|
c->session_key_ctx = NULL;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|