mirror of https://github.com/sipwise/rtpengine.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1021 lines
28 KiB
1021 lines
28 KiB
#include "crypto.h"
|
|
|
|
#include <string.h>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/hmac.h>
|
|
#include <glib.h>
|
|
|
|
#include "str.h"
|
|
#include "helpers.h"
|
|
#include "rtp.h"
|
|
#include "rtcp.h"
|
|
#include "log.h"
|
|
#include "rtplib.h"
|
|
#include "rtcplib.h"
|
|
#include "main.h"
|
|
#include "ssllib.h"
|
|
#include "types.h"
|
|
|
|
#include "xt_RTPENGINE.h"
|
|
|
|
__thread GString *crypto_debug_string;
|
|
|
|
static int aes_cm_encrypt_rtp(struct crypto_context *, struct rtp_header *, str *, uint32_t);
|
|
static int aes_cm_encrypt_rtcp(struct crypto_context *, struct rtcp_packet *, str *, uint32_t);
|
|
static int aes_gcm_encrypt_rtp(struct crypto_context *, struct rtp_header *, str *, uint32_t);
|
|
static int aes_gcm_decrypt_rtp(struct crypto_context *, struct rtp_header *, str *, uint32_t);
|
|
static int aes_gcm_encrypt_rtcp(struct crypto_context *, struct rtcp_packet *, str *, uint32_t);
|
|
static int aes_gcm_decrypt_rtcp(struct crypto_context *, struct rtcp_packet *, str *, uint32_t);
|
|
static int hmac_sha1_rtp(struct crypto_context *, char *out, str *in, uint32_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, uint32_t idx);
|
|
static int aes_f8_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, uint32_t idx);
|
|
static int aes_cm_session_key_init(struct crypto_context *c);
|
|
static int aes_gcm_session_key_init(struct crypto_context *c);
|
|
static int aes_f8_session_key_init(struct crypto_context *c);
|
|
static int evp_session_key_cleanup(struct crypto_context *c);
|
|
static int null_crypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, uint32_t idx);
|
|
static int null_crypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, uint32_t idx);
|
|
|
|
/* all lengths are in bytes */
|
|
struct crypto_suite __crypto_suites[] = {
|
|
{
|
|
.name = "AEAD_AES_256_GCM",
|
|
.dtls_name = "SRTP_AEAD_AES_256_GCM",
|
|
.master_key_len = 32,
|
|
.master_salt_len = 12,
|
|
.session_key_len = 32,
|
|
.session_salt_len = 12,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AEAD_AES_GCM_256,
|
|
.kernel_hmac = REH_NULL,
|
|
.srtp_auth_tag = 0,
|
|
.srtcp_auth_tag = 0,
|
|
.srtp_auth_key_len = 0,
|
|
.srtcp_auth_key_len = 0,
|
|
.encrypt_rtp = aes_gcm_encrypt_rtp,
|
|
.decrypt_rtp = aes_gcm_decrypt_rtp,
|
|
.encrypt_rtcp = aes_gcm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_gcm_decrypt_rtcp,
|
|
.session_key_init = aes_gcm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
.aead_evp = EVP_aes_256_gcm,
|
|
},
|
|
{
|
|
.name = "AEAD_AES_128_GCM",
|
|
.dtls_name = "SRTP_AEAD_AES_128_GCM",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 12,
|
|
.session_key_len = 16,
|
|
.session_salt_len = 12,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AEAD_AES_GCM_128,
|
|
.kernel_hmac = REH_NULL,
|
|
.srtp_auth_tag = 0,
|
|
.srtcp_auth_tag = 0,
|
|
.srtp_auth_key_len = 0,
|
|
.srtcp_auth_key_len = 0,
|
|
.encrypt_rtp = aes_gcm_encrypt_rtp,
|
|
.decrypt_rtp = aes_gcm_decrypt_rtp,
|
|
.encrypt_rtcp = aes_gcm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_gcm_decrypt_rtcp,
|
|
.session_key_init = aes_gcm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
.aead_evp = EVP_aes_128_gcm,
|
|
},
|
|
{
|
|
.name = "AES_256_CM_HMAC_SHA1_80",
|
|
//.dtls_name = "SRTP_AES128_CM_SHA1_80",
|
|
.master_key_len = 32,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 32,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_CM_256,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 10,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = aes_cm_encrypt_rtp,
|
|
.decrypt_rtp = aes_cm_encrypt_rtp,
|
|
.encrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_init = aes_cm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "AES_256_CM_HMAC_SHA1_32",
|
|
//.dtls_name = "SRTP_AES128_CM_SHA1_32",
|
|
.master_key_len = 32,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 32,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_CM_256,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 4,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = aes_cm_encrypt_rtp,
|
|
.decrypt_rtp = aes_cm_encrypt_rtp,
|
|
.encrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_init = aes_cm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "AES_192_CM_HMAC_SHA1_80",
|
|
//.dtls_name = "SRTP_AES128_CM_SHA1_80",
|
|
.master_key_len = 24,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 24,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_CM_192,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 10,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = aes_cm_encrypt_rtp,
|
|
.decrypt_rtp = aes_cm_encrypt_rtp,
|
|
.encrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_init = aes_cm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "AES_192_CM_HMAC_SHA1_32",
|
|
//.dtls_name = "SRTP_AES128_CM_SHA1_32",
|
|
.master_key_len = 24,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 24,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_CM_192,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 4,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = aes_cm_encrypt_rtp,
|
|
.decrypt_rtp = aes_cm_encrypt_rtp,
|
|
.encrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_init = aes_cm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "AES_CM_128_HMAC_SHA1_80",
|
|
.dtls_name = "SRTP_AES128_CM_SHA1_80",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 16,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_CM_128,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 10,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = aes_cm_encrypt_rtp,
|
|
.decrypt_rtp = aes_cm_encrypt_rtp,
|
|
.encrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_init = aes_cm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "AES_CM_128_HMAC_SHA1_32",
|
|
.dtls_name = "SRTP_AES128_CM_SHA1_32",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 16,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_CM_128,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 4,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = aes_cm_encrypt_rtp,
|
|
.decrypt_rtp = aes_cm_encrypt_rtp,
|
|
.encrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.decrypt_rtcp = aes_cm_encrypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_init = aes_cm_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "F8_128_HMAC_SHA1_80",
|
|
// .dtls_name = "SRTP_AES128_F8_SHA1_80",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 16,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_F8,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 10,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.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,
|
|
.session_key_init = aes_f8_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "F8_128_HMAC_SHA1_32",
|
|
// .dtls_name = "SRTP_AES128_F8_SHA1_32",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 16,
|
|
.session_salt_len = 14,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_AES_F8,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 4,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.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,
|
|
.session_key_init = aes_f8_session_key_init,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "NULL_HMAC_SHA1_80",
|
|
// .dtls_name = "SRTP_NULL_SHA1_80",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 0,
|
|
.session_salt_len = 0,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_NULL,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 10,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = null_crypt_rtp,
|
|
.decrypt_rtp = null_crypt_rtp,
|
|
.encrypt_rtcp = null_crypt_rtcp,
|
|
.decrypt_rtcp = null_crypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
{
|
|
.name = "NULL_HMAC_SHA1_32",
|
|
// .dtls_name = "SRTP_NULL_SHA1_32",
|
|
.master_key_len = 16,
|
|
.master_salt_len = 14,
|
|
.session_key_len = 0,
|
|
.session_salt_len = 0,
|
|
.srtp_lifetime = 1ULL << 48,
|
|
.srtcp_lifetime = 1ULL << 31,
|
|
.kernel_cipher = REC_NULL,
|
|
.kernel_hmac = REH_HMAC_SHA1,
|
|
.srtp_auth_tag = 4,
|
|
.srtcp_auth_tag = 10,
|
|
.srtp_auth_key_len = 20,
|
|
.srtcp_auth_key_len = 20,
|
|
.encrypt_rtp = null_crypt_rtp,
|
|
.decrypt_rtp = null_crypt_rtp,
|
|
.encrypt_rtcp = null_crypt_rtcp,
|
|
.decrypt_rtcp = null_crypt_rtcp,
|
|
.hash_rtp = hmac_sha1_rtp,
|
|
.hash_rtcp = hmac_sha1_rtcp,
|
|
.session_key_cleanup = evp_session_key_cleanup,
|
|
},
|
|
};
|
|
|
|
/* those crypto suites we can */
|
|
const struct crypto_suite *crypto_suites = __crypto_suites;
|
|
const unsigned int num_crypto_suites = G_N_ELEMENTS(__crypto_suites);
|
|
|
|
|
|
|
|
|
|
const struct crypto_suite * crypto_find_suite(const str *s) {
|
|
int i;
|
|
const struct crypto_suite *cs;
|
|
|
|
for (i = 0; i < num_crypto_suites; i++) {
|
|
cs = &crypto_suites[i];
|
|
|
|
if (str_casecmp_str(&cs->name_str, s) == 0)
|
|
return cs;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* rfc 3711 section 4.1 and 4.1.1
|
|
* "in" and "out" MAY point to the same buffer */
|
|
static void aes_ctr(unsigned char *out, str *in, EVP_CIPHER_CTX *ecc, const unsigned char *iv) {
|
|
unsigned char ivx[16];
|
|
unsigned char key_block[16];
|
|
unsigned char *p, *q;
|
|
unsigned int left;
|
|
int outlen, i;
|
|
gboolean aligned = TRUE;
|
|
uint64_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;
|
|
|
|
if ((GPOINTER_TO_UINT(pi) % sizeof(*pi)) != 0)
|
|
aligned = FALSE;
|
|
if ((GPOINTER_TO_UINT(qi) % sizeof(*qi)) != 0)
|
|
aligned = FALSE;
|
|
|
|
while (left) {
|
|
EVP_EncryptUpdate(ecc, key_block, &outlen, ivx, 16);
|
|
assert(outlen == 16);
|
|
|
|
if (left < 16 || !aligned) {
|
|
p = (void *) pi;
|
|
q = (void *) qi;
|
|
for (i = 0; i < 16; i++) {
|
|
*q++ = *p++ ^ key_block[i];
|
|
left--;
|
|
if (!left)
|
|
goto done;
|
|
}
|
|
}
|
|
else {
|
|
qi[0] = pi[0] ^ ki[0];
|
|
qi[1] = pi[1] ^ ki[1];
|
|
left -= 16;
|
|
}
|
|
qi += 2;
|
|
pi += 2;
|
|
|
|
for (i = 15; i >= 0; i--) {
|
|
ivx[i]++;
|
|
if (G_LIKELY(ivx[i]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
done:
|
|
;
|
|
}
|
|
|
|
static void aes_ctr_no_ctx(unsigned char *out, str *in, const unsigned char *key, const EVP_CIPHER *ciph,
|
|
const unsigned char *iv)
|
|
{
|
|
EVP_CIPHER_CTX *ctx;
|
|
unsigned char block[16];
|
|
int len;
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
ctx = EVP_CIPHER_CTX_new();
|
|
#else
|
|
EVP_CIPHER_CTX ctx_s;
|
|
ctx = &ctx_s;
|
|
EVP_CIPHER_CTX_init(ctx);
|
|
#endif
|
|
EVP_EncryptInit_ex(ctx, ciph, NULL, key, NULL);
|
|
aes_ctr(out, in, ctx, iv);
|
|
EVP_EncryptFinal_ex(ctx, block, &len);
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
#else
|
|
EVP_CIPHER_CTX_cleanup(ctx);
|
|
#endif
|
|
}
|
|
|
|
/* rfc 3711 section 4.3.1 and 4.3.3
|
|
* key: 128 bits
|
|
* x: 112 bits
|
|
* n <= 256
|
|
* out->len := n / 8 */
|
|
static void prf_n(str *out, const unsigned char *key, const EVP_CIPHER *ciph, const unsigned char *x) {
|
|
unsigned char iv[16];
|
|
unsigned char o[32];
|
|
unsigned char in[32];
|
|
str in_s;
|
|
|
|
assert(sizeof(o) >= out->len);
|
|
|
|
ZERO(iv);
|
|
memcpy(iv, x, 14);
|
|
/* iv[14] = iv[15] = 0; := x << 16 */
|
|
ZERO(in); /* outputs the key stream */
|
|
str_init_len(&in_s, (void *) in, out->len > 16 ? 32 : 16);
|
|
aes_ctr_no_ctx(o, &in_s, key, ciph, iv);
|
|
|
|
memcpy(out->s, o, out->len);
|
|
}
|
|
|
|
|
|
|
|
/* rfc 3711 section 4.3.1 */
|
|
int crypto_gen_session_key(struct crypto_context *c, str *out, unsigned char label, unsigned int index_len) {
|
|
unsigned char key_id[7]; /* [ label, 48-bit ROC || SEQ ] */
|
|
unsigned char x[14];
|
|
int i;
|
|
|
|
if (!out->len)
|
|
return 0;
|
|
|
|
ZERO(key_id);
|
|
/* key_id[1..6] := r; or 1..4 for rtcp
|
|
* key_derivation_rate == 0 --> r == 0 */
|
|
|
|
key_id[0] = label;
|
|
assert(sizeof(x) >= c->params.crypto_suite->master_salt_len);
|
|
memcpy(x, c->params.master_salt, c->params.crypto_suite->master_salt_len);
|
|
// AEAD uses 12 bytes master salt; pad on the right to get 14
|
|
// Errata: https://www.rfc-editor.org/errata_search.php?rfc=7714
|
|
if (c->params.crypto_suite->master_salt_len == 12)
|
|
x[12] = x[13] = '\x00';
|
|
for (i = 13 - index_len; i < 14; i++)
|
|
x[i] = key_id[i - (13 - index_len)] ^ x[i];
|
|
|
|
prf_n(out, c->params.master_key, c->params.crypto_suite->aes_evp, x);
|
|
|
|
ilogs(srtp, LOG_DEBUG, "Generated session key: master key "
|
|
"%02x%02x%02x%02x..., "
|
|
"master salt "
|
|
"%02x%02x%02x%02x..., "
|
|
"label %02x, length %zu, result "
|
|
"%02x%02x%02x%02x...",
|
|
c->params.master_key[0],
|
|
c->params.master_key[1],
|
|
c->params.master_key[2],
|
|
c->params.master_key[3],
|
|
c->params.master_salt[0],
|
|
c->params.master_salt[1],
|
|
c->params.master_salt[2],
|
|
c->params.master_salt[3],
|
|
label, out->len,
|
|
(unsigned char) out->s[0],
|
|
(unsigned char) out->s[1],
|
|
(unsigned char) out->s[2],
|
|
(unsigned char) out->s[3]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* All versions of libsrtp w/openssl prior to 1.6 and 2.1 have
|
|
* a bug in iv generation for AES-256 SRTCP only (SRTP is ok).
|
|
* https://github.com/cisco/libsrtp/issues/264
|
|
* Example: FreeSWITCH 1.6.x.
|
|
* The bug is equivalent to:
|
|
*
|
|
* // idx <= 16 - no left shift
|
|
* // ivi[1] ^= ssrc - don't use ssrc
|
|
* // ivi[2] ^= idxh - don't use idxh
|
|
*/
|
|
|
|
/* rfc 3711 section 4.1.1 */
|
|
static int aes_cm_encrypt(struct crypto_context *c, uint32_t ssrc, str *s, uint32_t idx) {
|
|
unsigned char iv[16];
|
|
uint32_t *ivi;
|
|
uint32_t idxh, idxl;
|
|
|
|
memcpy(iv, c->session_salt, 14);
|
|
iv[14] = iv[15] = '\0';
|
|
ivi = (void *) iv;
|
|
idxh = htonl((idx & 0xffff0000ULL) >> 16);
|
|
idxl = htonl((idx & 0x0000ffffULL) << 16);
|
|
|
|
ivi[1] ^= ssrc;
|
|
ivi[2] ^= idxh;
|
|
ivi[3] ^= idxl;
|
|
|
|
aes_ctr((void *) s->s, s, c->session_key_ctx[0], iv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* rfc 3711 section 4.1 */
|
|
static int aes_cm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, uint32_t idx) {
|
|
return aes_cm_encrypt(c, r->ssrc, s, idx);
|
|
}
|
|
|
|
/* rfc 3711 sections 3.4 and 4.1 */
|
|
static int aes_cm_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, uint32_t idx) {
|
|
return aes_cm_encrypt(c, r->ssrc, s, idx);
|
|
}
|
|
|
|
/* rfc 7714 section 8 */
|
|
|
|
union aes_gcm_rtp_iv {
|
|
unsigned char bytes[12];
|
|
struct {
|
|
uint16_t zeros;
|
|
uint32_t ssrc;
|
|
uint32_t roq;
|
|
uint16_t seq;
|
|
} __attribute__((__packed__));
|
|
} __attribute__((__packed__));
|
|
|
|
_Static_assert(offsetof(union aes_gcm_rtp_iv, seq) == 10,
|
|
"union aes_gcm_rtp_iv not packed");
|
|
|
|
static int aes_gcm_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, uint32_t idx) {
|
|
union aes_gcm_rtp_iv iv;
|
|
int len, ciphertext_len;
|
|
|
|
memcpy(iv.bytes, c->session_salt, 12);
|
|
|
|
iv.ssrc ^= r->ssrc;
|
|
iv.roq ^= htonl((idx & 0xffffff0000ULL) >> 16);
|
|
iv.seq ^= htons( idx & 0x000000ffffULL);
|
|
|
|
EVP_EncryptInit_ex(c->session_key_ctx[0], c->params.crypto_suite->aead_evp(), NULL,
|
|
(const unsigned char *) c->session_key, iv.bytes);
|
|
|
|
// nominally 12 bytes of AAD
|
|
EVP_EncryptUpdate(c->session_key_ctx[0], NULL, &len, (void *)r, s->s - (char *)r);
|
|
|
|
EVP_EncryptUpdate(c->session_key_ctx[0], (unsigned char *) s->s, &len,
|
|
(const unsigned char *) s->s, s->len);
|
|
ciphertext_len = len;
|
|
if (!EVP_EncryptFinal_ex(c->session_key_ctx[0], (unsigned char *) s->s+len, &len))
|
|
return 1;
|
|
ciphertext_len += len;
|
|
// append the tag to the str buffer
|
|
EVP_CIPHER_CTX_ctrl(c->session_key_ctx[0], EVP_CTRL_GCM_GET_TAG, 16, s->s+ciphertext_len);
|
|
s->len = ciphertext_len + 16;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aes_gcm_decrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, uint32_t idx) {
|
|
union aes_gcm_rtp_iv iv;
|
|
int len, plaintext_len;
|
|
|
|
if (s->len < 16)
|
|
return -1;
|
|
|
|
memcpy(iv.bytes, c->session_salt, 12);
|
|
|
|
iv.ssrc ^= r->ssrc;
|
|
iv.roq ^= htonl((idx & 0xffff0000ULL) >> 16);
|
|
iv.seq ^= htons( idx & 0x0000ffffULL);
|
|
|
|
EVP_DecryptInit_ex(c->session_key_ctx[0], c->params.crypto_suite->aead_evp(), NULL,
|
|
(const unsigned char *) c->session_key, iv.bytes);
|
|
|
|
// nominally 12 bytes of AAD
|
|
EVP_DecryptUpdate(c->session_key_ctx[0], NULL, &len, (void *)r, s->s - (char *)r);
|
|
|
|
// decrypt partial buffer - the last 16 bytes are the tag
|
|
EVP_DecryptUpdate(c->session_key_ctx[0], (unsigned char *) s->s, &len,
|
|
(const unsigned char *) s->s, s->len-16);
|
|
plaintext_len = len;
|
|
EVP_CIPHER_CTX_ctrl(c->session_key_ctx[0], EVP_CTRL_GCM_SET_TAG, 16, s->s + s->len-16);
|
|
if (!EVP_DecryptFinal_ex(c->session_key_ctx[0], (unsigned char *) s->s+len, &len))
|
|
return 1;
|
|
plaintext_len += len;
|
|
s->len = plaintext_len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* rfc 7714 section 9 */
|
|
|
|
union aes_gcm_rtcp_iv {
|
|
unsigned char bytes[12];
|
|
struct {
|
|
uint16_t zeros_a;
|
|
uint32_t ssrc;
|
|
uint16_t zeros_b;
|
|
uint32_t srtcp;
|
|
} __attribute__((__packed__));
|
|
} __attribute__((__packed__));
|
|
|
|
_Static_assert(offsetof(union aes_gcm_rtcp_iv, srtcp) == 8,
|
|
"union aes_gcm_rtcp_iv not packed");
|
|
|
|
static int aes_gcm_encrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, uint32_t idx) {
|
|
union aes_gcm_rtcp_iv iv;
|
|
uint32_t e_idx;
|
|
int len, ciphertext_len;
|
|
|
|
memcpy(iv.bytes, c->session_salt, 12);
|
|
|
|
iv.ssrc ^= r->ssrc;
|
|
iv.srtcp ^= htonl(idx & 0x007fffffffULL);
|
|
e_idx = htonl((idx & 0x007fffffffULL) | 0x80000000ULL);
|
|
|
|
EVP_EncryptInit_ex(c->session_key_ctx[0], c->params.crypto_suite->aead_evp(), NULL,
|
|
(const unsigned char *) c->session_key, iv.bytes);
|
|
|
|
// nominally 8 + 4 bytes of AAD
|
|
EVP_EncryptUpdate(c->session_key_ctx[0], NULL, &len, (void *)r, s->s - (char *)r);
|
|
EVP_EncryptUpdate(c->session_key_ctx[0], NULL, &len, (void *)&e_idx, 4);
|
|
|
|
EVP_EncryptUpdate(c->session_key_ctx[0], (unsigned char *) s->s, &len,
|
|
(const unsigned char *) s->s, s->len);
|
|
ciphertext_len = len;
|
|
if (!EVP_EncryptFinal_ex(c->session_key_ctx[0], (unsigned char *) s->s+len, &len))
|
|
return 1;
|
|
ciphertext_len += len;
|
|
// append the tag to the str buffer
|
|
EVP_CIPHER_CTX_ctrl(c->session_key_ctx[0], EVP_CTRL_GCM_GET_TAG, 16, s->s+ciphertext_len);
|
|
s->len = ciphertext_len + 16;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aes_gcm_decrypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, uint32_t idx) {
|
|
union aes_gcm_rtcp_iv iv;
|
|
uint32_t e_idx;
|
|
int len, plaintext_len;
|
|
|
|
if (s->len < 16)
|
|
return -1;
|
|
|
|
memcpy(iv.bytes, c->session_salt, 12);
|
|
|
|
iv.ssrc ^= r->ssrc;
|
|
iv.srtcp ^= htonl(idx & 0x007fffffffULL);
|
|
e_idx = htonl((idx & 0x007fffffffULL) | 0x80000000ULL);
|
|
|
|
EVP_DecryptInit_ex(c->session_key_ctx[0], c->params.crypto_suite->aead_evp(), NULL,
|
|
(const unsigned char *) c->session_key, iv.bytes);
|
|
|
|
// nominally 8 + 4 bytes of AAD
|
|
EVP_DecryptUpdate(c->session_key_ctx[0], NULL, &len, (void *)r, s->s - (char *)r);
|
|
EVP_DecryptUpdate(c->session_key_ctx[0], NULL, &len, (void *)&e_idx, 4);
|
|
|
|
// decrypt partial buffer - the last 16 bytes are the tag
|
|
EVP_DecryptUpdate(c->session_key_ctx[0], (unsigned char *) s->s, &len,
|
|
(const unsigned char *) s->s, s->len-16);
|
|
plaintext_len = len;
|
|
EVP_CIPHER_CTX_ctrl(c->session_key_ctx[0], EVP_CTRL_GCM_SET_TAG, 16, s->s + s->len-16);
|
|
if (!EVP_DecryptFinal_ex(c->session_key_ctx[0], (unsigned char *) s->s+len, &len))
|
|
return 1;
|
|
plaintext_len += len;
|
|
s->len = plaintext_len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* 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) {
|
|
unsigned char key_block[16], last_key_block[16], /* S(j), S(j-1) */
|
|
ivx[16], /* IV' */
|
|
x[16];
|
|
int i, outlen, left;
|
|
uint32_t j;
|
|
unsigned char *p;
|
|
uint64_t *pi, *ki, *lki, *xi;
|
|
uint32_t *xu;
|
|
|
|
EVP_EncryptUpdate(c->session_key_ctx[1], ivx, &outlen, iv, 16);
|
|
assert(outlen == 16);
|
|
|
|
pi = (void *) s->s;
|
|
ki = (void *) key_block;
|
|
lki = (void *) last_key_block;
|
|
xi = (void *) x;
|
|
xu = (void *) x;
|
|
left = s->len;
|
|
j = 0;
|
|
ZERO(last_key_block);
|
|
|
|
while (left) {
|
|
/* S(j) = E(k_e, IV' XOR j XOR S(j-1)) */
|
|
memcpy(x, ivx, 16);
|
|
|
|
xu[3] ^= htonl(j);
|
|
|
|
xi[0] ^= lki[0];
|
|
xi[1] ^= lki[1];
|
|
|
|
EVP_EncryptUpdate(c->session_key_ctx[0], key_block, &outlen, x, 16);
|
|
assert(outlen == 16);
|
|
|
|
if (G_UNLIKELY(left < 16)) {
|
|
p = (void *) pi;
|
|
for (i = 0; i < 16; i++) {
|
|
*p++ ^= key_block[i];
|
|
left--;
|
|
if (!left)
|
|
goto done;
|
|
}
|
|
abort();
|
|
}
|
|
|
|
*pi++ ^= ki[0];
|
|
*pi++ ^= ki[1];
|
|
left -= 16;
|
|
if (!left)
|
|
break;
|
|
|
|
j++;
|
|
memcpy(last_key_block, key_block, 16);
|
|
}
|
|
|
|
done:
|
|
;
|
|
}
|
|
|
|
/* rfc 3711 section 4.1.2.2 */
|
|
static int aes_f8_encrypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, uint32_t idx) {
|
|
unsigned char iv[16];
|
|
uint32_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, uint32_t idx) {
|
|
unsigned char iv[16];
|
|
uint32_t i;
|
|
|
|
memset(iv, 0, 4);
|
|
i = htonl(0x80000000ULL | idx);
|
|
memcpy(&iv[4], &i, 4);
|
|
memcpy(&iv[8], r, 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, uint32_t index) {
|
|
unsigned char hmac[20];
|
|
uint32_t roc;
|
|
|
|
roc = htonl((index & 0xffffffff0000ULL) >> 16);
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
|
EVP_MAC_CTX *hc;
|
|
|
|
hc = EVP_MAC_CTX_dup(rtpe_hmac_sha1_base);
|
|
EVP_MAC_init(hc, (unsigned char *) c->session_auth_key,
|
|
c->params.crypto_suite->srtp_auth_key_len, NULL);
|
|
EVP_MAC_update(hc, (unsigned char *) in->s, in->len);
|
|
EVP_MAC_update(hc, (unsigned char *) &roc, sizeof(roc));
|
|
size_t outsize = sizeof(hmac);
|
|
EVP_MAC_final(hc, hmac, &outsize, outsize);
|
|
EVP_MAC_CTX_free(hc);
|
|
#else // <3.0
|
|
HMAC_CTX *hc;
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
hc = HMAC_CTX_new();
|
|
#else
|
|
HMAC_CTX hc_s;
|
|
HMAC_CTX_init(&hc_s);
|
|
hc = &hc_s;
|
|
#endif
|
|
|
|
HMAC_Init_ex(hc, c->session_auth_key, c->params.crypto_suite->srtp_auth_key_len, EVP_sha1(), NULL);
|
|
HMAC_Update(hc, (unsigned char *) in->s, in->len);
|
|
HMAC_Update(hc, (unsigned char *) &roc, sizeof(roc));
|
|
HMAC_Final(hc, hmac, NULL);
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
HMAC_CTX_free(hc);
|
|
#else
|
|
HMAC_CTX_cleanup(hc);
|
|
#endif
|
|
#endif
|
|
|
|
assert(sizeof(hmac) >= c->params.crypto_suite->srtp_auth_tag);
|
|
memcpy(out, hmac, c->params.crypto_suite->srtp_auth_tag);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* rfc 3711, sections 4.2 and 4.2.1 */
|
|
static int hmac_sha1_rtcp(struct crypto_context *c, char *out, str *in) {
|
|
unsigned char hmac[20];
|
|
|
|
if (!HMAC(EVP_sha1(), c->session_auth_key, c->params.crypto_suite->srtcp_auth_key_len,
|
|
(unsigned char *) in->s, in->len, hmac, NULL))
|
|
{
|
|
memset(out, 0, c->params.crypto_suite->srtcp_auth_tag);
|
|
return 1;
|
|
}
|
|
|
|
assert(sizeof(hmac) >= c->params.crypto_suite->srtcp_auth_tag);
|
|
memcpy(out, hmac, c->params.crypto_suite->srtcp_auth_tag);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int aes_cm_session_key_init(struct crypto_context *c) {
|
|
evp_session_key_cleanup(c);
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
c->session_key_ctx[0] = EVP_CIPHER_CTX_new();
|
|
#else
|
|
c->session_key_ctx[0] = g_slice_alloc(sizeof(EVP_CIPHER_CTX));
|
|
EVP_CIPHER_CTX_init(c->session_key_ctx[0]);
|
|
#endif
|
|
EVP_EncryptInit_ex(c->session_key_ctx[0], c->params.crypto_suite->aes_evp, NULL,
|
|
(unsigned char *) c->session_key, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int aes_gcm_session_key_init(struct crypto_context *c) {
|
|
evp_session_key_cleanup(c);
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
c->session_key_ctx[0] = EVP_CIPHER_CTX_new();
|
|
#else
|
|
c->session_key_ctx[0] = g_slice_alloc(sizeof(EVP_CIPHER_CTX));
|
|
EVP_CIPHER_CTX_init(c->session_key_ctx[0]);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int aes_f8_session_key_init(struct crypto_context *c) {
|
|
unsigned char m[16];
|
|
int i;
|
|
int k_e_len, k_s_len; /* n_e, n_s */
|
|
unsigned char *key;
|
|
|
|
aes_cm_session_key_init(c);
|
|
|
|
k_e_len = c->params.crypto_suite->session_key_len;
|
|
k_s_len = c->params.crypto_suite->session_salt_len;
|
|
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];
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
c->session_key_ctx[1] = EVP_CIPHER_CTX_new();
|
|
#else
|
|
c->session_key_ctx[1] = g_slice_alloc(sizeof(EVP_CIPHER_CTX));
|
|
EVP_CIPHER_CTX_init(c->session_key_ctx[1]);
|
|
#endif
|
|
EVP_EncryptInit_ex(c->session_key_ctx[1], EVP_aes_128_ecb(), NULL, m, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int evp_session_key_cleanup(struct crypto_context *c) {
|
|
unsigned char block[16];
|
|
int len, i;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(c->session_key_ctx); i++) {
|
|
if (!c->session_key_ctx[i])
|
|
continue;
|
|
|
|
EVP_EncryptFinal_ex(c->session_key_ctx[i], block, &len);
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
EVP_CIPHER_CTX_free(c->session_key_ctx[i]);
|
|
#else
|
|
EVP_CIPHER_CTX_cleanup(c->session_key_ctx[i]);
|
|
g_slice_free1(sizeof(EVP_CIPHER_CTX), c->session_key_ctx[i]);
|
|
#endif
|
|
c->session_key_ctx[i] = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int null_crypt_rtp(struct crypto_context *c, struct rtp_header *r, str *s, uint32_t idx) {
|
|
return 0;
|
|
}
|
|
static int null_crypt_rtcp(struct crypto_context *c, struct rtcp_packet *r, str *s, uint32_t idx) {
|
|
return 0;
|
|
}
|
|
|
|
static void dump_key(struct crypto_context *c, int log_level) {
|
|
char *k, *s;
|
|
|
|
if (!c->params.crypto_suite)
|
|
return;
|
|
|
|
k = g_base64_encode(c->params.master_key, c->params.crypto_suite->master_key_len);
|
|
s = g_base64_encode(c->params.master_salt, c->params.crypto_suite->master_salt_len);
|
|
|
|
ilogs(srtp, log_level, "--- %s key %s%s%s salt %s%s%s", c->params.crypto_suite->name, FMT_M(k), FMT_M(s));
|
|
|
|
g_free(k);
|
|
g_free(s);
|
|
}
|
|
|
|
void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out) {
|
|
int log_level = LOG_DEBUG;
|
|
|
|
if (rtpe_config.log_keys)
|
|
log_level = LOG_ERROR;
|
|
|
|
if (get_log_level(core) < log_level)
|
|
return;
|
|
|
|
ilogs(srtp, log_level, "SRTP keys, incoming:");
|
|
dump_key(in, log_level);
|
|
ilogs(srtp, log_level, "SRTP keys, outgoing:");
|
|
dump_key(out, log_level);
|
|
}
|
|
|
|
char *crypto_params_sdes_dump(const struct crypto_params_sdes *cps, char **buf) {
|
|
if (*buf)
|
|
g_free(*buf);
|
|
|
|
GString *s = g_string_new("");
|
|
if (!cps || !cps->params.crypto_suite) {
|
|
g_string_append(s, "<none>");
|
|
goto out;
|
|
}
|
|
|
|
g_string_append_printf(s, "suite %s, tag %u, key ", cps->params.crypto_suite->name, cps->tag);
|
|
char *b = g_base64_encode(cps->params.master_key, cps->params.crypto_suite->master_key_len);
|
|
g_string_append_printf(s, "%s salt ", b);
|
|
g_free(b);
|
|
b = g_base64_encode(cps->params.master_salt, cps->params.crypto_suite->master_salt_len);
|
|
g_string_append_printf(s, "%s", b);
|
|
g_free(b);
|
|
|
|
out:
|
|
*buf = g_string_free(s, FALSE);
|
|
return *buf;
|
|
}
|
|
|
|
void crypto_init_main(void) {
|
|
struct crypto_suite *cs;
|
|
for (unsigned int i = 0; i < num_crypto_suites; i++) {
|
|
cs = &__crypto_suites[i];
|
|
cs->idx = i;
|
|
str_init(&cs->name_str, (char *) cs->name);
|
|
switch(cs->master_key_len) {
|
|
case 16:
|
|
cs->aes_evp = EVP_aes_128_ecb();
|
|
break;
|
|
case 24:
|
|
cs->aes_evp = EVP_aes_192_ecb();
|
|
break;
|
|
case 32:
|
|
cs->aes_evp = EVP_aes_256_ecb();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void __crypto_debug_printf(const char *fmt, ...) {
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
g_string_append_vprintf(crypto_debug_string, fmt, va);
|
|
va_end(va);
|
|
}
|