From 5e5c8538077aeb1cb53e1c58ced58eabe1e23fbd Mon Sep 17 00:00:00 2001 From: Linus Yang Date: Sun, 9 Mar 2014 17:02:06 +0800 Subject: [PATCH] darwin: initial support for CommonCrypto API --- config.h.in | 9 +++ configure | 42 ++++++++++++++ configure.ac | 15 +++++ src/encrypt.c | 155 +++++++++++++++++++++++++++++++++++++++++++------- src/encrypt.h | 34 ++++++++++- 5 files changed, 233 insertions(+), 22 deletions(-) diff --git a/config.h.in b/config.h.in index 75c1a6be..ae942160 100644 --- a/config.h.in +++ b/config.h.in @@ -18,12 +18,18 @@ /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H +/* Define to 1 if you have the `CCCryptorCreateWithMode' function. */ +#undef HAVE_CCCRYPTORCREATEWITHMODE + /* Define to 1 if you have the `clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME /* Define to 1 to use the syscall interface for clock_gettime */ #undef HAVE_CLOCK_SYSCALL +/* Define to 1 if you have the header file. */ +#undef HAVE_COMMONCRYPTO_COMMONCRYPTO_H + /* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you don't. */ #undef HAVE_DECL_INET_NTOP @@ -276,6 +282,9 @@ /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME +/* Use Apple CommonCrypto library */ +#undef USE_CRYPTO_APPLECC + /* Use OpenSSL library */ #undef USE_CRYPTO_OPENSSL diff --git a/configure b/configure index a9d94a7d..00f4a8c3 100755 --- a/configure +++ b/configure @@ -752,6 +752,7 @@ with_openssl_lib with_polarssl with_polarssl_include with_polarssl_lib +enable_applecc enable_assert enable_largefile ' @@ -1391,6 +1392,7 @@ Optional Features: --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) + --enable-applecc enable Apple CommonCrypto API support --disable-assert turn off assertions --disable-largefile omit support for large files @@ -12978,6 +12980,46 @@ $as_echo "#define USE_CRYPTO_POLARSSL 1" >>confdefs.h ;; esac +# Check whether --enable-applecc was given. +if test "${enable_applecc+set}" = set; then : + enableval=$enable_applecc; + for ac_header in CommonCrypto/CommonCrypto.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "CommonCrypto/CommonCrypto.h" "ac_cv_header_CommonCrypto_CommonCrypto_h" "$ac_includes_default" +if test "x$ac_cv_header_CommonCrypto_CommonCrypto_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_COMMONCRYPTO_COMMONCRYPTO_H 1 +_ACEOF + +else + as_fn_error $? "CommonCrypto header files not found." "$LINENO" 5; break + +fi + +done + + for ac_func in CCCryptorCreateWithMode +do : + ac_fn_c_check_func "$LINENO" "CCCryptorCreateWithMode" "ac_cv_func_CCCryptorCreateWithMode" +if test "x$ac_cv_func_CCCryptorCreateWithMode" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CCCRYPTORCREATEWITHMODE 1 +_ACEOF + +else + as_fn_error $? "CommonCrypto API needs OS X (>= 10.7) and iOS (>= 5.0)." "$LINENO" 5; break + +fi +done + + +$as_echo "#define USE_CRYPTO_APPLECC 1" >>confdefs.h + + + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } if ${ac_cv_c_restrict+:} false; then : diff --git a/configure.ac b/configure.ac index f4a633cd..185929d0 100755 --- a/configure.ac +++ b/configure.ac @@ -55,6 +55,21 @@ case "${with_crypto_library}" in ;; esac +dnl Checks for Apple CommonCrypto API +AC_ARG_ENABLE(applecc, + AS_HELP_STRING([--enable-applecc], [enable Apple CommonCrypto API support]), + [ + AC_CHECK_HEADERS(CommonCrypto/CommonCrypto.h, + [], + [AC_MSG_ERROR([CommonCrypto header files not found.]); break] + ) + AC_CHECK_FUNCS([CCCryptorCreateWithMode], , + [AC_MSG_ERROR([CommonCrypto API needs OS X (>= 10.7) and iOS (>= 5.0).]); break] + ) + AC_DEFINE([USE_CRYPTO_APPLECC], [1], [Use Apple CommonCrypto library]) + ] +) + dnl Checks for inet_ntop ss_FUNC_INET_NTOP diff --git a/src/encrypt.c b/src/encrypt.c index 0d15aad4..fbdd8519 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -17,8 +17,6 @@ #include #define CIPHER_UNSUPPORTED "unsupported" -#endif - #include #ifdef _WIN32 #include @@ -27,6 +25,8 @@ #include #endif +#endif + #include "encrypt.h" #include "utils.h" @@ -89,6 +89,34 @@ static const char* supported_ciphers_polarssl[CIPHER_NUM] = }; #endif +#ifdef USE_CRYPTO_APPLECC +static const CCAlgorithm supported_ciphers_applecc[CIPHER_NUM] = +{ + kCCAlgorithmInvalid, + kCCAlgorithmRC4, + kCCAlgorithmAES, + kCCAlgorithmAES, + kCCAlgorithmAES, + kCCAlgorithmBlowfish, + kCCAlgorithmInvalid, + kCCAlgorithmInvalid, + kCCAlgorithmInvalid, + kCCAlgorithmCAST, + kCCAlgorithmDES, + kCCAlgorithmInvalid, + kCCAlgorithmRC2, + kCCAlgorithmInvalid +}; + +static const int supported_ciphers_iv_size[CIPHER_NUM] = { + 0, 0, 16, 16, 16, 8, 16, 16, 16, 8, 8, 8, 8, 16 +}; + +static const int supported_ciphers_key_size[CIPHER_NUM] = { + 0, 16, 16, 24, 32, 16, 16, 24, 32, 16, 8, 16, 16, 16 +}; +#endif + static int random_compare(const void *_x, const void *_y, uint32_t i, uint64_t a) { uint8_t x = *((uint8_t *) _x); @@ -243,7 +271,7 @@ int cipher_key_size (const cipher_kt_t *cipher) return 0; } /* Override PolarSSL 32 bit default key size with sane 128 bit default */ - if (POLARSSL_CIPHER_ID_BLOWFISH == cipher->base->cipher) { + if (cipher->base != NULL && POLARSSL_CIPHER_ID_BLOWFISH == cipher->base->cipher) { return 128 / 8; } return cipher->key_length / 8; @@ -384,10 +412,6 @@ int rand_bytes(uint8_t *output, int len) } rand_initialised = 1; } -#ifdef DEBUG - int orig_len = len; - uint8_t *orig_output = output; -#endif while (len > 0) { if (ctr_drbg_random(&cd_ctx, output, blen) != 0) { return 0; @@ -413,7 +437,7 @@ const cipher_kt_t *get_cipher_type(int method) const char *polarname = supported_ciphers_polarssl[method]; if (strcmp(polarname, CIPHER_UNSUPPORTED) == 0) { LOGE("Cipher %s currently is not supported by PolarSSL library", ciphername); - FATAL("Unsupported cipher in PolarSSL"); + return NULL; } return cipher_info_from_string(polarname); #endif @@ -433,7 +457,7 @@ const digest_type_t *get_digest_type(const char *digest) #endif } -void cipher_context_init(cipher_ctx_t *evp, int method, int enc) +void cipher_context_init(cipher_ctx_t *ctx, int method, int enc) { if (method <= TABLE || method >= CIPHER_NUM) { LOGE("cipher_context_init(): Illegal method"); @@ -441,6 +465,26 @@ void cipher_context_init(cipher_ctx_t *evp, int method, int enc) } const char *ciphername = supported_ciphers[method]; +#if defined(USE_CRYPTO_APPLECC) + cipher_cc_t *cc = &ctx->cc; + cc->cryptor = NULL; + cc->cipher = supported_ciphers_applecc[method]; + if (cc->cipher == kCCAlgorithmInvalid) { + cc->valid = kCCContextInvalid; + } else { + cc->valid = kCCContextValid; + if (cc->cipher == kCCAlgorithmRC4) { + cc->mode = kCCModeRC4; + cc->padding = ccNoPadding; + } else { + cc->mode = kCCModeCFB; + cc->padding = ccPKCS7Padding; + } + return; + } +#endif + + cipher_evp_t *evp = &ctx->evp; const cipher_kt_t *cipher = get_cipher_type(method); #if defined(USE_CRYPTO_OPENSSL) if (cipher == NULL) { @@ -471,8 +515,42 @@ void cipher_context_init(cipher_ctx_t *evp, int method, int enc) #endif } -void cipher_context_set_iv(cipher_ctx_t *evp, uint8_t *iv, size_t iv_len, int enc) +void cipher_context_set_iv(cipher_ctx_t *ctx, uint8_t *iv, size_t iv_len, int enc) { +#ifdef USE_CRYPTO_APPLECC + cipher_cc_t *cc = &ctx->cc; + if (cc->valid == kCCContextValid) { + memcpy(cc->iv, iv, iv_len); + memcpy(cc->key, enc_key, enc_key_len); + cc->iv_len = iv_len; + cc->key_len = enc_key_len; + cc->encrypt = enc ? kCCEncrypt : kCCDecrypt; + if (cc->cryptor != NULL) { + CCCryptorRelease(cc->cryptor); + cc->cryptor = NULL; + } + + CCCryptorStatus ret; + ret = CCCryptorCreateWithMode( + cc->encrypt, + cc->mode, + cc->cipher, + cc->padding, + cc->iv, cc->key, cc->key_len, + NULL, 0, 0, 0, + &cc->cryptor); + if (ret != kCCSuccess) { + if (cc->cryptor != NULL) { + CCCryptorRelease(cc->cryptor); + cc->cryptor = NULL; + } + FATAL("Cannot set CommonCrypto key and IV"); + } + return; + } +#endif + + cipher_evp_t *evp = &ctx->evp; if (evp == NULL || iv == NULL) { LOGE("cipher_context_set_keyiv(): Cipher context or IV is null"); return; @@ -506,12 +584,25 @@ void cipher_context_set_iv(cipher_ctx_t *evp, uint8_t *iv, size_t iv_len, int en } #endif #endif + #ifdef DEBUG - dump("IV", iv, iv_len); + dump("IV", (char *) iv, iv_len); #endif } -void cipher_context_release(cipher_ctx_t *evp) { +void cipher_context_release(cipher_ctx_t *ctx) { +#ifdef USE_CRYPTO_APPLECC + cipher_cc_t *cc = &ctx->cc; + if (cc->cryptor != NULL) { + CCCryptorRelease(cc->cryptor); + cc->cryptor = NULL; + } + if (cc->valid == kCCContextValid) { + return; + } +#endif + + cipher_evp_t *evp = &ctx->evp; #if defined(USE_CRYPTO_OPENSSL) EVP_CIPHER_CTX_cleanup(evp); #elif defined(USE_CRYPTO_POLARSSL) @@ -519,14 +610,23 @@ void cipher_context_release(cipher_ctx_t *evp) { #endif } -int cipher_context_update(cipher_ctx_t *evp, uint8_t *output, int *olen, - const uint8_t *input, int ilen) { +static int cipher_context_update(cipher_ctx_t *ctx, uint8_t *output, int *olen, + const uint8_t *input, int ilen) { + cipher_evp_t *evp = &ctx->evp; +#ifdef USE_CRYPTO_APPLECC + cipher_cc_t *cc = &ctx->cc; + if (cc->valid == kCCContextValid) { + CCCryptorStatus ret; + ret = CCCryptorUpdate(cc->cryptor, input, ilen, output, ilen + BLOCK_SIZE, (size_t *) olen); + return (ret == kCCSuccess) ? 1 : 0; + } +#endif #if defined(USE_CRYPTO_OPENSSL) - return EVP_CipherUpdate(evp, (uint8_t *) output, olen, - (const uint8_t *) input, (size_t) ilen); + return EVP_CipherUpdate(evp, (uint8_t *) output, olen, + (const uint8_t *) input, (size_t) ilen); #elif defined(USE_CRYPTO_POLARSSL) - return !cipher_update(evp, (const uint8_t *) input, (size_t) ilen, - (uint8_t *) output, (size_t *) olen); + return !cipher_update(evp, (const uint8_t *) input, (size_t) ilen, + (uint8_t *) output, (size_t *) olen); #endif } @@ -743,11 +843,26 @@ void enc_key_init(int method, const char *pass) OpenSSL_add_all_algorithms(); #endif +#if defined(USE_CRYPTO_POLARSSL) && defined(USE_CRYPTO_APPLECC) + cipher_kt_t cipher_info; +#endif + uint8_t iv[MAX_IV_LENGTH]; const cipher_kt_t *cipher = get_cipher_type(method); if (cipher == NULL) { - LOGE("Cipher %s not found in crypto library", supported_ciphers[method]); - FATAL("Cannot initialize cipher"); + do { +#if defined(USE_CRYPTO_POLARSSL) && defined(USE_CRYPTO_APPLECC) + if (supported_ciphers_applecc[method] != kCCAlgorithmInvalid) { + cipher_info.base = NULL; + cipher_info.key_length = supported_ciphers_key_size[method] * 8; + cipher_info.iv_size = supported_ciphers_iv_size[method]; + cipher = (const cipher_kt_t *) &cipher_info; + break; + } +#endif + LOGE("Cipher %s not found in crypto library", supported_ciphers[method]); + FATAL("Cannot initialize cipher"); + } while (0); } const digest_type_t *md = get_digest_type("MD5"); if (md == NULL) { diff --git a/src/encrypt.h b/src/encrypt.h index c940a9f9..0a52ffb3 100644 --- a/src/encrypt.h +++ b/src/encrypt.h @@ -25,7 +25,7 @@ #include typedef EVP_CIPHER cipher_kt_t; -typedef EVP_CIPHER_CTX cipher_ctx_t; +typedef EVP_CIPHER_CTX cipher_evp_t; typedef EVP_MD digest_type_t; #define MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH #define MAX_IV_LENGTH EVP_MAX_IV_LENGTH @@ -36,7 +36,7 @@ typedef EVP_MD digest_type_t; #include #include typedef cipher_info_t cipher_kt_t; -typedef cipher_context_t cipher_ctx_t; +typedef cipher_context_t cipher_evp_t; typedef md_info_t digest_type_t; #define MAX_KEY_LENGTH 64 #define MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH @@ -44,6 +44,36 @@ typedef md_info_t digest_type_t; #endif +#ifdef USE_CRYPTO_APPLECC + +#include + +#define kCCAlgorithmInvalid UINT32_MAX +#define kCCContextValid 0 +#define kCCContextInvalid -1 + +typedef struct { + CCCryptorRef cryptor; + int valid; + CCOperation encrypt; + CCAlgorithm cipher; + CCMode mode; + CCPadding padding; + uint8_t iv[MAX_IV_LENGTH]; + uint8_t key[MAX_KEY_LENGTH]; + size_t iv_len; + size_t key_len; +} cipher_cc_t; + +#endif + +typedef struct { + cipher_evp_t evp; +#ifdef USE_CRYPTO_APPLECC + cipher_cc_t cc; +#endif +} cipher_ctx_t; + #ifdef HAVE_STDINT_H #include #elif HAVE_INTTYPES_H