From 1bc791708afaf176631f5ad8052e420ac13739b0 Mon Sep 17 00:00:00 2001 From: Stephen Lombardo Date: Wed, 29 May 2013 11:18:32 -0400 Subject: [PATCH] separate out openssl implementation to separate source file --- src/crypto.c | 6 +- src/crypto.h | 12 ++++ src/crypto_impl.c | 127 +++++++++++--------------------------- src/crypto_openssl.c | 143 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 95 deletions(-) create mode 100644 src/crypto_openssl.c diff --git a/src/crypto.c b/src/crypto.c index 50213b5..61b9978 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -38,12 +38,12 @@ #include "btreeInt.h" #include "crypto.h" -const char* codec_get_cipher_version() { +static const char* codec_get_cipher_version() { return CIPHER_VERSION; } /* Generate code to return a string value */ -void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value){ +static void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value){ Vdbe *v = sqlite3GetVdbe(pParse); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC); @@ -69,7 +69,7 @@ static int codec_set_btree_to_codec_pagesize(sqlite3 *db, Db *pDb, codec_ctx *ct return rc; } -int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) { +static int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) { struct Db *pDb = &db->aDb[nDb]; CODEC_TRACE(("codec_set_pass_key: entered db=%p nDb=%d zKey=%s nKey=%d for_ctx=%d\n", db, nDb, (char *)zKey, nKey, for_ctx)); if(pDb->pBt) { diff --git a/src/crypto.h b/src/crypto.h index 508b5a1..ea5b1d0 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -82,6 +82,15 @@ #define HMAC_SALT_MASK 0x3a #endif +#ifndef CIPHER_MAX_IV_SZ +#define CIPHER_MAX_IV_SZ 16 +#endif + +#ifndef CIPHER_MAX_KEY_SZ +#define CIPHER_MAX_KEY_SZ 64 +#endif + + #ifdef CODEC_DEBUG #define CODEC_TRACE(X) {printf X;fflush(stdout);} #else @@ -138,6 +147,9 @@ static void cipher_hex2bin(const char *hex, int sz, unsigned char *out){ typedef struct codec_ctx codec_ctx; +void sqlcipher_free(void *ptr, int sz); +void* sqlcipher_malloc(int sz); + /* utility functions */ void* sqlcipher_memset(void *v, unsigned char value, int len); int sqlcipher_ismemset(const void *v, unsigned char value, int len); diff --git a/src/crypto_impl.c b/src/crypto_impl.c index f35144d..8d78fd1 100644 --- a/src/crypto_impl.c +++ b/src/crypto_impl.c @@ -33,9 +33,6 @@ /* BEGIN CRYPTO */ #ifdef SQLITE_HAS_CODEC -#include -#include -#include #include "sqliteInt.h" #include "btreeInt.h" #include "crypto.h" @@ -47,14 +44,13 @@ #endif #endif +#include "crypto_openssl.c" + /* the default implementation of SQLCipher uses a cipher_ctx to keep track of read / write state separately. The following struct and associated functions are defined here */ typedef struct { int derive_key; - EVP_CIPHER *evp_cipher; - EVP_CIPHER_CTX ectx; - HMAC_CTX hctx; int kdf_iter; int fast_kdf_iter; int key_sz; @@ -67,6 +63,7 @@ typedef struct { unsigned char *key; unsigned char *hmac_key; char *pass; + void *lib_ctx; } cipher_ctx; void sqlcipher_cipher_ctx_free(cipher_ctx **); @@ -82,9 +79,6 @@ int sqlcipher_page_hmac(cipher_ctx *, Pgno, unsigned char *, int, unsigned char static unsigned int default_flags = DEFAULT_CIPHER_FLAGS; static unsigned char hmac_salt_mask = HMAC_SALT_MASK; -static unsigned int openssl_external_init = 0; -static unsigned int openssl_init_count = 0; - struct codec_ctx { int kdf_salt_sz; int page_sz; @@ -96,50 +90,6 @@ struct codec_ctx { cipher_ctx *write_ctx; }; -/* activate and initialize sqlcipher. Most importantly, this will automatically - intialize OpenSSL's EVP system if it hasn't already be externally. Note that - this function may be called multiple times as new codecs are intiialized. - Thus it performs some basic counting to ensure that only the last and final - sqlcipher_deactivate() will free the EVP structures. -*/ -void sqlcipher_activate() { - sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); - - /* we'll initialize openssl and increment the internal init counter - but only if it hasn't been initalized outside of SQLCipher by this program - e.g. on startup */ - if(openssl_init_count == 0 && EVP_get_cipherbyname(CIPHER) != NULL) { - openssl_external_init = 1; - } - - if(openssl_external_init == 0) { - if(openssl_init_count == 0) { - OpenSSL_add_all_algorithms(); - } - openssl_init_count++; - } - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); -} - -/* deactivate SQLCipher, most imporantly decremeting the activation count and - freeing the EVP structures on the final deactivation to ensure that - OpenSSL memory is cleaned up */ -void sqlcipher_deactivate() { - sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); - /* If it is initialized externally, then the init counter should never be greater than zero. - This should prevent SQLCipher from "cleaning up" openssl - when something else in the program might be using it. */ - if(openssl_external_init == 0) { - openssl_init_count--; - /* if the counter reaches zero after it's decremented release EVP memory - Note: this code will only be reached if OpensSSL_add_all_algorithms() - is called by SQLCipher internally. */ - if(openssl_init_count == 0) { - EVP_cleanup(); - } - } - sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); -} /* constant time memset using volitile to avoid having the memset optimized out by the compiler. @@ -185,11 +135,6 @@ int sqlcipher_memcmp(const void *v0, const void *v1, int len) { return (result != 0); } -/* generate a defined number of pseudorandom bytes */ -int sqlcipher_random (void *buffer, int length) { - return RAND_bytes((unsigned char *)buffer, length); -} - /** * Free and wipe memory. Uses SQLites internal sqlite3_free so that memory * can be countend and memory leak detection works in the test suite. @@ -243,13 +188,15 @@ void* sqlcipher_malloc(int sz) { * returns SQLITE_NOMEM if an error occured allocating memory */ int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) { + int rc; cipher_ctx *ctx; *iCtx = (cipher_ctx *) sqlcipher_malloc(sizeof(cipher_ctx)); ctx = *iCtx; if(ctx == NULL) return SQLITE_NOMEM; - ctx->key = (unsigned char *) sqlcipher_malloc(EVP_MAX_KEY_LENGTH); - ctx->hmac_key = (unsigned char *) sqlcipher_malloc(EVP_MAX_KEY_LENGTH); + if((rc = sqlcipher_ctx_init(&ctx->lib_ctx)) != SQLITE_OK) return rc; + ctx->key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ); + ctx->hmac_key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ); if(ctx->key == NULL) return SQLITE_NOMEM; if(ctx->hmac_key == NULL) return SQLITE_NOMEM; @@ -265,6 +212,7 @@ int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) { void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) { cipher_ctx *ctx = *iCtx; CODEC_TRACE(("cipher_ctx_free: entered iCtx=%p\n", iCtx)); + sqlcipher_ctx_free(&ctx->lib_ctx); sqlcipher_free(ctx->key, ctx->key_sz); sqlcipher_free(ctx->hmac_key, ctx->key_sz); sqlcipher_free(ctx->pass, ctx->pass_sz); @@ -281,14 +229,14 @@ int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) { CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2)); if( - c1->evp_cipher == c2->evp_cipher - && c1->iv_sz == c2->iv_sz + c1->iv_sz == c2->iv_sz && c1->kdf_iter == c2->kdf_iter && c1->fast_kdf_iter == c2->fast_kdf_iter && c1->key_sz == c2->key_sz && c1->pass_sz == c2->pass_sz && c1->flags == c2->flags && c1->hmac_sz == c2->hmac_sz + && sqlcipher_ctx_cmp(c1->lib_ctx, c2->lib_ctx) && ( c1->pass == c2->pass || !sqlcipher_memcmp((const unsigned char*)c1->pass, @@ -310,16 +258,20 @@ int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) { int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) { void *key = target->key; void *hmac_key = target->hmac_key; + void *lib_ctx = target->lib_ctx; CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source)); sqlcipher_free(target->pass, target->pass_sz); memcpy(target, source, sizeof(cipher_ctx)); target->key = key; //restore pointer to previously allocated key data - memcpy(target->key, source->key, EVP_MAX_KEY_LENGTH); + memcpy(target->key, source->key, CIPHER_MAX_KEY_SZ); target->hmac_key = hmac_key; //restore pointer to previously allocated hmac key data - memcpy(target->hmac_key, source->hmac_key, EVP_MAX_KEY_LENGTH); + memcpy(target->hmac_key, source->hmac_key, CIPHER_MAX_KEY_SZ); + + target->lib_ctx = lib_ctx; // restore pointer to previouly allocated evp; + sqlcipher_ctx_copy(target->lib_ctx, source->lib_ctx); target->pass = sqlcipher_malloc(source->pass_sz); if(target->pass == NULL) return SQLITE_NOMEM; @@ -366,11 +318,12 @@ int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name, int cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx; int rc; - c_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name); - c_ctx->key_sz = EVP_CIPHER_key_length(c_ctx->evp_cipher); - c_ctx->iv_sz = EVP_CIPHER_iv_length(c_ctx->evp_cipher); - c_ctx->block_sz = EVP_CIPHER_block_size(c_ctx->evp_cipher); - c_ctx->hmac_sz = EVP_MD_size(EVP_sha1()); + sqlcipher_set_cipher(c_ctx->lib_ctx, cipher_name); + + c_ctx->key_sz = sqlcipher_get_key_sz(c_ctx->lib_ctx); + c_ctx->iv_sz = sqlcipher_get_iv_sz(c_ctx->lib_ctx); + c_ctx->block_sz = sqlcipher_get_block_sz(c_ctx->lib_ctx); + c_ctx->hmac_sz = sqlcipher_get_hmac_sz(c_ctx->lib_ctx); c_ctx->derive_key = 1; if(for_ctx == 2) @@ -382,8 +335,7 @@ int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name, int const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx) { cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx; - EVP_CIPHER *evp_cipher = c_ctx->evp_cipher; - return EVP_CIPHER_name(evp_cipher); + return sqlcipher_get_cipher(c_ctx->lib_ctx); } int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter, int for_ctx) { @@ -444,7 +396,7 @@ unsigned char sqlcipher_get_hmac_salt_mask() { /* set the codec flag for whether this individual database should be using hmac */ int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) { - int reserve = EVP_MAX_IV_LENGTH; /* base reserve size will be IV only */ + int reserve = CIPHER_MAX_IV_SZ; /* base reserve size will be IV only */ if(use) reserve += ctx->read_ctx->hmac_sz; /* if reserve will include hmac, update that size */ @@ -626,16 +578,14 @@ int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz memcpy(pgno_raw, &pgno, sizeof(pgno)); } - HMAC_CTX_init(&ctx->hctx); - HMAC_Init_ex(&ctx->hctx, ctx->hmac_key, ctx->key_sz, EVP_sha1(), NULL); - /* include the encrypted page data, initialization vector, and page number in HMAC. This will prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise valid pages out of order in a database */ - HMAC_Update(&ctx->hctx, in, in_sz); - HMAC_Update(&ctx->hctx, (const unsigned char*) pgno_raw, sizeof(pgno)); - HMAC_Final(&ctx->hctx, out, NULL); - HMAC_CTX_cleanup(&ctx->hctx); + sqlcipher_hmac( + ctx->hmac_key, ctx->key_sz, + in, in_sz, + (unsigned char*) &pgno_raw, sizeof(pgno), + out); return SQLITE_OK; } @@ -707,17 +657,8 @@ int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int } } } - - EVP_CipherInit(&c_ctx->ectx, c_ctx->evp_cipher, NULL, NULL, mode); - EVP_CIPHER_CTX_set_padding(&c_ctx->ectx, 0); - EVP_CipherInit(&c_ctx->ectx, NULL, c_ctx->key, iv_out, mode); - EVP_CipherUpdate(&c_ctx->ectx, out, &tmp_csz, in, size); - csz = tmp_csz; - out += tmp_csz; - EVP_CipherFinal(&c_ctx->ectx, out, &tmp_csz); - csz += tmp_csz; - EVP_CIPHER_CTX_cleanup(&c_ctx->ectx); - assert(size == csz); + + sqlcipher_cipher(c_ctx->lib_ctx, mode, c_ctx->key, c_ctx->key_sz, iv_out, in, size, out); if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) { sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out); @@ -755,7 +696,7 @@ int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { cipher_hex2bin(z, n, c_ctx->key); } else { CODEC_TRACE(("codec_key_derive: deriving key using full PBKDF2 with %d iterations\n", c_ctx->kdf_iter)); - PKCS5_PBKDF2_HMAC_SHA1( c_ctx->pass, c_ctx->pass_sz, + sqlcipher_kdf( c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key); @@ -779,7 +720,9 @@ int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { CODEC_TRACE(("codec_key_derive: deriving hmac key from encryption key using PBKDF2 with %d iterations\n", c_ctx->fast_kdf_iter)); - PKCS5_PBKDF2_HMAC_SHA1( (const char*)c_ctx->key, c_ctx->key_sz, + + + sqlcipher_kdf( (const char*)c_ctx->key, c_ctx->key_sz, ctx->hmac_kdf_salt, ctx->kdf_salt_sz, c_ctx->fast_kdf_iter, c_ctx->key_sz, c_ctx->hmac_key); } diff --git a/src/crypto_openssl.c b/src/crypto_openssl.c new file mode 100644 index 0000000..416306a --- /dev/null +++ b/src/crypto_openssl.c @@ -0,0 +1,143 @@ +#include +#include +#include + +typedef struct { + EVP_CIPHER *evp_cipher; + unsigned char * buffer; +} openssl_ctx; + + +static unsigned int openssl_external_init = 0; +static unsigned int openssl_init_count = 0; + +/* activate and initialize sqlcipher. Most importantly, this will automatically + intialize OpenSSL's EVP system if it hasn't already be externally. Note that + this function may be called multiple times as new codecs are intiialized. + Thus it performs some basic counting to ensure that only the last and final + sqlcipher_deactivate() will free the EVP structures. +*/ +void sqlcipher_activate(void *ctx) { + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); + + /* we'll initialize openssl and increment the internal init counter + but only if it hasn't been initalized outside of SQLCipher by this program + e.g. on startup */ + if(openssl_init_count == 0 && EVP_get_cipherbyname(CIPHER) != NULL) { + openssl_external_init = 1; + } + + if(openssl_external_init == 0) { + if(openssl_init_count == 0) { + OpenSSL_add_all_algorithms(); + } + openssl_init_count++; + } + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +/* deactivate SQLCipher, most imporantly decremeting the activation count and + freeing the EVP structures on the final deactivation to ensure that + OpenSSL memory is cleaned up */ +void sqlcipher_deactivate() { + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); + /* If it is initialized externally, then the init counter should never be greater than zero. + This should prevent SQLCipher from "cleaning up" openssl + when something else in the program might be using it. */ + if(openssl_external_init == 0) { + openssl_init_count--; + /* if the counter reaches zero after it's decremented release EVP memory + Note: this code will only be reached if OpensSSL_add_all_algorithms() + is called by SQLCipher internally. */ + if(openssl_init_count == 0) { + EVP_cleanup(); + } + } + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); +} + +/* generate a defined number of pseudorandom bytes */ +int sqlcipher_random (void *buffer, int length) { + return RAND_bytes((unsigned char *)buffer, length); +} + +int sqlcipher_hmac(unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) { + HMAC_CTX hctx; + HMAC_CTX_init(&hctx); + HMAC_Init_ex(&hctx, hmac_key, key_sz, EVP_sha1(), NULL); + HMAC_Update(&hctx, in, in_sz); + HMAC_Update(&hctx, in2, in2_sz); + HMAC_Final(&hctx, out, NULL); + HMAC_CTX_cleanup(&hctx); + return SQLITE_OK; +} + +int sqlcipher_kdf(const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) { + PKCS5_PBKDF2_HMAC_SHA1(pass, pass_sz, salt, salt_sz, workfactor, key_sz, key); + return SQLITE_OK; +} + +int sqlcipher_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) { + EVP_CIPHER_CTX ectx; + int tmp_csz, csz; + + EVP_CipherInit(&ectx, ((openssl_ctx *)ctx)->evp_cipher, NULL, NULL, mode); + EVP_CIPHER_CTX_set_padding(&ectx, 0); // no padding + EVP_CipherInit(&ectx, NULL, key, iv, mode); + EVP_CipherUpdate(&ectx, out, &tmp_csz, in, in_sz); + csz = tmp_csz; + out += tmp_csz; + EVP_CipherFinal(&ectx, out, &tmp_csz); + csz += tmp_csz; + EVP_CIPHER_CTX_cleanup(&ectx); + assert(in_sz == csz); + return SQLITE_OK; +} + +int sqlcipher_set_cipher(void *ctx, const char *cipher_name) { + openssl_ctx *o_ctx = (openssl_ctx *)ctx; + o_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name); + return SQLITE_OK; +} + +const char* sqlcipher_get_cipher(void *ctx) { + return EVP_CIPHER_name(((openssl_ctx *)ctx)->evp_cipher); +} + +int sqlcipher_get_key_sz(void *ctx) { + return EVP_CIPHER_key_length(((openssl_ctx *)ctx)->evp_cipher); +} + +int sqlcipher_get_iv_sz(void *ctx) { + return EVP_CIPHER_iv_length(((openssl_ctx *)ctx)->evp_cipher); +} + +int sqlcipher_get_block_sz(void *ctx) { + return EVP_CIPHER_block_size(((openssl_ctx *)ctx)->evp_cipher); +} + +int sqlcipher_get_hmac_sz(void *ctx) { + return EVP_MD_size(EVP_sha1()); +} + +int sqlcipher_ctx_copy(void *target_ctx, void *source_ctx) { + memcpy(target_ctx, source_ctx, sizeof(openssl_ctx)); + return SQLITE_OK; +} + +int sqlcipher_ctx_cmp(void *c1, void *c2) { + return ((openssl_ctx *)c1)->evp_cipher == ((openssl_ctx *)c2)->evp_cipher; +} + +int sqlcipher_ctx_init(void **ctx) { + *ctx = sqlcipher_malloc(sizeof(openssl_ctx)); + if(*ctx == NULL) return SQLITE_NOMEM; + return SQLITE_OK; +} + +int sqlcipher_ctx_free(void **ctx) { + sqlcipher_free(*ctx, sizeof(openssl_ctx)); + return SQLITE_OK; +} + +