Add AES-256 support.
diff --git a/crypto/Makefile.in b/crypto/Makefile.in
index c14dba5..842d08e 100644
--- a/crypto/Makefile.in
+++ b/crypto/Makefile.in
@@ -46,16 +46,23 @@
test/kernel_driver$(EXE) test/aes_calc$(EXE) test/rand_gen$(EXE) \
test/env$(EXE)
-# data values used to test the aes_calc application
+# data values used to test the aes_calc application for AES-128
+k128=000102030405060708090a0b0c0d0e0f
+p128=00112233445566778899aabbccddeeff
+c128=69c4e0d86a7b0430d8cdb78070b4c55a
-k=000102030405060708090a0b0c0d0e0f
-p=00112233445566778899aabbccddeeff
-c=69c4e0d86a7b0430d8cdb78070b4c55a
+
+# data values used to test the aes_calc application for AES-256
+k256=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+p256=00112233445566778899aabbccddeeff
+c256=8ea2b7ca516745bfeafc49904b496089
+
runtest: libcryptomodule.a $(testapp)
test/env$(EXE) # print out information on the build environment
@echo "running libcryptomodule test applications..."
- test `test/aes_calc $k $p` = $c
+ test `test/aes_calc $(k128) $(p128)` = $(c128)
+ test `test/aes_calc $(k256) $(p256)` = $(c256)
test/cipher_driver$(EXE) -v >/dev/null
test/datatypes_driver$(EXE) -v >/dev/null
test/stat_driver$(EXE) >/dev/null
diff --git a/crypto/cipher/aes.c b/crypto/cipher/aes.c
index 520d3c0..a17b9e4 100644
--- a/crypto/cipher/aes.c
+++ b/crypto/cipher/aes.c
@@ -1410,6 +1410,69 @@
}
}
+static void
+aes_256_expand_encryption_key(const unsigned char *key,
+ aes_expanded_key_t *expanded_key) {
+ int i;
+ gf2_8 rc;
+
+ /* initialize round constant */
+ rc = 1;
+
+ expanded_key->num_rounds = 14;
+
+ v128_copy_octet_string(&expanded_key->round[0], key);
+ v128_copy_octet_string(&expanded_key->round[1], key+16);
+
+#if 0
+ debug_print(mod_aes_icm,
+ "expanded key[0]: %s", v128_hex_string(&expanded_key->round[0]));
+ debug_print(mod_aes_icm,
+ "expanded key[1]: %s", v128_hex_string(&expanded_key->round[1]));
+#endif
+
+ /* loop over rest of round keys */
+ for (i=2; i < 15; i++) {
+
+ /* munge first word of round key */
+ if ((i & 1) == 0) {
+ expanded_key->round[i].v8[0] = aes_sbox[expanded_key->round[i-1].v8[13]] ^ rc;
+ expanded_key->round[i].v8[1] = aes_sbox[expanded_key->round[i-1].v8[14]];
+ expanded_key->round[i].v8[2] = aes_sbox[expanded_key->round[i-1].v8[15]];
+ expanded_key->round[i].v8[3] = aes_sbox[expanded_key->round[i-1].v8[12]];
+
+ /* modify round constant */
+ rc = gf2_8_shift(rc);
+ }
+ else {
+ expanded_key->round[i].v8[0] = aes_sbox[expanded_key->round[i-1].v8[12]];
+ expanded_key->round[i].v8[1] = aes_sbox[expanded_key->round[i-1].v8[13]];
+ expanded_key->round[i].v8[2] = aes_sbox[expanded_key->round[i-1].v8[14]];
+ expanded_key->round[i].v8[3] = aes_sbox[expanded_key->round[i-1].v8[15]];
+ }
+
+ expanded_key->round[i].v32[0] ^= expanded_key->round[i-2].v32[0];
+
+ /* set remaining 32 bit words to the exor of the one previous with
+ * the one eight words previous */
+
+ expanded_key->round[i].v32[1] =
+ expanded_key->round[i].v32[0] ^ expanded_key->round[i-2].v32[1];
+
+ expanded_key->round[i].v32[2] =
+ expanded_key->round[i].v32[1] ^ expanded_key->round[i-2].v32[2];
+
+ expanded_key->round[i].v32[3] =
+ expanded_key->round[i].v32[2] ^ expanded_key->round[i-2].v32[3];
+
+#if 0
+ debug_print2(mod_aes_icm,
+ "expanded key[%d]: %s", i,v128_hex_string(&expanded_key->round[i]));
+#endif
+
+ }
+}
+
err_status_t
aes_expand_encryption_key(const uint8_t *key,
int key_len,
@@ -1418,6 +1481,14 @@
aes_128_expand_encryption_key(key, expanded_key);
return err_status_ok;
}
+ else if (key_len == 24) {
+ /* AES-192 not yet supported */
+ return err_status_bad_param;
+ }
+ else if (key_len == 32) {
+ aes_256_expand_encryption_key(key, expanded_key);
+ return err_status_ok;
+ }
else
return err_status_bad_param;
}
@@ -1428,16 +1499,17 @@
aes_expanded_key_t *expanded_key) {
int i;
err_status_t status;
+ int num_rounds = expanded_key->num_rounds;
status = aes_expand_encryption_key(key, key_len, expanded_key);
if (status)
return status;
/* invert the order of the round keys */
- for (i=0; i < 5; i++) {
+ for (i=0; i < num_rounds/2; i++) {
v128_t tmp;
- v128_copy(&tmp, &expanded_key->round[10-i]);
- v128_copy(&expanded_key->round[10-i], &expanded_key->round[i]);
+ v128_copy(&tmp, &expanded_key->round[num_rounds-i]);
+ v128_copy(&expanded_key->round[num_rounds-i], &expanded_key->round[i]);
v128_copy(&expanded_key->round[i], &tmp);
}
@@ -1449,7 +1521,7 @@
* followed by the T4 table (which cancels out the use of the sbox
* in the U-tables)
*/
- for (i=1; i < 10; i++) {
+ for (i=1; i < num_rounds; i++) {
#ifdef CPU_RISC
uint32_t tmp;
@@ -1932,7 +2004,7 @@
/* add in the subkey */
v128_xor_eq(plaintext, &exp_key->round[0]);
- /* now do nine rounds */
+ /* now do the rounds */
aes_round(plaintext, &exp_key->round[1]);
aes_round(plaintext, &exp_key->round[2]);
aes_round(plaintext, &exp_key->round[3]);
@@ -1942,9 +2014,21 @@
aes_round(plaintext, &exp_key->round[7]);
aes_round(plaintext, &exp_key->round[8]);
aes_round(plaintext, &exp_key->round[9]);
- /* the last round is different */
-
- aes_final_round(plaintext, &exp_key->round[10]);
+ if (exp_key->num_rounds == 10) {
+ aes_final_round(plaintext, &exp_key->round[10]);
+ }
+ else if (exp_key->num_rounds == 12) {
+ aes_round(plaintext, &exp_key->round[10]);
+ aes_round(plaintext, &exp_key->round[11]);
+ aes_final_round(plaintext, &exp_key->round[12]);
+ }
+ else if (exp_key->num_rounds == 14) {
+ aes_round(plaintext, &exp_key->round[10]);
+ aes_round(plaintext, &exp_key->round[11]);
+ aes_round(plaintext, &exp_key->round[12]);
+ aes_round(plaintext, &exp_key->round[13]);
+ aes_final_round(plaintext, &exp_key->round[14]);
+ }
}
void
@@ -1953,7 +2037,7 @@
/* add in the subkey */
v128_xor_eq(plaintext, &exp_key->round[0]);
- /* now do nine rounds */
+ /* now do the rounds */
aes_inv_round(plaintext, &exp_key->round[1]);
aes_inv_round(plaintext, &exp_key->round[2]);
aes_inv_round(plaintext, &exp_key->round[3]);
@@ -1963,6 +2047,19 @@
aes_inv_round(plaintext, &exp_key->round[7]);
aes_inv_round(plaintext, &exp_key->round[8]);
aes_inv_round(plaintext, &exp_key->round[9]);
- /* the last round is different */
- aes_inv_final_round(plaintext, &exp_key->round[10]);
+ if (exp_key->num_rounds == 10) {
+ aes_inv_final_round(plaintext, &exp_key->round[10]);
+ }
+ else if (exp_key->num_rounds == 12) {
+ aes_inv_round(plaintext, &exp_key->round[10]);
+ aes_inv_round(plaintext, &exp_key->round[11]);
+ aes_inv_final_round(plaintext, &exp_key->round[12]);
+ }
+ else if (exp_key->num_rounds == 14) {
+ aes_inv_round(plaintext, &exp_key->round[10]);
+ aes_inv_round(plaintext, &exp_key->round[11]);
+ aes_inv_round(plaintext, &exp_key->round[12]);
+ aes_inv_round(plaintext, &exp_key->round[13]);
+ aes_inv_final_round(plaintext, &exp_key->round[14]);
+ }
}
diff --git a/crypto/cipher/aes_cbc.c b/crypto/cipher/aes_cbc.c
index 1887292..0ffbb06 100644
--- a/crypto/cipher/aes_cbc.c
+++ b/crypto/cipher/aes_cbc.c
@@ -63,7 +63,7 @@
debug_print(mod_aes_cbc,
"allocating cipher with key length %d", key_len);
- if (key_len != 16)
+ if (key_len != 16 && key_len != 24 && key_len != 32)
return err_status_bad_param;
/* allocate memory a cipher of type aes_cbc */
@@ -429,6 +429,100 @@
&aes_cbc_test_case_0 /* pointer to next testcase */
};
+/*
+ * Test case 2 is like test case 0, but for 256-bit keys. (FIPS 197
+ * appendix C.3).
+ */
+
+
+uint8_t aes_cbc_test_case_2_key[32] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+};
+
+uint8_t aes_cbc_test_case_2_plaintext[64] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+};
+
+uint8_t aes_cbc_test_case_2_ciphertext[80] = {
+ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
+ 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89,
+ 0x72, 0x72, 0x6e, 0xe7, 0x71, 0x39, 0xbf, 0x11,
+ 0xe5, 0x40, 0xe2, 0x7c, 0x54, 0x65, 0x1d, 0xee
+};
+
+uint8_t aes_cbc_test_case_2_iv[16] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+cipher_test_case_t aes_cbc_test_case_2 = {
+ 32, /* octets in key */
+ aes_cbc_test_case_2_key, /* key */
+ aes_cbc_test_case_2_iv, /* initialization vector */
+ 16, /* octets in plaintext */
+ aes_cbc_test_case_2_plaintext, /* plaintext */
+ 32, /* octets in ciphertext */
+ aes_cbc_test_case_2_ciphertext, /* ciphertext */
+ &aes_cbc_test_case_1 /* pointer to next testcase */
+};
+
+
+/*
+ * this test case is taken directly from Appendix F.2 of NIST Special
+ * Publication SP 800-38A
+ */
+
+uint8_t aes_cbc_test_case_3_key[32] = {
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
+ 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
+ 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
+};
+
+uint8_t aes_cbc_test_case_3_plaintext[64] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+};
+
+uint8_t aes_cbc_test_case_3_ciphertext[80] = {
+ 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
+ 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+ 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
+ 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+ 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
+ 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+ 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
+ 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
+ 0xfb, 0x98, 0x20, 0x2c, 0x45, 0xb2, 0xe4, 0xa0,
+ 0x63, 0xc4, 0x68, 0xba, 0x84, 0x39, 0x16, 0x5a
+};
+
+uint8_t aes_cbc_test_case_3_iv[16] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+};
+
+cipher_test_case_t aes_cbc_test_case_3 = {
+ 32, /* octets in key */
+ aes_cbc_test_case_3_key, /* key */
+ aes_cbc_test_case_3_iv, /* initialization vector */
+ 64, /* octets in plaintext */
+ aes_cbc_test_case_3_plaintext, /* plaintext */
+ 80, /* octets in ciphertext */
+ aes_cbc_test_case_3_ciphertext, /* ciphertext */
+ &aes_cbc_test_case_2 /* pointer to next testcase */
+};
+
cipher_type_t aes_cbc = {
(cipher_alloc_func_t) aes_cbc_alloc,
(cipher_dealloc_func_t) aes_cbc_dealloc,
@@ -438,7 +532,7 @@
(cipher_set_iv_func_t) aes_cbc_set_iv,
(char *) aes_cbc_description,
(int) 0, /* instance count */
- (cipher_test_case_t *) &aes_cbc_test_case_1,
+ (cipher_test_case_t *) &aes_cbc_test_case_3,
(debug_module_t *) &mod_aes_cbc
};
diff --git a/crypto/cipher/aes_icm.c b/crypto/cipher/aes_icm.c
index 5460ff4..1532c7e 100644
--- a/crypto/cipher/aes_icm.c
+++ b/crypto/cipher/aes_icm.c
@@ -101,12 +101,13 @@
/*
* Ismacryp, for example, uses 16 byte key + 8 byte
* salt so this function is called with key_len = 24.
- * The check for key_len = 30 does not apply. Our usage
+ * The check for key_len = 30/38/46 does not apply. Our usage
* of aes functions with key_len = values other than 30
* has not broken anything. Don't know what would be the
* effect of skipping this check for srtp in general.
*/
- if (!forIsmacryp && key_len != 30)
+ if (!(forIsmacryp && key_len > 16 && key_len < 30) &&
+ key_len != 30 && key_len != 38 && key_len != 46)
return err_status_bad_param;
/* allocate memory a cipher of type aes_icm */
@@ -164,24 +165,31 @@
err_status_t
aes_icm_context_init(aes_icm_ctx_t *c, const uint8_t *key, int key_len) {
err_status_t status;
+ int base_key_len;
+
+ if (key_len > 16 && key_len < 30) /* Ismacryp */
+ base_key_len = 16;
+ else if (key_len == 30 || key_len == 38 || key_len == 46)
+ base_key_len = key_len - 14;
+ else
+ return err_status_bad_param;
+
/* set counter and initial values to 'offset' value */
- /* FIX!!! this assumes the salt is at key + 16, and thus that the */
- /* FIX!!! cipher key length is 16! Also note this copies past the
- end of the 'key' array by 2 bytes! */
- v128_copy_octet_string(&c->counter, key + 16);
- v128_copy_octet_string(&c->offset, key + 16);
+ /* Note this copies past the end of the 'key' array by 2 bytes! */
+ v128_copy_octet_string(&c->counter, key + base_key_len);
+ v128_copy_octet_string(&c->offset, key + base_key_len);
/* force last two octets of the offset to zero (for srtp compatibility) */
c->offset.v8[14] = c->offset.v8[15] = 0;
c->counter.v8[14] = c->counter.v8[15] = 0;
debug_print(mod_aes_icm,
- "key: %s", octet_string_hex_string(key, 16));
+ "key: %s", octet_string_hex_string(key, base_key_len));
debug_print(mod_aes_icm,
"offset: %s", v128_hex_string(&c->offset));
/* expand key */
- status = aes_expand_encryption_key(key, 16, &c->expanded_key);
+ status = aes_expand_encryption_key(key, base_key_len, &c->expanded_key);
if (status) {
v128_set_to_zero(&c->counter);
v128_set_to_zero(&c->offset);
@@ -492,6 +500,46 @@
NULL /* pointer to next testcase */
};
+uint8_t aes_icm_test_case_1_key[46] = {
+ 0x57, 0xf8, 0x2f, 0xe3, 0x61, 0x3f, 0xd1, 0x70,
+ 0xa8, 0x5e, 0xc9, 0x3c, 0x40, 0xb1, 0xf0, 0x92,
+ 0x2e, 0xc4, 0xcb, 0x0d, 0xc0, 0x25, 0xb5, 0x82,
+ 0x72, 0x14, 0x7c, 0xc4, 0x38, 0x94, 0x4a, 0x98,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd
+};
+
+uint8_t aes_icm_test_case_1_nonce[16] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+uint8_t aes_icm_test_case_1_plaintext[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+uint8_t aes_icm_test_case_1_ciphertext[32] = {
+ 0x92, 0xbd, 0xd2, 0x8a, 0x93, 0xc3, 0xf5, 0x25,
+ 0x11, 0xc6, 0x77, 0xd0, 0x8b, 0x55, 0x15, 0xa4,
+ 0x9d, 0xa7, 0x1b, 0x23, 0x78, 0xa8, 0x54, 0xf6,
+ 0x70, 0x50, 0x75, 0x6d, 0xed, 0x16, 0x5b, 0xac
+};
+
+cipher_test_case_t aes_icm_test_case_1 = {
+ 46, /* octets in key */
+ aes_icm_test_case_1_key, /* key */
+ aes_icm_test_case_1_nonce, /* packet index */
+ 32, /* octets in plaintext */
+ aes_icm_test_case_1_plaintext, /* plaintext */
+ 32, /* octets in ciphertext */
+ aes_icm_test_case_1_ciphertext, /* ciphertext */
+ &aes_icm_test_case_0 /* pointer to next testcase */
+};
+
+
/*
* note: the encrypt function is identical to the decrypt function
@@ -506,7 +554,7 @@
(cipher_set_iv_func_t) aes_icm_set_iv,
(char *) aes_icm_description,
(int) 0, /* instance count */
- (cipher_test_case_t *) &aes_icm_test_case_0,
+ (cipher_test_case_t *) &aes_icm_test_case_1,
(debug_module_t *) &mod_aes_icm
};
diff --git a/crypto/kernel/crypto_kernel.c b/crypto/kernel/crypto_kernel.c
index 230dda6..6dfd766 100644
--- a/crypto/kernel/crypto_kernel.c
+++ b/crypto/kernel/crypto_kernel.c
@@ -151,10 +151,10 @@
status = crypto_kernel_load_cipher_type(&null_cipher, NULL_CIPHER);
if (status)
return status;
- status = crypto_kernel_load_cipher_type(&aes_icm, AES_128_ICM);
+ status = crypto_kernel_load_cipher_type(&aes_icm, AES_ICM);
if (status)
return status;
- status = crypto_kernel_load_cipher_type(&aes_cbc, AES_128_CBC);
+ status = crypto_kernel_load_cipher_type(&aes_cbc, AES_CBC);
if (status)
return status;
diff --git a/crypto/test/aes_calc.c b/crypto/test/aes_calc.c
index 0ff242a..fe3c6ad 100644
--- a/crypto/test/aes_calc.c
+++ b/crypto/test/aes_calc.c
@@ -28,14 +28,14 @@
exit(255);
}
-#define AES_KEY_LEN 16
+#define AES_MAX_KEY_LEN 32
int
main (int argc, char *argv[]) {
v128_t data;
- uint8_t key[AES_KEY_LEN];
+ uint8_t key[AES_MAX_KEY_LEN];
aes_expanded_key_t exp_key;
- int len;
+ int key_len, len;
int verbose;
err_status_t status;
@@ -56,22 +56,23 @@
}
/* read in key, checking length */
- if (strlen(argv[1]) > AES_KEY_LEN*2) {
+ if (strlen(argv[1]) > AES_MAX_KEY_LEN*2) {
fprintf(stderr,
"error: too many digits in key "
- "(should be %d hexadecimal digits, found %u)\n",
- AES_KEY_LEN*2, (unsigned)strlen(argv[1]));
+ "(should be at most %d hexadecimal digits, found %u)\n",
+ AES_MAX_KEY_LEN*2, (unsigned)strlen(argv[1]));
exit(1);
}
- len = hex_string_to_octet_string((char*)key, argv[1], AES_KEY_LEN*2);
+ len = hex_string_to_octet_string((char*)key, argv[1], AES_MAX_KEY_LEN*2);
/* check that hex string is the right length */
- if (len < AES_KEY_LEN*2) {
+ if (len != 32 && len != 48 && len != 64) {
fprintf(stderr,
- "error: too few digits in key "
- "(should be %d hexadecimal digits, found %d)\n",
- AES_KEY_LEN*2, len);
+ "error: bad number of digits in key "
+ "(should be 32/48/64 hexadecimal digits, found %d)\n",
+ len);
exit(1);
}
+ key_len = len/2;
/* read in plaintext, checking length */
if (strlen(argv[2]) > 16*2) {
@@ -97,7 +98,7 @@
}
/* encrypt plaintext */
- status = aes_expand_encryption_key(key, 16, &exp_key);
+ status = aes_expand_encryption_key(key, key_len, &exp_key);
if (status) {
fprintf(stderr,
"error: AES key expansion failed.\n");
@@ -108,7 +109,7 @@
/* write ciphertext to output */
if (verbose) {
- printf("key:\t\t%s\n", octet_string_hex_string(key, 16));
+ printf("key:\t\t%s\n", octet_string_hex_string(key, key_len));
printf("ciphertext:\t");
}
printf("%s\n", v128_hex_string(&data));
diff --git a/crypto/test/cipher_driver.c b/crypto/test/cipher_driver.c
index 2fac6c1..ea41ff5 100644
--- a/crypto/test/cipher_driver.c
+++ b/crypto/test/cipher_driver.c
@@ -120,10 +120,13 @@
main(int argc, char *argv[]) {
cipher_t *c = NULL;
err_status_t status;
- unsigned char test_key[20] = {
+ unsigned char test_key[48] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
};
int q;
unsigned do_timing_test = 0;
@@ -169,8 +172,13 @@
cipher_driver_test_array_throughput(&aes_icm, 30, num_cipher);
for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
+ cipher_driver_test_array_throughput(&aes_icm, 46, num_cipher);
+
+ for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
cipher_driver_test_array_throughput(&aes_cbc, 16, num_cipher);
+ for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8)
+ cipher_driver_test_array_throughput(&aes_cbc, 32, num_cipher);
}
if (do_validation) {
@@ -196,7 +204,7 @@
check_status(status);
- /* run the throughput test on the aes_icm cipher */
+ /* run the throughput test on the aes_icm cipher (128-bit key) */
status = cipher_type_alloc(&aes_icm, &c, 30);
if (status) {
fprintf(stderr, "error: can't allocate cipher\n");
@@ -216,6 +224,27 @@
status = cipher_dealloc(c);
check_status(status);
+
+ /* repeat the tests with 256-bit keys */
+ status = cipher_type_alloc(&aes_icm, &c, 46);
+ if (status) {
+ fprintf(stderr, "error: can't allocate cipher\n");
+ exit(status);
+ }
+
+ status = cipher_init(c, test_key, direction_encrypt);
+ check_status(status);
+
+ if (do_timing_test)
+ cipher_driver_test_throughput(c);
+
+ if (do_validation) {
+ status = cipher_driver_test_buffering(c);
+ check_status(status);
+ }
+
+ status = cipher_dealloc(c);
+ check_status(status);
return 0;
}
@@ -227,7 +256,7 @@
int max_enc_len = 2048; /* should be a power of two */
int num_trials = 1000000;
- printf("timing %s throughput:\n", c->type->description);
+ printf("timing %s throughput, key length %d:\n", c->type->description, c->key_len);
fflush(stdout);
for (i=min_enc_len; i <= max_enc_len; i = i * 2)
printf("msg len: %d\tgigabits per second: %f\n",
@@ -472,8 +501,8 @@
int max_enc_len = 2048; /* should be a power of two */
int num_trials = 1000000;
- printf("timing %s throughput with array size %d:\n",
- (ca[0])->type->description, num_cipher);
+ printf("timing %s throughput with key length %d, array size %d:\n",
+ (ca[0])->type->description, (ca[0])->key_len, num_cipher);
fflush(stdout);
for (i=min_enc_len; i <= max_enc_len; i = i * 4)
printf("msg len: %d\tgigabits per second: %f\n", i,
diff --git a/crypto/test/stat_driver.c b/crypto/test/stat_driver.c
index 306c495..f9d75b7 100644
--- a/crypto/test/stat_driver.c
+++ b/crypto/test/stat_driver.c
@@ -37,7 +37,9 @@
int i, j;
extern cipher_type_t aes_icm;
cipher_t *c;
- uint8_t key[30] = {
+ uint8_t key[46] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -99,5 +101,39 @@
err_check(cipher_dealloc(c));
+ printf("running stat_tests on AES-256-ICM, expecting success\n");
+ /* set buffer to cipher output */
+ for (i=0; i < 2500; i++)
+ buffer[i] = 0;
+ err_check(cipher_type_alloc(&aes_icm, &c, 46));
+ err_check(cipher_init(c, key, direction_encrypt));
+ err_check(cipher_set_iv(c, &nonce));
+ err_check(cipher_encrypt(c, buffer, &buf_len));
+ /* run tests on cipher outout */
+ printf("monobit %d\n", stat_test_monobit(buffer));
+ printf("poker %d\n", stat_test_poker(buffer));
+ printf("runs %d\n", stat_test_runs(buffer));
+
+ printf("runs test (please be patient): ");
+ fflush(stdout);
+ num_fail = 0;
+ v128_set_to_zero(&nonce);
+ for(j=0; j < num_trials; j++) {
+ for (i=0; i < 2500; i++)
+ buffer[i] = 0;
+ nonce.v32[3] = i;
+ err_check(cipher_set_iv(c, &nonce));
+ err_check(cipher_encrypt(c, buffer, &buf_len));
+ if (stat_test_runs(buffer)) {
+ num_fail++;
+ }
+ }
+
+ printf("%d failures in %d tests\n", num_fail, num_trials);
+ printf("(nota bene: a small fraction of stat_test failures does not \n"
+ "indicate that the random source is invalid)\n");
+
+ err_check(cipher_dealloc(c));
+
return 0;
}
diff --git a/include/srtp.h b/include/srtp.h
index cf7d6c9..3813956 100644
--- a/include/srtp.h
+++ b/include/srtp.h
@@ -599,6 +599,70 @@
void
crypto_policy_set_null_cipher_hmac_sha1_80(crypto_policy_t *p);
+
+/**
+ * @brief crypto_policy_set_aes_cm_256_hmac_sha1_80() sets a crypto
+ * policy structure to a encryption and authentication policy using AES-256
+ * for RTP protection.
+ *
+ * @param p is a pointer to the policy structure to be set
+ *
+ * The function call crypto_policy_set_aes_cm_256_hmac_sha1_80(&p)
+ * sets the crypto_policy_t at location p to use policy
+ * AES_CM_256_HMAC_SHA1_80 as defined in
+ * draft-ietf-avt-srtp-big-aes-03.txt. This policy uses AES-256
+ * Counter Mode encryption and HMAC-SHA1 authentication, with an 80 bit
+ * authentication tag.
+ *
+ * This function is a convenience that helps to avoid dealing directly
+ * with the policy data structure. You are encouraged to initialize
+ * policy elements with this function call. Doing so may allow your
+ * code to be forward compatible with later versions of libSRTP that
+ * include more elements in the crypto_policy_t datatype.
+ *
+ * @return void.
+ *
+ */
+
+void crypto_policy_set_aes_cm_256_hmac_sha1_80(crypto_policy_t *p);
+
+
+/**
+ * @brief crypto_policy_set_aes_cm_256_hmac_sha1_32() sets a crypto
+ * policy structure to a short-authentication tag policy using AES-256
+ * encryption.
+ *
+ * @param p is a pointer to the policy structure to be set
+ *
+ * The function call crypto_policy_set_aes_cm_256_hmac_sha1_32(&p)
+ * sets the crypto_policy_t at location p to use policy
+ * AES_CM_256_HMAC_SHA1_32 as defined in
+ * draft-ietf-avt-srtp-big-aes-03.txt. This policy uses AES-256
+ * Counter Mode encryption and HMAC-SHA1 authentication, with an
+ * authentication tag that is only 32 bits long. This length is
+ * considered adequate only for protecting audio and video media that
+ * use a stateless playback function. See Section 7.5 of RFC 3711
+ * (http://www.ietf.org/rfc/rfc3711.txt).
+ *
+ * This function is a convenience that helps to avoid dealing directly
+ * with the policy data structure. You are encouraged to initialize
+ * policy elements with this function call. Doing so may allow your
+ * code to be forward compatible with later versions of libSRTP that
+ * include more elements in the crypto_policy_t datatype.
+ *
+ * @warning This crypto policy is intended for use in SRTP, but not in
+ * SRTCP. It is recommended that a policy that uses longer
+ * authentication tags be used for SRTCP. See Section 7.5 of RFC 3711
+ * (http://www.ietf.org/rfc/rfc3711.txt).
+ *
+ * @return void.
+ *
+ */
+
+void
+crypto_policy_set_aes_cm_256_hmac_sha1_32(crypto_policy_t *p);
+
+
/**
* @brief srtp_dealloc() deallocates storage for an SRTP session
* context.
diff --git a/srtp/srtp.c b/srtp/srtp.c
index fee38a6..d81a1f5 100644
--- a/srtp/srtp.c
+++ b/srtp/srtp.c
@@ -398,36 +398,76 @@
#define MAX_SRTP_KEY_LEN 256
+/* Get the base key length corresponding to a given combined key+salt
+ * length for the given cipher.
+ * Assumption is that for AES-ICM a key length < 30 is Ismacryp using
+ * AES-128 and short salts; everything else uses a salt length of 14.
+ * TODO: key and salt lengths should be separate fields in the policy. */
+inline int base_key_length(const cipher_type_t *cipher, int key_length)
+{
+ if (cipher != &aes_icm)
+ return key_length;
+ else if (key_length > 16 && key_length < 30)
+ return 16;
+ return key_length - 14;
+}
+
err_status_t
srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) {
err_status_t stat;
srtp_kdf_t kdf;
uint8_t tmp_key[MAX_SRTP_KEY_LEN];
-
+ int kdf_keylen = 30, rtp_keylen, rtcp_keylen;
+ int rtp_base_key_len, rtp_salt_len;
+ int rtcp_base_key_len, rtcp_salt_len;
+
+ /* If RTP or RTCP have a key length > AES-128, assume matching kdf. */
+ /* TODO: kdf algorithm, master key length, and master salt length should
+ * be part of srtp_policy_t. */
+ rtp_keylen = cipher_get_key_length(srtp->rtp_cipher);
+ if (rtp_keylen > kdf_keylen)
+ kdf_keylen = rtp_keylen;
+
+ rtcp_keylen = cipher_get_key_length(srtp->rtcp_cipher);
+ if (rtcp_keylen > kdf_keylen)
+ kdf_keylen = rtcp_keylen;
+
/* initialize KDF state */
- srtp_kdf_init(&kdf, AES_128_ICM, (const uint8_t *)key, 30);
+ stat = srtp_kdf_init(&kdf, AES_ICM, (const uint8_t *)key, kdf_keylen);
+ if (stat) {
+ return err_status_init_fail;
+ }
+
+ rtp_base_key_len = base_key_length(srtp->rtp_cipher->type, rtp_keylen);
+ rtp_salt_len = rtp_keylen - rtp_base_key_len;
/* generate encryption key */
- srtp_kdf_generate(&kdf, label_rtp_encryption,
- tmp_key, cipher_get_key_length(srtp->rtp_cipher));
+ stat = srtp_kdf_generate(&kdf, label_rtp_encryption,
+ tmp_key, rtp_base_key_len);
+ if (stat) {
+ /* zeroize temp buffer */
+ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ return err_status_init_fail;
+ }
+
/*
- * if the cipher in the srtp context is aes_icm, then we need
+ * if the cipher in the srtp context uses a salt, then we need
* to generate the salt value
*/
- if (srtp->rtp_cipher->type == &aes_icm) {
- /* FIX!!! this is really the cipher key length; rest is salt */
- int base_key_len = 16;
- int salt_len = cipher_get_key_length(srtp->rtp_cipher) - base_key_len;
-
- debug_print(mod_srtp, "found aes_icm, generating salt", NULL);
+ if (rtp_salt_len > 0) {
+ debug_print(mod_srtp, "found rtp_salt_len > 0, generating salt", NULL);
/* generate encryption salt, put after encryption key */
- srtp_kdf_generate(&kdf, label_rtp_salt,
- tmp_key + base_key_len, salt_len);
+ stat = srtp_kdf_generate(&kdf, label_rtp_salt,
+ tmp_key + rtp_base_key_len, rtp_salt_len);
+ if (stat) {
+ /* zeroize temp buffer */
+ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ return err_status_init_fail;
+ }
}
debug_print(mod_srtp, "cipher key: %s",
- octet_string_hex_string(tmp_key,
- cipher_get_key_length(srtp->rtp_cipher)));
+ octet_string_hex_string(tmp_key, rtp_keylen));
/* initialize cipher */
stat = cipher_init(srtp->rtp_cipher, tmp_key, direction_any);
@@ -438,8 +478,13 @@
}
/* generate authentication key */
- srtp_kdf_generate(&kdf, label_rtp_msg_auth,
- tmp_key, auth_get_key_length(srtp->rtp_auth));
+ stat = srtp_kdf_generate(&kdf, label_rtp_msg_auth,
+ tmp_key, auth_get_key_length(srtp->rtp_auth));
+ if (stat) {
+ /* zeroize temp buffer */
+ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ return err_status_init_fail;
+ }
debug_print(mod_srtp, "auth key: %s",
octet_string_hex_string(tmp_key,
auth_get_key_length(srtp->rtp_auth)));
@@ -456,27 +501,37 @@
* ...now initialize SRTCP keys
*/
+ rtcp_base_key_len = base_key_length(srtp->rtcp_cipher->type, rtcp_keylen);
+ rtcp_salt_len = rtcp_keylen - rtcp_base_key_len;
+
/* generate encryption key */
- srtp_kdf_generate(&kdf, label_rtcp_encryption,
- tmp_key, cipher_get_key_length(srtp->rtcp_cipher));
+ stat = srtp_kdf_generate(&kdf, label_rtcp_encryption,
+ tmp_key, rtcp_base_key_len);
+ if (stat) {
+ /* zeroize temp buffer */
+ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ return err_status_init_fail;
+ }
+
/*
- * if the cipher in the srtp context is aes_icm, then we need
+ * if the cipher in the srtp context uses a salt, then we need
* to generate the salt value
*/
- if (srtp->rtcp_cipher->type == &aes_icm) {
- /* FIX!!! this is really the cipher key length; rest is salt */
- int base_key_len = 16;
- int salt_len = cipher_get_key_length(srtp->rtcp_cipher) - base_key_len;
-
- debug_print(mod_srtp, "found aes_icm, generating rtcp salt", NULL);
+ if (rtcp_salt_len > 0) {
+ debug_print(mod_srtp, "found rtcp_salt_len > 0, generating rtcp salt",
+ NULL);
/* generate encryption salt, put after encryption key */
- srtp_kdf_generate(&kdf, label_rtcp_salt,
- tmp_key + base_key_len, salt_len);
+ stat = srtp_kdf_generate(&kdf, label_rtcp_salt,
+ tmp_key + rtcp_base_key_len, rtcp_salt_len);
+ if (stat) {
+ /* zeroize temp buffer */
+ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ return err_status_init_fail;
+ }
}
debug_print(mod_srtp, "rtcp cipher key: %s",
- octet_string_hex_string(tmp_key,
- cipher_get_key_length(srtp->rtcp_cipher)));
+ octet_string_hex_string(tmp_key, rtcp_keylen));
/* initialize cipher */
stat = cipher_init(srtp->rtcp_cipher, tmp_key, direction_any);
@@ -487,8 +542,14 @@
}
/* generate authentication key */
- srtp_kdf_generate(&kdf, label_rtcp_msg_auth,
- tmp_key, auth_get_key_length(srtp->rtcp_auth));
+ stat = srtp_kdf_generate(&kdf, label_rtcp_msg_auth,
+ tmp_key, auth_get_key_length(srtp->rtcp_auth));
+ if (stat) {
+ /* zeroize temp buffer */
+ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ return err_status_init_fail;
+ }
+
debug_print(mod_srtp, "rtcp auth key: %s",
octet_string_hex_string(tmp_key,
auth_get_key_length(srtp->rtcp_auth)));
@@ -502,8 +563,10 @@
}
/* clear memory then return */
- srtp_kdf_clear(&kdf);
+ stat = srtp_kdf_clear(&kdf);
octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+ if (stat)
+ return err_status_init_fail;
return err_status_ok;
}
@@ -1433,7 +1496,7 @@
void
crypto_policy_set_rtp_default(crypto_policy_t *p) {
- p->cipher_type = AES_128_ICM;
+ p->cipher_type = AES_ICM;
p->cipher_key_len = 30; /* default 128 bits per RFC 3711 */
p->auth_type = HMAC_SHA1;
p->auth_key_len = 20; /* default 160 bits per RFC 3711 */
@@ -1445,7 +1508,7 @@
void
crypto_policy_set_rtcp_default(crypto_policy_t *p) {
- p->cipher_type = AES_128_ICM;
+ p->cipher_type = AES_ICM;
p->cipher_key_len = 30; /* default 128 bits per RFC 3711 */
p->auth_type = HMAC_SHA1;
p->auth_key_len = 20; /* default 160 bits per RFC 3711 */
@@ -1463,7 +1526,7 @@
* note that this crypto policy is intended for SRTP, but not SRTCP
*/
- p->cipher_type = AES_128_ICM;
+ p->cipher_type = AES_ICM;
p->cipher_key_len = 30; /* 128 bit key, 112 bit salt */
p->auth_type = HMAC_SHA1;
p->auth_key_len = 20; /* 160 bit key */
@@ -1482,7 +1545,7 @@
* note that this crypto policy is intended for SRTP, but not SRTCP
*/
- p->cipher_type = AES_128_ICM;
+ p->cipher_type = AES_ICM;
p->cipher_key_len = 30; /* 128 bit key, 112 bit salt */
p->auth_type = NULL_AUTH;
p->auth_key_len = 0;
@@ -1509,6 +1572,40 @@
}
+void
+crypto_policy_set_aes_cm_256_hmac_sha1_80(crypto_policy_t *p) {
+
+ /*
+ * corresponds to draft-ietf-avt-big-aes-03.txt
+ */
+
+ p->cipher_type = AES_ICM;
+ p->cipher_key_len = 46;
+ p->auth_type = HMAC_SHA1;
+ p->auth_key_len = 20; /* default 160 bits per RFC 3711 */
+ p->auth_tag_len = 10; /* default 80 bits per RFC 3711 */
+ p->sec_serv = sec_serv_conf_and_auth;
+}
+
+
+void
+crypto_policy_set_aes_cm_256_hmac_sha1_32(crypto_policy_t *p) {
+
+ /*
+ * corresponds to draft-ietf-avt-big-aes-03.txt
+ *
+ * note that this crypto policy is intended for SRTP, but not SRTCP
+ */
+
+ p->cipher_type = AES_ICM;
+ p->cipher_key_len = 46;
+ p->auth_type = HMAC_SHA1;
+ p->auth_key_len = 20; /* default 160 bits per RFC 3711 */
+ p->auth_tag_len = 4; /* default 80 bits per RFC 3711 */
+ p->sec_serv = sec_serv_conf_and_auth;
+}
+
+
/*
* secure rtcp functions
*/
@@ -1958,10 +2055,16 @@
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
break;
+ case srtp_profile_aes256_cm_sha1_80:
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+ break;
+ case srtp_profile_aes256_cm_sha1_32:
+ crypto_policy_set_aes_cm_256_hmac_sha1_32(policy);
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+ break;
/* the following profiles are not (yet) supported */
case srtp_profile_null_sha1_32:
- case srtp_profile_aes256_cm_sha1_80:
- case srtp_profile_aes256_cm_sha1_32:
default:
return err_status_bad_param;
}
@@ -1984,10 +2087,14 @@
case srtp_profile_null_sha1_80:
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
break;
+ case srtp_profile_aes256_cm_sha1_80:
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+ break;
+ case srtp_profile_aes256_cm_sha1_32:
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+ break;
/* the following profiles are not (yet) supported */
case srtp_profile_null_sha1_32:
- case srtp_profile_aes256_cm_sha1_80:
- case srtp_profile_aes256_cm_sha1_32:
default:
return err_status_bad_param;
}
@@ -2016,10 +2123,14 @@
case srtp_profile_null_sha1_80:
return 16;
break;
+ case srtp_profile_aes256_cm_sha1_80:
+ return 32;
+ break;
+ case srtp_profile_aes256_cm_sha1_32:
+ return 32;
+ break;
/* the following profiles are not (yet) supported */
case srtp_profile_null_sha1_32:
- case srtp_profile_aes256_cm_sha1_80:
- case srtp_profile_aes256_cm_sha1_32:
default:
return 0; /* indicate error by returning a zero */
}
@@ -2038,10 +2149,14 @@
case srtp_profile_null_sha1_80:
return 14;
break;
+ case srtp_profile_aes256_cm_sha1_80:
+ return 14;
+ break;
+ case srtp_profile_aes256_cm_sha1_32:
+ return 14;
+ break;
/* the following profiles are not (yet) supported */
case srtp_profile_null_sha1_32:
- case srtp_profile_aes256_cm_sha1_80:
- case srtp_profile_aes256_cm_sha1_32:
default:
return 0; /* indicate error by returning a zero */
}
diff --git a/test/srtp_driver.c b/test/srtp_driver.c
index d4c2afd..51b33f5 100644
--- a/test/srtp_driver.c
+++ b/test/srtp_driver.c
@@ -63,6 +63,9 @@
srtp_validate(void);
err_status_t
+srtp_validate_aes_256(void);
+
+err_status_t
srtp_create_big_policy(srtp_policy_t **list);
err_status_t
@@ -286,6 +289,19 @@
}
/*
+ * run validation test against the reference packets for
+ * AES-256
+ */
+ printf("testing srtp_protect and srtp_unprotect against "
+ "reference packets (AES-256)\n");
+ if (srtp_validate_aes_256() == err_status_ok)
+ printf("passed\n\n");
+ else {
+ printf("failed\n");
+ exit(1);
+ }
+
+ /*
* test the function srtp_remove_stream()
*/
printf("testing srtp_remove_stream()...");
@@ -1276,6 +1292,114 @@
}
+/*
+ * srtp_validate_aes_256() verifies the correctness of libsrtp by comparing
+ * some computed packets against some pre-computed reference values.
+ * These packets were made with the AES-CM-256/HMAC-SHA-1-80 policy.
+ */
+
+
+err_status_t
+srtp_validate_aes_256() {
+ unsigned char test_key[46] = {
+ 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
+ 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
+ 0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
+ 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
+
+ 0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
+ 0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
+ };
+ uint8_t srtp_plaintext_ref[28] = {
+ 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
+ 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab
+ };
+ uint8_t srtp_plaintext[38] = {
+ 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
+ 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+ 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ uint8_t srtp_ciphertext[38] = {
+ 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
+ 0xca, 0xfe, 0xba, 0xbe, 0xf1, 0xd9, 0xde, 0x17,
+ 0xff, 0x25, 0x1f, 0xf1, 0xaa, 0x00, 0x77, 0x74,
+ 0xb0, 0xb4, 0xb4, 0x0d, 0xa0, 0x8d, 0x9d, 0x9a,
+ 0x5b, 0x3a, 0x55, 0xd8, 0x87, 0x3b
+ };
+ srtp_t srtp_snd, srtp_recv;
+ err_status_t status;
+ int len;
+ srtp_policy_t policy;
+
+ /*
+ * create a session with a single stream using the default srtp
+ * policy and with the SSRC value 0xcafebabe
+ */
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp);
+ crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtcp);
+ policy.ssrc.type = ssrc_specific;
+ policy.ssrc.value = 0xcafebabe;
+ policy.key = test_key;
+ policy.ekt = NULL;
+ policy.window_size = 128;
+ policy.allow_repeat_tx = 0;
+ policy.next = NULL;
+
+ status = srtp_create(&srtp_snd, &policy);
+ if (status)
+ return status;
+
+ /*
+ * protect plaintext, then compare with ciphertext
+ */
+ len = 28;
+ status = srtp_protect(srtp_snd, srtp_plaintext, &len);
+ if (status || (len != 38))
+ return err_status_fail;
+
+ debug_print(mod_driver, "ciphertext:\n %s",
+ octet_string_hex_string(srtp_plaintext, len));
+ debug_print(mod_driver, "ciphertext reference:\n %s",
+ octet_string_hex_string(srtp_ciphertext, len));
+
+ if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
+ return err_status_fail;
+
+ /*
+ * create a receiver session context comparable to the one created
+ * above - we need to do this so that the replay checking doesn't
+ * complain
+ */
+ status = srtp_create(&srtp_recv, &policy);
+ if (status)
+ return status;
+
+ /*
+ * unprotect ciphertext, then compare with plaintext
+ */
+ status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
+ if (status || (len != 28))
+ return status;
+
+ if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
+ return err_status_fail;
+
+ status = srtp_dealloc(srtp_snd);
+ if (status)
+ return status;
+
+ status = srtp_dealloc(srtp_recv);
+ if (status)
+ return status;
+
+ return err_status_ok;
+}
+
+
err_status_t
srtp_create_big_policy(srtp_policy_t **list) {
extern const srtp_policy_t *policy_array[];
@@ -1538,6 +1662,41 @@
NULL
};
+unsigned char test_256_key[46] = {
+ 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
+ 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
+ 0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
+ 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
+
+ 0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
+ 0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
+};
+
+const srtp_policy_t aes_256_hmac_policy = {
+ { ssrc_any_outbound, 0 }, /* SSRC */
+ { /* SRTP policy */
+ AES_ICM, /* cipher type */
+ 46, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 20, /* auth key length in octets */
+ 10, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ { /* SRTCP policy */
+ AES_ICM, /* cipher type */
+ 46, /* cipher key length in octets */
+ HMAC_SHA1, /* authentication func type */
+ 20, /* auth key length in octets */
+ 10, /* auth tag length in octets */
+ sec_serv_conf_and_auth /* security services flag */
+ },
+ test_256_key,
+ NULL, /* indicates that EKT is not in use */
+ 128, /* replay window size */
+ 0, /* retransmission not allowed */
+ NULL
+};
+
uint8_t ekt_test_key[16] = {
0x77, 0x26, 0x9d, 0xac, 0x16, 0xa3, 0x28, 0xca,
0x8e, 0xc9, 0x68, 0x4b, 0xcc, 0xc4, 0xd2, 0x1b
@@ -1602,6 +1761,7 @@
#endif
&default_policy,
&null_policy,
+ &aes_256_hmac_policy,
&hmac_only_with_ekt_policy,
NULL
};