diff --git a/libs/srtp/Makefile.am b/libs/srtp/Makefile.am index fb27e6c6d8..6b84d81ae2 100644 --- a/libs/srtp/Makefile.am +++ b/libs/srtp/Makefile.am @@ -5,28 +5,37 @@ AM_CFLAGS = $(new_AM_CFLAGS) -I./src -Icrypto/include -I$(srcdir)/include -I$ AM_CPPFLAGS = $(AM_CFLAGS) AM_LDFLAGS = $(new_AM_LDFLAGS) -L. +HMAC_OBJS = @HMAC_OBJS@ +RNG_EXTRA_OBJS = @RNG_EXTRA_OBJS@ +AES_ICM_OBJS = @AES_ICM_OBJS@ lib_LTLIBRARIES = libsrtp.la libcryptomath.la libsrtp_la_SOURCES = srtp/srtp.c srtp/ekt.c crypto/cipher/cipher.c crypto/cipher/null_cipher.c \ - crypto/cipher/aes.c crypto/cipher/aes_icm.c \ - crypto/cipher/aes_cbc.c \ - crypto/hash/null_auth.c crypto/hash/sha1.c \ - crypto/hash/hmac.c crypto/hash/auth.c \ + crypto/hash/null_auth.c crypto/hash/auth.c \ crypto/math/datatypes.c crypto/math/stat.c \ crypto/kernel/crypto_kernel.c crypto/kernel/alloc.c \ crypto/kernel/key.c \ crypto/rng/prng.c crypto/rng/ctr_prng.c \ crypto/kernel/err.c \ - crypto/replay/rdb.c crypto/replay/rdbx.c crypto/replay/ut_sim.c + crypto/replay/rdb.c crypto/replay/rdbx.c crypto/replay/ut_sim.c + libsrtp_la_LDFLAGS = -version-info 1:42:1 EXTRA_DIST= + +if ENABLE_OPENSSL +libsrtp_la_SOURCES += crypto/cipher/aes_icm_ossl.c crypto/cipher/aes_gcm_ossl.c +libsrtp_la_SOURCES += crypto/rng/rand_source_ossl.c +else +libsrtp_la_SOURCES += crypto/hash/sha1.c crypto/hash/hmac.c +libsrtp_la_SOURCES += crypto/cipher/aes_icm.c crypto/cipher/aes.c crypto/cipher/aes_cbc.c if RNG_OBJS_LINUX libsrtp_la_SOURCES += crypto/rng/rand_linux_kernel.c EXTRA_DIST += crypto/rng/rand_source.c else libsrtp_la_SOURCES += crypto/rng/rand_source.c endif +endif if GDOI libsrtp_la_SOURCES += gdoi/srtp+gdoi.c diff --git a/libs/srtp/README b/libs/srtp/README index 7364f7dc85..8ea9f72d08 100644 --- a/libs/srtp/README +++ b/libs/srtp/README @@ -26,9 +26,10 @@ The configure script accepts the following options: --enable-syslog use syslog for error reporting --disable-stdout use stdout for error reporting --enable-console use /dev/console for error reporting + --enable-openssl use OpenSSL crypto primitives --gdoi use GDOI key management (disabled at present) -By default, debugging is enabled and stdout is used for debugging. +By default, debbuging is enabled and stdout is used for debugging. You can use the above configure options to have the debugging output sent to syslog or the system console. Alternatively, you can define ERR_REPORTING_FILE in include/conf.h to be any other file that can be @@ -77,7 +78,7 @@ Applications Manual srtp keying uses the -k option; automated key management using gdoi will be added later. -usage: rtpw [-d ]* [-k [-a][-e]] [-s | -r] dest_ip dest_port +usage: rtpw [-d ]* [-k [-a][-e ][-g]] [-s | -r] dest_ip dest_port or rtpw -l Either the -s (sender) or -r (receiver) option must be chosen. @@ -86,25 +87,15 @@ or rtpw -l which the dictionary will be sent, respectively. options: - - -s (s)rtp sender - causes app to send words - - -r (s)rtp receive - causes app to receive words - - -k use srtp master key , where the - key is a hexadecimal value (without the - leading "0x") - - -e encrypt/decrypt (for data confidentiality) - (requires use of -k option as well) - - -a message authentication - (requires use of -k option as well) - - -l list debug modules - - -d turn on debugging for module - + -a use message authentication + -e use encryption (use 128, 192, or 256 for key size) + -g Use AES-GCM mode (must be used with -e) + -k sets the srtp master key + -s act as rtp sender + -r act as rtp receiver + -l list debug modules + -d turn on debugging for module + -i specify input/output file In order to get random 30-byte values for use as key/salt pairs , you can use the following bash function to format the output of @@ -119,7 +110,7 @@ An example of an SRTP session using two rtpw programs follows: set k=c1eec3717da76195bb878578790af71c4ee9f859e197a414a78d5abc7451 -[sh1]$ test/rtpw -s -k $k -ea 0.0.0.0 9999 +[sh1]$ test/rtpw -s -k $k -e 128 -a 0.0.0.0 9999 Security services: confidentiality message authentication set master key/salt to C1EEC3717DA76195BB878578790AF71C/4EE9F859E197A414A78D5ABC7451 setting SSRC to 2078917053 @@ -129,7 +120,7 @@ sending word: aa sending word: aal ... -[sh2]$ test/rtpw -r -k $k -ea 0.0.0.0 9999 +[sh2]$ test/rtpw -r -k $k -e 128 -a 0.0.0.0 9999 security services: confidentiality message authentication set master key/salt to C1EEC3717DA76195BB878578790AF71C/4EE9F859E197A414A78D5ABC7451 19 octets received from SSRC 2078917053 word: A diff --git a/libs/srtp/configure.gnu b/libs/srtp/configure.gnu index c78238de46..d561908e68 100644 --- a/libs/srtp/configure.gnu +++ b/libs/srtp/configure.gnu @@ -1,4 +1,4 @@ #! /bin/sh srcpath=$(dirname $0 2>/dev/null ) || srcpath="." -$srcpath/configure "$@" --disable-shared --with-pic +$srcpath/configure "$@" --disable-shared --with-pic --enable-openssl diff --git a/libs/srtp/configure.in b/libs/srtp/configure.in index 93b28afdd4..58506cbc1b 100644 --- a/libs/srtp/configure.in +++ b/libs/srtp/configure.in @@ -143,22 +143,6 @@ if test "$cross_compiling" != yes; then [AC_CHECK_FILE(/dev/random, DEV_URANDOM=/dev/random)]) fi -AC_MSG_CHECKING(which random device to use) -if test "$enable_kernel_linux" = "yes"; then - RNG_OBJS=rand_linux_kernel.o - AC_MSG_RESULT([Linux kernel builtin]) -else -RNG_OBJS=rand_source.o - if test -n "$DEV_URANDOM"; then - AC_DEFINE_UNQUOTED(DEV_URANDOM, "$DEV_URANDOM",[Path to random device]) - AC_MSG_RESULT([$DEV_URANDOM]) - else - AC_MSG_RESULT([standard rand() function...]) - fi -fi -AC_SUBST(RNG_OBJS) -AM_CONDITIONAL(RNG_OBJS_LINUX, test x$enable_kernel_linux = xyes) - dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(stdlib.h) @@ -273,6 +257,56 @@ if test "$enable_generic_aesicm" = "yes"; then fi AC_MSG_RESULT($enable_generic_aesicm) +AC_MSG_CHECKING(whether to leverage OpenSSL crypto) +AC_ARG_ENABLE(openssl, + [AS_HELP_STRING([--enable-openssl], + [compile in OpenSSL crypto engine])], + [], enable_openssl=no) +if test "$enable_openssl" = "yes"; then + echo $enable_openssl + LDFLAGS="$LDFLAGS $(pkg-config --libs openssl)"; + CFLAGS="$CFLAGS $(pkg-config --cflags openssl)"; + + AC_CHECK_LIB([crypto], [EVP_EncryptInit], [], + [AC_MSG_FAILURE([can't find openssl >1.0.1 crypto lib])]) + AC_CHECK_LIB([crypto], [EVP_aes_128_ctr], [], + [AC_MSG_FAILURE([can't find openssl >1.0.1 crypto lib])]) + AC_CHECK_LIB([crypto], [EVP_aes_128_gcm], [], + [AC_MSG_FAILURE([can't find openssl >1.0.1 crypto lib])]) + AC_DEFINE(OPENSSL, 1, [Define this to use OpenSSL crypto.]) + AES_ICM_OBJS="crypto/cipher/aes_icm_ossl.o crypto/cipher/aes_gcm_ossl.o" + RNG_OBJS=rand_source_ossl.o + HMAC_OBJS=crypto/hash/hmac_ossl.o + USE_OPENSSL=1 + AC_SUBST(USE_OPENSSL) +else + echo $enable_openssl + AES_ICM_OBJS="crypto/cipher/aes_icm.o crypto/cipher/aes.o crypto/cipher/aes_cbc.o" + AC_MSG_CHECKING(which random device to use) + if test "$enable_kernel_linux" = "yes"; then + RNG_OBJS=rand_linux_kernel.o + AC_MSG_RESULT([Linux kernel builtin]) + else + RNG_OBJS=rand_source.o + if test -n "$DEV_URANDOM"; then + AC_DEFINE_UNQUOTED(DEV_URANDOM, "$DEV_URANDOM",[Path to random device]) + AC_MSG_RESULT([$DEV_URANDOM]) + else + AC_MSG_RESULT([standard rand() function...]) + fi + fi + RNG_EXTRA_OBJS="crypto/rng/prng.o crypto/rng/ctr_prng.o" + HMAC_OBJS="crypto/hash/hmac.o crypto/hash/sha1.o" +fi +AM_CONDITIONAL([ENABLE_OPENSSL],[test "${enable_openssl}" = "yes"]) +AM_CONDITIONAL([RNG_OBJS_LINUX], test x$enable_kernel_linux = xyes) + +AC_SUBST(AES_ICM_OBJS) +AC_SUBST(RNG_OBJS) +AC_SUBST(RNG_EXTRA_OBJS) +AC_SUBST(HMAC_OBJS) +AC_MSG_RESULT($enable_openssl) + AC_MSG_CHECKING(whether to use syslog for error reporting) AC_ARG_ENABLE(syslog, [AS_HELP_STRING([--enable-syslog], [use syslog for error reporting])], diff --git a/libs/srtp/crypto/Makefile.in b/libs/srtp/crypto/Makefile.in index 9d52104210..c6248fcf63 100644 --- a/libs/srtp/crypto/Makefile.in +++ b/libs/srtp/crypto/Makefile.in @@ -9,14 +9,14 @@ top_builddir = @top_builddir@ VPATH = @srcdir@ CC = @CC@ -INCDIR = -Iinclude -I$(srcdir)/include +INCDIR = -Iinclude -I$(srcdir)/include DEFS = @DEFS@ CPPFLAGS= @CPPFLAGS@ CFLAGS = @CFLAGS@ LIBS = @LIBS@ -LDFLAGS = @LDFLAGS@ -L. +LDFLAGS = @LDFLAGS@ -L. -L.. COMPILE = $(CC) $(DEFS) $(INCDIR) $(CPPFLAGS) $(CFLAGS) -CRYPTOLIB = -lcryptomodule +CRYPTOLIB = -lsrtp RANLIB = @RANLIB@ @@ -25,7 +25,7 @@ RANLIB = @RANLIB@ # `make clean` will work on the cygwin platform EXE = @EXE@ # Random source. -RNG_OBJS = @RNG_OBJS@ +USE_OPENSSL = @USE_OPENSSL@ ifdef ARCH DEFS += -D$(ARCH)=1 @@ -41,9 +41,13 @@ dummy : all runtest # test applications +ifneq (1, $(USE_OPENSSL)) +AES_CALC = test/aes_calc$(EXE) +endif + testapp = #test/cipher_driver$(EXE) test/datatypes_driver$(EXE) \ #test/stat_driver$(EXE) test/sha1_driver$(EXE) \ - #test/kernel_driver$(EXE) test/aes_calc$(EXE) test/rand_gen$(EXE) \ + #test/kernel_driver$(EXE) $(AES_CALC) test/rand_gen$(EXE) \ #test/env$(EXE) # data values used to test the aes_calc application for AES-128 @@ -58,60 +62,31 @@ p256=00112233445566778899aabbccddeeff c256=8ea2b7ca516745bfeafc49904b496089 -runtest: libcryptomodule.a $(testapp) +runtest: $(testapp) test/env$(EXE) # print out information on the build environment - @echo "running libcryptomodule test applications..." + @echo "running crypto test applications..." +ifneq (1, $(USE_OPENSSL)) test `test/aes_calc $(k128) $(p128)` = $(c128) test `test/aes_calc $(k256) $(p256)` = $(c256) +endif test/cipher_driver$(EXE) -v >/dev/null test/datatypes_driver$(EXE) -v >/dev/null test/stat_driver$(EXE) >/dev/null test/sha1_driver$(EXE) -v >/dev/null test/kernel_driver$(EXE) -v >/dev/null test/rand_gen$(EXE) -n 256 >/dev/null - @echo "libcryptomodule test applications passed." + @echo "crypto test applications passed." -# libcryptomodule.a (the crypto engine) - -ciphers = cipher/cipher.o cipher/null_cipher.o \ - cipher/aes.o cipher/aes_icm.o \ - cipher/aes_cbc.o - -hashes = hash/null_auth.o hash/sha1.o \ - hash/hmac.o hash/auth.o - -math = math/datatypes.o math/stat.o - -rng = rng/$(RNG_OBJS) rng/rand_source.o rng/prng.o rng/ctr_prng.o - -err = kernel/err.o - -kernel = kernel/crypto_kernel.o kernel/alloc.o \ - kernel/key.o $(rng) $(err) - -xfm = ae_xfm/xfm.o - -cryptobj = $(ciphers) $(hashes) $(math) $(stat) $(kernel) $(xfm) # the rule for making object files and test apps %.o: %.c $(COMPILE) -c $< -o $@ -%$(EXE): %.c libcryptomodule.a +%$(EXE): %.c $(COMPILE) $(LDFLAGS) $< -o $@ $(CRYPTOLIB) $(LIBS) -ifndef AR - AR=ar -endif - -# and the crypto module library itself - -libcryptomodule.a: $(cryptobj) - $(AR) cr libcryptomodule.a $(cryptobj) - $(RANLIB) libcryptomodule.a - -all: libcryptomodule.a $(testapp) +all: $(testapp) # housekeeping functions diff --git a/libs/srtp/crypto/cipher/aes_cbc.c b/libs/srtp/crypto/cipher/aes_cbc.c index ed33f5b01c..fad74a411e 100644 --- a/libs/srtp/crypto/cipher/aes_cbc.c +++ b/libs/srtp/crypto/cipher/aes_cbc.c @@ -104,36 +104,25 @@ aes_cbc_dealloc(cipher_t *c) { } err_status_t -aes_cbc_context_init(aes_cbc_ctx_t *c, const uint8_t *key, int key_len, - cipher_direction_t dir) { - err_status_t status; +aes_cbc_context_init(aes_cbc_ctx_t *c, const uint8_t *key, int key_len) { debug_print(mod_aes_cbc, "key: %s", octet_string_hex_string(key, key_len)); - /* expand key for the appropriate direction */ - switch (dir) { - case (direction_encrypt): - status = aes_expand_encryption_key(key, key_len, &c->expanded_key); - if (status) - return status; - break; - case (direction_decrypt): - status = aes_expand_decryption_key(key, key_len, &c->expanded_key); - if (status) - return status; - break; - default: - return err_status_bad_param; - } - + /* + * Save the key until we have the IV later. We don't + * know the direction until the IV is set. + */ + c->key_len = (key_len <= 32 ? key_len : 32); + memcpy(c->key, key, c->key_len); return err_status_ok; } err_status_t -aes_cbc_set_iv(aes_cbc_ctx_t *c, void *iv) { +aes_cbc_set_iv(aes_cbc_ctx_t *c, void *iv, int direction) { + err_status_t status; int i; /* v128_t *input = iv; */ uint8_t *input = (uint8_t*) iv; @@ -144,6 +133,24 @@ aes_cbc_set_iv(aes_cbc_ctx_t *c, void *iv) { debug_print(mod_aes_cbc, "setting iv: %s", v128_hex_string(&c->state)); + /* expand key for the appropriate direction */ + switch (direction) { + case (direction_encrypt): + status = aes_expand_encryption_key(c->key, c->key_len, &c->expanded_key); + memset(c->key, 0, 32); + if (status) + return status; + break; + case (direction_decrypt): + status = aes_expand_decryption_key(c->key, c->key_len, &c->expanded_key); + memset(c->key, 0, 32); + if (status) + return status; + break; + default: + return err_status_bad_param; + } + return err_status_ok; } @@ -375,6 +382,8 @@ cipher_test_case_t aes_cbc_test_case_0 = { aes_cbc_test_case_0_plaintext, /* plaintext */ 32, /* octets in ciphertext */ aes_cbc_test_case_0_ciphertext, /* ciphertext */ + 0, + NULL, NULL /* pointer to next testcase */ }; @@ -426,6 +435,8 @@ cipher_test_case_t aes_cbc_test_case_1 = { aes_cbc_test_case_1_plaintext, /* plaintext */ 80, /* octets in ciphertext */ aes_cbc_test_case_1_ciphertext, /* ciphertext */ + 0, + NULL, &aes_cbc_test_case_0 /* pointer to next testcase */ }; @@ -467,6 +478,8 @@ cipher_test_case_t aes_cbc_test_case_2 = { aes_cbc_test_case_2_plaintext, /* plaintext */ 32, /* octets in ciphertext */ aes_cbc_test_case_2_ciphertext, /* ciphertext */ + 0, + NULL, &aes_cbc_test_case_1 /* pointer to next testcase */ }; @@ -520,6 +533,8 @@ cipher_test_case_t aes_cbc_test_case_3 = { aes_cbc_test_case_3_plaintext, /* plaintext */ 80, /* octets in ciphertext */ aes_cbc_test_case_3_ciphertext, /* ciphertext */ + 0, + NULL, &aes_cbc_test_case_2 /* pointer to next testcase */ }; @@ -527,9 +542,11 @@ cipher_type_t aes_cbc = { (cipher_alloc_func_t) aes_cbc_alloc, (cipher_dealloc_func_t) aes_cbc_dealloc, (cipher_init_func_t) aes_cbc_context_init, + (cipher_set_aad_func_t) 0, (cipher_encrypt_func_t) aes_cbc_nist_encrypt, (cipher_decrypt_func_t) aes_cbc_nist_decrypt, (cipher_set_iv_func_t) aes_cbc_set_iv, + (cipher_get_tag_func_t) 0, (char *) aes_cbc_description, (int) 0, /* instance count */ (cipher_test_case_t *) &aes_cbc_test_case_3, diff --git a/libs/srtp/crypto/cipher/aes_gcm_ossl.c b/libs/srtp/crypto/cipher/aes_gcm_ossl.c new file mode 100644 index 0000000000..f36ce9d3b2 --- /dev/null +++ b/libs/srtp/crypto/cipher/aes_gcm_ossl.c @@ -0,0 +1,529 @@ +/* + * aes_gcm_ossl.c + * + * AES Galois Counter Mode + * + * John A. Foley + * Cisco Systems, Inc. + * + */ + +/* + * + * Copyright (c) 2013, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include "aes_icm_ossl.h" +#include "aes_gcm_ossl.h" +#include "alloc.h" +#include "crypto_types.h" + + +debug_module_t mod_aes_gcm = { + 0, /* debugging is off by default */ + "aes gcm" /* printable module name */ +}; + +/* + * The following are the global singleton instances for the + * 128-bit and 256-bit GCM ciphers. + */ +extern cipher_type_t aes_gcm_128_openssl; +extern cipher_type_t aes_gcm_256_openssl; + +/* + * For now we only support 8 octet tags. The spec allows for + * optional 12 and 16 byte tags. These longer tag lengths may + * be implemented in the future. + */ +#define GCM_AUTH_TAG_LEN 8 + + +/* + * This function allocates a new instance of this crypto engine. + * The key_len parameter should be one of 30 or 46 for + * AES-128-GCM or AES-256-GCM respectively. Note that the + * key length includes the 14 byte salt value that is used when + * initializing the KDF. + */ +err_status_t aes_gcm_openssl_alloc (cipher_t **c, int key_len) +{ + aes_gcm_ctx_t *gcm; + int tmp; + uint8_t *allptr; + + debug_print(mod_aes_gcm, "allocating cipher with key length %d", key_len); + + /* + * Verify the key_len is valid for one of: AES-128/256 + */ + if (key_len != AES_128_KEYSIZE_WSALT && + key_len != AES_256_KEYSIZE_WSALT) { + return (err_status_bad_param); + } + + /* allocate memory a cipher of type aes_gcm */ + tmp = sizeof(cipher_t) + sizeof(aes_gcm_ctx_t); + allptr = crypto_alloc(tmp); + if (allptr == NULL) { + return (err_status_alloc_fail); + } + + /* set pointers */ + *c = (cipher_t*)allptr; + (*c)->state = allptr + sizeof(cipher_t); + gcm = (aes_gcm_ctx_t *)(*c)->state; + + /* increment ref_count */ + switch (key_len) { + case AES_128_KEYSIZE_WSALT: + (*c)->type = &aes_gcm_128_openssl; + (*c)->algorithm = AES_128_GCM; + aes_gcm_128_openssl.ref_count++; + ((aes_gcm_ctx_t*)(*c)->state)->key_size = AES_128_KEYSIZE; + ((aes_gcm_ctx_t*)(*c)->state)->tag_len = GCM_AUTH_TAG_LEN; + break; + case AES_256_KEYSIZE_WSALT: + (*c)->type = &aes_gcm_256_openssl; + (*c)->algorithm = AES_256_GCM; + aes_gcm_256_openssl.ref_count++; + ((aes_gcm_ctx_t*)(*c)->state)->key_size = AES_256_KEYSIZE; + ((aes_gcm_ctx_t*)(*c)->state)->tag_len = GCM_AUTH_TAG_LEN; + break; + } + + /* set key size */ + (*c)->key_len = key_len; + EVP_CIPHER_CTX_init(&gcm->ctx); + + return (err_status_ok); +} + + +/* + * This function deallocates a GCM session + */ +err_status_t aes_gcm_openssl_dealloc (cipher_t *c) +{ + aes_gcm_ctx_t *ctx; + + ctx = (aes_gcm_ctx_t*)c->state; + if (ctx) { + EVP_CIPHER_CTX_cleanup(&ctx->ctx); + /* decrement ref_count for the appropriate engine */ + switch (ctx->key_size) { + case AES_256_KEYSIZE: + aes_gcm_256_openssl.ref_count--; + break; + case AES_128_KEYSIZE: + aes_gcm_128_openssl.ref_count--; + break; + default: + return (err_status_dealloc_fail); + break; + } + } + + /* zeroize entire state*/ + octet_string_set_to_zero((uint8_t*)c, sizeof(cipher_t) + sizeof(aes_gcm_ctx_t)); + + /* free memory */ + crypto_free(c); + + return (err_status_ok); +} + +/* + * aes_gcm_openssl_context_init(...) initializes the aes_gcm_context + * using the value in key[]. + * + * the key is the secret key + */ +err_status_t aes_gcm_openssl_context_init (aes_gcm_ctx_t *c, const uint8_t *key) +{ + c->dir = direction_any; + + /* copy key to be used later when CiscoSSL crypto context is created */ + v128_copy_octet_string((v128_t*)&c->key, key); + + if (c->key_size == AES_256_KEYSIZE) { + debug_print(mod_aes_gcm, "Copying last 16 bytes of key: %s", + v128_hex_string((v128_t*)(key + AES_128_KEYSIZE))); + v128_copy_octet_string(((v128_t*)(&c->key.v8)) + 1, + key + AES_128_KEYSIZE); + } + + debug_print(mod_aes_gcm, "key: %s", v128_hex_string((v128_t*)&c->key)); + + EVP_CIPHER_CTX_cleanup(&c->ctx); + + return (err_status_ok); +} + + +/* + * aes_gcm_openssl_set_iv(c, iv) sets the counter value to the exor of iv with + * the offset + */ +err_status_t aes_gcm_openssl_set_iv (aes_gcm_ctx_t *c, void *iv, + int direction) +{ + const EVP_CIPHER *evp; + v128_t *nonce = iv; + + if (direction != direction_encrypt && direction != direction_decrypt) { + return (err_status_bad_param); + } + c->dir = direction; + + debug_print(mod_aes_gcm, "setting iv: %s", v128_hex_string(nonce)); + + switch (c->key_size) { + case AES_256_KEYSIZE: + evp = EVP_aes_256_gcm(); + break; + case AES_128_KEYSIZE: + evp = EVP_aes_128_gcm(); + break; + default: + return (err_status_bad_param); + break; + } + + if (!EVP_CipherInit_ex(&c->ctx, evp, NULL, (const unsigned char*)&c->key.v8, + NULL, (c->dir == direction_encrypt ? 1 : 0))) { + return (err_status_init_fail); + } + + /* set IV len and the IV value, the followiong 3 calls are required */ + if (!EVP_CIPHER_CTX_ctrl(&c->ctx, EVP_CTRL_GCM_SET_IVLEN, 12, 0)) { + return (err_status_init_fail); + } + if (!EVP_CIPHER_CTX_ctrl(&c->ctx, EVP_CTRL_GCM_SET_IV_FIXED, -1, iv)) { + return (err_status_init_fail); + } + if (!EVP_CIPHER_CTX_ctrl(&c->ctx, EVP_CTRL_GCM_IV_GEN, 0, iv)) { + return (err_status_init_fail); + } + + return (err_status_ok); +} + +/* + * This function processes the AAD + * + * Parameters: + * c Crypto context + * aad Additional data to process for AEAD cipher suites + * aad_len length of aad buffer + */ +err_status_t aes_gcm_openssl_set_aad (aes_gcm_ctx_t *c, unsigned char *aad, + unsigned int aad_len) +{ + int rv; + + /* + * Set dummy tag, OpenSSL requires the Tag to be set before + * processing AAD + */ + EVP_CIPHER_CTX_ctrl(&c->ctx, EVP_CTRL_GCM_SET_TAG, c->tag_len, aad); + + rv = EVP_Cipher(&c->ctx, NULL, aad, aad_len); + if (rv != aad_len) { + return (err_status_algo_fail); + } else { + return (err_status_ok); + } +} + +/* + * This function encrypts a buffer using AES GCM mode + * + * Parameters: + * c Crypto context + * buf data to encrypt + * enc_len length of encrypt buffer + */ +err_status_t aes_gcm_openssl_encrypt (aes_gcm_ctx_t *c, unsigned char *buf, + unsigned int *enc_len) +{ + if (c->dir != direction_encrypt && c->dir != direction_decrypt) { + return (err_status_bad_param); + } + + /* + * Encrypt the data + */ + EVP_Cipher(&c->ctx, buf, buf, *enc_len); + + return (err_status_ok); +} + +/* + * This function calculates and returns the GCM tag for a given context. + * This should be called after encrypting the data. The *len value + * is increased by the tag size. The caller must ensure that *buf has + * enough room to accept the appended tag. + * + * Parameters: + * c Crypto context + * buf data to encrypt + * len length of encrypt buffer + */ +err_status_t aes_gcm_openssl_get_tag (aes_gcm_ctx_t *c, unsigned char *buf, + int *len) +{ + /* + * Calculate the tag + */ + EVP_Cipher(&c->ctx, NULL, NULL, 0); + + /* + * Retreive the tag + */ + EVP_CIPHER_CTX_ctrl(&c->ctx, EVP_CTRL_GCM_GET_TAG, c->tag_len, buf); + + /* + * Increase encryption length by desired tag size + */ + *len = c->tag_len; + + return (err_status_ok); +} + + +/* + * This function decrypts a buffer using AES GCM mode + * + * Parameters: + * c Crypto context + * buf data to encrypt + * enc_len length of encrypt buffer + */ +err_status_t aes_gcm_openssl_decrypt (aes_gcm_ctx_t *c, unsigned char *buf, + unsigned int *enc_len) +{ + if (c->dir != direction_encrypt && c->dir != direction_decrypt) { + return (err_status_bad_param); + } + + /* + * Set the tag before decrypting + */ + EVP_CIPHER_CTX_ctrl(&c->ctx, EVP_CTRL_GCM_SET_TAG, c->tag_len, + buf + (*enc_len - c->tag_len)); + EVP_Cipher(&c->ctx, buf, buf, *enc_len - c->tag_len); + + /* + * Check the tag + */ + if (EVP_Cipher(&c->ctx, NULL, NULL, 0)) { + return (err_status_auth_fail); + } + + /* + * Reduce the buffer size by the tag length since the tag + * is not part of the original payload + */ + *enc_len -= c->tag_len; + + return (err_status_ok); +} + + + +/* + * Name of this crypto engine + */ +char aes_gcm_128_openssl_description[] = "AES-128 GCM using openssl"; +char aes_gcm_256_openssl_description[] = "AES-256 GCM using openssl"; + + +/* + * KAT values for AES self-test. These + * values we're derived from independent test code + * using OpenSSL. + */ +uint8_t aes_gcm_test_case_0_key[AES_128_KEYSIZE_WSALT] = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, +}; + +uint8_t aes_gcm_test_case_0_iv[12] = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 +}; + +uint8_t aes_gcm_test_case_0_plaintext[60] = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 +}; + +uint8_t aes_gcm_test_case_0_aad[20] = { + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 +}; + +uint8_t aes_gcm_test_case_0_ciphertext[68] = { + 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, + /* the last 8 bytes are the tag */ + 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, +}; + +cipher_test_case_t aes_gcm_test_case_0 = { + AES_128_KEYSIZE_WSALT, /* octets in key */ + aes_gcm_test_case_0_key, /* key */ + aes_gcm_test_case_0_iv, /* packet index */ + 60, /* octets in plaintext */ + aes_gcm_test_case_0_plaintext, /* plaintext */ + 68, /* octets in ciphertext */ + aes_gcm_test_case_0_ciphertext, /* ciphertext + tag */ + 20, /* octets in AAD */ + aes_gcm_test_case_0_aad, /* AAD */ + NULL /* pointer to next testcase */ +}; + +uint8_t aes_gcm_test_case_1_key[AES_256_KEYSIZE_WSALT] = { + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0xa5, 0x59, 0x09, 0xc5, 0x54, 0x66, 0x93, 0x1c, + 0xaf, 0xf5, 0x26, 0x9a, 0x21, 0xd5, 0x14, 0xb2, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + +}; + +uint8_t aes_gcm_test_case_1_iv[12] = { + 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 +}; + +uint8_t aes_gcm_test_case_1_plaintext[60] = { + 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39 +}; + +uint8_t aes_gcm_test_case_1_aad[20] = { + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 +}; + +uint8_t aes_gcm_test_case_1_ciphertext[68] = { + 0x0b, 0x11, 0xcf, 0xaf, 0x68, 0x4d, 0xae, 0x46, + 0xc7, 0x90, 0xb8, 0x8e, 0xb7, 0x6a, 0x76, 0x2a, + 0x94, 0x82, 0xca, 0xab, 0x3e, 0x39, 0xd7, 0x86, + 0x1b, 0xc7, 0x93, 0xed, 0x75, 0x7f, 0x23, 0x5a, + 0xda, 0xfd, 0xd3, 0xe2, 0x0e, 0x80, 0x87, 0xa9, + 0x6d, 0xd7, 0xe2, 0x6a, 0x7d, 0x5f, 0xb4, 0x80, + 0xef, 0xef, 0xc5, 0x29, 0x12, 0xd1, 0xaa, 0x10, + 0x09, 0xc9, 0x86, 0xc1, + /* the last 8 bytes are the tag */ + 0x45, 0xbc, 0x03, 0xe6, 0xe1, 0xac, 0x0a, 0x9f, +}; + +cipher_test_case_t aes_gcm_test_case_1 = { + AES_256_KEYSIZE_WSALT, /* octets in key */ + aes_gcm_test_case_1_key, /* key */ + aes_gcm_test_case_1_iv, /* packet index */ + 60, /* octets in plaintext */ + aes_gcm_test_case_1_plaintext, /* plaintext */ + 68, /* octets in ciphertext */ + aes_gcm_test_case_1_ciphertext, /* ciphertext + tag */ + 20, /* octets in AAD */ + aes_gcm_test_case_1_aad, /* AAD */ + NULL /* pointer to next testcase */ +}; + +/* + * This is the vector function table for this crypto engine. + */ +cipher_type_t aes_gcm_128_openssl = { + (cipher_alloc_func_t) aes_gcm_openssl_alloc, + (cipher_dealloc_func_t) aes_gcm_openssl_dealloc, + (cipher_init_func_t) aes_gcm_openssl_context_init, + (cipher_set_aad_func_t) aes_gcm_openssl_set_aad, + (cipher_encrypt_func_t) aes_gcm_openssl_encrypt, + (cipher_decrypt_func_t) aes_gcm_openssl_decrypt, + (cipher_set_iv_func_t) aes_gcm_openssl_set_iv, + (cipher_get_tag_func_t) aes_gcm_openssl_get_tag, + (char*) aes_gcm_128_openssl_description, + (int) 0, /* instance count */ + (cipher_test_case_t*) &aes_gcm_test_case_0, + (debug_module_t*) &mod_aes_gcm, + (cipher_type_id_t) AES_128_GCM +}; + +/* + * This is the vector function table for this crypto engine. + */ +cipher_type_t aes_gcm_256_openssl = { + (cipher_alloc_func_t) aes_gcm_openssl_alloc, + (cipher_dealloc_func_t) aes_gcm_openssl_dealloc, + (cipher_init_func_t) aes_gcm_openssl_context_init, + (cipher_set_aad_func_t) aes_gcm_openssl_set_aad, + (cipher_encrypt_func_t) aes_gcm_openssl_encrypt, + (cipher_decrypt_func_t) aes_gcm_openssl_decrypt, + (cipher_set_iv_func_t) aes_gcm_openssl_set_iv, + (cipher_get_tag_func_t) aes_gcm_openssl_get_tag, + (char*) aes_gcm_256_openssl_description, + (int) 0, /* instance count */ + (cipher_test_case_t*) &aes_gcm_test_case_1, + (debug_module_t*) &mod_aes_gcm, + (cipher_type_id_t) AES_256_GCM +}; + diff --git a/libs/srtp/crypto/cipher/aes_icm.c b/libs/srtp/crypto/cipher/aes_icm.c index e38038269e..7a8e56f850 100644 --- a/libs/srtp/crypto/cipher/aes_icm.c +++ b/libs/srtp/crypto/cipher/aes_icm.c @@ -9,7 +9,7 @@ /* * - * Copyright (c) 2001-2006, Cisco Systems, Inc. + * Copyright (c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -272,7 +272,7 @@ aes_icm_set_octet(aes_icm_ctx_t *c, */ err_status_t -aes_icm_set_iv(aes_icm_ctx_t *c, void *iv) { +aes_icm_set_iv(aes_icm_ctx_t *c, void *iv, int direction) { v128_t *nonce = (v128_t *) iv; debug_print(mod_aes_icm, @@ -503,6 +503,8 @@ cipher_test_case_t aes_icm_test_case_0 = { aes_icm_test_case_0_plaintext, /* plaintext */ 32, /* octets in ciphertext */ aes_icm_test_case_0_ciphertext, /* ciphertext */ + 0, + NULL, NULL /* pointer to next testcase */ }; @@ -542,6 +544,8 @@ cipher_test_case_t aes_icm_test_case_1 = { aes_icm_test_case_1_plaintext, /* plaintext */ 32, /* octets in ciphertext */ aes_icm_test_case_1_ciphertext, /* ciphertext */ + 0, + NULL, &aes_icm_test_case_0 /* pointer to next testcase */ }; @@ -555,9 +559,11 @@ cipher_type_t aes_icm = { (cipher_alloc_func_t) aes_icm_alloc, (cipher_dealloc_func_t) aes_icm_dealloc, (cipher_init_func_t) aes_icm_context_init, + (cipher_set_aad_func_t) 0, (cipher_encrypt_func_t) aes_icm_encrypt, (cipher_decrypt_func_t) aes_icm_encrypt, (cipher_set_iv_func_t) aes_icm_set_iv, + (cipher_get_tag_func_t) 0, (char *) aes_icm_description, (int) 0, /* instance count */ (cipher_test_case_t *) &aes_icm_test_case_1, diff --git a/libs/srtp/crypto/cipher/aes_icm_ossl.c b/libs/srtp/crypto/cipher/aes_icm_ossl.c new file mode 100644 index 0000000000..2d9d4e068b --- /dev/null +++ b/libs/srtp/crypto/cipher/aes_icm_ossl.c @@ -0,0 +1,537 @@ +/* + * aes_icm_ossl.c + * + * AES Integer Counter Mode + * + * John A. Foley + * Cisco Systems, Inc. + * + * 2/24/2012: This module was modified to use CiscoSSL for AES counter + * mode. Eddy Lem contributed the code to allow this. + * + * 12/20/2012: Added support for AES-192 and AES-256. + */ + +/* + * + * Copyright (c) 2013, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include "aes_icm_ossl.h" +#include "crypto_types.h" +#include "alloc.h" +#include "crypto_types.h" + + +debug_module_t mod_aes_icm = { + 0, /* debugging is off by default */ + "aes icm ossl" /* printable module name */ +}; +extern cipher_test_case_t aes_icm_test_case_0; +extern cipher_type_t aes_icm; +extern cipher_type_t aes_icm_192; +extern cipher_type_t aes_icm_256; + +/* + * integer counter mode works as follows: + * + * 16 bits + * <-----> + * +------+------+------+------+------+------+------+------+ + * | nonce | pakcet index | ctr |---+ + * +------+------+------+------+------+------+------+------+ | + * | + * +------+------+------+------+------+------+------+------+ v + * | salt |000000|->(+) + * +------+------+------+------+------+------+------+------+ | + * | + * +---------+ + * | encrypt | + * +---------+ + * | + * +------+------+------+------+------+------+------+------+ | + * | keystream block |<--+ + * +------+------+------+------+------+------+------+------+ + * + * All fields are big-endian + * + * ctr is the block counter, which increments from zero for + * each packet (16 bits wide) + * + * packet index is distinct for each packet (48 bits wide) + * + * nonce can be distinct across many uses of the same key, or + * can be a fixed value per key, or can be per-packet randomness + * (64 bits) + * + */ + +/* + * This function allocates a new instance of this crypto engine. + * The key_len parameter should be one of 30, 38, or 46 for + * AES-128, AES-192, and AES-256 respectively. Note, this key_len + * value is inflated, as it also accounts for the 112 bit salt + * value. + */ +err_status_t aes_icm_openssl_alloc (cipher_t **c, int key_len, int x) +{ + aes_icm_ctx_t *icm; + int tmp; + uint8_t *allptr; + + debug_print(mod_aes_icm, "allocating cipher with key length %d", key_len); + + /* + * Verify the key_len is valid for one of: AES-128/192/256 + */ + if (key_len != AES_128_KEYSIZE_WSALT && key_len != AES_192_KEYSIZE_WSALT && + key_len != AES_256_KEYSIZE_WSALT) { + return err_status_bad_param; + } + + /* allocate memory a cipher of type aes_icm */ + tmp = sizeof(cipher_t) + sizeof(aes_icm_ctx_t); + allptr = (uint8_t*)crypto_alloc(tmp); + if (allptr == NULL) { + return err_status_alloc_fail; + } + + /* set pointers */ + *c = (cipher_t*)allptr; + (*c)->state = allptr + sizeof(cipher_t); + icm = (aes_icm_ctx_t*)(*c)->state; + + /* increment ref_count */ + switch (key_len) { + case AES_128_KEYSIZE_WSALT: + (*c)->algorithm = AES_128_ICM; + (*c)->type = &aes_icm; + aes_icm.ref_count++; + ((aes_icm_ctx_t*)(*c)->state)->key_size = AES_128_KEYSIZE; + break; + case AES_192_KEYSIZE_WSALT: + (*c)->algorithm = AES_192_ICM; + (*c)->type = &aes_icm_192; + aes_icm_192.ref_count++; + ((aes_icm_ctx_t*)(*c)->state)->key_size = AES_192_KEYSIZE; + break; + case AES_256_KEYSIZE_WSALT: + (*c)->algorithm = AES_256_ICM; + (*c)->type = &aes_icm_256; + aes_icm_256.ref_count++; + ((aes_icm_ctx_t*)(*c)->state)->key_size = AES_256_KEYSIZE; + break; + } + + /* set key size */ + (*c)->key_len = key_len; + EVP_CIPHER_CTX_init(&icm->ctx); + + return err_status_ok; +} + + +/* + * This function deallocates an instance of this engine + */ +err_status_t aes_icm_openssl_dealloc (cipher_t *c) +{ + aes_icm_ctx_t *ctx; + + if (c == NULL) { + return err_status_bad_param; + } + + /* + * Free the EVP context + */ + ctx = (aes_icm_ctx_t*)c->state; + if (ctx != NULL) { + EVP_CIPHER_CTX_cleanup(&ctx->ctx); + /* decrement ref_count for the appropriate engine */ + switch (ctx->key_size) { + case AES_256_KEYSIZE: + aes_icm_256.ref_count--; + break; + case AES_192_KEYSIZE: + aes_icm_192.ref_count--; + break; + case AES_128_KEYSIZE: + aes_icm.ref_count--; + break; + default: + return err_status_dealloc_fail; + break; + } + } + + /* zeroize entire state*/ + octet_string_set_to_zero((uint8_t*)c, + sizeof(cipher_t) + sizeof(aes_icm_ctx_t)); + + /* free memory */ + crypto_free(c); + + return err_status_ok; +} + +/* + * aes_icm_openssl_context_init(...) initializes the aes_icm_context + * using the value in key[]. + * + * the key is the secret key + * + * the salt is unpredictable (but not necessarily secret) data which + * randomizes the starting point in the keystream + */ +err_status_t aes_icm_openssl_context_init (aes_icm_ctx_t *c, const uint8_t *key) +{ + /* + * set counter and initial values to 'offset' value, being careful not to + * go past the end of the key buffer + */ + v128_set_to_zero(&c->counter); + v128_set_to_zero(&c->offset); + memcpy(&c->counter, key + c->key_size, SALT_SIZE); + memcpy(&c->offset, key + c->key_size, SALT_SIZE); + + /* force last two octets of the offset to zero (for srtp compatibility) */ + c->offset.v8[SALT_SIZE] = c->offset.v8[SALT_SIZE + 1] = 0; + c->counter.v8[SALT_SIZE] = c->counter.v8[SALT_SIZE + 1] = 0; + + /* copy key to be used later when CiscoSSL crypto context is created */ + v128_copy_octet_string((v128_t*)&c->key, key); + + /* if the key is greater than 16 bytes, copy the second + * half. Note, we treat AES-192 and AES-256 the same here + * for simplicity. The storage location receiving the + * key is statically allocated to handle a full 32 byte key + * regardless of the cipher in use. + */ + if (c->key_size == AES_256_KEYSIZE || c->key_size == AES_192_KEYSIZE) { + debug_print(mod_aes_icm, "Copying last 16 bytes of key: %s", + v128_hex_string((v128_t*)(key + AES_128_KEYSIZE))); + v128_copy_octet_string(((v128_t*)(&c->key.v8)) + 1, key + AES_128_KEYSIZE); + } + + debug_print(mod_aes_icm, "key: %s", v128_hex_string((v128_t*)&c->key)); + debug_print(mod_aes_icm, "offset: %s", v128_hex_string(&c->offset)); + + EVP_CIPHER_CTX_cleanup(&c->ctx); + + return err_status_ok; +} + + +/* + * aes_icm_set_iv(c, iv) sets the counter value to the exor of iv with + * the offset + */ +err_status_t aes_icm_openssl_set_iv (aes_icm_ctx_t *c, void *iv, int dir) +{ + const EVP_CIPHER *evp; + v128_t *nonce = (v128_t*)iv; + + debug_print(mod_aes_icm, "setting iv: %s", v128_hex_string(nonce)); + + v128_xor(&c->counter, &c->offset, nonce); + + debug_print(mod_aes_icm, "set_counter: %s", v128_hex_string(&c->counter)); + + switch (c->key_size) { + case AES_256_KEYSIZE: + evp = EVP_aes_256_ctr(); + break; + case AES_192_KEYSIZE: + evp = EVP_aes_192_ctr(); + break; + case AES_128_KEYSIZE: + evp = EVP_aes_128_ctr(); + break; + default: + return err_status_bad_param; + break; + } + + if (!EVP_EncryptInit_ex(&c->ctx, evp, + NULL, c->key.v8, c->counter.v8)) { + return err_status_fail; + } else { + return err_status_ok; + } +} + +/* + * This function encrypts a buffer using AES CTR mode + * + * Parameters: + * c Crypto context + * buf data to encrypt + * enc_len length of encrypt buffer + */ +err_status_t aes_icm_openssl_encrypt (aes_icm_ctx_t *c, unsigned char *buf, unsigned int *enc_len) +{ + int len = 0; + + debug_print(mod_aes_icm, "rs0: %s", v128_hex_string(&c->counter)); + + if (!EVP_EncryptUpdate(&c->ctx, buf, &len, buf, *enc_len)) { + return err_status_cipher_fail; + } + *enc_len = len; + + if (!EVP_EncryptFinal_ex(&c->ctx, buf, (int*)&len)) { + return err_status_cipher_fail; + } + *enc_len += len; + + return err_status_ok; +} + +/* + * Abstraction layer for encrypt. + */ +err_status_t aes_icm_output (aes_icm_ctx_t *c, uint8_t *buffer, int num_octets_to_output) +{ + unsigned int len = num_octets_to_output; + + /* zeroize the buffer */ + octet_string_set_to_zero(buffer, num_octets_to_output); + + /* exor keystream into buffer */ + return aes_icm_openssl_encrypt(c, buffer, &len); +} + +/* + * Name of this crypto engine + */ +char aes_icm_openssl_description[] = "AES-128 counter mode using openssl"; +char aes_icm_192_openssl_description[] = "AES-192 counter mode using openssl"; +char aes_icm_256_openssl_description[] = "AES-256 counter mode using openssl"; + + +/* + * KAT values for AES self-test. These + * values came from the legacy libsrtp code. + */ +uint8_t aes_icm_test_case_0_key[AES_128_KEYSIZE_WSALT] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd +}; + +uint8_t aes_icm_test_case_0_nonce[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +uint8_t aes_icm_test_case_0_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_0_ciphertext[32] = { + 0xe0, 0x3e, 0xad, 0x09, 0x35, 0xc9, 0x5e, 0x80, + 0xe1, 0x66, 0xb1, 0x6d, 0xd9, 0x2b, 0x4e, 0xb4, + 0xd2, 0x35, 0x13, 0x16, 0x2b, 0x02, 0xd0, 0xf7, + 0x2a, 0x43, 0xa2, 0xfe, 0x4a, 0x5f, 0x97, 0xab +}; + +cipher_test_case_t aes_icm_test_case_0 = { + AES_128_KEYSIZE_WSALT, /* octets in key */ + aes_icm_test_case_0_key, /* key */ + aes_icm_test_case_0_nonce, /* packet index */ + 32, /* octets in plaintext */ + aes_icm_test_case_0_plaintext, /* plaintext */ + 32, /* octets in ciphertext */ + aes_icm_test_case_0_ciphertext, /* ciphertext */ + 0, + NULL, + NULL /* pointer to next testcase */ +}; + +/* + * KAT values for AES-192-CTR self-test. These + * values came from section 7 of RFC 6188. + */ +uint8_t aes_icm_192_test_case_1_key[AES_192_KEYSIZE_WSALT] = { + 0xea, 0xb2, 0x34, 0x76, 0x4e, 0x51, 0x7b, 0x2d, + 0x3d, 0x16, 0x0d, 0x58, 0x7d, 0x8c, 0x86, 0x21, + 0x97, 0x40, 0xf6, 0x5f, 0x99, 0xb6, 0xbc, 0xf7, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd +}; + +uint8_t aes_icm_192_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_192_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_192_test_case_1_ciphertext[32] = { + 0x35, 0x09, 0x6c, 0xba, 0x46, 0x10, 0x02, 0x8d, + 0xc1, 0xb5, 0x75, 0x03, 0x80, 0x4c, 0xe3, 0x7c, + 0x5d, 0xe9, 0x86, 0x29, 0x1d, 0xcc, 0xe1, 0x61, + 0xd5, 0x16, 0x5e, 0xc4, 0x56, 0x8f, 0x5c, 0x9a +}; + +cipher_test_case_t aes_icm_192_test_case_1 = { + AES_192_KEYSIZE_WSALT, /* octets in key */ + aes_icm_192_test_case_1_key, /* key */ + aes_icm_192_test_case_1_nonce, /* packet index */ + 32, /* octets in plaintext */ + aes_icm_192_test_case_1_plaintext, /* plaintext */ + 32, /* octets in ciphertext */ + aes_icm_192_test_case_1_ciphertext, /* ciphertext */ + 0, + NULL, + NULL /* pointer to next testcase */ +}; + + +/* + * KAT values for AES-256-CTR self-test. These + * values came from section 7 of RFC 6188. + */ +uint8_t aes_icm_256_test_case_2_key[AES_256_KEYSIZE_WSALT] = { + 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_256_test_case_2_nonce[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +uint8_t aes_icm_256_test_case_2_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_256_test_case_2_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_256_test_case_2 = { + AES_256_KEYSIZE_WSALT, /* octets in key */ + aes_icm_256_test_case_2_key, /* key */ + aes_icm_256_test_case_2_nonce, /* packet index */ + 32, /* octets in plaintext */ + aes_icm_256_test_case_2_plaintext, /* plaintext */ + 32, /* octets in ciphertext */ + aes_icm_256_test_case_2_ciphertext, /* ciphertext */ + 0, + NULL, + NULL /* pointer to next testcase */ +}; + +/* + * This is the function table for this crypto engine. + * note: the encrypt function is identical to the decrypt function + */ +cipher_type_t aes_icm = { + (cipher_alloc_func_t) aes_icm_openssl_alloc, + (cipher_dealloc_func_t) aes_icm_openssl_dealloc, + (cipher_init_func_t) aes_icm_openssl_context_init, + (cipher_set_aad_func_t) 0, + (cipher_encrypt_func_t) aes_icm_openssl_encrypt, + (cipher_decrypt_func_t) aes_icm_openssl_encrypt, + (cipher_set_iv_func_t) aes_icm_openssl_set_iv, + (cipher_get_tag_func_t) 0, + (char*) aes_icm_openssl_description, + (int) 0, /* instance count */ + (cipher_test_case_t*) &aes_icm_test_case_0, + (debug_module_t*) &mod_aes_icm, + (cipher_type_id_t) AES_ICM +}; + +/* + * This is the function table for this crypto engine. + * note: the encrypt function is identical to the decrypt function + */ +cipher_type_t aes_icm_192 = { + (cipher_alloc_func_t) aes_icm_openssl_alloc, + (cipher_dealloc_func_t) aes_icm_openssl_dealloc, + (cipher_init_func_t) aes_icm_openssl_context_init, + (cipher_set_aad_func_t) 0, + (cipher_encrypt_func_t) aes_icm_openssl_encrypt, + (cipher_decrypt_func_t) aes_icm_openssl_encrypt, + (cipher_set_iv_func_t) aes_icm_openssl_set_iv, + (cipher_get_tag_func_t) 0, + (char*) aes_icm_192_openssl_description, + (int) 0, /* instance count */ + (cipher_test_case_t*) &aes_icm_192_test_case_1, + (debug_module_t*) &mod_aes_icm, + (cipher_type_id_t) AES_192_ICM +}; + +/* + * This is the function table for this crypto engine. + * note: the encrypt function is identical to the decrypt function + */ +cipher_type_t aes_icm_256 = { + (cipher_alloc_func_t) aes_icm_openssl_alloc, + (cipher_dealloc_func_t) aes_icm_openssl_dealloc, + (cipher_init_func_t) aes_icm_openssl_context_init, + (cipher_set_aad_func_t) 0, + (cipher_encrypt_func_t) aes_icm_openssl_encrypt, + (cipher_decrypt_func_t) aes_icm_openssl_encrypt, + (cipher_set_iv_func_t) aes_icm_openssl_set_iv, + (cipher_get_tag_func_t) 0, + (char*) aes_icm_256_openssl_description, + (int) 0, /* instance count */ + (cipher_test_case_t*) &aes_icm_256_test_case_2, + (debug_module_t*) &mod_aes_icm, + (cipher_type_id_t) AES_256_ICM +}; + diff --git a/libs/srtp/crypto/cipher/cipher.c b/libs/srtp/crypto/cipher/cipher.c index f465ec6c5a..07b472ebff 100644 --- a/libs/srtp/crypto/cipher/cipher.c +++ b/libs/srtp/crypto/cipher/cipher.c @@ -10,7 +10,7 @@ /* * - * Copyright (c) 2001-2006, Cisco Systems, Inc. + * Copyright (c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ */ #include "cipher.h" +#include "crypto_types.h" #include "rand_source.h" /* used in invertibiltiy tests */ #include "alloc.h" /* for crypto_alloc(), crypto_free() */ @@ -87,6 +88,7 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { err_status_t status; uint8_t buffer[SELF_TEST_BUF_OCTETS]; uint8_t buffer2[SELF_TEST_BUF_OCTETS]; + int tag_len; unsigned int len; int i, j, case_num = 0; @@ -105,7 +107,6 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { * encryption and decryption functions */ while (test_case != NULL) { - /* allocate cipher */ status = cipher_type_alloc(ct, &c, test_case->key_length_octets); if (status) @@ -117,7 +118,7 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { debug_print(mod_cipher, "testing encryption", NULL); /* initialize cipher */ - status = cipher_init(c, test_case->key, direction_encrypt); + status = cipher_init(c, test_case->key); if (status) { cipher_dealloc(c); return status; @@ -136,12 +137,30 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { test_case->plaintext_length_octets)); /* set the initialization vector */ - status = cipher_set_iv(c, test_case->idx); + status = cipher_set_iv(c, test_case->idx, direction_encrypt); if (status) { cipher_dealloc(c); return status; } + if (c->algorithm == AES_128_GCM || c->algorithm == AES_256_GCM) { + debug_print(mod_cipher, "IV: %s", + octet_string_hex_string(test_case->idx, 12)); + + /* + * Set the AAD + */ + status = cipher_set_aad(c, test_case->aad, + test_case->aad_length_octets); + if (status) { + cipher_dealloc(c); + return status; + } + debug_print(mod_cipher, "AAD: %s", + octet_string_hex_string(test_case->aad, + test_case->aad_length_octets)); + } + /* encrypt */ len = test_case->plaintext_length_octets; status = cipher_encrypt(c, buffer, &len); @@ -150,6 +169,18 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { return status; } + if (c->algorithm == AES_128_GCM || c->algorithm == AES_256_GCM) { + /* + * Get the GCM tag + */ + status = cipher_get_tag(c, buffer + len, &tag_len); + if (status) { + cipher_dealloc(c); + return status; + } + len += tag_len; + } + debug_print(mod_cipher, "ciphertext: %s", octet_string_hex_string(buffer, test_case->ciphertext_length_octets)); @@ -184,7 +215,7 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { debug_print(mod_cipher, "testing decryption", NULL); /* re-initialize cipher for decryption */ - status = cipher_init(c, test_case->key, direction_decrypt); + status = cipher_init(c, test_case->key); if (status) { cipher_dealloc(c); return status; @@ -203,12 +234,27 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { test_case->plaintext_length_octets)); /* set the initialization vector */ - status = cipher_set_iv(c, test_case->idx); + status = cipher_set_iv(c, test_case->idx, direction_decrypt); if (status) { cipher_dealloc(c); return status; } + if (c->algorithm == AES_128_GCM || c->algorithm == AES_256_GCM) { + /* + * Set the AAD + */ + status = cipher_set_aad(c, test_case->aad, + test_case->aad_length_octets); + if (status) { + cipher_dealloc(c); + return status; + } + debug_print(mod_cipher, "AAD: %s", + octet_string_hex_string(test_case->aad, + test_case->aad_length_octets)); + } + /* decrypt */ len = test_case->ciphertext_length_octets; status = cipher_decrypt(c, buffer, &len); @@ -297,19 +343,34 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { if (status) return status; /* initialize cipher */ - status = cipher_init(c, key, direction_encrypt); + status = cipher_init(c, key); if (status) { cipher_dealloc(c); return status; } /* set initialization vector */ - status = cipher_set_iv(c, test_case->idx); + status = cipher_set_iv(c, test_case->idx, direction_encrypt); if (status) { cipher_dealloc(c); return status; } + if (c->algorithm == AES_128_GCM || c->algorithm == AES_256_GCM) { + /* + * Set the AAD + */ + status = cipher_set_aad(c, test_case->aad, + test_case->aad_length_octets); + if (status) { + cipher_dealloc(c); + return status; + } + debug_print(mod_cipher, "AAD: %s", + octet_string_hex_string(test_case->aad, + test_case->aad_length_octets)); + } + /* encrypt buffer with cipher */ plaintext_len = length; status = cipher_encrypt(c, buffer, &length); @@ -317,6 +378,17 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { cipher_dealloc(c); return status; } + if (c->algorithm == AES_128_GCM || c->algorithm == AES_256_GCM) { + /* + * Get the GCM tag + */ + status = cipher_get_tag(c, buffer + length, &tag_len); + if (status) { + cipher_dealloc(c); + return status; + } + length += tag_len; + } debug_print(mod_cipher, "ciphertext: %s", octet_string_hex_string(buffer, length)); @@ -324,16 +396,30 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { * re-initialize cipher for decryption, re-set the iv, then * decrypt the ciphertext */ - status = cipher_init(c, key, direction_decrypt); + status = cipher_init(c, key); if (status) { cipher_dealloc(c); return status; } - status = cipher_set_iv(c, test_case->idx); + status = cipher_set_iv(c, test_case->idx, direction_decrypt); if (status) { cipher_dealloc(c); return status; } + if (c->algorithm == AES_128_GCM || c->algorithm == AES_256_GCM) { + /* + * Set the AAD + */ + status = cipher_set_aad(c, test_case->aad, + test_case->aad_length_octets); + if (status) { + cipher_dealloc(c); + return status; + } + debug_print(mod_cipher, "AAD: %s", + octet_string_hex_string(test_case->aad, + test_case->aad_length_octets)); + } status = cipher_decrypt(c, buffer, &length); if (status) { cipher_dealloc(c); @@ -344,8 +430,9 @@ cipher_type_test(const cipher_type_t *ct, const cipher_test_case_t *test_data) { octet_string_hex_string(buffer, length)); /* compare the resulting plaintext with the original one */ - if (length != (unsigned int)plaintext_len) + if (length != (unsigned int)plaintext_len) { return err_status_algo_fail; + } status = err_status_ok; for (i=0; i < plaintext_len; i++) if (buffer[i] != buffer2[i]) { @@ -405,7 +492,7 @@ cipher_bits_per_second(cipher_t *c, int octets_in_buffer, int num_trials) { v128_set_to_zero(&nonce); timer = clock(); for(i=0; i < num_trials; i++, nonce.v32[3] = i) { - cipher_set_iv(c, &nonce); + cipher_set_iv(c, &nonce, direction_encrypt); cipher_encrypt(c, enc_buf, &len); } timer = clock() - timer; diff --git a/libs/srtp/crypto/cipher/null_cipher.c b/libs/srtp/crypto/cipher/null_cipher.c index ca38f72318..001e20ff47 100644 --- a/libs/srtp/crypto/cipher/null_cipher.c +++ b/libs/srtp/crypto/cipher/null_cipher.c @@ -10,7 +10,7 @@ /* * - * Copyright (c) 2001-2006, Cisco Systems, Inc. + * Copyright (c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -130,6 +130,8 @@ null_cipher_test_0 = { NULL, /* plaintext */ 0, /* octets in plaintext */ NULL, /* ciphertext */ + 0, + NULL, NULL /* pointer to next testcase */ }; @@ -142,9 +144,11 @@ cipher_type_t null_cipher = { (cipher_alloc_func_t) null_cipher_alloc, (cipher_dealloc_func_t) null_cipher_dealloc, (cipher_init_func_t) null_cipher_init, + (cipher_set_aad_func_t) 0, (cipher_encrypt_func_t) null_cipher_encrypt, (cipher_decrypt_func_t) null_cipher_encrypt, (cipher_set_iv_func_t) null_cipher_set_iv, + (cipher_get_tag_func_t) 0, (char *) null_cipher_description, (int) 0, (cipher_test_case_t *) &null_cipher_test_0, diff --git a/libs/srtp/crypto/hash/hmac_ossl.c b/libs/srtp/crypto/hash/hmac_ossl.c new file mode 100644 index 0000000000..dcf91b57ea --- /dev/null +++ b/libs/srtp/crypto/hash/hmac_ossl.c @@ -0,0 +1,297 @@ +/* + * hmac_ossl.c + * + * Implementation of hmac auth_type_t that leverages OpenSSL + * + * John A. Foley + * Cisco Systems, Inc. + */ +/* + * + * Copyright(c) 2013, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "hmac.h" +#include "alloc.h" +#include + +/* the debug module for authentiation */ + +debug_module_t mod_hmac = { + 0, /* debugging is off by default */ + "hmac sha-1 openssl" /* printable name for module */ +}; + + +err_status_t +hmac_alloc (auth_t **a, int key_len, int out_len) +{ + extern auth_type_t hmac; + uint8_t *pointer; + hmac_ctx_t *new_hmac_ctx; + + debug_print(mod_hmac, "allocating auth func with key length %d", key_len); + debug_print(mod_hmac, " tag length %d", out_len); + + /* + * check key length - note that we don't support keys larger + * than 20 bytes yet + */ + if (key_len > 20) { + return err_status_bad_param; + } + + /* check output length - should be less than 20 bytes */ + if (out_len > 20) { + return err_status_bad_param; + } + + /* allocate memory for auth and hmac_ctx_t structures */ + pointer = (uint8_t*)crypto_alloc(sizeof(hmac_ctx_t) + sizeof(auth_t)); + if (pointer == NULL) { + return err_status_alloc_fail; + } + + /* set pointers */ + *a = (auth_t*)pointer; + (*a)->type = &hmac; + (*a)->state = pointer + sizeof(auth_t); + (*a)->out_len = out_len; + (*a)->key_len = key_len; + (*a)->prefix_len = 0; + new_hmac_ctx = (hmac_ctx_t*)((*a)->state); + memset(new_hmac_ctx, 0, sizeof(hmac_ctx_t)); + + /* increment global count of all hmac uses */ + hmac.ref_count++; + + return err_status_ok; +} + +err_status_t +hmac_dealloc (auth_t *a) +{ + extern auth_type_t hmac; + hmac_ctx_t *hmac_ctx; + + hmac_ctx = (hmac_ctx_t*)a->state; + if (hmac_ctx->ctx_initialized) { + EVP_MD_CTX_cleanup(&hmac_ctx->ctx); + } + if (hmac_ctx->init_ctx_initialized) { + EVP_MD_CTX_cleanup(&hmac_ctx->init_ctx); + } + + /* zeroize entire state*/ + octet_string_set_to_zero((uint8_t*)a, + sizeof(hmac_ctx_t) + sizeof(auth_t)); + + /* free memory */ + crypto_free(a); + + /* decrement global count of all hmac uses */ + hmac.ref_count--; + + return err_status_ok; +} + +err_status_t +hmac_init (hmac_ctx_t *state, const uint8_t *key, int key_len) +{ + int i; + uint8_t ipad[64]; + + /* + * check key length - note that we don't support keys larger + * than 20 bytes yet + */ + if (key_len > 20) { + return err_status_bad_param; + } + + /* + * set values of ipad and opad by exoring the key into the + * appropriate constant values + */ + for (i = 0; i < key_len; i++) { + ipad[i] = key[i] ^ 0x36; + state->opad[i] = key[i] ^ 0x5c; + } + /* set the rest of ipad, opad to constant values */ + for (; i < 64; i++) { + ipad[i] = 0x36; + ((uint8_t*)state->opad)[i] = 0x5c; + } + + debug_print(mod_hmac, "ipad: %s", octet_string_hex_string(ipad, 64)); + + /* initialize sha1 context */ + sha1_init(&state->init_ctx); + state->init_ctx_initialized = 1; + + /* hash ipad ^ key */ + sha1_update(&state->init_ctx, ipad, 64); + return (hmac_start(state)); +} + +err_status_t +hmac_start (hmac_ctx_t *state) +{ + if (state->ctx_initialized) { + EVP_MD_CTX_cleanup(&state->ctx); + } + if (!EVP_MD_CTX_copy(&state->ctx, &state->init_ctx)) { + return err_status_auth_fail; + } else { + state->ctx_initialized = 1; + return err_status_ok; + } +} + +err_status_t +hmac_update (hmac_ctx_t *state, const uint8_t *message, int msg_octets) +{ + + debug_print(mod_hmac, "input: %s", + octet_string_hex_string(message, msg_octets)); + + /* hash message into sha1 context */ + sha1_update(&state->ctx, message, msg_octets); + + return err_status_ok; +} + +err_status_t +hmac_compute (hmac_ctx_t *state, const void *message, + int msg_octets, int tag_len, uint8_t *result) +{ + uint32_t hash_value[5]; + uint32_t H[5]; + int i; + + /* check tag length, return error if we can't provide the value expected */ + if (tag_len > 20) { + return err_status_bad_param; + } + + /* hash message, copy output into H */ + sha1_update(&state->ctx, message, msg_octets); + sha1_final(&state->ctx, H); + + /* + * note that we don't need to debug_print() the input, since the + * function hmac_update() already did that for us + */ + debug_print(mod_hmac, "intermediate state: %s", + octet_string_hex_string((uint8_t*)H, 20)); + + /* re-initialize hash context */ + sha1_init(&state->ctx); + + /* hash opad ^ key */ + sha1_update(&state->ctx, (uint8_t*)state->opad, 64); + + /* hash the result of the inner hash */ + sha1_update(&state->ctx, (uint8_t*)H, 20); + + /* the result is returned in the array hash_value[] */ + sha1_final(&state->ctx, hash_value); + + /* copy hash_value to *result */ + for (i = 0; i < tag_len; i++) { + result[i] = ((uint8_t*)hash_value)[i]; + } + + debug_print(mod_hmac, "output: %s", + octet_string_hex_string((uint8_t*)hash_value, tag_len)); + + return err_status_ok; +} + + +/* begin test case 0 */ + +uint8_t + hmac_test_case_0_key[20] = { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b +}; + +uint8_t + hmac_test_case_0_data[8] = { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 /* "Hi There" */ +}; + +uint8_t + hmac_test_case_0_tag[20] = { + 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, + 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, + 0xf1, 0x46, 0xbe, 0x00 +}; + +auth_test_case_t + hmac_test_case_0 = { + 20, /* octets in key */ + hmac_test_case_0_key, /* key */ + 8, /* octets in data */ + hmac_test_case_0_data, /* data */ + 20, /* octets in tag */ + hmac_test_case_0_tag, /* tag */ + NULL /* pointer to next testcase */ +}; + +/* end test case 0 */ + +char hmac_description[] = "hmac sha-1 authentication function"; + +/* + * auth_type_t hmac is the hmac metaobject + */ + +auth_type_t + hmac = { + (auth_alloc_func) hmac_alloc, + (auth_dealloc_func) hmac_dealloc, + (auth_init_func) hmac_init, + (auth_compute_func) hmac_compute, + (auth_update_func) hmac_update, + (auth_start_func) hmac_start, + (char*) hmac_description, + (int) 0, /* instance count */ + (auth_test_case_t*) &hmac_test_case_0, + (debug_module_t*) &mod_hmac, + (auth_type_id_t) HMAC_SHA1 +}; + diff --git a/libs/srtp/crypto/include/aes_cbc.h b/libs/srtp/crypto/include/aes_cbc.h index bc4e41a4c1..f92591d968 100644 --- a/libs/srtp/crypto/include/aes_cbc.h +++ b/libs/srtp/crypto/include/aes_cbc.h @@ -17,6 +17,8 @@ typedef struct { v128_t state; /* cipher chaining state */ v128_t previous; /* previous ciphertext block */ + uint8_t key[32]; + int key_len; aes_expanded_key_t expanded_key; /* the cipher key */ } aes_cbc_ctx_t; @@ -31,10 +33,10 @@ aes_cbc_encrypt(aes_cbc_ctx_t *c, err_status_t aes_cbc_context_init(aes_cbc_ctx_t *c, const uint8_t *key, - int key_len, cipher_direction_t dir); + int key_len); err_status_t -aes_cbc_set_iv(aes_cbc_ctx_t *c, void *iv); +aes_cbc_set_iv(aes_cbc_ctx_t *c, void *iv, int direction); err_status_t aes_cbc_nist_encrypt(aes_cbc_ctx_t *c, diff --git a/libs/srtp/crypto/include/aes_gcm_ossl.h b/libs/srtp/crypto/include/aes_gcm_ossl.h new file mode 100644 index 0000000000..87b3e9f7e1 --- /dev/null +++ b/libs/srtp/crypto/include/aes_gcm_ossl.h @@ -0,0 +1,62 @@ +/* + * aes_gcm_ossl.h + * + * Header for AES Galois Counter Mode. + * + * John A. Foley + * Cisco Systems, Inc. + * + */ +/* + * + * Copyright (c) 2013, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AES_GCM_OSSL_H +#define AES_GCM_OSSL_H + +#include "cipher.h" +#include +#include + +typedef struct { + v256_t key; + int key_size; + int tag_len; + EVP_CIPHER_CTX ctx; + cipher_direction_t dir; +} aes_gcm_ctx_t; + +#endif /* AES_GCM_OSSL_H */ + diff --git a/libs/srtp/crypto/include/aes_icm.h b/libs/srtp/crypto/include/aes_icm.h index dac0cdccc6..bbcc6c3f5c 100644 --- a/libs/srtp/crypto/include/aes_icm.h +++ b/libs/srtp/crypto/include/aes_icm.h @@ -29,7 +29,7 @@ aes_icm_context_init(aes_icm_ctx_t *c, int key_len); err_status_t -aes_icm_set_iv(aes_icm_ctx_t *c, void *iv); +aes_icm_set_iv(aes_icm_ctx_t *c, void *iv, int direction); err_status_t aes_icm_encrypt(aes_icm_ctx_t *c, diff --git a/libs/srtp/crypto/include/aes_icm_ossl.h b/libs/srtp/crypto/include/aes_icm_ossl.h new file mode 100644 index 0000000000..89da7e0693 --- /dev/null +++ b/libs/srtp/crypto/include/aes_icm_ossl.h @@ -0,0 +1,73 @@ +/* + * aes_icm.h + * + * Header for AES Integer Counter Mode. + * + * David A. McGrew + * Cisco Systems, Inc. + * + */ +/* + * + * Copyright (c) 2001-2005,2012, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AES_ICM_H +#define AES_ICM_H + +#include "cipher.h" +#include +#include + +#define SALT_SIZE 14 +#define AES_128_KEYSIZE AES_BLOCK_SIZE +#define AES_192_KEYSIZE AES_BLOCK_SIZE + AES_BLOCK_SIZE / 2 +#define AES_256_KEYSIZE AES_BLOCK_SIZE * 2 +#define AES_128_KEYSIZE_WSALT AES_128_KEYSIZE + SALT_SIZE +#define AES_192_KEYSIZE_WSALT AES_192_KEYSIZE + SALT_SIZE +#define AES_256_KEYSIZE_WSALT AES_256_KEYSIZE + SALT_SIZE + +typedef struct { + v128_t counter; /* holds the counter value */ + v128_t offset; /* initial offset value */ + v256_t key; + int key_size; + EVP_CIPHER_CTX ctx; +} aes_icm_ctx_t; + +err_status_t aes_icm_openssl_set_iv(aes_icm_ctx_t *c, void *iv, int dir); + + +#endif /* AES_ICM_H */ + diff --git a/libs/srtp/crypto/include/cipher.h b/libs/srtp/crypto/include/cipher.h index eff6dd154b..f98d2398d1 100644 --- a/libs/srtp/crypto/include/cipher.h +++ b/libs/srtp/crypto/include/cipher.h @@ -8,7 +8,7 @@ */ /* * - * Copyright (c) 2001-2006, Cisco Systems, Inc. + * Copyright (c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -84,11 +84,10 @@ typedef err_status_t (*cipher_alloc_func_t) /* * a cipher_init_func_t [re-]initializes a cipher_t with a given key - * and direction (i.e., encrypt or decrypt) */ typedef err_status_t (*cipher_init_func_t) -(void *state, const uint8_t *key, int key_len, cipher_direction_t dir); +(void *state, const uint8_t *key, int key_len); /* a cipher_dealloc_func_t de-allocates a cipher_t */ @@ -99,6 +98,13 @@ typedef err_status_t (*cipher_dealloc_func_t)(cipher_pointer_t cp); typedef err_status_t (*cipher_set_segment_func_t) (void *state, xtd_seq_num_t idx); +/* + * a cipher_set_aad_func_t processes the AAD data for AEAD ciphers + */ +typedef err_status_t (*cipher_set_aad_func_t) + (void *state, uint8_t *aad, unsigned int aad_len); + + /* a cipher_encrypt_func_t encrypts data in-place */ typedef err_status_t (*cipher_encrypt_func_t) @@ -114,7 +120,15 @@ typedef err_status_t (*cipher_decrypt_func_t) */ typedef err_status_t (*cipher_set_iv_func_t) - (cipher_pointer_t cp, void *iv); + (cipher_pointer_t cp, void *iv, cipher_direction_t direction); + +/* + * a cipher_get_tag_funct_t function is used to get the authentication + * tag that was calculated by an AEAD cipher. + */ +typedef err_status_t (*cipher_get_tag_func_t) + (void *state, void *tag, int *len); + /* * cipher_test_case_t is a (list of) key, salt, xtd_seq_num_t, @@ -132,6 +146,8 @@ typedef struct cipher_test_case_t { uint8_t *plaintext; /* plaintext */ int ciphertext_length_octets; /* octets in plaintext */ uint8_t *ciphertext; /* ciphertext */ + int aad_length_octets; /* octets in AAD */ + uint8_t *aad; /* AAD */ struct cipher_test_case_t *next_test_case; /* pointer to next testcase */ } cipher_test_case_t; @@ -141,9 +157,11 @@ typedef struct cipher_type_t { cipher_alloc_func_t alloc; cipher_dealloc_func_t dealloc; cipher_init_func_t init; + cipher_set_aad_func_t set_aad; cipher_encrypt_func_t encrypt; cipher_encrypt_func_t decrypt; cipher_set_iv_func_t set_iv; + cipher_get_tag_func_t get_tag; char *description; int ref_count; cipher_test_case_t *test_data; @@ -160,9 +178,7 @@ typedef struct cipher_t { cipher_type_t *type; void *state; int key_len; -#ifdef FORCE_64BIT_ALIGN - int pad; -#endif + int algorithm; } cipher_t; /* some syntactic sugar on these function types */ @@ -171,16 +187,23 @@ typedef struct cipher_t { #define cipher_dealloc(c) (((c)->type)->dealloc(c)) -#define cipher_init(c, k, dir) (((c)->type)->init(((c)->state), (k), ((c)->key_len), (dir))) +#define cipher_init(c, k) (((c)->type)->init(((c)->state), (k), ((c)->key_len))) #define cipher_encrypt(c, buf, len) \ (((c)->type)->encrypt(((c)->state), (buf), (len))) +#define cipher_get_tag(c, buf, len) \ + (((c)->type)->get_tag(((c)->state), (buf), (len))) + #define cipher_decrypt(c, buf, len) \ (((c)->type)->decrypt(((c)->state), (buf), (len))) -#define cipher_set_iv(c, n) \ - ((c) ? (((c)->type)->set_iv(((cipher_pointer_t)(c)->state), (n))) : \ +#define cipher_set_iv(c, n, dir) \ + ((c) ? (((c)->type)->set_iv(((cipher_pointer_t)(c)->state), (n), (dir))) : \ + err_status_no_such_op) +#define cipher_set_aad(c, a, l) \ + (((c) && (((c)->type)->set_aad)) ? \ + (((c)->type)->set_aad(((c)->state), (a), (l))) : \ err_status_no_such_op) err_status_t diff --git a/libs/srtp/crypto/include/crypto_types.h b/libs/srtp/crypto/include/crypto_types.h index 35317108c3..dbb50c37fe 100644 --- a/libs/srtp/crypto/include/crypto_types.h +++ b/libs/srtp/crypto/include/crypto_types.h @@ -8,7 +8,7 @@ */ /* * - * Copyright(c) 2001-2006 Cisco Systems, Inc. + * Copyright(c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -141,6 +141,34 @@ */ #define STRONGHOLD_CIPHER AES_ICM +/** + * @brief AES-192 Integer Counter Mode (AES ICM) + * AES-192 ICM is a deprecated alternate name for AES ICM. + */ +#define AES_192_ICM 4 + +/** + * @brief AES-256 Integer Counter Mode (AES ICM) + * AES-256 ICM is a deprecated alternate name for AES ICM. + */ +#define AES_256_ICM 5 + +/** + * @brief AES-128_GCM Galois Counter Mode (AES GCM) + * + * AES-128 GCM is the variant of galois counter mode that is used by + * Secure RTP. This cipher uses a 16-octet key. + */ +#define AES_128_GCM 6 + +/** + * @brief AES-256_GCM Galois Counter Mode (AES GCM) + * + * AES-256 GCM is the variant of galois counter mode that is used by + * Secure RTP. This cipher uses a 32-octet key. + */ +#define AES_256_GCM 7 + /** * @} */ diff --git a/libs/srtp/crypto/include/datatypes.h b/libs/srtp/crypto/include/datatypes.h index 24c9daaf38..e523ea62f0 100644 --- a/libs/srtp/crypto/include/datatypes.h +++ b/libs/srtp/crypto/include/datatypes.h @@ -92,6 +92,12 @@ typedef union { uint64_t v64[2]; } v128_t; +typedef union { + uint8_t v8[32]; + uint16_t v16[16]; + uint32_t v32[8]; + uint64_t v64[4]; +} v256_t; /* some useful and simple math functions */ diff --git a/libs/srtp/crypto/include/hmac.h b/libs/srtp/crypto/include/hmac.h index 262c0e2d6e..875f45c649 100644 --- a/libs/srtp/crypto/include/hmac.h +++ b/libs/srtp/crypto/include/hmac.h @@ -9,7 +9,7 @@ */ /* * - * Copyright (c) 2001-2006, Cisco Systems, Inc. + * Copyright (c) 2001-2006,2013, Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,10 @@ typedef struct { uint8_t opad[64]; sha1_ctx_t ctx; sha1_ctx_t init_ctx; +#ifdef OPENSSL + int ctx_initialized; + int init_ctx_initialized; +#endif } hmac_ctx_t; err_status_t diff --git a/libs/srtp/crypto/include/prng.h b/libs/srtp/crypto/include/prng.h index fb96b5ebaa..c493383cba 100644 --- a/libs/srtp/crypto/include/prng.h +++ b/libs/srtp/crypto/include/prng.h @@ -12,7 +12,12 @@ #include "rand_source.h" /* for rand_source_func_t definition */ #include "aes.h" /* for aes */ +//FIXME: this is temporary until we pull in the code to use OpenSSL for RNG +#ifdef OPENSSL +#include "aes_icm_ossl.h" /* for aes ctr */ +#else #include "aes_icm.h" /* for aes ctr */ +#endif #define MAX_PRNG_OUT_LEN 0xffffffffU diff --git a/libs/srtp/crypto/include/sha1.h b/libs/srtp/crypto/include/sha1.h index e3af4d4b4b..8b02f76811 100644 --- a/libs/srtp/crypto/include/sha1.h +++ b/libs/srtp/crypto/include/sha1.h @@ -48,6 +48,43 @@ #define SHA1_H #include "err.h" +#ifdef OPENSSL +#include + +typedef EVP_MD_CTX sha1_ctx_t; + +/* + * sha1_init(&ctx) initializes the SHA1 context ctx + * + * sha1_update(&ctx, msg, len) hashes the len octets starting at msg + * into the SHA1 context + * + * sha1_final(&ctx, output) performs the final processing of the SHA1 + * context and writes the result to the 20 octets at output + * + * Return values are ignored on the EVP functions since all three + * of these functions return void. + * + */ + +void inline sha1_init (sha1_ctx_t *ctx) +{ + EVP_MD_CTX_init(ctx); + EVP_DigestInit(ctx, EVP_sha1()); +} + +void inline sha1_update (sha1_ctx_t *ctx, const uint8_t *M, int octets_in_msg) +{ + EVP_DigestUpdate(ctx, M, octets_in_msg); +} + +void inline sha1_final (sha1_ctx_t *ctx, uint32_t *output) +{ + unsigned int len = 0; + + EVP_DigestFinal(ctx, (unsigned char*)output, &len); +} +#else #include "datatypes.h" typedef struct { @@ -104,5 +141,7 @@ sha1_final(sha1_ctx_t *ctx, uint32_t output[5]); void sha1_core(const uint32_t M[16], uint32_t hash_value[5]); + +#endif /* else OPENSSL */ #endif /* SHA1_H */ diff --git a/libs/srtp/crypto/kernel/crypto_kernel.c b/libs/srtp/crypto/kernel/crypto_kernel.c index 90c4a3073a..656c010460 100644 --- a/libs/srtp/crypto/kernel/crypto_kernel.c +++ b/libs/srtp/crypto/kernel/crypto_kernel.c @@ -8,7 +8,7 @@ */ /* * - * Copyright(c) 2001-2006 Cisco Systems, Inc. + * Copyright(c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,7 +69,12 @@ extern debug_module_t mod_alloc; extern cipher_type_t null_cipher; extern cipher_type_t aes_icm; +#ifndef OPENSSL extern cipher_type_t aes_cbc; +#else +extern cipher_type_t aes_gcm_128_openssl; +extern cipher_type_t aes_gcm_256_openssl; +#endif /* @@ -137,6 +142,7 @@ crypto_kernel_init() { if (status) return status; +#ifndef OPENSSL /* initialize pseudorandom number generator */ status = ctr_prng_init(rand_source_get_octet_string); if (status) @@ -146,6 +152,7 @@ crypto_kernel_init() { status = stat_test_rand_source_with_repetition(ctr_prng_get_octet_string, MAX_RNG_TRIALS); if (status) return status; +#endif /* load cipher types */ status = crypto_kernel_load_cipher_type(&null_cipher, NULL_CIPHER); @@ -154,9 +161,20 @@ crypto_kernel_init() { status = crypto_kernel_load_cipher_type(&aes_icm, AES_ICM); if (status) return status; +#ifndef OPENSSL status = crypto_kernel_load_cipher_type(&aes_cbc, AES_CBC); if (status) return status; +#else + status = crypto_kernel_load_cipher_type(&aes_gcm_128_openssl, AES_128_GCM); + if (status) { + return status; + } + status = crypto_kernel_load_cipher_type(&aes_gcm_256_openssl, AES_256_GCM); + if (status) { + return status; + } +#endif /* load auth func types */ status = crypto_kernel_load_auth_type(&null_auth, NULL_AUTH); @@ -567,7 +585,11 @@ crypto_kernel_set_debug_module(char *name, int on) { err_status_t crypto_get_random(unsigned char *buffer, unsigned int length) { if (crypto_kernel.state == crypto_kernel_state_secure) +#ifdef OPENSSL + return rand_source_get_octet_string(buffer, length); +#else return ctr_prng_get_octet_string(buffer, length); +#endif else return err_status_fail; } diff --git a/libs/srtp/crypto/rng/ctr_prng.c b/libs/srtp/crypto/rng/ctr_prng.c index 41d46a8f55..285124d415 100644 --- a/libs/srtp/crypto/rng/ctr_prng.c +++ b/libs/srtp/crypto/rng/ctr_prng.c @@ -66,7 +66,11 @@ ctr_prng_init(rand_source_func_t random_source) { return status; /* initialize aes ctr context with random key */ +#ifdef OPENSSL + status = aes_icm_openssl_context_init(&ctr_prng.state, tmp_key, 30); +#else status = aes_icm_context_init(&ctr_prng.state, tmp_key, 30); +#endif if (status) return status; diff --git a/libs/srtp/crypto/rng/rand_source_ossl.c b/libs/srtp/crypto/rng/rand_source_ossl.c new file mode 100644 index 0000000000..ee836ce750 --- /dev/null +++ b/libs/srtp/crypto/rng/rand_source_ossl.c @@ -0,0 +1,66 @@ +/* + * rand_source_ossl.c + * + * implements a random source based on OpenSSL RAND_bytes() + * + * John A. Foley + * Cisco Systems, Inc. + */ +/* + * + * Copyright(c) 2013, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met:crypto/test/aes_calc.c + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "rand_source.h" +#include + + +err_status_t rand_source_init (void) +{ + return err_status_ok; +} + +err_status_t rand_source_get_octet_string (void *dest, uint32_t len) +{ + if (RAND_bytes(dest, len) == 1) { + return err_status_ok; + } else { + return err_status_fail; + } +} + +err_status_t rand_source_deinit (void) +{ + return err_status_ok; +} diff --git a/libs/srtp/crypto/test/cipher_driver.c b/libs/srtp/crypto/test/cipher_driver.c index ea41ff5a4c..c4b4d668de 100644 --- a/libs/srtp/crypto/test/cipher_driver.c +++ b/libs/srtp/crypto/test/cipher_driver.c @@ -9,7 +9,7 @@ /* * - * Copyright (c) 2001-2006, Cisco Systems, Inc. + * Copyright (c) 2001-2006,2013 Cisco Systems, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,7 +48,12 @@ #include /* for memset() */ #include /* for getopt() */ #include "cipher.h" +#ifdef OPENSSL +#include "aes_icm_ossl.h" +#include "aes_gcm_ossl.h" +#else #include "aes_icm.h" +#endif #include "null_cipher.h" #define PRINT_DEBUG 0 @@ -114,7 +119,14 @@ check_status(err_status_t s) { extern cipher_type_t null_cipher; extern cipher_type_t aes_icm; +#ifndef OPENSSL extern cipher_type_t aes_cbc; +#else +extern cipher_type_t aes_icm_192; +extern cipher_type_t aes_icm_256; +extern cipher_type_t aes_gcm_128_openssl; +extern cipher_type_t aes_gcm_256_openssl; +#endif int main(int argc, char *argv[]) { @@ -171,6 +183,7 @@ main(int argc, char *argv[]) { for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) cipher_driver_test_array_throughput(&aes_icm, 30, num_cipher); +#ifndef OPENSSL for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) cipher_driver_test_array_throughput(&aes_icm, 46, num_cipher); @@ -179,19 +192,41 @@ main(int argc, char *argv[]) { for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) cipher_driver_test_array_throughput(&aes_cbc, 32, num_cipher); +#else + for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) + cipher_driver_test_array_throughput(&aes_icm_192, 38, num_cipher); + + for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) + cipher_driver_test_array_throughput(&aes_icm_256, 46, num_cipher); + + for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) { + cipher_driver_test_array_throughput(&aes_gcm_128_openssl, 30, num_cipher); + } + + for (num_cipher=1; num_cipher < max_num_cipher; num_cipher *=8) { + cipher_driver_test_array_throughput(&aes_gcm_256_openssl, 46, num_cipher); + } +#endif } if (do_validation) { cipher_driver_self_test(&null_cipher); cipher_driver_self_test(&aes_icm); +#ifndef OPENSSL cipher_driver_self_test(&aes_cbc); +#else + cipher_driver_self_test(&aes_icm_192); + cipher_driver_self_test(&aes_icm_256); + cipher_driver_self_test(&aes_gcm_128_openssl); + cipher_driver_self_test(&aes_gcm_256_openssl); +#endif } /* do timing and/or buffer_test on null_cipher */ status = cipher_type_alloc(&null_cipher, &c, 0); check_status(status); - status = cipher_init(c, NULL, direction_encrypt); + status = cipher_init(c, NULL); check_status(status); if (do_timing_test) @@ -211,7 +246,7 @@ main(int argc, char *argv[]) { exit(status); } - status = cipher_init(c, test_key, direction_encrypt); + status = cipher_init(c, test_key); check_status(status); if (do_timing_test) @@ -226,13 +261,17 @@ main(int argc, char *argv[]) { check_status(status); /* repeat the tests with 256-bit keys */ +#ifndef OPENSSL status = cipher_type_alloc(&aes_icm, &c, 46); +#else + status = cipher_type_alloc(&aes_icm_256, &c, 46); +#endif if (status) { fprintf(stderr, "error: can't allocate cipher\n"); exit(status); } - status = cipher_init(c, test_key, direction_encrypt); + status = cipher_init(c, test_key); check_status(status); if (do_timing_test) @@ -245,8 +284,48 @@ main(int argc, char *argv[]) { status = cipher_dealloc(c); check_status(status); - - return 0; + +#ifdef OPENSSL + /* run the throughput test on the aes_gcm_128_openssl cipher */ + status = cipher_type_alloc(&aes_gcm_128_openssl, &c, 30); + if (status) { + fprintf(stderr, "error: can't allocate GCM 128 cipher\n"); + exit(status); + } + status = cipher_init(c, test_key); + 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); + + /* run the throughput test on the aes_gcm_256_openssl cipher */ + status = cipher_type_alloc(&aes_gcm_256_openssl, &c, 46); + if (status) { + fprintf(stderr, "error: can't allocate GCM 256 cipher\n"); + exit(status); + } + status = cipher_init(c, test_key); + 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); +#endif + + return 0; } void @@ -306,7 +385,7 @@ cipher_driver_test_buffering(cipher_t *c) { buffer0[j] = buffer1[j] = 0; /* initialize cipher */ - status = cipher_set_iv(c, idx); + status = cipher_set_iv(c, idx, direction_encrypt); if (status) return status; @@ -316,7 +395,7 @@ cipher_driver_test_buffering(cipher_t *c) { return status; /* re-initialize cipher */ - status = cipher_set_iv(c, idx); + status = cipher_set_iv(c, idx, direction_encrypt); if (status) return status; @@ -409,7 +488,7 @@ cipher_array_alloc_init(cipher_t ***ca, int num_ciphers, key[j] = (uint8_t) rand(); for (; j < klen_pad; j++) key[j] = 0; - status = cipher_init(*cipher_array, key, direction_encrypt); + status = cipher_init(*cipher_array, key); if (status) return status; @@ -476,7 +555,7 @@ cipher_array_bits_per_second(cipher_t *cipher_array[], int num_cipher, unsigned octets_to_encrypt = octets_in_buffer; /* encrypt buffer with cipher */ - cipher_set_iv(cipher_array[cipher_index], &nonce); + cipher_set_iv(cipher_array[cipher_index], &nonce, direction_encrypt); cipher_encrypt(cipher_array[cipher_index], enc_buf, &octets_to_encrypt); /* choose a cipher at random from the array*/ diff --git a/libs/srtp/crypto/test/env.c b/libs/srtp/crypto/test/env.c index 37a6e2731b..4967ad5050 100644 --- a/libs/srtp/crypto/test/env.c +++ b/libs/srtp/crypto/test/env.c @@ -80,6 +80,7 @@ main(void) { printf("using stdout for error reporting\t(ERR_REPORTING_STDOUT == 1)\n"); #endif +#ifndef OPENSSL #ifdef DEV_URANDOM str = DEV_URANDOM; #else @@ -90,6 +91,7 @@ main(void) { if (strcmp("", str) == 0) { err_count++; } +#endif if (err_count) printf("warning: configuration is probably in error " diff --git a/libs/srtp/crypto/test/stat_driver.c b/libs/srtp/crypto/test/stat_driver.c index 145cd0210a..b2738e8fb4 100644 --- a/libs/srtp/crypto/test/stat_driver.c +++ b/libs/srtp/crypto/test/stat_driver.c @@ -32,10 +32,14 @@ err_check(err_status_t s) { int main (int argc, char *argv[]) { - uint8_t buffer[2500]; + uint8_t buffer[2532]; unsigned int buf_len = 2500; int i, j; extern cipher_type_t aes_icm; +#ifdef OPENSSL + extern cipher_type_t aes_gcm_128_openssl; + extern cipher_type_t aes_gcm_256_openssl; +#endif cipher_t *c; uint8_t key[46] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -73,8 +77,8 @@ main (int argc, char *argv[]) { for (i=0; i < 2500; i++) buffer[i] = 0; err_check(cipher_type_alloc(&aes_icm, &c, 30)); - err_check(cipher_init(c, key, direction_encrypt)); - err_check(cipher_set_iv(c, &nonce)); + err_check(cipher_init(c, key)); + err_check(cipher_set_iv(c, &nonce, direction_encrypt)); err_check(cipher_encrypt(c, buffer, &buf_len)); /* run tests on cipher outout */ printf("monobit %d\n", stat_test_monobit(buffer)); @@ -89,7 +93,7 @@ main (int argc, char *argv[]) { for (i=0; i < 2500; i++) buffer[i] = 0; nonce.v32[3] = i; - err_check(cipher_set_iv(c, &nonce)); + err_check(cipher_set_iv(c, &nonce, direction_encrypt)); err_check(cipher_encrypt(c, buffer, &buf_len)); if (stat_test_runs(buffer)) { num_fail++; @@ -107,8 +111,8 @@ main (int argc, char *argv[]) { 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_init(c, key)); + err_check(cipher_set_iv(c, &nonce, direction_encrypt)); err_check(cipher_encrypt(c, buffer, &buf_len)); /* run tests on cipher outout */ printf("monobit %d\n", stat_test_monobit(buffer)); @@ -123,13 +127,75 @@ main (int argc, char *argv[]) { for (i=0; i < 2500; i++) buffer[i] = 0; nonce.v32[3] = i; - err_check(cipher_set_iv(c, &nonce)); + err_check(cipher_set_iv(c, &nonce, direction_encrypt)); err_check(cipher_encrypt(c, buffer, &buf_len)); if (stat_test_runs(buffer)) { num_fail++; } } +#ifdef OPENSSL + { + printf("running stat_tests on AES-128-GCM, expecting success\n"); + /* set buffer to cipher output */ + for (i=0; i < 2500; i++) { + buffer[i] = 0; + } + err_check(cipher_type_alloc(&aes_gcm_128_openssl, &c, 30)); + err_check(cipher_init(c, key)); + err_check(cipher_set_iv(c, &nonce, direction_encrypt)); + 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)); + 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, direction_encrypt)); + err_check(cipher_encrypt(c, buffer, &buf_len)); + buf_len = 2500; + if (stat_test_runs(buffer)) { + num_fail++; + } + } + + printf("running stat_tests on AES-256-GCM, expecting success\n"); + /* set buffer to cipher output */ + for (i=0; i < 2500; i++) { + buffer[i] = 0; + } + err_check(cipher_type_alloc(&aes_gcm_256_openssl, &c, 46)); + err_check(cipher_init(c, key)); + err_check(cipher_set_iv(c, &nonce, direction_encrypt)); + 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)); + 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, direction_encrypt)); + err_check(cipher_encrypt(c, buffer, &buf_len)); + buf_len = 2500; + if (stat_test_runs(buffer)) { + num_fail++; + } + } + } +#endif + 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"); diff --git a/libs/srtp/include/srtp.h b/libs/srtp/include/srtp.h index b4d48d110b..a9c73d46e7 100644 --- a/libs/srtp/include/srtp.h +++ b/libs/srtp/include/srtp.h @@ -88,6 +88,13 @@ extern "C" { */ #define SRTP_MAX_TRAILER_LEN SRTP_MAX_TAG_LEN +/* + * SRTP_AEAD_SALT_LEN is the length of the SALT values used with + * GCM mode. GCM mode requires an IV. The SALT value is used + * as part of the IV formation logic applied to each RTP packet. + */ +#define SRTP_AEAD_SALT_LEN 12 + /* * nota bene: since libSRTP doesn't support the use of the MKI, the * SRTP_MAX_TRAILER_LEN value is just the maximum tag length @@ -663,6 +670,130 @@ void crypto_policy_set_aes_cm_256_hmac_sha1_80(crypto_policy_t *p); void crypto_policy_set_aes_cm_256_hmac_sha1_32(crypto_policy_t *p); +/** + * @brief crypto_policy_set_aes_cm_256_null_auth() sets a crypto + * policy structure to an encryption-only policy + * + * @param p is a pointer to the policy structure to be set + * + * The function call crypto_policy_set_aes_cm_256_null_auth(&p) sets + * the crypto_policy_t at location p to use the SRTP default cipher + * (AES-256 Counter Mode), but to use no authentication method. This + * policy is NOT RECOMMENDED unless it is unavoidable; 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 policy is NOT RECOMMENDED for SRTP unless it is + * unavoidable, and it is NOT RECOMMENDED at all 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_null_auth(crypto_policy_t *p); + +/** + * @brief crypto_policy_set_aes_gcm_128_8_auth() sets a crypto + * policy structure to an AEAD encryption policy. + * + * @param p is a pointer to the policy structure to be set + * + * The function call crypto_policy_set_aes_gcm_128_8_auth(&p) sets + * the crypto_policy_t at location p to use the SRTP default cipher + * (AES-128 Galois Counter Mode) with 8 octet auth tag. This + * policy applies confidentiality and authentication to both the + * RTP and RTCP packets. + * + * 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_gcm_128_8_auth(crypto_policy_t *p); + +/** + * @brief crypto_policy_set_aes_gcm_256_8_auth() sets a crypto + * policy structure to an AEAD encryption policy + * + * @param p is a pointer to the policy structure to be set + * + * The function call crypto_policy_set_aes_gcm_256_8_auth(&p) sets + * the crypto_policy_t at location p to use the SRTP default cipher + * (AES-256 Galois Counter Mode) with 8 octet auth tag. This + * policy applies confidentiality and authentication to both the + * RTP and RTCP packets. + * + * 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_gcm_256_8_auth(crypto_policy_t *p); + +/** + * @brief crypto_policy_set_aes_gcm_128_8_only_auth() sets a crypto + * policy structure to an AEAD authentication-only policy + * + * @param p is a pointer to the policy structure to be set + * + * The function call crypto_policy_set_aes_gcm_128_8_only_auth(&p) sets + * the crypto_policy_t at location p to use the SRTP default cipher + * (AES-128 Galois Counter Mode) with 8 octet auth tag. This policy + * applies confidentiality and authentication to the RTP packets, + * but only authentication to the RTCP packets. + * + * 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_gcm_128_8_only_auth(crypto_policy_t *p); + +/** + * @brief crypto_policy_set_aes_gcm_256_8_only_auth() sets a crypto + * policy structure to an AEAD authentication-only policy + * + * @param p is a pointer to the policy structure to be set + * + * The function call crypto_policy_set_aes_gcm_256_8_only_auth(&p) sets + * the crypto_policy_t at location p to use the SRTP default cipher + * (AES-256 Galois Counter Mode) with 8 octet auth tag. This policy + * applies confidentiality and authentication to the RTP packets, + * but only authentication to the RTCP packets. + * + * 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_gcm_256_8_only_auth(crypto_policy_t *p); + /** * @brief srtp_dealloc() deallocates storage for an SRTP session diff --git a/libs/srtp/include/srtp_priv.h b/libs/srtp/include/srtp_priv.h index 825017018f..270ebafca5 100644 --- a/libs/srtp/include/srtp_priv.h +++ b/libs/srtp/include/srtp_priv.h @@ -77,7 +77,7 @@ typedef struct { unsigned m:1; /* marker bit */ unsigned seq:16; /* sequence number */ unsigned ts:32; /* timestamp */ - unsigned ssrc:32; /* synchronization source */ + uint32_t ssrc; /* synchronization source */ } srtp_hdr_t; #else /* BIG_ENDIAN */ @@ -91,7 +91,7 @@ typedef struct { unsigned pt:7; /* payload type */ unsigned seq:16; /* sequence number */ unsigned ts:32; /* timestamp */ - unsigned ssrc:32; /* synchronization source */ + uint32_t ssrc; /* synchronization source */ } srtp_hdr_t; #endif @@ -117,7 +117,7 @@ typedef struct { unsigned version:2; /* protocol version */ unsigned pt:8; /* payload type */ unsigned len:16; /* length */ - unsigned ssrc:32; /* synchronization source */ + uint32_t ssrc; /* synchronization source */ } srtcp_hdr_t; typedef struct { @@ -220,6 +220,8 @@ typedef struct srtp_stream_ctx_t { direction_t direction; int allow_repeat_tx; ekt_stream_t ekt; + uint8_t salt[SRTP_AEAD_SALT_LEN]; /* used with GCM mode for SRTP */ + uint8_t c_salt[SRTP_AEAD_SALT_LEN]; /* used with GCM mode for SRTCP */ struct srtp_stream_ctx_t *next; /* linked list of streams */ } srtp_stream_ctx_t; diff --git a/libs/srtp/srtp/ekt.c b/libs/srtp/srtp/ekt.c index 4b3d95b2f7..1079809d8f 100644 --- a/libs/srtp/srtp/ekt.c +++ b/libs/srtp/srtp/ekt.c @@ -149,10 +149,13 @@ ekt_stream_init_from_policy(ekt_stream_t stream_data, ekt_policy_t policy) { void aes_decrypt_with_raw_key(void *ciphertext, const void *key, int key_len) { +#ifndef OPENSSL +//FIXME: need to get this working through the crypto module interface aes_expanded_key_t expanded_key; aes_expand_decryption_key(key, key_len, &expanded_key); aes_decrypt(ciphertext, &expanded_key); +#endif } /* diff --git a/libs/srtp/srtp/srtp.c b/libs/srtp/srtp/srtp.c index 7fd19e6f10..4dbda3e272 100644 --- a/libs/srtp/srtp/srtp.c +++ b/libs/srtp/srtp/srtp.c @@ -232,6 +232,13 @@ srtp_stream_dealloc(srtp_t session, srtp_stream_ctx_t *stream) { return status; /* DAM - need to deallocate EKT here */ + + /* + * zeroize the salt value + */ + memset(stream->salt, 0, SRTP_AEAD_SALT_LEN); + memset(stream->c_salt, 0, SRTP_AEAD_SALT_LEN); + /* deallocate srtp stream context */ crypto_free(stream); @@ -271,14 +278,20 @@ srtp_stream_clone(const srtp_stream_ctx_t *stream_template, /* set key limit to point to that of the template */ status = key_limit_clone(stream_template->limit, &str->limit); - if (status) + if (status) { + crypto_free(*str_ptr); + *str_ptr = NULL; return status; + } /* initialize replay databases */ status = rdbx_init(&str->rtp_rdbx, rdbx_get_window_size(&stream_template->rtp_rdbx)); - if (status) + if (status) { + crypto_free(*str_ptr); + *str_ptr = NULL; return status; + } rdb_init(&str->rtcp_rdb); str->allow_repeat_tx = stream_template->allow_repeat_tx; @@ -293,6 +306,10 @@ srtp_stream_clone(const srtp_stream_ctx_t *stream_template, /* set pointer to EKT data associated with stream */ str->ekt = stream_template->ekt; + /* Copy the salt values */ + memcpy(str->salt, stream_template->salt, SRTP_AEAD_SALT_LEN); + memcpy(str->c_salt, stream_template->c_salt, SRTP_AEAD_SALT_LEN); + /* defensive coding */ str->next = NULL; @@ -343,7 +360,7 @@ srtp_kdf_init(srtp_kdf_t *kdf, cipher_type_id_t cipher_id, const uint8_t *key, i if (stat) return stat; - stat = cipher_init(kdf->cipher, key, direction_encrypt); + stat = cipher_init(kdf->cipher, key); if (stat) { cipher_dealloc(kdf->cipher); return stat; @@ -363,7 +380,7 @@ srtp_kdf_generate(srtp_kdf_t *kdf, srtp_prf_label label, v128_set_to_zero(&nonce); nonce.v8[7] = label; - status = cipher_set_iv(kdf->cipher, &nonce); + status = cipher_set_iv(kdf->cipher, &nonce, direction_encrypt); if (status) return status; @@ -401,11 +418,24 @@ srtp_kdf_clear(srtp_kdf_t *kdf) { * TODO: key and salt lengths should be separate fields in the policy. */ static inline int base_key_length(const cipher_type_t *cipher, int key_length) { - if (cipher->id != AES_ICM) - return key_length; - else if (key_length > 16 && key_length < 30) + switch (cipher->id) { + case AES_128_ICM: + case AES_192_ICM: + case AES_256_ICM: + /* The legacy modes are derived from + * the configured key length on the policy */ + return key_length - 14; + break; + case AES_128_GCM: return 16; - return key_length - 14; + break; + case AES_256_GCM: + return 32; + break; + default: + return key_length; + break; + } } err_status_t @@ -427,6 +457,8 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { rtcp_keylen = cipher_get_key_length(srtp->rtcp_cipher); if (rtcp_keylen > kdf_keylen) kdf_keylen = rtcp_keylen; + debug_print(mod_srtp, "srtp key len: %d", rtp_keylen); + debug_print(mod_srtp, "srtcp key len: %d", rtcp_keylen); /* initialize KDF state */ stat = srtp_kdf_init(&kdf, AES_ICM, (const uint8_t *)key, kdf_keylen); @@ -436,6 +468,7 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { rtp_base_key_len = base_key_length(srtp->rtp_cipher->type, rtp_keylen); rtp_salt_len = rtp_keylen - rtp_base_key_len; + debug_print(mod_srtp, "rtp salt len: %d", rtp_salt_len); /* generate encryption key */ stat = srtp_kdf_generate(&kdf, label_rtp_encryption, @@ -461,6 +494,7 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN); return err_status_init_fail; } + memcpy(srtp->salt, tmp_key + rtp_base_key_len, SRTP_AEAD_SALT_LEN); } debug_print(mod_srtp, "cipher key: %s", octet_string_hex_string(tmp_key, rtp_base_key_len)); @@ -470,7 +504,7 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { } /* initialize cipher */ - stat = cipher_init(srtp->rtp_cipher, tmp_key, direction_any); + stat = cipher_init(srtp->rtp_cipher, tmp_key); if (stat) { /* zeroize temp buffer */ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN); @@ -503,6 +537,7 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { rtcp_base_key_len = base_key_length(srtp->rtcp_cipher->type, rtcp_keylen); rtcp_salt_len = rtcp_keylen - rtcp_base_key_len; + debug_print(mod_srtp, "rtcp salt len: %d", rtcp_salt_len); /* generate encryption key */ stat = srtp_kdf_generate(&kdf, label_rtcp_encryption, @@ -529,6 +564,7 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN); return err_status_init_fail; } + memcpy(srtp->c_salt, tmp_key + rtcp_base_key_len, SRTP_AEAD_SALT_LEN); } debug_print(mod_srtp, "rtcp cipher key: %s", octet_string_hex_string(tmp_key, rtcp_base_key_len)); @@ -538,7 +574,7 @@ srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) { } /* initialize cipher */ - stat = cipher_init(srtp->rtcp_cipher, tmp_key, direction_any); + stat = cipher_init(srtp->rtcp_cipher, tmp_key); if (stat) { /* zeroize temp buffer */ octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN); @@ -711,6 +747,365 @@ srtp_stream_init(srtp_stream_ctx_t *srtp, return err_status_ok; } +/* + * AEAD uses a new IV formation method. This function implements + * section 9.1 from draft-ietf-avtcore-srtp-aes-gcm-07.txt. The + * calculation is defined as, where (+) is the xor operation: + * + * + * 0 0 0 0 0 0 0 0 0 0 1 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 + * +--+--+--+--+--+--+--+--+--+--+--+--+ + * |00|00| SSRC | ROC | SEQ |---+ + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | Encryption Salt |->(+) + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | Initialization Vector |<--+ + * +--+--+--+--+--+--+--+--+--+--+--+--+* + * + * Input: *stream - pointer to SRTP stream context, used to retrieve + * the SALT + * *iv - Pointer to receive the calculated IV + * *seq - The ROC and SEQ value to use for the + * IV calculation. + * *hdr - The RTP header, used to get the SSRC value + * + */ +static void srtp_calc_aead_iv(srtp_stream_ctx_t *stream, v128_t *iv, + xtd_seq_num_t *seq, srtp_hdr_t *hdr) +{ + v128_t in; + v128_t salt; + v128_t roc_seq; + + memset(&in, 0, sizeof(v128_t)); + memset(&salt, 0, sizeof(v128_t)); + + /* + * Convert seq# to v128_t so we can manipulate the byte order + */ + v128_copy_octet_string(&roc_seq, (const uint8_t *)seq); + debug_print(mod_srtp, "GCM/CCM ROC/SEQ = %s\n", v128_hex_string(&roc_seq)); + + /* + * Now move ROC and SEQ into input array in the + * proper order + */ + in.v8[11] = roc_seq.v8[0]; + in.v8[10] = roc_seq.v8[1]; + in.v8[9] = roc_seq.v8[2]; + in.v8[8] = roc_seq.v8[3]; + in.v8[7] = roc_seq.v8[4]; + in.v8[6] = roc_seq.v8[5]; + + /* + * Copy in the RTP SSRC value + */ + memcpy(&in.v8[2], &hdr->ssrc, 4); + debug_print(mod_srtp, "Pre-salted RTP IV = %s\n", v128_hex_string(&in)); + + /* + * Get the SALT value from the context + */ + memcpy(salt.v8, stream->salt, SRTP_AEAD_SALT_LEN); + debug_print(mod_srtp, "RTP SALT = %s\n", v128_hex_string(&salt)); + + /* + * Finally, apply tyhe SALT to the input + */ + v128_xor(iv, &in, &salt); +} + + +/* + * This function handles outgoing SRTP packets while in AEAD mode, + * which currently supports AES-GCM encryption. All packets are + * encrypted and authenticated. + */ +static err_status_t +srtp_protect_aead (srtp_ctx_t *ctx, srtp_stream_ctx_t *stream, + void *rtp_hdr, int *pkt_octet_len) +{ + srtp_hdr_t *hdr = (srtp_hdr_t*)rtp_hdr; + uint32_t *enc_start; /* pointer to start of encrypted portion */ + unsigned enc_octet_len = 0; /* number of octets in encrypted portion */ + xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ + int delta; /* delta of local pkt idx and that in hdr */ + err_status_t status; + int tag_len; + v128_t iv; + unsigned int aad_len; + + debug_print(mod_srtp, "function srtp_protect_aead", NULL); + + /* + * update the key usage limit, and check it to make sure that we + * didn't just hit either the soft limit or the hard limit, and call + * the event handler if we hit either. + */ + switch (key_limit_update(stream->limit)) { + case key_event_normal: + break; + case key_event_hard_limit: + srtp_handle_event(ctx, stream, event_key_hard_limit); + return err_status_key_expired; + case key_event_soft_limit: + default: + srtp_handle_event(ctx, stream, event_key_soft_limit); + break; + } + + /* get tag length from stream */ + tag_len = auth_get_tag_length(stream->rtp_auth); + + /* + * find starting point for encryption and length of data to be + * encrypted - the encrypted portion starts after the rtp header + * extension, if present; otherwise, it starts after the last csrc, + * if any are present + * + * if we're not providing confidentiality, set enc_start to NULL + */ + if (stream->rtp_services & sec_serv_conf) { + enc_start = (uint32_t*)hdr + uint32s_in_rtp_header + hdr->cc; + if (hdr->x == 1) { + srtp_hdr_xtnd_t *xtn_hdr = (srtp_hdr_xtnd_t*)enc_start; + enc_start += (ntohs(xtn_hdr->length) + 1); + } + enc_octet_len = (unsigned int)(*pkt_octet_len - + ((enc_start - (uint32_t*)hdr) << 2)); + } else { + enc_start = NULL; + } + + /* + * estimate the packet index using the start of the replay window + * and the sequence number from the header + */ + delta = rdbx_estimate_index(&stream->rtp_rdbx, &est, ntohs(hdr->seq)); + status = rdbx_check(&stream->rtp_rdbx, delta); + if (status) { + if (status != err_status_replay_fail || !stream->allow_repeat_tx) { + return status; /* we've been asked to reuse an index */ + } + } else { + rdbx_add_index(&stream->rtp_rdbx, delta); + } + +#ifdef NO_64BIT_MATH + debug_print2(mod_srtp, "estimated packet index: %08x%08x", + high32(est), low32(est)); +#else + debug_print(mod_srtp, "estimated packet index: %016llx", est); +#endif + + /* + * AEAD uses a new IV formation method + */ + srtp_calc_aead_iv(stream, &iv, &est, hdr); + status = cipher_set_iv(stream->rtp_cipher, &iv, direction_encrypt); + if (status) { + return err_status_cipher_fail; + } + + /* shift est, put into network byte order */ +#ifdef NO_64BIT_MATH + est = be64_to_cpu(make64((high32(est) << 16) | + (low32(est) >> 16), + low32(est) << 16)); +#else + est = be64_to_cpu(est << 16); +#endif + + /* + * Set the AAD over the RTP header + */ + aad_len = (uint8_t *)enc_start - (uint8_t *)hdr; + status = cipher_set_aad(stream->rtp_cipher, (uint8_t*)hdr, aad_len); + if (status) { + return ( err_status_cipher_fail); + } + + /* Encrypt the payload */ + status = cipher_encrypt(stream->rtp_cipher, + (uint8_t*)enc_start, &enc_octet_len); + if (status) { + return err_status_cipher_fail; + } + /* + * If we're doing GCM, we need to get the tag + * and append that to the output + */ + status = cipher_get_tag(stream->rtp_cipher, + (uint8_t*)enc_start+enc_octet_len, &tag_len); + if (status) { + return ( err_status_cipher_fail); + } + enc_octet_len += tag_len; + + /* increase the packet length by the length of the auth tag */ + *pkt_octet_len += tag_len; + + return err_status_ok; +} + + +/* + * This function handles incoming SRTP packets while in AEAD mode, + * which currently supports AES-GCM encryption. All packets are + * encrypted and authenticated. Note, the auth tag is at the end + * of the packet stream and is automatically checked by GCM + * when decrypting the payload. + */ +static err_status_t +srtp_unprotect_aead (srtp_ctx_t *ctx, srtp_stream_ctx_t *stream, int delta, + xtd_seq_num_t est, void *srtp_hdr, int *pkt_octet_len) +{ + srtp_hdr_t *hdr = (srtp_hdr_t*)srtp_hdr; + uint32_t *enc_start; /* pointer to start of encrypted portion */ + unsigned enc_octet_len = 0; /* number of octets in encrypted portion */ + v128_t iv; + err_status_t status; + int tag_len; + unsigned int aad_len; + + debug_print(mod_srtp, "function srtp_unprotect_aead", NULL); + +#ifdef NO_64BIT_MATH + debug_print2(mod_srtp, "estimated u_packet index: %08x%08x", high32(est), low32(est)); +#else + debug_print(mod_srtp, "estimated u_packet index: %016llx", est); +#endif + + /* get tag length from stream */ + tag_len = auth_get_tag_length(stream->rtp_auth); + + /* + * AEAD uses a new IV formation method + */ + srtp_calc_aead_iv(stream, &iv, &est, hdr); + status = cipher_set_iv(stream->rtp_cipher, &iv, direction_decrypt); + if (status) { + return err_status_cipher_fail; + } + + /* + * find starting point for decryption and length of data to be + * decrypted - the encrypted portion starts after the rtp header + * extension, if present; otherwise, it starts after the last csrc, + * if any are present + */ + enc_start = (uint32_t*)hdr + uint32s_in_rtp_header + hdr->cc; + if (hdr->x == 1) { + srtp_hdr_xtnd_t *xtn_hdr = (srtp_hdr_xtnd_t*)enc_start; + enc_start += (ntohs(xtn_hdr->length) + 1); + } + /* + * We pass the tag down to the cipher when doing GCM mode + */ + enc_octet_len = (unsigned int) *pkt_octet_len - + ((enc_start - (uint32_t *)hdr) << 2); + + /* + * update the key usage limit, and check it to make sure that we + * didn't just hit either the soft limit or the hard limit, and call + * the event handler if we hit either. + */ + switch (key_limit_update(stream->limit)) { + case key_event_normal: + break; + case key_event_soft_limit: + srtp_handle_event(ctx, stream, event_key_soft_limit); + break; + case key_event_hard_limit: + srtp_handle_event(ctx, stream, event_key_hard_limit); + return err_status_key_expired; + default: + break; + } + + /* + * Set the AAD for AES-GCM, which is the RTP header + */ + aad_len = (uint8_t *)enc_start - (uint8_t *)hdr; + status = cipher_set_aad(stream->rtp_cipher, (uint8_t*)hdr, aad_len); + if (status) { + return ( err_status_cipher_fail); + } + + /* Decrypt the ciphertext. This also checks the auth tag based + * on the AAD we just specified above */ + status = cipher_decrypt(stream->rtp_cipher, + (uint8_t*)enc_start, &enc_octet_len); + if (status) { + return status; + } + + /* + * verify that stream is for received traffic - this check will + * detect SSRC collisions, since a stream that appears in both + * srtp_protect() and srtp_unprotect() will fail this test in one of + * those functions. + * + * we do this check *after* the authentication check, so that the + * latter check will catch any attempts to fool us into thinking + * that we've got a collision + */ + if (stream->direction != dir_srtp_receiver) { + if (stream->direction == dir_unknown) { + stream->direction = dir_srtp_receiver; + } else { + srtp_handle_event(ctx, stream, event_ssrc_collision); + } + } + + /* + * if the stream is a 'provisional' one, in which the template context + * is used, then we need to allocate a new stream at this point, since + * the authentication passed + */ + if (stream == ctx->stream_template) { + srtp_stream_ctx_t *new_stream; + + /* + * allocate and initialize a new stream + * + * note that we indicate failure if we can't allocate the new + * stream, and some implementations will want to not return + * failure here + */ + status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); + if (status) { + return status; + } + + /* add new stream to the head of the stream_list */ + new_stream->next = ctx->stream_list; + ctx->stream_list = new_stream; + + /* set stream (the pointer used in this function) */ + stream = new_stream; + } + + /* + * the message authentication function passed, so add the packet + * index into the replay database + */ + rdbx_add_index(&stream->rtp_rdbx, delta); + + /* decrease the packet length by the length of the auth tag */ + *pkt_octet_len -= tag_len; + + return err_status_ok; +} + + + + err_status_t srtp_protect(srtp_ctx_t *ctx, void *rtp_hdr, int *pkt_octet_len) { srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; @@ -772,13 +1167,22 @@ srtp_stream_init(srtp_stream_ctx_t *srtp, * srtp_protect() and srtp_unprotect() will fail this test in one of * those functions. */ - if (stream->direction != dir_srtp_sender) { + if (stream->direction != dir_srtp_sender) { if (stream->direction == dir_unknown) { stream->direction = dir_srtp_sender; } else { srtp_handle_event(ctx, stream, event_ssrc_collision); } - } + } + + /* + * Check if this is an AEAD stream (GCM mode). If so, then dispatch + * the request to our AEAD handler. + */ + if (stream->rtp_cipher->algorithm == AES_128_GCM || + stream->rtp_cipher->algorithm == AES_256_GCM) { + return srtp_protect_aead(ctx, stream, rtp_hdr, pkt_octet_len); + } /* * update the key usage limit, and check it to make sure that we @@ -857,7 +1261,8 @@ srtp_stream_init(srtp_stream_ctx_t *srtp, /* * if we're using rindael counter mode, set nonce and seq */ - if (stream->rtp_cipher->type->id == AES_ICM) { + if (stream->rtp_cipher->type->id == AES_ICM || + stream->rtp_cipher->type->id == AES_256_ICM) { v128_t iv; iv.v32[0] = 0; @@ -868,7 +1273,7 @@ srtp_stream_init(srtp_stream_ctx_t *srtp, #else iv.v64[1] = be64_to_cpu(est << 16); #endif - status = cipher_set_iv(stream->rtp_cipher, &iv); + status = cipher_set_iv(stream->rtp_cipher, &iv, direction_encrypt); } else { v128_t iv; @@ -881,7 +1286,7 @@ srtp_stream_init(srtp_stream_ctx_t *srtp, iv.v64[0] = 0; #endif iv.v64[1] = be64_to_cpu(est); - status = cipher_set_iv(stream->rtp_cipher, &iv); + status = cipher_set_iv(stream->rtp_cipher, &iv, direction_encrypt); } if (status) return err_status_cipher_fail; @@ -1027,6 +1432,15 @@ srtp_unprotect(srtp_ctx_t *ctx, void *srtp_hdr, int *pkt_octet_len) { debug_print(mod_srtp, "estimated u_packet index: %016llx", est); #endif + /* + * Check if this is an AEAD stream (GCM mode). If so, then dispatch + * the request to our AEAD handler. + */ + if (stream->rtp_cipher->algorithm == AES_128_GCM || + stream->rtp_cipher->algorithm == AES_256_GCM) { + return srtp_unprotect_aead(ctx, stream, delta, est, srtp_hdr, pkt_octet_len); + } + /* get tag length from stream */ tag_len = auth_get_tag_length(stream->rtp_auth); @@ -1034,7 +1448,8 @@ srtp_unprotect(srtp_ctx_t *ctx, void *srtp_hdr, int *pkt_octet_len) { * set the cipher's IV properly, depending on whatever cipher we * happen to be using */ - if (stream->rtp_cipher->type->id == AES_ICM) { + if (stream->rtp_cipher->type->id == AES_ICM || + stream->rtp_cipher->type->id == AES_256_ICM) { /* aes counter mode */ iv.v32[0] = 0; @@ -1045,7 +1460,7 @@ srtp_unprotect(srtp_ctx_t *ctx, void *srtp_hdr, int *pkt_octet_len) { #else iv.v64[1] = be64_to_cpu(est << 16); #endif - status = cipher_set_iv(stream->rtp_cipher, &iv); + status = cipher_set_iv(stream->rtp_cipher, &iv, direction_decrypt); } else { /* no particular format - set the iv to the pakcet index */ @@ -1056,7 +1471,7 @@ srtp_unprotect(srtp_ctx_t *ctx, void *srtp_hdr, int *pkt_octet_len) { iv.v64[0] = 0; #endif iv.v64[1] = be64_to_cpu(est); - status = cipher_set_iv(stream->rtp_cipher, &iv); + status = cipher_set_iv(stream->rtp_cipher, &iv, direction_decrypt); } if (status) return err_status_cipher_fail; @@ -1613,11 +2028,470 @@ crypto_policy_set_aes_cm_256_hmac_sha1_32(crypto_policy_t *p) { p->sec_serv = sec_serv_conf_and_auth; } +/* + * AES-256 with no authentication. + */ +void +crypto_policy_set_aes_cm_256_null_auth (crypto_policy_t *p) +{ + p->cipher_type = AES_ICM; + p->cipher_key_len = 46; + p->auth_type = NULL_AUTH; + p->auth_key_len = 0; + p->auth_tag_len = 0; + p->sec_serv = sec_serv_conf; +} + +#ifdef OPENSSL +/* + * AES-128 GCM mode with 8 octet auth tag. + */ +void +crypto_policy_set_aes_gcm_128_8_auth(crypto_policy_t *p) { + p->cipher_type = AES_128_GCM; + p->cipher_key_len = AES_128_KEYSIZE_WSALT; + p->auth_type = NULL_AUTH; /* GCM handles the auth for us */ + p->auth_key_len = 0; + p->auth_tag_len = 8; /* 8 octet tag length */ + p->sec_serv = sec_serv_conf_and_auth; +} + +/* + * AES-256 GCM mode with 8 octet auth tag. + */ +void +crypto_policy_set_aes_gcm_256_8_auth(crypto_policy_t *p) { + p->cipher_type = AES_256_GCM; + p->cipher_key_len = AES_256_KEYSIZE_WSALT; + p->auth_type = NULL_AUTH; /* GCM handles the auth for us */ + p->auth_key_len = 0; + p->auth_tag_len = 8; /* 8 octet tag length */ + p->sec_serv = sec_serv_conf_and_auth; +} + +/* + * AES-128 GCM mode with 8 octet auth tag, no RTCP encryption. + */ +void +crypto_policy_set_aes_gcm_128_8_only_auth(crypto_policy_t *p) { + p->cipher_type = AES_128_GCM; + p->cipher_key_len = AES_128_KEYSIZE_WSALT; + p->auth_type = NULL_AUTH; /* GCM handles the auth for us */ + p->auth_key_len = 0; + p->auth_tag_len = 8; /* 8 octet tag length */ + p->sec_serv = sec_serv_auth; /* This only applies to RTCP */ +} + +/* + * AES-256 GCM mode with 8 octet auth tag, no RTCP encryption. + */ +void +crypto_policy_set_aes_gcm_256_8_only_auth(crypto_policy_t *p) { + p->cipher_type = AES_256_GCM; + p->cipher_key_len = AES_256_KEYSIZE_WSALT; + p->auth_type = NULL_AUTH; /* GCM handles the auth for us */ + p->auth_key_len = 0; + p->auth_tag_len = 8; /* 8 octet tag length */ + p->sec_serv = sec_serv_auth; /* This only applies to RTCP */ +} +#endif /* * secure rtcp functions */ +/* + * AEAD uses a new IV formation method. This function implements + * section 10.1 from draft-ietf-avtcore-srtp-aes-gcm-07.txt. The + * calculation is defined as, where (+) is the xor operation: + * + * 0 1 2 3 4 5 6 7 8 9 10 11 + * +--+--+--+--+--+--+--+--+--+--+--+--+ + * |00|00| SSRC |00|00|0+SRTCP Idx|---+ + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | Encryption Salt |->(+) + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | + * +--+--+--+--+--+--+--+--+--+--+--+--+ | + * | Initialization Vector |<--+ + * +--+--+--+--+--+--+--+--+--+--+--+--+* + * + * Input: *stream - pointer to SRTP stream context, used to retrieve + * the SALT + * *iv - Pointer to recieve the calculated IV + * seq_num - The SEQ value to use for the IV calculation. + * *hdr - The RTP header, used to get the SSRC value + * + */ +static void srtp_calc_aead_iv_srtcp(srtp_stream_ctx_t *stream, v128_t *iv, + uint32_t seq_num, srtcp_hdr_t *hdr) +{ + v128_t in; + v128_t salt; + + memset(&in, 0, sizeof(v128_t)); + memset(&salt, 0, sizeof(v128_t)); + + in.v16[0] = 0; + memcpy(&in.v16[1], &hdr->ssrc, 4); /* still in network order! */ + in.v16[3] = 0; + in.v32[2] = 0x7FFFFFFF & htonl(seq_num); /* bit 32 is suppose to be zero */ + + debug_print(mod_srtp, "Pre-salted RTCP IV = %s\n", v128_hex_string(&in)); + + /* + * Get the SALT value from the context + */ + memcpy(salt.v8, stream->c_salt, 12); + debug_print(mod_srtp, "RTCP SALT = %s\n", v128_hex_string(&salt)); + + /* + * Finally, apply the SALT to the input + */ + v128_xor(iv, &in, &salt); +} + +/* + * This code handles AEAD ciphers for outgoing RTCP. We currently support + * AES-GCM mode with 128 or 256 bit keys. + */ +static err_status_t +srtp_protect_rtcp_aead (srtp_t ctx, srtp_stream_ctx_t *stream, + void *rtcp_hdr, int *pkt_octet_len) +{ + srtcp_hdr_t *hdr = (srtcp_hdr_t*)rtcp_hdr; + uint32_t *enc_start; /* pointer to start of encrypted portion */ + uint32_t *trailer; /* pointer to start of trailer */ + unsigned enc_octet_len = 0; /* number of octets in encrypted portion */ + uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + err_status_t status; + int tag_len; + uint32_t seq_num; + v128_t iv; + uint32_t tseq; + + /* get tag length from stream context */ + tag_len = auth_get_tag_length(stream->rtcp_auth); + + /* + * set encryption start and encryption length - if we're not + * providing confidentiality, set enc_start to NULL + */ + enc_start = (uint32_t*)hdr + uint32s_in_rtcp_header; + enc_octet_len = *pkt_octet_len - octets_in_rtcp_header; + + /* NOTE: hdr->length is not usable - it refers to only the first + RTCP report in the compound packet! */ + /* NOTE: trailer is 32-bit aligned because RTCP 'packets' are always + multiples of 32-bits (RFC 3550 6.1) */ + trailer = (uint32_t*)((char*)enc_start + enc_octet_len + tag_len); + + if (stream->rtcp_services & sec_serv_conf) { + *trailer = htonl(SRTCP_E_BIT); /* set encrypt bit */ + } else { + enc_start = NULL; + enc_octet_len = 0; + /* 0 is network-order independant */ + *trailer = 0x00000000; /* set encrypt bit */ + } + + /* + * set the auth_tag pointer to the proper location, which is after + * the payload, but before the trailer + * (note that srtpc *always* provides authentication, unlike srtp) + */ + /* Note: This would need to change for optional mikey data */ + auth_tag = (uint8_t*)hdr + *pkt_octet_len; + + /* + * check sequence number for overruns, and copy it into the packet + * if its value isn't too big + */ + status = rdb_increment(&stream->rtcp_rdb); + if (status) { + return status; + } + seq_num = rdb_get_value(&stream->rtcp_rdb); + *trailer |= htonl(seq_num); + debug_print(mod_srtp, "srtcp index: %x", seq_num); + + /* + * Calculating the IV and pass it down to the cipher + */ + srtp_calc_aead_iv_srtcp(stream, &iv, seq_num, hdr); + status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_encrypt); + if (status) { + return err_status_cipher_fail; + } + + /* + * Set the AAD for GCM mode + */ + if (enc_start) { + /* + * If payload encryption is enabled, then the AAD consist of + * the RTCP header and the seq# at the end of the packet + */ + status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, + octets_in_rtcp_header); + if (status) { + return ( err_status_cipher_fail); + } + } else { + /* + * Since payload encryption is not enabled, we must authenticate + * the entire packet as described in section 10.3 in revision 07 + * of the draft. + */ + status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, + *pkt_octet_len); + if (status) { + return ( err_status_cipher_fail); + } + } + /* + * put the idx# into network byte order and process it as AAD + */ + tseq = htonl(*trailer); + status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)&tseq, + sizeof(srtcp_trailer_t)); + if (status) { + return ( err_status_cipher_fail); + } + + /* if we're encrypting, exor keystream into the message */ + if (enc_start) { + status = cipher_encrypt(stream->rtcp_cipher, + (uint8_t*)enc_start, &enc_octet_len); + if (status) { + return err_status_cipher_fail; + } + /* + * Get the tag and append that to the output + */ + status = cipher_get_tag(stream->rtcp_cipher, (uint8_t*)auth_tag, + &tag_len); + if (status) { + return ( err_status_cipher_fail); + } + enc_octet_len += tag_len; + } else { + /* + * Even though we're not encrypting the payload, we need + * to run the cipher to get the auth tag. + */ + unsigned nolen = 0; + status = cipher_encrypt(stream->rtcp_cipher, NULL, &nolen); + if (status) { + return err_status_cipher_fail; + } + /* + * Get the tag and append that to the output + */ + status = cipher_get_tag(stream->rtcp_cipher, (uint8_t*)auth_tag, + &tag_len); + if (status) { + return ( err_status_cipher_fail); + } + enc_octet_len += tag_len; + } + + /* increase the packet length by the length of the auth tag and seq_num*/ + *pkt_octet_len += (tag_len + sizeof(srtcp_trailer_t)); + + return err_status_ok; +} + +/* + * This function handles incoming SRTCP packets while in AEAD mode, + * which currently supports AES-GCM encryption. Note, the auth tag is + * at the end of the packet stream and is automatically checked by GCM + * when decrypting the payload. + */ +static err_status_t +srtp_unprotect_rtcp_aead (srtp_t ctx, srtp_stream_ctx_t *stream, + void *srtcp_hdr, int *pkt_octet_len) +{ + srtcp_hdr_t *hdr = (srtcp_hdr_t*)srtcp_hdr; + uint32_t *enc_start; /* pointer to start of encrypted portion */ + uint32_t *trailer; /* pointer to start of trailer */ + unsigned enc_octet_len = 0; /* number of octets in encrypted portion */ + uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + err_status_t status; + int tag_len; + unsigned int tmp_len; + uint32_t seq_num; + v128_t iv; + uint32_t tseq; + + /* get tag length from stream context */ + tag_len = auth_get_tag_length(stream->rtcp_auth); + + /* Validate packet length */ + if (*pkt_octet_len < (octets_in_rtcp_header + tag_len + + sizeof(srtcp_trailer_t))) { + return err_status_bad_param; + } + + /* + * set encryption start, encryption length, and trailer + */ + /* index & E (encryption) bit follow normal data. hdr->len + is the number of words (32-bit) in the normal packet minus 1 */ + /* This should point trailer to the word past the end of the + normal data. */ + /* This would need to be modified for optional mikey data */ + /* + * NOTE: trailer is 32-bit aligned because RTCP 'packets' are always + * multiples of 32-bits (RFC 3550 6.1) + */ + trailer = (uint32_t*)((char*)hdr + *pkt_octet_len - sizeof(srtcp_trailer_t)); + /* + * We pass the tag down to the cipher when doing GCM mode + */ + enc_octet_len = *pkt_octet_len - (octets_in_rtcp_header + + sizeof(srtcp_trailer_t)); + auth_tag = (uint8_t*)hdr + *pkt_octet_len - tag_len - sizeof(srtcp_trailer_t); + + if (*((unsigned char*)trailer) & SRTCP_E_BYTE_BIT) { + enc_start = (uint32_t*)hdr + uint32s_in_rtcp_header; + } else { + enc_octet_len = 0; + enc_start = NULL; /* this indicates that there's no encryption */ + } + + /* + * check the sequence number for replays + */ + /* this is easier than dealing with bitfield access */ + seq_num = ntohl(*trailer) & SRTCP_INDEX_MASK; + debug_print(mod_srtp, "srtcp index: %x", seq_num); + status = rdb_check(&stream->rtcp_rdb, seq_num); + if (status) { + return status; + } + + /* + * Calculate and set the IV + */ + srtp_calc_aead_iv_srtcp(stream, &iv, seq_num, hdr); + status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt); + if (status) { + return err_status_cipher_fail; + } + + /* + * Set the AAD for GCM mode + */ + if (enc_start) { + /* + * If payload encryption is enabled, then the AAD consist of + * the RTCP header and the seq# at the end of the packet + */ + status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, + octets_in_rtcp_header); + if (status) { + return ( err_status_cipher_fail); + } + } else { + /* + * Since payload encryption is not enabled, we must authenticate + * the entire packet as described in section 10.3 in revision 07 + * of the draft. + */ + status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, + (*pkt_octet_len - tag_len - sizeof(srtcp_trailer_t))); + if (status) { + return ( err_status_cipher_fail); + } + } + + /* + * put the idx# into network byte order, and process it as AAD + */ + tseq = htonl(*trailer); + status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)&tseq, + sizeof(srtcp_trailer_t)); + if (status) { + return ( err_status_cipher_fail); + } + + /* if we're decrypting, exor keystream into the message */ + if (enc_start) { + status = cipher_decrypt(stream->rtcp_cipher, + (uint8_t*)enc_start, &enc_octet_len); + if (status) { + return status; + } + } else { + /* + * Still need to run the cipher to check the tag + */ + tmp_len = tag_len; + status = cipher_decrypt(stream->rtcp_cipher, (uint8_t*)auth_tag, + &tmp_len); + if (status) { + return status; + } + } + + /* decrease the packet length by the length of the auth tag and seq_num*/ + *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t)); + + /* + * verify that stream is for received traffic - this check will + * detect SSRC collisions, since a stream that appears in both + * srtp_protect() and srtp_unprotect() will fail this test in one of + * those functions. + * + * we do this check *after* the authentication check, so that the + * latter check will catch any attempts to fool us into thinking + * that we've got a collision + */ + if (stream->direction != dir_srtp_receiver) { + if (stream->direction == dir_unknown) { + stream->direction = dir_srtp_receiver; + } else { + srtp_handle_event(ctx, stream, event_ssrc_collision); + } + } + + /* + * if the stream is a 'provisional' one, in which the template context + * is used, then we need to allocate a new stream at this point, since + * the authentication passed + */ + if (stream == ctx->stream_template) { + srtp_stream_ctx_t *new_stream; + + /* + * allocate and initialize a new stream + * + * note that we indicate failure if we can't allocate the new + * stream, and some implementations will want to not return + * failure here + */ + status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); + if (status) { + return status; + } + + /* add new stream to the head of the stream_list */ + new_stream->next = ctx->stream_list; + ctx->stream_list = new_stream; + + /* set stream (the pointer used in this function) */ + stream = new_stream; + } + + /* we've passed the authentication check, so add seq_num to the rdb */ + rdb_add_index(&stream->rtcp_rdb, seq_num); + + return err_status_ok; +} + err_status_t srtp_protect_rtcp(srtp_t ctx, void *rtcp_hdr, int *pkt_octet_len) { srtcp_hdr_t *hdr = (srtcp_hdr_t *)rtcp_hdr; @@ -1677,6 +2551,15 @@ srtp_protect_rtcp(srtp_t ctx, void *rtcp_hdr, int *pkt_octet_len) { } } + /* + * Check if this is an AEAD stream (GCM mode). If so, then dispatch + * the request to our AEAD handler. + */ + if (stream->rtp_cipher->algorithm == AES_128_GCM || + stream->rtp_cipher->algorithm == AES_256_GCM) { + return srtp_protect_rtcp_aead(ctx, stream, rtcp_hdr, pkt_octet_len); + } + /* get tag length from stream context */ tag_len = auth_get_tag_length(stream->rtcp_auth); @@ -1736,7 +2619,7 @@ srtp_protect_rtcp(srtp_t ctx, void *rtcp_hdr, int *pkt_octet_len) { iv.v32[1] = hdr->ssrc; /* still in network order! */ iv.v32[2] = htonl(seq_num >> 16); iv.v32[3] = htonl(seq_num << 16); - status = cipher_set_iv(stream->rtcp_cipher, &iv); + status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_encrypt); } else { v128_t iv; @@ -1746,7 +2629,7 @@ srtp_protect_rtcp(srtp_t ctx, void *rtcp_hdr, int *pkt_octet_len) { iv.v32[1] = 0; iv.v32[2] = 0; iv.v32[3] = htonl(seq_num); - status = cipher_set_iv(stream->rtcp_cipher, &iv); + status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_encrypt); } if (status) return err_status_cipher_fail; @@ -1857,6 +2740,15 @@ srtp_unprotect_rtcp(srtp_t ctx, void *srtcp_hdr, int *pkt_octet_len) { } } + /* + * Check if this is an AEAD stream (GCM mode). If so, then dispatch + * the request to our AEAD handler. + */ + if (stream->rtp_cipher->algorithm == AES_128_GCM || + stream->rtp_cipher->algorithm == AES_256_GCM) { + return srtp_unprotect_rtcp_aead(ctx, stream, srtcp_hdr, pkt_octet_len); + } + sec_serv_confidentiality = stream->rtcp_services == sec_serv_conf || stream->rtcp_services == sec_serv_conf_and_auth; @@ -1934,7 +2826,7 @@ srtp_unprotect_rtcp(srtp_t ctx, void *srtcp_hdr, int *pkt_octet_len) { iv.v32[1] = hdr->ssrc; /* still in network order! */ iv.v32[2] = htonl(seq_num >> 16); iv.v32[3] = htonl(seq_num << 16); - status = cipher_set_iv(stream->rtcp_cipher, &iv); + status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt); } else { v128_t iv; @@ -1944,7 +2836,7 @@ srtp_unprotect_rtcp(srtp_t ctx, void *srtcp_hdr, int *pkt_octet_len) { iv.v32[1] = 0; iv.v32[2] = 0; iv.v32[3] = htonl(seq_num); - status = cipher_set_iv(stream->rtcp_cipher, &iv); + status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt); } if (status) diff --git a/libs/srtp/test/rtpw.c b/libs/srtp/test/rtpw.c index f18d42045e..ae902689d0 100644 --- a/libs/srtp/test/rtpw.c +++ b/libs/srtp/test/rtpw.c @@ -90,8 +90,7 @@ #define USEC_RATE (5e5) #define MAX_WORD_LEN 128 #define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a)) -#define MAX_KEY_LEN 64 -#define MASTER_KEY_LEN 30 +#define MAX_KEY_LEN 96 #ifndef HAVE_USLEEP @@ -153,6 +152,8 @@ main (int argc, char *argv[]) { sec_serv_t sec_servs = sec_serv_none; unsigned char ttl = 5; int c; + int key_size = 128; + int gcm_on = 0; char *input_key = NULL; char *address = NULL; char key[MAX_KEY_LEN]; @@ -187,7 +188,7 @@ main (int argc, char *argv[]) { /* check args */ while (1) { - c = getopt_s(argc, argv, "k:rsaeld:"); + c = getopt_s(argc, argv, "k:rsgae:ld:"); if (c == -1) { break; } @@ -196,11 +197,20 @@ main (int argc, char *argv[]) { input_key = optarg_s; break; case 'e': + key_size = atoi(optarg_s); + if (key_size != 128 && key_size != 256) { + printf("error: encryption key size must be 128 or 256 (%d)\n", key_size); + exit(1); + } sec_servs |= sec_serv_conf; break; case 'a': sec_servs |= sec_serv_auth; break; + case 'g': + gcm_on = 1; + sec_servs |= sec_serv_auth; + break; case 'r': prog_type = receiver; break; @@ -331,16 +341,73 @@ main (int argc, char *argv[]) { */ switch (sec_servs) { case sec_serv_conf_and_auth: - crypto_policy_set_rtp_default(&policy.rtp); - crypto_policy_set_rtcp_default(&policy.rtcp); + if (gcm_on) { +#ifdef OPENSSL + switch (key_size) { + case 128: + crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp); + crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp); + break; + case 256: + crypto_policy_set_aes_gcm_256_8_auth(&policy.rtp); + crypto_policy_set_aes_gcm_256_8_auth(&policy.rtcp); + break; + } +#else + printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); + return 0; +#endif + } else { + switch (key_size) { + case 128: + crypto_policy_set_rtp_default(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + case 256: + crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + } + } break; case sec_serv_conf: - crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); - crypto_policy_set_rtcp_default(&policy.rtcp); + if (gcm_on) { + printf("error: GCM mode must always be used with auth enabled\n"); + return -1; + } else { + switch (key_size) { + case 128: + crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + case 256: + crypto_policy_set_aes_cm_256_null_auth(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + break; + } + } break; case sec_serv_auth: - crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); - crypto_policy_set_rtcp_default(&policy.rtcp); + if (gcm_on) { +#ifdef OPENSSL + switch (key_size) { + case 128: + crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtp); + crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtcp); + break; + case 256: + crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtp); + crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtcp); + break; + } +#else + printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); + return 0; +#endif + } else { + crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); + crypto_policy_set_rtcp_default(&policy.rtcp); + } break; default: printf("error: unknown security service requested\n"); @@ -359,21 +426,21 @@ main (int argc, char *argv[]) { /* * read key from hexadecimal on command line into an octet string */ - len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN*2); + len = hex_string_to_octet_string(key, input_key, policy.rtp.cipher_key_len*2); /* check that hex string is the right length */ - if (len < MASTER_KEY_LEN*2) { + if (len < policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", - MASTER_KEY_LEN*2, len); + policy.rtp.cipher_key_len*2, len); exit(1); } - if (strlen(input_key) > MASTER_KEY_LEN*2) { + if (strlen(input_key) > policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", - MASTER_KEY_LEN*2, (unsigned)strlen(input_key)); + policy.rtp.cipher_key_len*2, (unsigned)strlen(input_key)); exit(1); } @@ -541,7 +608,8 @@ usage(char *string) { "[-s | -r] dest_ip dest_port\n" "or %s -l\n" "where -a use message authentication\n" - " -e use encryption\n" + " -e use encryption (use 128 or 256 for key size)\n" + " -g Use AES-GCM mode (must be used with -e)\n" " -k sets the srtp master key\n" " -s act as rtp sender\n" " -r act as rtp receiver\n" diff --git a/libs/srtp/test/rtpw_test.sh b/libs/srtp/test/rtpw_test.sh index b5d66ee0a5..c3c32caf6b 100755 --- a/libs/srtp/test/rtpw_test.sh +++ b/libs/srtp/test/rtpw_test.sh @@ -10,7 +10,7 @@ DURATION=3 key=2b2edc5034f61a72345ca5986d7bfd0189aa6dc2ecab32fd9af74df6dfc6 -ARGS="-k $key -ae" +ARGS="-k $key -a -e 128" # First, we run "killall" to get rid of all existing rtpw processes. # This step also enables this script to clean up after itself; if this @@ -66,6 +66,55 @@ kill $sender_pid wait $receiver_pid wait $sender_pid + +key=033490ba9e82994fc21013395739038992b2edc5034f61a72345ca598d7bfd0189aa6dc2ecab32fd9af74df6dfc6 + +ARGS="-k $key -a -e 256" + +echo $0 ": starting rtpw receiver process... " + +$RTPW $* $ARGS -r 0.0.0.0 $DEST_PORT & + +receiver_pid=$! + +echo $0 ": receiver PID = $receiver_pid" + +sleep 1 + +# verify that the background job is running +ps | grep -q $receiver_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 254 +fi + +echo $0 ": starting rtpw sender process..." + +$RTPW $* $ARGS -s 127.0.0.1 $DEST_PORT & + +sender_pid=$! + +echo $0 ": sender PID = $sender_pid" + +# verify that the background job is running +ps | grep -q $sender_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 255 +fi + +sleep $DURATION + +kill $receiver_pid +kill $sender_pid + +wait $receiver_pid +wait $sender_pid + echo $0 ": done (test passed)" else diff --git a/libs/srtp/test/rtpw_test_gcm.sh b/libs/srtp/test/rtpw_test_gcm.sh new file mode 100644 index 0000000000..dfac33514e --- /dev/null +++ b/libs/srtp/test/rtpw_test_gcm.sh @@ -0,0 +1,119 @@ +#!/bin/sh +# +# usage: rtpw_test +# +# tests the rtpw sender and receiver functions + +RTPW=./rtpw +DEST_PORT=9999 +DURATION=3 + +# First, we run "killall" to get rid of all existing rtpw processes. +# This step also enables this script to clean up after itself; if this +# script is interrupted after the rtpw processes are started but before +# they are killed, those processes will linger. Re-running the script +# will get rid of them. + +killall rtpw 2>/dev/null + +if test -x $RTPW; then + +GCMARGS128="-k 012345678901234567890123456789012345678901234567890123456789 -g -e 128" +echo $0 ": starting GCM mode 128-bit rtpw receiver process... " + +exec $RTPW $* $GCMARGS128 -r 127.0.0.1 $DEST_PORT & + +receiver_pid=$! + +echo $0 ": receiver PID = $receiver_pid" + +sleep 1 + +# verify that the background job is running +ps | grep -q $receiver_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 254 +fi + +echo $0 ": starting GCM 128-bit rtpw sender process..." + +exec $RTPW $* $GCMARGS128 -s 127.0.0.1 $DEST_PORT & + +sender_pid=$! + +echo $0 ": sender PID = $sender_pid" + +# verify that the background job is running +ps | grep -q $sender_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 255 +fi + +sleep $DURATION + +kill $receiver_pid +kill $sender_pid + + + +GCMARGS256="-k 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901 -g -e 256" +echo $0 ": starting GCM mode 256-bit rtpw receiver process... " + +exec $RTPW $* $GCMARGS256 -r 127.0.0.1 $DEST_PORT & + +receiver_pid=$! + +echo $0 ": receiver PID = $receiver_pid" + +sleep 1 + +# verify that the background job is running +ps | grep -q $receiver_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 254 +fi + +echo $0 ": starting GCM 256-bit rtpw sender process..." + +exec $RTPW $* $GCMARGS256 -s 127.0.0.1 $DEST_PORT & + +sender_pid=$! + +echo $0 ": sender PID = $sender_pid" + +# verify that the background job is running +ps | grep -q $sender_pid +retval=$? +echo $retval +if [ $retval != 0 ]; then + echo $0 ": error" + exit 255 +fi + +sleep $DURATION + +kill $receiver_pid +kill $sender_pid + + +echo $0 ": done (test passed)" + +else + +echo "error: can't find executable" $RTPW +exit 1 + +fi + +# EOF + + diff --git a/libs/srtp/test/srtp_driver.c b/libs/srtp/test/srtp_driver.c index a1b48661f0..783d5182e3 100644 --- a/libs/srtp/test/srtp_driver.c +++ b/libs/srtp/test/srtp_driver.c @@ -104,7 +104,7 @@ srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len); double mips_estimate(int num_trials, int *ignore); -extern uint8_t test_key[30]; +extern uint8_t test_key[46]; void usage(char *prog_name) { @@ -288,6 +288,8 @@ main (int argc, char *argv[]) { exit(1); } +//FIXME: need to get this working with the OpenSSL AES module +#ifndef OPENSSL /* * run validation test against the reference packets for * AES-256 @@ -300,6 +302,7 @@ main (int argc, char *argv[]) { printf("failed\n"); exit(1); } +#endif /* * test the function srtp_remove_stream() @@ -1527,10 +1530,12 @@ srtp_test_remove_stream() { * srtp policy definitions - these definitions are used above */ -unsigned char test_key[30] = { +unsigned char test_key[46] = { 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0, 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39, 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb, + 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6, 0xc1, 0x73, + 0xc3, 0x17, 0xf2, 0xda, 0xbe, 0x35, 0x77, 0x93, 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6 }; @@ -1660,6 +1665,108 @@ const srtp_policy_t hmac_only_policy = { NULL }; +#ifdef OPENSSL +const srtp_policy_t aes128_gcm_8_policy = { + { ssrc_any_outbound, 0 }, /* SSRC */ + { /* SRTP policy */ + AES_128_GCM, /* cipher type */ + 30, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + { /* SRTCP policy */ + AES_128_GCM, /* cipher type */ + 30, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + test_key, + NULL, /* indicates that EKT is not in use */ + 128, /* replay window size */ + 0, /* retransmission not allowed */ + NULL +}; + +const srtp_policy_t aes128_gcm_8_cauth_policy = { + { ssrc_any_outbound, 0 }, /* SSRC */ + { /* SRTP policy */ + AES_128_GCM, /* cipher type */ + 30, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + { /* SRTCP policy */ + AES_128_GCM, /* cipher type */ + 30, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_auth /* security services flag */ + }, + test_key, + NULL, /* indicates that EKT is not in use */ + 128, /* replay window size */ + 0, /* retransmission not allowed */ + NULL +}; + +const srtp_policy_t aes256_gcm_8_policy = { + { ssrc_any_outbound, 0 }, /* SSRC */ + { /* SRTP policy */ + AES_256_GCM, /* cipher type */ + 46, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + { /* SRTCP policy */ + AES_256_GCM, /* cipher type */ + 46, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + test_key, + NULL, /* indicates that EKT is not in use */ + 128, /* replay window size */ + 0, /* retransmission not allowed */ + NULL +}; + +const srtp_policy_t aes256_gcm_8_cauth_policy = { + { ssrc_any_outbound, 0 }, /* SSRC */ + { /* SRTP policy */ + AES_256_GCM, /* cipher type */ + 46, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + { /* SRTCP policy */ + AES_256_GCM, /* cipher type */ + 46, /* cipher key length in octets */ + NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 8, /* auth tag length in octets */ + sec_serv_auth /* security services flag */ + }, + test_key, + NULL, /* indicates that EKT is not in use */ + 128, /* replay window size */ + 0, /* retransmission not allowed */ + NULL +}; +#endif + const srtp_policy_t null_policy = { { ssrc_any_outbound, 0 }, /* SSRC */ { @@ -1783,6 +1890,12 @@ policy_array[] = { &aes_tmmh_policy, #endif &default_policy, +#ifdef OPENSSL + &aes128_gcm_8_policy, + &aes128_gcm_8_cauth_policy, + &aes256_gcm_8_policy, + &aes256_gcm_8_cauth_policy, +#endif &null_policy, &aes_256_hmac_policy, &hmac_only_with_ekt_policy,