/* * encrypt.c - Manage the global encryptor * * Copyright (C) 2013 - 2016, Max Lv * * This file is part of the shadowsocks-libev. * * shadowsocks-libev is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * shadowsocks-libev is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with shadowsocks-libev; see the file COPYING. If not, see * . */ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(USE_CRYPTO_OPENSSL) #include #include #include #include #elif defined(USE_CRYPTO_POLARSSL) #include #include #include #include #include #include #define CIPHER_UNSUPPORTED "unsupported" #include #ifdef _WIN32 #include #include #else #include #endif #elif defined(USE_CRYPTO_MBEDTLS) #include #include #include #include #include #define CIPHER_UNSUPPORTED "unsupported" #include #ifdef _WIN32 #include #include #else #include #endif #endif #include #ifndef __MINGW32__ #include #endif #include "cache.h" #include "encrypt.h" #include "utils.h" #define OFFSET_ROL(p, o) ((uint64_t)(*(p + o)) << (8 * o)) static uint8_t *enc_table; static uint8_t *dec_table; static uint8_t enc_key[MAX_KEY_LENGTH]; static int enc_key_len; static int enc_iv_len; static int enc_method; static struct cache *iv_cache; #ifdef DEBUG static void dump(char *tag, char *text, int len) { int i; printf("%s: ", tag); for (i = 0; i < len; i++) printf("0x%02x ", (uint8_t)text[i]); printf("\n"); } #endif static const char *supported_ciphers[CIPHER_NUM] = { "table", "rc4", "rc4-md5-6", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "salsa20", "chacha20", "chacha20-ietf" }; #ifdef USE_CRYPTO_POLARSSL static const char *supported_ciphers_polarssl[CIPHER_NUM] = { "table", "ARC4-128", "ARC4-128", "ARC4-128", "AES-128-CFB128", "AES-192-CFB128", "AES-256-CFB128", "AES-128-CTR", "AES-192-CTR", "AES-256-CTR", "BLOWFISH-CFB64", "CAMELLIA-128-CFB128", "CAMELLIA-192-CFB128", "CAMELLIA-256-CFB128", CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, "salsa20", "chacha20", "chacha20-ietf" }; #endif #ifdef USE_CRYPTO_MBEDTLS static const char *supported_ciphers_mbedtls[CIPHER_NUM] = { "table", "ARC4-128", "ARC4-128", "ARC4-128", "AES-128-CFB128", "AES-192-CFB128", "AES-256-CFB128", "AES-128-CTR", "AES-192-CTR", "AES-256-CTR", "BLOWFISH-CFB64", "CAMELLIA-128-CFB128", "CAMELLIA-192-CFB128", "CAMELLIA-256-CFB128", CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, CIPHER_UNSUPPORTED, "salsa20", "chacha20", "chacha20-ietf" }; #endif #ifdef USE_CRYPTO_APPLECC static const CCAlgorithm supported_ciphers_applecc[CIPHER_NUM] = { kCCAlgorithmInvalid, kCCAlgorithmRC4, kCCAlgorithmRC4, kCCAlgorithmRC4, kCCAlgorithmAES, kCCAlgorithmAES, kCCAlgorithmAES, kCCAlgorithmAES, kCCAlgorithmAES, kCCAlgorithmAES, kCCAlgorithmBlowfish, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmCAST, kCCAlgorithmDES, kCCAlgorithmInvalid, kCCAlgorithmRC2, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmInvalid }; static const CCMode supported_modes_applecc[CIPHER_NUM] = { kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCModeRC4, kCCModeRC4, kCCModeCFB, kCCModeCFB, kCCModeCFB, kCCModeCTR, kCCModeCTR, kCCModeCTR, kCCModeCFB, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCModeCFB, kCCModeCFB, kCCModeCFB, kCCModeCFB, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmInvalid, kCCAlgorithmInvalid }; #endif static const int supported_ciphers_iv_size[CIPHER_NUM] = { 0, 0, 6, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 8, 8, 8, 8, 16, 8, 8, 12 }; static const int supported_ciphers_key_size[CIPHER_NUM] = { 0, 16, 16, 16, 16, 24, 32, 16, 24, 32, 16, 16, 24, 32, 16, 8, 16, 16, 16, 32, 32, 32 }; static int safe_memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *_s1 = (const unsigned char *)s1; const unsigned char *_s2 = (const unsigned char *)s2; int ret = 0; size_t i; for (i = 0; i < n; i++) ret |= _s1[i] ^ _s2[i]; return !!ret; } int balloc(buffer_t *ptr, size_t capacity) { sodium_memzero(ptr, sizeof(buffer_t)); ptr->array = ss_malloc(capacity); ptr->capacity = capacity; return capacity; } int brealloc(buffer_t *ptr, size_t len, size_t capacity) { if (ptr == NULL) return -1; size_t real_capacity = max(len, capacity); if (ptr->capacity < real_capacity) { ptr->array = ss_realloc(ptr->array, real_capacity); ptr->capacity = real_capacity; } return real_capacity; } void bfree(buffer_t *ptr) { if (ptr == NULL) return; ptr->idx = 0; ptr->len = 0; ptr->capacity = 0; if (ptr->array != NULL) { ss_free(ptr->array); } } static int crypto_stream_xor_ic(uint8_t *c, const uint8_t *m, uint64_t mlen, const uint8_t *n, uint64_t ic, const uint8_t *k, int method) { switch (method) { case SALSA20: return crypto_stream_salsa20_xor_ic(c, m, mlen, n, ic, k); case CHACHA20: return crypto_stream_chacha20_xor_ic(c, m, mlen, n, ic, k); case CHACHA20IETF: return crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, n, (uint32_t)ic, k); } // always return 0 return 0; } static int random_compare(const void *_x, const void *_y, uint32_t i, uint64_t a) { uint8_t x = *((uint8_t *)_x); uint8_t y = *((uint8_t *)_y); return a % (x + i) - a % (y + i); } static void merge(uint8_t *left, int llength, uint8_t *right, int rlength, uint32_t salt, uint64_t key) { uint8_t *ltmp = (uint8_t *)malloc(llength * sizeof(uint8_t)); uint8_t *rtmp = (uint8_t *)malloc(rlength * sizeof(uint8_t)); uint8_t *ll = ltmp; uint8_t *rr = rtmp; uint8_t *result = left; memcpy(ltmp, left, llength * sizeof(uint8_t)); memcpy(rtmp, right, rlength * sizeof(uint8_t)); while (llength > 0 && rlength > 0) { if (random_compare(ll, rr, salt, key) <= 0) { *result = *ll; ++ll; --llength; } else { *result = *rr; ++rr; --rlength; } ++result; } if (llength > 0) { while (llength > 0) { *result = *ll; ++result; ++ll; --llength; } } else { while (rlength > 0) { *result = *rr; ++result; ++rr; --rlength; } } ss_free(ltmp); ss_free(rtmp); } static void merge_sort(uint8_t array[], int length, uint32_t salt, uint64_t key) { uint8_t middle; uint8_t *left, *right; int llength; if (length <= 1) { return; } middle = length / 2; llength = length - middle; left = array; right = array + llength; merge_sort(left, llength, salt, key); merge_sort(right, middle, salt, key); merge(left, llength, right, middle, salt, key); } int enc_get_iv_len() { return enc_iv_len; } uint8_t* enc_get_key() { return enc_key; } int enc_get_key_len() { return enc_key_len; } unsigned char *enc_md5(const unsigned char *d, size_t n, unsigned char *md) { #if defined(USE_CRYPTO_OPENSSL) return MD5(d, n, md); #elif defined(USE_CRYPTO_POLARSSL) static unsigned char m[16]; if (md == NULL) { md = m; } md5(d, n, md); return md; #elif defined(USE_CRYPTO_MBEDTLS) static unsigned char m[16]; if (md == NULL) { md = m; } mbedtls_md5(d, n, md); return md; #endif } void enc_table_init(const char *pass) { uint32_t i; uint64_t key = 0; uint8_t *digest; enc_table = ss_malloc(256); dec_table = ss_malloc(256); digest = enc_md5((const uint8_t *)pass, strlen(pass), NULL); for (i = 0; i < 8; i++) key += OFFSET_ROL(digest, i); for (i = 0; i < 256; ++i) enc_table[i] = i; for (i = 1; i < 1024; ++i) merge_sort(enc_table, 256, i, key); for (i = 0; i < 256; ++i) // gen decrypt table from encrypt table dec_table[enc_table[i]] = i; } int cipher_iv_size(const cipher_t *cipher) { #if defined(USE_CRYPTO_OPENSSL) if (cipher->info == NULL) return cipher->iv_len; else return EVP_CIPHER_iv_length(cipher->info); #elif defined(USE_CRYPTO_POLARSSL) || defined(USE_CRYPTO_MBEDTLS) if (cipher == NULL) { return 0; } return cipher->info->iv_size; #endif } int cipher_key_size(const cipher_t *cipher) { #if defined(USE_CRYPTO_OPENSSL) if (cipher->info == NULL) return cipher->key_len; else return EVP_CIPHER_key_length(cipher->info); #elif defined(USE_CRYPTO_POLARSSL) if (cipher == NULL) { return 0; } /* Override PolarSSL 32 bit default key size with sane 128 bit default */ if (cipher->info->base != NULL && POLARSSL_CIPHER_ID_BLOWFISH == cipher->info->base->cipher) { return 128 / 8; } return cipher->info->key_length / 8; #elif defined(USE_CRYPTO_MBEDTLS) /* * Semi-API changes (technically public, morally private) * Renamed a few headers to include _internal in the name. Those headers are * not supposed to be included by users. * Changed md_info_t into an opaque structure (use md_get_xxx() accessors). * Changed pk_info_t into an opaque structure. * Changed cipher_base_t into an opaque structure. */ if (cipher == NULL) { return 0; } /* From Version 1.2.7 released 2013-04-13 Default Blowfish keysize is now 128-bits */ return cipher->info->key_bitlen / 8; #endif } void bytes_to_key_with_size(const char *pass, size_t len, uint8_t *md, size_t md_size) { uint8_t result[128]; enc_md5((const unsigned char *)pass, len, result); memcpy(md, result, 16); int i = 16; for (; i < md_size; i += 16) { memcpy(result + 16, pass, len); enc_md5(result, 16 + len, result); memcpy(md + i, result, 16); } } int bytes_to_key(const cipher_t *cipher, const digest_type_t *md, const uint8_t *pass, uint8_t *key) { size_t datal; datal = strlen((const char *)pass); #if defined(USE_CRYPTO_OPENSSL) MD5_CTX c; unsigned char md_buf[MAX_MD_SIZE]; int nkey; int addmd; unsigned int i, j, mds; mds = 16; nkey = cipher_key_size(cipher); if (pass == NULL) return nkey; memset(&c, 0, sizeof(MD5_CTX)); for (j = 0, addmd = 0; j < nkey; addmd++) { MD5_Init(&c); if (addmd) { MD5_Update(&c, md_buf, mds); } MD5_Update(&c, pass, datal); MD5_Final(md_buf, &c); for (i = 0; i < mds; i++, j++) { if (j >= nkey) break; key[j] = md_buf[i]; } } return nkey; #elif defined(USE_CRYPTO_POLARSSL) md_context_t c; unsigned char md_buf[MAX_MD_SIZE]; int nkey; int addmd; unsigned int i, j, mds; nkey = cipher_key_size(cipher); mds = md_get_size(md); memset(&c, 0, sizeof(md_context_t)); if (pass == NULL) return nkey; if (md_init_ctx(&c, md)) return 0; for (j = 0, addmd = 0; j < nkey; addmd++) { md_starts(&c); if (addmd) { md_update(&c, md_buf, mds); } md_update(&c, pass, datal); md_finish(&c, md_buf); for (i = 0; i < mds; i++, j++) { if (j >= nkey) break; key[j] = md_buf[i]; } } md_free_ctx(&c); return nkey; #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_context_t c; unsigned char md_buf[MAX_MD_SIZE]; int nkey; int addmd; unsigned int i, j, mds; nkey = cipher_key_size(cipher); mds = mbedtls_md_get_size(md); memset(&c, 0, sizeof(mbedtls_md_context_t)); if (pass == NULL) return nkey; if (mbedtls_md_setup(&c, md, 1)) return 0; for (j = 0, addmd = 0; j < nkey; addmd++) { mbedtls_md_starts(&c); if (addmd) { mbedtls_md_update(&c, md_buf, mds); } mbedtls_md_update(&c, pass, datal); mbedtls_md_finish(&c, &(md_buf[0])); for (i = 0; i < mds; i++, j++) { if (j >= nkey) break; key[j] = md_buf[i]; } } mbedtls_md_free(&c); return nkey; #endif } int rand_bytes(uint8_t *output, int len) { randombytes_buf(output, len); // always return success return 0; } const cipher_kt_t * get_cipher_type(int method) { if (method <= TABLE || method >= CIPHER_NUM) { LOGE("get_cipher_type(): Illegal method"); return NULL; } if (method == RC4_MD5 || method == RC4_MD5_6) { method = RC4; } if (method >= SALSA20) { return NULL; } const char *ciphername = supported_ciphers[method]; #if defined(USE_CRYPTO_OPENSSL) return EVP_get_cipherbyname(ciphername); #elif defined(USE_CRYPTO_POLARSSL) const char *polarname = supported_ciphers_polarssl[method]; if (strcmp(polarname, CIPHER_UNSUPPORTED) == 0) { LOGE("Cipher %s currently is not supported by PolarSSL library", ciphername); return NULL; } return cipher_info_from_string(polarname); #elif defined(USE_CRYPTO_MBEDTLS) const char *mbedtlsname = supported_ciphers_mbedtls[method]; if (strcmp(mbedtlsname, CIPHER_UNSUPPORTED) == 0) { LOGE("Cipher %s currently is not supported by mbed TLS library", ciphername); return NULL; } return mbedtls_cipher_info_from_string(mbedtlsname); #endif } const digest_type_t * get_digest_type(const char *digest) { if (digest == NULL) { LOGE("get_digest_type(): Digest name is null"); return NULL; } #if defined(USE_CRYPTO_OPENSSL) return EVP_get_digestbyname(digest); #elif defined(USE_CRYPTO_POLARSSL) return md_info_from_string(digest); #elif defined(USE_CRYPTO_MBEDTLS) return mbedtls_md_info_from_string(digest); #endif } void cipher_context_init(cipher_ctx_t *ctx, int method, int enc) { if (method <= TABLE || method >= CIPHER_NUM) { LOGE("cipher_context_init(): Illegal method"); return; } if (method >= SALSA20) { enc_iv_len = supported_ciphers_iv_size[method]; return; } 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 = supported_modes_applecc[method]; cc->padding = ccNoPadding; } else { cc->mode = supported_modes_applecc[method]; if (cc->mode == kCCModeCTR) { cc->padding = ccNoPadding; } else { cc->padding = ccPKCS7Padding; } } return; } #endif const cipher_kt_t *cipher = get_cipher_type(method); #if defined(USE_CRYPTO_OPENSSL) ctx->evp = EVP_CIPHER_CTX_new(); cipher_evp_t *evp = ctx->evp; if (cipher == NULL) { LOGE("Cipher %s not found in OpenSSL library", ciphername); FATAL("Cannot initialize cipher"); } if (!EVP_CipherInit_ex(evp, cipher, NULL, NULL, NULL, enc)) { LOGE("Cannot initialize cipher %s", ciphername); exit(EXIT_FAILURE); } if (!EVP_CIPHER_CTX_set_key_length(evp, enc_key_len)) { EVP_CIPHER_CTX_cleanup(evp); LOGE("Invalid key length: %d", enc_key_len); exit(EXIT_FAILURE); } if (method > RC4_MD5) { EVP_CIPHER_CTX_set_padding(evp, 1); } #elif defined(USE_CRYPTO_POLARSSL) ctx->evp = (cipher_evp_t *)ss_malloc(sizeof(cipher_evp_t)); cipher_evp_t *evp = ctx->evp; if (cipher == NULL) { LOGE("Cipher %s not found in PolarSSL library", ciphername); FATAL("Cannot initialize PolarSSL cipher"); } if (cipher_init_ctx(evp, cipher) != 0) { FATAL("Cannot initialize PolarSSL cipher context"); } #elif defined(USE_CRYPTO_MBEDTLS) ctx->evp = (cipher_evp_t *)ss_malloc(sizeof(cipher_evp_t)); cipher_evp_t *evp = ctx->evp; if (cipher == NULL) { LOGE("Cipher %s not found in mbed TLS library", ciphername); FATAL("Cannot initialize mbed TLS cipher"); } mbedtls_cipher_init(evp); if (mbedtls_cipher_setup(evp, cipher) != 0) { FATAL("Cannot initialize mbed TLS cipher context"); } #endif } void cipher_context_set_iv(cipher_ctx_t *ctx, uint8_t *iv, size_t iv_len, int enc) { const unsigned char *true_key; if (iv == NULL) { LOGE("cipher_context_set_iv(): IV is null"); return; } if (!enc) { memcpy(ctx->iv, iv, iv_len); } if (enc_method >= SALSA20) { return; } if (enc_method == RC4_MD5 || enc_method == RC4_MD5_6) { unsigned char key_iv[32]; memcpy(key_iv, enc_key, 16); memcpy(key_iv + 16, iv, iv_len); true_key = enc_md5(key_iv, 16 + iv_len, NULL); iv_len = 0; } else { true_key = enc_key; } #ifdef USE_CRYPTO_APPLECC cipher_cc_t *cc = &ctx->cc; if (cc->valid == kCCContextValid) { memcpy(cc->iv, iv, iv_len); memcpy(cc->key, true_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, kCCModeOptionCTR_BE, &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) { LOGE("cipher_context_set_iv(): Cipher context is null"); return; } #if defined(USE_CRYPTO_OPENSSL) if (!EVP_CipherInit_ex(evp, NULL, NULL, true_key, iv, enc)) { EVP_CIPHER_CTX_cleanup(evp); FATAL("Cannot set key and IV"); } #elif defined(USE_CRYPTO_POLARSSL) // XXX: PolarSSL 1.3.11: cipher_free_ctx deprecated, Use cipher_free() instead. if (cipher_setkey(evp, true_key, enc_key_len * 8, enc) != 0) { cipher_free_ctx(evp); FATAL("Cannot set PolarSSL cipher key"); } #if POLARSSL_VERSION_NUMBER >= 0x01030000 if (cipher_set_iv(evp, iv, iv_len) != 0) { cipher_free_ctx(evp); FATAL("Cannot set PolarSSL cipher IV"); } if (cipher_reset(evp) != 0) { cipher_free_ctx(evp); FATAL("Cannot finalize PolarSSL cipher context"); } #else if (cipher_reset(evp, iv) != 0) { cipher_free_ctx(evp); FATAL("Cannot set PolarSSL cipher IV"); } #endif #elif defined(USE_CRYPTO_MBEDTLS) if (mbedtls_cipher_setkey(evp, true_key, enc_key_len * 8, enc) != 0) { mbedtls_cipher_free(evp); FATAL("Cannot set mbed TLS cipher key"); } if (mbedtls_cipher_set_iv(evp, iv, iv_len) != 0) { mbedtls_cipher_free(evp); FATAL("Cannot set mbed TLS cipher IV"); } if (mbedtls_cipher_reset(evp) != 0) { mbedtls_cipher_free(evp); FATAL("Cannot finalize mbed TLS cipher context"); } #endif #ifdef DEBUG dump("IV", (char *)iv, iv_len); #endif } void cipher_context_release(cipher_ctx_t *ctx) { if (enc_method >= SALSA20) { return; } #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 #if defined(USE_CRYPTO_OPENSSL) EVP_CIPHER_CTX_free(ctx->evp); #elif defined(USE_CRYPTO_POLARSSL) // NOTE: cipher_free_ctx deprecated in PolarSSL 1.3.11 cipher_free_ctx(ctx->evp); ss_free(ctx->evp); #elif defined(USE_CRYPTO_MBEDTLS) // NOTE: cipher_free_ctx deprecated mbedtls_cipher_free(ctx->evp); ss_free(ctx->evp); #endif } static int cipher_context_update(cipher_ctx_t *ctx, uint8_t *output, size_t *olen, const uint8_t *input, size_t ilen) { #ifdef USE_CRYPTO_APPLECC cipher_cc_t *cc = &ctx->cc; if (cc->valid == kCCContextValid) { CCCryptorStatus ret; ret = CCCryptorUpdate(cc->cryptor, input, ilen, output, ilen, olen); return (ret == kCCSuccess) ? 1 : 0; } #endif cipher_evp_t *evp = ctx->evp; #if defined(USE_CRYPTO_OPENSSL) int err = 0, tlen = *olen; err = EVP_CipherUpdate(evp, (uint8_t *)output, &tlen, (const uint8_t *)input, ilen); *olen = tlen; return err; #elif defined(USE_CRYPTO_POLARSSL) return !cipher_update(evp, (const uint8_t *)input, ilen, (uint8_t *)output, olen); #elif defined(USE_CRYPTO_MBEDTLS) return !mbedtls_cipher_update(evp, (const uint8_t *)input, ilen, (uint8_t *)output, olen); #endif } int ss_md5_hmac(char *auth, char *msg, int msg_len, uint8_t *iv) { uint8_t hash[MD5_BYTES]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_md5(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_MD5), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #else md5_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, MD5_BYTES); return 0; } int ss_md5_hmac_with_key(char *auth, char *msg, int msg_len, uint8_t *auth_key, int key_len) { uint8_t hash[MD5_BYTES]; #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_md5(), auth_key, key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_MD5), auth_key, key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #else md5_hmac(auth_key, key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, MD5_BYTES); return 0; } int ss_md5_hash_func(char *auth, char *msg, int msg_len) { uint8_t hash[MD5_BYTES]; #if defined(USE_CRYPTO_OPENSSL) MD5((uint8_t *)msg, msg_len, (uint8_t *)hash); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_MD5), (uint8_t *)msg, msg_len, (uint8_t *)hash); #else md5((uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, MD5_BYTES); return 0; } int ss_sha1_hmac(char *auth, char *msg, int msg_len, uint8_t *iv) { uint8_t hash[SHA1_BYTES]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #else sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, SHA1_BYTES); return 0; } int ss_sha1_hmac_with_key(char *auth, char *msg, int msg_len, uint8_t *auth_key, int key_len) { uint8_t hash[SHA1_BYTES]; #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), auth_key, key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #else sha1_hmac(auth_key, key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, SHA1_BYTES); return 0; } int ss_sha1_hash_func(char *auth, char *msg, int msg_len) { uint8_t hash[SHA1_BYTES]; #if defined(USE_CRYPTO_OPENSSL) SHA1((uint8_t *)msg, msg_len, (uint8_t *)hash); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), (uint8_t *)msg, msg_len, (uint8_t *)hash); #else sha1((uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, SHA1_BYTES); return 0; } int ss_aes_128_cbc(char *encrypt, char *out_data, char *key) { unsigned char iv[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #if defined(USE_CRYPTO_OPENSSL) AES_KEY aes; AES_set_encrypt_key((unsigned char*)key, 128, &aes); AES_cbc_encrypt((const unsigned char *)encrypt, (unsigned char *)out_data, 16, &aes, iv, AES_ENCRYPT); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_aes_context aes; unsigned char output[16]; mbedtls_aes_setkey_enc( &aes, (unsigned char *)key, 128 ); mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, 16, iv, (unsigned char *)encrypt, output ); memcpy(out_data, output, 16); #else aes_context aes; unsigned char output[16]; aes_setkey_enc( &aes, (unsigned char *)key, 128 ); aes_crypt_cbc( &aes, AES_ENCRYPT, 16, iv, (unsigned char *)encrypt, output ); memcpy(out_data, output, 16); #endif return 0; } int ss_onetimeauth(buffer_t *buf, uint8_t *iv, size_t capacity) { uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); brealloc(buf, ONETIMEAUTH_BYTES + buf->len, capacity); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, buf->len, (uint8_t *)hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type( MBEDTLS_MD_SHA1), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, buf->len, (uint8_t *)hash); #else sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, buf->len, (uint8_t *)hash); #endif memcpy(buf->array + buf->len, hash, ONETIMEAUTH_BYTES); buf->len += ONETIMEAUTH_BYTES; return 0; } int ss_onetimeauth_verify(buffer_t *buf, uint8_t *iv) { uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); size_t len = buf->len - ONETIMEAUTH_BYTES; #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, len, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type( MBEDTLS_MD_SHA1), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, len, hash); #else sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, len, hash); #endif return safe_memcmp(buf->array + len, hash, ONETIMEAUTH_BYTES); } int ss_encrypt_all(buffer_t *plain, int method, int auth, size_t capacity) { if (method > TABLE) { cipher_ctx_t evp; cipher_context_init(&evp, method, 1); size_t iv_len = enc_iv_len; int err = 1; static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, iv_len + plain->len, capacity); buffer_t *cipher = &tmp; cipher->len = plain->len; uint8_t iv[MAX_IV_LENGTH]; rand_bytes(iv, iv_len); cipher_context_set_iv(&evp, iv, iv_len, 1); memcpy(cipher->array, iv, iv_len); if (auth) { ss_onetimeauth(plain, iv, capacity); cipher->len = plain->len; } if (method >= SALSA20) { crypto_stream_xor_ic((uint8_t *)(cipher->array + iv_len), (const uint8_t *)plain->array, (uint64_t)(plain->len), (const uint8_t *)iv, 0, enc_key, method); } else { err = cipher_context_update(&evp, (uint8_t *)(cipher->array + iv_len), &cipher->len, (const uint8_t *)plain->array, plain->len); } if (!err) { bfree(plain); cipher_context_release(&evp); return -1; } #ifdef DEBUG dump("PLAIN", plain->array, plain->len); dump("CIPHER", cipher->array + iv_len, cipher->len); #endif cipher_context_release(&evp); brealloc(plain, iv_len + cipher->len, capacity); memcpy(plain->array, cipher->array, iv_len + cipher->len); plain->len = iv_len + cipher->len; return 0; } else { char *begin = plain->array; char *ptr = plain->array; while (ptr < begin + plain->len) { *ptr = (char)enc_table[(uint8_t)*ptr]; ptr++; } return 0; } } int ss_encrypt(buffer_t *plain, enc_ctx_t *ctx, size_t capacity) { if (ctx != NULL) { static buffer_t tmp = { 0, 0, 0, NULL }; int err = 1; size_t iv_len = 0; if (!ctx->init) { iv_len = enc_iv_len; } brealloc(&tmp, iv_len + plain->len, capacity); buffer_t *cipher = &tmp; cipher->len = plain->len; if (!ctx->init) { cipher_context_set_iv(&ctx->evp, ctx->evp.iv, iv_len, 1); memcpy(cipher->array, ctx->evp.iv, iv_len); ctx->counter = 0; ctx->init = 1; } if (enc_method >= SALSA20) { int padding = ctx->counter % SODIUM_BLOCK_SIZE; brealloc(cipher, iv_len + (padding + cipher->len) * 2, capacity); if (padding) { brealloc(plain, plain->len + padding, capacity); memmove(plain->array + padding, plain->array, plain->len); sodium_memzero(plain->array, padding); } crypto_stream_xor_ic((uint8_t *)(cipher->array + iv_len), (const uint8_t *)plain->array, (uint64_t)(plain->len + padding), (const uint8_t *)ctx->evp.iv, ctx->counter / SODIUM_BLOCK_SIZE, enc_key, enc_method); ctx->counter += plain->len; if (padding) { memmove(cipher->array + iv_len, cipher->array + iv_len + padding, cipher->len); } } else { err = cipher_context_update(&ctx->evp, (uint8_t *)(cipher->array + iv_len), &cipher->len, (const uint8_t *)plain->array, plain->len); if (!err) { return -1; } } #ifdef DEBUG dump("PLAIN", plain->array, plain->len); dump("CIPHER", cipher->array + iv_len, cipher->len); #endif brealloc(plain, iv_len + cipher->len, capacity); memcpy(plain->array, cipher->array, iv_len + cipher->len); plain->len = iv_len + cipher->len; return 0; } else { char *begin = plain->array; char *ptr = plain->array; while (ptr < begin + plain->len) { *ptr = (char)enc_table[(uint8_t)*ptr]; ptr++; } return 0; } } int ss_decrypt_all(buffer_t *cipher, int method, int auth, size_t capacity) { if (method > TABLE) { size_t iv_len = enc_iv_len; int ret = 1; if (cipher->len <= iv_len) { return -1; } cipher_ctx_t evp; cipher_context_init(&evp, method, 0); static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, cipher->len, capacity); buffer_t *plain = &tmp; plain->len = cipher->len - iv_len; uint8_t iv[MAX_IV_LENGTH]; memcpy(iv, cipher->array, iv_len); cipher_context_set_iv(&evp, iv, iv_len, 0); if (method >= SALSA20) { crypto_stream_xor_ic((uint8_t *)plain->array, (const uint8_t *)(cipher->array + iv_len), (uint64_t)(cipher->len - iv_len), (const uint8_t *)iv, 0, enc_key, method); } else { ret = cipher_context_update(&evp, (uint8_t *)plain->array, &plain->len, (const uint8_t *)(cipher->array + iv_len), cipher->len - iv_len); } if (auth || (plain->array[0] & ONETIMEAUTH_FLAG)) { if (plain->len > ONETIMEAUTH_BYTES) { ret = !ss_onetimeauth_verify(plain, iv); if (ret) { plain->len -= ONETIMEAUTH_BYTES; } } else { ret = 0; } } if (!ret) { bfree(cipher); cipher_context_release(&evp); return -1; } #ifdef DEBUG dump("PLAIN", plain->array, plain->len); dump("CIPHER", cipher->array + iv_len, cipher->len - iv_len); #endif cipher_context_release(&evp); brealloc(cipher, plain->len, capacity); memcpy(cipher->array, plain->array, plain->len); cipher->len = plain->len; return 0; } else { char *begin = cipher->array; char *ptr = cipher->array; while (ptr < begin + cipher->len) { *ptr = (char)dec_table[(uint8_t)*ptr]; ptr++; } return 0; } } int ss_decrypt(buffer_t *cipher, enc_ctx_t *ctx, size_t capacity) { if (ctx != NULL) { static buffer_t tmp = { 0, 0, 0, NULL }; size_t iv_len = 0; int err = 1; brealloc(&tmp, cipher->len, capacity); buffer_t *plain = &tmp; plain->len = cipher->len; if (!ctx->init) { uint8_t iv[MAX_IV_LENGTH]; iv_len = enc_iv_len; plain->len -= iv_len; memcpy(iv, cipher->array, iv_len); cipher_context_set_iv(&ctx->evp, iv, iv_len, 0); ctx->counter = 0; ctx->init = 1; if (enc_method > RC4) { if (cache_key_exist(iv_cache, (char *)iv, iv_len)) { bfree(cipher); return -1; } else { cache_insert(iv_cache, (char *)iv, iv_len, NULL); } } } if (enc_method >= SALSA20) { int padding = ctx->counter % SODIUM_BLOCK_SIZE; brealloc(plain, (plain->len + padding) * 2, capacity); if (padding) { brealloc(cipher, cipher->len + padding, capacity); memmove(cipher->array + iv_len + padding, cipher->array + iv_len, cipher->len - iv_len); sodium_memzero(cipher->array + iv_len, padding); } crypto_stream_xor_ic((uint8_t *)plain->array, (const uint8_t *)(cipher->array + iv_len), (uint64_t)(cipher->len - iv_len + padding), (const uint8_t *)ctx->evp.iv, ctx->counter / SODIUM_BLOCK_SIZE, enc_key, enc_method); ctx->counter += cipher->len - iv_len; if (padding) { memmove(plain->array, plain->array + padding, plain->len); } } else { err = cipher_context_update(&ctx->evp, (uint8_t *)plain->array, &plain->len, (const uint8_t *)(cipher->array + iv_len), cipher->len - iv_len); } if (!err) { bfree(cipher); return -1; } #ifdef DEBUG dump("PLAIN", plain->array, plain->len); dump("CIPHER", cipher->array + iv_len, cipher->len - iv_len); #endif brealloc(cipher, plain->len, capacity); memcpy(cipher->array, plain->array, plain->len); cipher->len = plain->len; return 0; } else { char *begin = cipher->array; char *ptr = cipher->array; while (ptr < begin + cipher->len) { *ptr = (char)dec_table[(uint8_t)*ptr]; ptr++; } return 0; } } void enc_ctx_init(int method, enc_ctx_t *ctx, int enc) { sodium_memzero(ctx, sizeof(enc_ctx_t)); cipher_context_init(&ctx->evp, method, enc); if (enc) { rand_bytes(ctx->evp.iv, enc_iv_len); } } void enc_key_init(int method, const char *pass) { if (method <= TABLE || method >= CIPHER_NUM) { LOGE("enc_key_init(): Illegal method"); return; } // Initialize cache cache_create(&iv_cache, 256, NULL); #if defined(USE_CRYPTO_OPENSSL) OpenSSL_add_all_algorithms(); #else cipher_kt_t cipher_info; #endif cipher_t cipher; memset(&cipher, 0, sizeof(cipher_t)); // Initialize sodium for random generator if (sodium_init() == -1) { FATAL("Failed to initialize sodium"); } if (method == SALSA20 || method == CHACHA20 || method == CHACHA20IETF) { #if defined(USE_CRYPTO_OPENSSL) cipher.info = NULL; cipher.key_len = supported_ciphers_key_size[method]; cipher.iv_len = supported_ciphers_iv_size[method]; #endif #if defined(USE_CRYPTO_POLARSSL) cipher.info = &cipher_info; cipher.info->base = NULL; cipher.info->key_length = supported_ciphers_key_size[method] * 8; cipher.info->iv_size = supported_ciphers_iv_size[method]; #endif #if defined(USE_CRYPTO_MBEDTLS) // XXX: key_length changed to key_bitlen in mbed TLS 2.0.0 cipher.info = &cipher_info; cipher.info->base = NULL; cipher.info->key_bitlen = supported_ciphers_key_size[method] * 8; cipher.info->iv_size = supported_ciphers_iv_size[method]; #endif } else { cipher.info = (cipher_kt_t *)get_cipher_type(method); } if (cipher.info == NULL && cipher.key_len == 0) { 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.info = (cipher_kt_t *)&cipher_info; break; } #endif #if defined(USE_CRYPTO_MBEDTLS) && defined(USE_CRYPTO_APPLECC) // XXX: key_length changed to key_bitlen in mbed TLS 2.0.0 if (supported_ciphers_applecc[method] != kCCAlgorithmInvalid) { cipher_info.base = NULL; cipher_info.key_bitlen = supported_ciphers_key_size[method] * 8; cipher_info.iv_size = supported_ciphers_iv_size[method]; cipher.info = (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) { FATAL("MD5 Digest not found in crypto library"); } enc_key_len = bytes_to_key(&cipher, md, (const uint8_t *)pass, enc_key); if (enc_key_len == 0) { FATAL("Cannot generate key and IV"); } if (method == RC4_MD5 || method == RC4_MD5_6) { enc_iv_len = supported_ciphers_iv_size[method]; } else { enc_iv_len = cipher_iv_size(&cipher); } enc_method = method; } int enc_init(const char *pass, const char *method) { int m = TABLE; if (method != NULL) { for (m = TABLE; m < CIPHER_NUM; m++) if (strcmp(method, supported_ciphers[m]) == 0) { break; } if (m >= CIPHER_NUM) { LOGE("Invalid cipher name: %s, use rc4-md5 instead", method); m = RC4_MD5; } } if (m == TABLE) { enc_table_init(pass); } else { enc_key_init(m, pass); } return m; } int ss_check_hash(buffer_t *buf, chunk_t *chunk, enc_ctx_t *ctx, size_t capacity) { int i, j, k; ssize_t blen = buf->len; uint32_t cidx = chunk->idx; brealloc(chunk->buf, chunk->len + blen, capacity); brealloc(buf, chunk->len + blen, capacity); for (i = 0, j = 0, k = 0; i < blen; i++) { chunk->buf->array[cidx++] = buf->array[k++]; if (cidx == CLEN_BYTES) { uint16_t clen = ntohs(*((uint16_t *)chunk->buf->array)); brealloc(chunk->buf, clen + AUTH_BYTES, capacity); chunk->len = clen; } if (cidx == chunk->len + AUTH_BYTES) { // Compare hash uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t key[MAX_IV_LENGTH + sizeof(uint32_t)]; uint32_t c = htonl(chunk->counter); memcpy(key, ctx->evp.iv, enc_iv_len); memcpy(key + enc_iv_len, &c, sizeof(uint32_t)); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash); #else sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash); #endif if (safe_memcmp(hash, chunk->buf->array + CLEN_BYTES, ONETIMEAUTH_BYTES) != 0) { return 0; } // Copy chunk back to buffer memmove(buf->array + j + chunk->len, buf->array + k, blen - i - 1); memcpy(buf->array + j, chunk->buf->array + AUTH_BYTES, chunk->len); // Reset the base offset j += chunk->len; k = j; cidx = 0; chunk->counter++; } } buf->len = j; chunk->idx = cidx; return 1; } int ss_gen_hash(buffer_t *buf, uint32_t *counter, enc_ctx_t *ctx, size_t capacity) { ssize_t blen = buf->len; uint16_t chunk_len = htons((uint16_t)blen); uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t key[MAX_IV_LENGTH + sizeof(uint32_t)]; uint32_t c = htonl(*counter); brealloc(buf, AUTH_BYTES + blen, capacity); memcpy(key, ctx->evp.iv, enc_iv_len); memcpy(key + enc_iv_len, &c, sizeof(uint32_t)); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf->array, blen, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type( MBEDTLS_MD_SHA1), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf->array, blen, hash); #else sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf->array, blen, hash); #endif memmove(buf->array + AUTH_BYTES, buf->array, blen); memcpy(buf->array + CLEN_BYTES, hash, ONETIMEAUTH_BYTES); memcpy(buf->array, &chunk_len, CLEN_BYTES); *counter = *counter + 1; buf->len = blen + AUTH_BYTES; return 0; }