From f38fe3f1e02d91b73d9123141145b414939ed838 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 19 Jun 2013 14:55:24 -0400 Subject: [PATCH] create a dedicated session key context to save some cpu --- daemon/call.c | 3 +++ daemon/crypto.c | 59 +++++++++++++++++++++++++++++++++++++++---------- daemon/crypto.h | 14 ++++++++++++ daemon/rtcp.c | 2 ++ daemon/rtp.c | 2 ++ 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 4e61090f3..e4352b51d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1614,6 +1614,9 @@ static void kill_callstream(struct callstream *s) { if (r->fd.fd != -1) poller_del_item(s->call->callmaster->poller, r->fd.fd); + + crypto_cleanup(&r->crypto.in); + crypto_cleanup(&r->crypto.out); } } } diff --git a/daemon/crypto.c b/daemon/crypto.c index 2bf4210e7..4dd532d64 100644 --- a/daemon/crypto.c +++ b/daemon/crypto.c @@ -3,6 +3,7 @@ #include #include #include +#include #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; +} diff --git a/daemon/crypto.h b/daemon/crypto.h index 168dc003d..278d125e0 100644 --- a/daemon/crypto.h +++ b/daemon/crypto.h @@ -32,6 +32,8 @@ typedef int (*crypto_func_rtp)(struct crypto_context *, struct rtp_header *, str typedef int (*crypto_func_rtcp)(struct crypto_context *, struct rtcp_packet *, str *, u_int64_t); typedef int (*hash_func_rtp)(struct crypto_context *, char *out, str *in, u_int64_t); typedef int (*hash_func_rtcp)(struct crypto_context *, char *out, str *in); +typedef int (*session_key_init_func)(struct crypto_context *); +typedef int (*session_key_cleanup_func)(struct crypto_context *); struct crypto_suite { const char *name; @@ -56,6 +58,8 @@ struct crypto_suite { decrypt_rtcp; hash_func_rtp hash_rtp; hash_func_rtcp hash_rtcp; + session_key_init_func session_key_init; + session_key_cleanup_func session_key_cleanup; }; struct crypto_context { @@ -78,6 +82,8 @@ struct crypto_context { char session_salt[14]; /* k_s */ char session_auth_key[20]; + void *session_key_ctx; + int have_session_key:1; }; @@ -117,6 +123,14 @@ static inline int crypto_decrypt_rtcp(struct crypto_context *c, struct rtcp_pack { return c->crypto_suite->decrypt_rtcp(c, rtcp, payload, index); } +static inline int crypto_init_session_key(struct crypto_context *c) { + return c->crypto_suite->session_key_init(c); +} +static inline void crypto_cleanup(struct crypto_context *c) { + if (!c->crypto_suite) + return; + c->crypto_suite->session_key_cleanup(c); +} diff --git a/daemon/rtcp.c b/daemon/rtcp.c index 1e7e3a901..08773df08 100644 --- a/daemon/rtcp.c +++ b/daemon/rtcp.c @@ -332,6 +332,8 @@ static inline int check_session_keys(struct crypto_context *c) { goto error; c->have_session_key = 1; + crypto_init_session_key(c); + return 0; error: diff --git a/daemon/rtp.c b/daemon/rtp.c index d68bd19bc..b07dc4243 100644 --- a/daemon/rtp.c +++ b/daemon/rtp.c @@ -30,6 +30,8 @@ static inline int check_session_keys(struct crypto_context *c) { goto error; c->have_session_key = 1; + crypto_init_session_key(c); + return 0; error: