start implementing in-kernel AES en/decryption for SRTP

session key derivation complete
git.mgm/mediaproxy-ng/github/master
Richard Fuchs 13 years ago
parent 05c1ade246
commit 4a2909daab

@ -5,6 +5,9 @@
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/version.h>
#include <linux/err.h>
#include <linux/crypto.h>
#include <crypto/aes.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/ipv6.h>
@ -100,6 +103,63 @@ static void table_push(struct mediaproxy_table *);
static struct mediaproxy_target *get_target(struct mediaproxy_table *, u_int16_t);
struct mp_crypto_context {
spinlock_t lock; /* protects roc and last_index */
unsigned char session_key[16];
unsigned char session_salt[14];
unsigned char session_auth_key[20];
u_int32_t roc;
};
struct mediaproxy_target {
atomic_t refcnt;
u_int32_t table;
struct mediaproxy_target_info target;
spinlock_t stats_lock;
struct mediaproxy_stats stats;
struct mp_crypto_context decrypt;
struct mp_crypto_context encrypt;
};
struct mediaproxy_table {
atomic_t refcnt;
rwlock_t target_lock;
pid_t pid;
u_int32_t id;
struct proc_dir_entry *proc;
struct proc_dir_entry *status;
struct proc_dir_entry *control;
struct proc_dir_entry *list;
struct proc_dir_entry *blist;
struct mediaproxy_target **target[256];
unsigned int buckets;
unsigned int targets;
};
struct mp_cipher {
const char *name;
};
struct mp_hmac {
const char *name;
};
static const struct file_operations proc_control_ops = {
.write = proc_control_write,
.open = proc_control_open,
@ -125,7 +185,7 @@ static const struct file_operations proc_blist_ops = {
.release = proc_blist_close,
};
static struct seq_operations proc_list_seq_ops = {
static const struct seq_operations proc_list_seq_ops = {
.start = proc_list_start,
.next = proc_list_next,
.stop = proc_list_stop,
@ -139,13 +199,40 @@ static const struct file_operations proc_main_list_ops = {
.release = seq_release,
};
static struct seq_operations proc_main_list_seq_ops = {
static const struct seq_operations proc_main_list_seq_ops = {
.start = proc_main_list_start,
.next = proc_main_list_next,
.stop = proc_main_list_stop,
.show = proc_main_list_show,
};
static const struct mp_cipher mp_ciphers[] = {
[MPC_INVALID] = {
.name = NULL,
},
[MPC_NULL] = {
.name = "NULL",
},
[MPC_AES_CM] = {
.name = "AES-CM",
},
[MPC_AES_F8] = {
.name = "AES-F8",
},
};
static const struct mp_hmac mp_hmacs[] = {
[MPH_INVALID] = {
.name = NULL,
},
[MPH_NULL] = {
.name = "NULL",
},
[MPH_HMAC_SHA1] = {
.name = "HMAC-SHA1",
},
};
@ -740,6 +827,171 @@ static int is_valid_address(struct mp_address *mpa) {
static int validate_srtp(struct mediaproxy_srtp *s) {
if (s->cipher <= MPC_INVALID)
return -1;
if (s->cipher >= __MPC_LAST)
return -1;
if (s->hmac <= MPH_INVALID)
return -1;
if (s->hmac >= __MPH_LAST)
return -1;
if (s->auth_tag_len > 20)
return -1;
if (s->mki_len > 128)
return -1;
return 0;
}
static void aes_ctr_128(unsigned char *out, const unsigned char *in, int in_len,
struct crypto_cipher *tfm, const char *iv)
{
unsigned char ivx[16];
unsigned char key_block[16];
unsigned char *p, *q;
unsigned int left;
int i;
u_int64_t *pi, *qi, *ki;
if (!tfm)
return;
memcpy(ivx, iv, 16);
pi = (void *) in;
qi = (void *) out;
ki = (void *) key_block;
left = in_len;
while (left) {
crypto_cipher_encrypt_one(tfm, key_block, ivx);
if (unlikely(left < 16)) {
p = (void *) pi;
q = (void *) qi;
for (i = 0; i < 16; i++) {
*q++ = *p++ ^ key_block[i];
left--;
if (!left)
goto done;
}
panic("BUG!");
}
*qi++ = *pi++ ^ ki[0];
*qi++ = *pi++ ^ ki[1];
left -= 16;
for (i = 15; i >= 0; i--) {
ivx[i]++;
if (likely(ivx[i]))
break;
}
}
done:
;
}
static int aes_ctr_128_no_ctx(unsigned char *out, const char *in, int in_len,
const unsigned char *key, const unsigned char *iv)
{
struct crypto_cipher *tfm;
tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
crypto_cipher_setkey(tfm, key, 16);
aes_ctr_128(out, in, in_len, tfm, iv);
crypto_free_cipher(tfm);
return 0;
}
static int prf_n(unsigned char *out, int len, const unsigned char *key, const unsigned char *x) {
unsigned char iv[16];
unsigned char o[32];
unsigned char in[32];
int in_len, ret;
memcpy(iv, x, 14);
iv[14] = iv[15] = 0;
in_len = len > 16 ? 32 : 16;
memset(in, 0, in_len);
ret = aes_ctr_128_no_ctx(o, in, in_len, key, iv);
if (ret)
return ret;
memcpy(out, o, len);
return 0;
}
static int gen_session_key(unsigned char *out, int len, struct mediaproxy_srtp *s, unsigned char label) {
unsigned char key_id[7];
unsigned char x[14];
int i, ret;
memset(key_id, 0, sizeof(key_id));
key_id[0] = label;
memcpy(x, s->master_salt, 14);
for (i = 13 - 6; i < 14; i++)
x[i] = key_id[i - (13 - 6)] ^ x[i];
ret = prf_n(out, len, s->master_key, x);
if (ret)
return ret;
return 0;
}
static int gen_session_keys(struct mp_crypto_context *c, struct mediaproxy_srtp *s) {
int ret;
if (s->cipher == MPC_NULL)
return 0;
ret = gen_session_key(c->session_key, 16, s, 0x00);
if (ret)
return ret;
ret = gen_session_key(c->session_auth_key, 20, s, 0x01);
if (ret)
return ret;
ret = gen_session_key(c->session_salt, 14, s, 0x02);
if (ret)
return ret;
DBG("master key %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
s->master_key[0], s->master_key[1], s->master_key[2], s->master_key[3],
s->master_key[4], s->master_key[5], s->master_key[6], s->master_key[7],
s->master_key[8], s->master_key[9], s->master_key[10], s->master_key[11],
s->master_key[12], s->master_key[13], s->master_key[14], s->master_key[15]);
DBG("master salt %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
s->master_salt[0], s->master_salt[1], s->master_salt[2], s->master_salt[3],
s->master_salt[4], s->master_salt[5], s->master_salt[6], s->master_salt[7],
s->master_salt[8], s->master_salt[9], s->master_salt[10], s->master_salt[11],
s->master_salt[12], s->master_salt[13]);
DBG("session key %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
c->session_key[0], c->session_key[1], c->session_key[2], c->session_key[3],
c->session_key[4], c->session_key[5], c->session_key[6], c->session_key[7],
c->session_key[8], c->session_key[9], c->session_key[10], c->session_key[11],
c->session_key[12], c->session_key[13], c->session_key[14], c->session_key[15]);
DBG("session salt %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
c->session_salt[0], c->session_salt[1], c->session_salt[2], c->session_salt[3],
c->session_salt[4], c->session_salt[5], c->session_salt[6], c->session_salt[7],
c->session_salt[8], c->session_salt[9], c->session_salt[10], c->session_salt[11],
c->session_salt[12], c->session_salt[13]);
return 0;
}
static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target_info *i, int update) {
unsigned char hi, lo;
@ -763,6 +1015,10 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
if (i->mirror_addr.family != i->src_addr.family)
return -EINVAL;
}
if (validate_srtp(&i->decrypt))
return -EINVAL;
if (validate_srtp(&i->encrypt))
return -EINVAL;
DBG("Creating new target\n");
@ -774,8 +1030,18 @@ static int table_new_target(struct mediaproxy_table *t, struct mediaproxy_target
g->table = t->id;
atomic_set(&g->refcnt, 1);
spin_lock_init(&g->stats_lock);
spin_lock_init(&g->decrypt.lock);
spin_lock_init(&g->encrypt.lock);
memcpy(&g->target, i, sizeof(*i));
err = gen_session_keys(&g->decrypt, &g->target.decrypt);
if (err)
goto fail2;
err = gen_session_keys(&g->encrypt, &g->target.encrypt);
if (err)
goto fail2;
err = -ENOMEM;
if (update)
gp = NULL;
else {
@ -982,7 +1248,7 @@ static ssize_t proc_control_write(struct file *file, const char __user *buf, siz
int err;
if (buflen != sizeof(msg))
return -EINVAL;
return -EIO;
inode = file->f_path.dentry->d_inode;
pde = PDE(inode);

@ -24,6 +24,35 @@ struct mp_address {
u_int16_t port;
};
enum mediaproxy_cipher {
MPC_INVALID = 0,
MPC_NULL,
MPC_AES_CM,
MPC_AES_F8,
__MPC_LAST
};
enum mediaproxy_hmac {
MPH_INVALID = 0,
MPH_NULL,
MPH_HMAC_SHA1,
__MPH_LAST
};
struct mediaproxy_srtp {
enum mediaproxy_cipher cipher;
enum mediaproxy_hmac hmac;
unsigned char master_key[16];
unsigned char master_salt[14];
u_int64_t mki;
u_int64_t last_index;
unsigned int auth_tag_len; /* in bytes */
unsigned int mki_len;
};
struct mediaproxy_target_info {
u_int16_t target_port;
@ -32,6 +61,9 @@ struct mediaproxy_target_info {
struct mp_address mirror_addr;
struct mediaproxy_srtp decrypt;
struct mediaproxy_srtp encrypt;
unsigned char tos;
};
@ -51,35 +83,5 @@ struct mediaproxy_list_entry {
struct mediaproxy_stats stats;
};
#ifdef __KERNEL__
struct mediaproxy_target {
atomic_t refcnt;
u_int32_t table;
struct mediaproxy_target_info target;
spinlock_t stats_lock;
struct mediaproxy_stats stats;
};
struct mediaproxy_table {
atomic_t refcnt;
rwlock_t target_lock;
pid_t pid;
u_int32_t id;
struct proc_dir_entry *proc;
struct proc_dir_entry *status;
struct proc_dir_entry *control;
struct proc_dir_entry *list;
struct proc_dir_entry *blist;
struct mediaproxy_target **target[256];
unsigned int buckets;
unsigned int targets;
};
#endif
#endif

Loading…
Cancel
Save