diff --git a/daemon/crypto.c b/daemon/crypto.c index 4eb4b4434..f1dfacf58 100644 --- a/daemon/crypto.c +++ b/daemon/crypto.c @@ -21,6 +21,8 @@ static int aes_cm_encrypt_rtp(struct crypto_context *, struct rtp_header *, str static int aes_cm_encrypt_rtcp(struct crypto_context *, struct rtcp_packet *, str *, u_int64_t); 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); /* all lengths are in bits, some code assumes everything to be multiples of 8 */ const struct crypto_suite crypto_suites[] = { @@ -83,6 +85,10 @@ const struct crypto_suite crypto_suites[] = { .srtcp_auth_tag = 80, .srtp_auth_key_len = 160, .srtcp_auth_key_len = 160, + .encrypt_rtp = aes_f8_encrypt_rtp, + .decrypt_rtp = aes_f8_encrypt_rtp, + .encrypt_rtcp = aes_f8_encrypt_rtcp, + .decrypt_rtcp = aes_f8_encrypt_rtcp, .hash_rtp = hmac_sha1_rtp, .hash_rtcp = hmac_sha1_rtcp, }, @@ -262,6 +268,108 @@ static int aes_cm_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, return aes_cm_encrypt(c, r->ssrc, s, idx); } +/* rfc 3711 sections 4.1.2 and 4.1.2.1 + * encrypts in place */ +static void aes_128_f8_encrypt(struct crypto_context *c, unsigned char *iv, str *s) { + EVP_CIPHER_CTX ecc; + unsigned char key_block[16], last_key_block[16], /* S(j), S(j-1) */ + ivx[16], /* IV' */ + m[16], + x[16]; + int i, outlen, left; + int k_e_len, k_s_len; /* n_e, n_s */ + u_int32_t j; + unsigned char *p, *key; + + k_e_len = c->crypto_suite->session_key_len / 8; + k_s_len = c->crypto_suite->session_salt_len / 8; + key = (unsigned char *) c->session_key; + + /* m = k_s || 0x555..5 */ + memcpy(m, c->session_salt, k_s_len); + for (i = k_s_len; i < k_e_len; i++) + m[i] = 0x55; + + /* IV' = E(k_e XOR m, IV) */ + for (i = 0; i < k_e_len; i++) + m[i] ^= key[i]; + + EVP_CIPHER_CTX_init(&ecc); + EVP_EncryptInit_ex(&ecc, EVP_aes_128_ecb(), NULL, m, NULL); + EVP_EncryptUpdate(&ecc, ivx, &outlen, iv, 16); + assert(outlen == 16); + EVP_EncryptFinal_ex(&ecc, key_block, &outlen); + EVP_CIPHER_CTX_cleanup(&ecc); + + p = (unsigned char *) s->s; + left = s->len; + j = 0; + ZERO(last_key_block); + + EVP_CIPHER_CTX_init(&ecc); + EVP_EncryptInit_ex(&ecc, EVP_aes_128_ecb(), NULL, (unsigned char *) c->session_key, NULL); + + while (left) { + /* S(j) = E(k_e, IV' XOR j XOR S(j-1)) */ + memcpy(x, ivx, 16); + + x[12] ^= ((j >> 24) & 0xff); + x[13] ^= ((j >> 16) & 0xff); + x[14] ^= ((j >> 8) & 0xff); + x[15] ^= ((j >> 0) & 0xff); + + for (i = 0; i < 16; i++) + x[i] ^= last_key_block[i]; + + EVP_EncryptUpdate(&ecc, key_block, &outlen, x, 16); + assert(outlen == 16); + + for (i = 0; i < 16; i++) { + *p ^= key_block[i]; + p++; + left--; + if (!left) + goto done; + } + + j++; + memcpy(last_key_block, key_block, 16); + } + +done: + EVP_EncryptFinal_ex(&ecc, key_block, &outlen); + EVP_CIPHER_CTX_cleanup(&ecc); +} + +/* rfc 3711 section 4.1.2.2 */ +static int aes_f8_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, u_int64_t idx) { + unsigned char iv[16]; + u_int32_t roc; + + iv[0] = '\0'; + memcpy(&iv[1], &r->m_pt, 11); /* m, pt, seq, ts, ssrc */ + roc = htonl((idx & 0xffffffff0000ULL) >> 16); + memcpy(&iv[12], &roc, sizeof(roc)); + + aes_128_f8_encrypt(c, iv, s); + + return 0; +} + +/* rfc 3711 section 4.1.2.3 */ +static int aes_f8_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, u_int64_t idx) { + unsigned char iv[16]; + u_int32_t i; + + memset(iv, 0, 4); + i = htonl(0x80000000ULL | idx); + memcpy(&iv[4], &i, 4); + memcpy(&iv[8], &r->header.v_p_x, 8); /* v, p, rc, pt, length, ssrc */ + + aes_128_f8_encrypt(c, iv, s); + + return 0; +} /* rfc 3711, sections 4.2 and 4.2.1 */ static int hmac_sha1_rtp(struct crypto_context *c, char *out, str *in, u_int64_t index) { unsigned char hmac[20];