summaryrefslogtreecommitdiff
path: root/src/crypto_impl.c
diff options
context:
space:
mode:
authorHans-Christoph Steiner <hans@eds.org>2012-03-30 20:42:12 -0400
committerHans-Christoph Steiner <hans@eds.org>2012-03-30 20:42:12 -0400
commit7bb481fda9ecb134804b49c2ce77ca28f7eea583 (patch)
tree31b520b9914d3e2453968abe375f2c102772c3dc /src/crypto_impl.c
Imported Upstream version 2.0.3
Diffstat (limited to 'src/crypto_impl.c')
-rw-r--r--src/crypto_impl.c833
1 files changed, 833 insertions, 0 deletions
diff --git a/src/crypto_impl.c b/src/crypto_impl.c
new file mode 100644
index 0000000..336afbd
--- /dev/null
+++ b/src/crypto_impl.c
@@ -0,0 +1,833 @@
+/*
+** SQLCipher
+** crypto_impl.c developed by Stephen Lombardo (Zetetic LLC)
+** sjlombardo at zetetic dot net
+** http://zetetic.net
+**
+** Copyright (c) 2011, ZETETIC LLC
+** 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 ZETETIC LLC 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 ZETETIC LLC ''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 ZETETIC LLC 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.
+**
+*/
+/* BEGIN CRYPTO */
+#ifdef SQLITE_HAS_CODEC
+
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include "sqliteInt.h"
+#include "btreeInt.h"
+#include "crypto.h"
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__)
+#include <sys/mman.h>
+#elif defined(_WIN32)
+# include <windows.h>
+#endif
+#endif
+
+/* 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;
+ int iv_sz;
+ int block_sz;
+ int pass_sz;
+ int reserve_sz;
+ int hmac_sz;
+ int use_hmac;
+ unsigned char *key;
+ unsigned char *hmac_key;
+ char *pass;
+} cipher_ctx;
+
+void sqlcipher_cipher_ctx_free(cipher_ctx **);
+int sqlcipher_cipher_ctx_cmp(cipher_ctx *, cipher_ctx *);
+int sqlcipher_cipher_ctx_copy(cipher_ctx *, cipher_ctx *);
+int sqlcipher_cipher_ctx_init(cipher_ctx **);
+int sqlcipher_cipher_ctx_set_pass(cipher_ctx *, const void *, int);
+int sqlcipher_cipher_ctx_key_derive(codec_ctx *, cipher_ctx *);
+
+/* prototype for pager HMAC function */
+int sqlcipher_page_hmac(cipher_ctx *, Pgno, unsigned char *, int, unsigned char *);
+
+struct codec_ctx {
+ int kdf_salt_sz;
+ int page_sz;
+ unsigned char *kdf_salt;
+ unsigned char *hmac_kdf_salt;
+ unsigned char *buffer;
+ Btree *pBt;
+ cipher_ctx *read_ctx;
+ cipher_ctx *write_ctx;
+};
+
+void sqlcipher_activate() {
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ if(EVP_get_cipherbyname(CIPHER) == NULL) {
+ OpenSSL_add_all_algorithms();
+ }
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+/* fixed time memory comparison routine */
+int sqlcipher_memcmp(const unsigned char *a0, const unsigned char *a1, int len) {
+ int i = 0, noMatch = 0;
+
+ for(i = 0; i < len; i++) {
+ noMatch = (noMatch || (a0[i] != a1[i]));
+ }
+
+ return noMatch;
+}
+
+/* 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 tet suite.
+ * If ptr is not null memory will be freed.
+ * If sz is greater than zero, the memory will be overwritten with zero before it is freed
+ * If sz is > 0, and not compiled with OMIT_MEMLOCK, system will attempt to unlock the
+ * memory segment so it can be paged
+ */
+void sqlcipher_free(void *ptr, int sz) {
+ if(ptr) {
+ if(sz > 0) {
+ memset(ptr, 0, sz);
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__)
+ munlock(ptr, sz);
+#elif defined(_WIN32)
+ VirtualUnlock(ptr, sz);
+#endif
+#endif
+ }
+ sqlite3_free(ptr);
+ }
+}
+
+/**
+ * allocate memory. Uses sqlite's internall malloc wrapper so memory can be
+ * reference counted and leak detection works. Unless compiled with OMIT_MEMLOCK
+ * attempts to lock the memory pages so sensitive information won't be swapped
+ */
+void* sqlcipher_malloc(int sz) {
+ void *ptr = sqlite3Malloc(sz);
+#ifndef OMIT_MEMLOCK
+ if(ptr) {
+#if defined(__unix__) || defined(__APPLE__)
+ mlock(ptr, sz);
+#elif defined(_WIN32)
+ VirtualLock(ptr, sz);
+#endif
+ }
+#endif
+ return ptr;
+}
+
+
+/**
+ * Initialize a a new cipher_ctx struct. This function will allocate memory
+ * for the cipher context and for the key
+ *
+ * returns SQLITE_OK if initialization was successful
+ * returns SQLITE_NOMEM if an error occured allocating memory
+ */
+int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) {
+ cipher_ctx *ctx;
+ *iCtx = (cipher_ctx *) sqlcipher_malloc(sizeof(cipher_ctx));
+ ctx = *iCtx;
+ if(ctx == NULL) return SQLITE_NOMEM;
+ memset(ctx, 0, sizeof(cipher_ctx));
+ ctx->key = (unsigned char *) sqlcipher_malloc(EVP_MAX_KEY_LENGTH);
+ ctx->hmac_key = (unsigned char *) sqlcipher_malloc(EVP_MAX_KEY_LENGTH);
+ if(ctx->key == NULL) return SQLITE_NOMEM;
+ if(ctx->hmac_key == NULL) return SQLITE_NOMEM;
+ return SQLITE_OK;
+}
+
+/**
+ * Free and wipe memory associated with a cipher_ctx
+ */
+void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) {
+ cipher_ctx *ctx = *iCtx;
+ CODEC_TRACE(("cipher_ctx_free: entered iCtx=%d\n", iCtx));
+ sqlcipher_free(ctx->key, ctx->key_sz);
+ sqlcipher_free(ctx->hmac_key, ctx->key_sz);
+ sqlcipher_free(ctx->pass, ctx->pass_sz);
+ sqlcipher_free(ctx, sizeof(cipher_ctx));
+}
+
+/**
+ * Compare one cipher_ctx to another.
+ *
+ * returns 0 if all the parameters (except the derived key data) are the same
+ * returns 1 otherwise
+ */
+int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
+ CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%d c2=%d\n", c1, c2));
+
+ if(
+ c1->evp_cipher == c2->evp_cipher
+ && 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->pass == c2->pass
+ || !sqlcipher_memcmp((const unsigned char*)c1->pass,
+ (const unsigned char*)c2->pass,
+ c1->pass_sz)
+ )
+ ) return 0;
+ return 1;
+}
+
+/**
+ * Copy one cipher_ctx to another. For instance, assuming that read_ctx is a
+ * fully initialized context, you could copy it to write_ctx and all yet data
+ * and pass information across
+ *
+ * returns SQLITE_OK if initialization was successful
+ * returns SQLITE_NOMEM if an error occured allocating memory
+ */
+int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
+ void *key = target->key;
+ void *hmac_key = target->hmac_key;
+
+ CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%d, source=%d\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);
+
+ target->hmac_key = hmac_key; //restore pointer to previously allocated hmac key data
+ memcpy(target->hmac_key, source->hmac_key, EVP_MAX_KEY_LENGTH);
+
+ target->pass = sqlcipher_malloc(source->pass_sz);
+ if(target->pass == NULL) return SQLITE_NOMEM;
+ memcpy(target->pass, source->pass, source->pass_sz);
+
+ return SQLITE_OK;
+}
+
+
+/**
+ * Set the raw password / key data for a cipher context
+ *
+ * returns SQLITE_OK if assignment was successfull
+ * returns SQLITE_NOMEM if an error occured allocating memory
+ * returns SQLITE_ERROR if the key couldn't be set because the pass was null or size was zero
+ */
+int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
+ sqlcipher_free(ctx->pass, ctx->pass_sz);
+ ctx->pass_sz = nKey;
+ if(zKey && nKey) {
+ ctx->pass = sqlcipher_malloc(nKey);
+ if(ctx->pass == NULL) return SQLITE_NOMEM;
+ memcpy(ctx->pass, zKey, nKey);
+ return SQLITE_OK;
+ }
+ return SQLITE_ERROR;
+}
+
+int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ int rc;
+
+ if((rc = sqlcipher_cipher_ctx_set_pass(c_ctx, zKey, nKey)) != SQLITE_OK) return rc;
+ c_ctx->derive_key = 1;
+
+ if(for_ctx == 2)
+ if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+ return rc;
+
+ return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name, int for_ctx) {
+ 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());
+ c_ctx->derive_key = 1;
+
+ if(for_ctx == 2)
+ if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+ return rc;
+
+ return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ int rc;
+
+ c_ctx->kdf_iter = kdf_iter;
+ c_ctx->derive_key = 1;
+
+ if(for_ctx == 2)
+ if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+ return rc;
+
+ return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter, int for_ctx) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ int rc;
+
+ c_ctx->fast_kdf_iter = fast_kdf_iter;
+ c_ctx->derive_key = 1;
+
+ if(for_ctx == 2)
+ if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+ return rc;
+
+ return SQLITE_OK;
+}
+
+
+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 */
+
+ if(use) reserve += ctx->read_ctx->hmac_sz; /* if reserve will include hmac, update that size */
+
+ /* calculate the amount of reserve needed in even increments of the cipher block size */
+
+ reserve = ((reserve % ctx->read_ctx->block_sz) == 0) ? reserve :
+ ((reserve / ctx->read_ctx->block_sz) + 1) * ctx->read_ctx->block_sz;
+
+ CODEC_TRACE(("sqlcipher_codec_ctx_set_use_hmac: use=%d block_sz=%d md_size=%d reserve=%d\n",
+ use, ctx->read_ctx->block_sz, ctx->read_ctx->hmac_sz, reserve));
+
+ ctx->write_ctx->use_hmac = ctx->read_ctx->use_hmac = use;
+ ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
+
+ return SQLITE_OK;
+}
+
+void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
+ ctx->pBt->db->errCode = error;
+}
+
+int sqlcipher_codec_ctx_get_pagesize(codec_ctx *ctx) {
+ return ctx->page_sz;
+}
+
+int sqlcipher_codec_ctx_get_reservesize(codec_ctx *ctx) {
+ return ctx->read_ctx->reserve_sz;
+}
+
+void* sqlcipher_codec_ctx_get_data(codec_ctx *ctx) {
+ return ctx->buffer;
+}
+
+void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx) {
+ return ctx->kdf_salt;
+}
+
+void sqlcipher_codec_get_pass(codec_ctx *ctx, void **zKey, int *nKey) {
+ *zKey = ctx->read_ctx->pass;
+ *nKey = ctx->read_ctx->pass_sz;
+}
+
+int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
+ /* attempt to free the existing page buffer */
+ sqlcipher_free(ctx->buffer,ctx->page_sz);
+ ctx->page_sz = size;
+
+ /* pre-allocate a page buffer of PageSize bytes. This will
+ be used as a persistent buffer for encryption and decryption
+ operations to avoid overhead of multiple memory allocations*/
+ ctx->buffer = sqlcipher_malloc(size);
+ if(ctx->buffer == NULL) return SQLITE_NOMEM;
+
+ return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_file *fd, const void *zKey, int nKey) {
+ int rc;
+ codec_ctx *ctx;
+ *iCtx = sqlcipher_malloc(sizeof(codec_ctx));
+ ctx = *iCtx;
+
+ if(ctx == NULL) return SQLITE_NOMEM;
+
+ memset(ctx, 0, sizeof(codec_ctx)); /* initialize all pointers and values to 0 */
+ ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
+
+ /* allocate space for salt data. Then read the first 16 bytes
+ directly off the database file. This is the salt for the
+ key derivation function. If we get a short read allocate
+ a new random salt value */
+ ctx->kdf_salt_sz = FILE_HEADER_SZ;
+ ctx->kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
+ if(ctx->kdf_salt == NULL) return SQLITE_NOMEM;
+
+ /* allocate space for separate hmac salt data. We want the
+ HMAC derivation salt to be different than the encryption
+ key derivation salt */
+ ctx->hmac_kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
+ if(ctx->hmac_kdf_salt == NULL) return SQLITE_NOMEM;
+
+
+ /*
+ Always overwrite page size and set to the default because the first page of the database
+ in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in
+ cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman
+ */
+ if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, SQLITE_DEFAULT_PAGE_SIZE)) != SQLITE_OK) return rc;
+
+ if((rc = sqlcipher_cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc;
+
+ if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
+ /* if unable to read the bytes, generate random salt */
+ if(sqlcipher_random(ctx->kdf_salt, FILE_HEADER_SZ) != 1) return SQLITE_ERROR;
+ }
+
+ if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, FAST_PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
+ if((rc = sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, 0)) != SQLITE_OK) return rc;
+
+ /* Use HMAC signatures by default. Note that codec_set_use_hmac will implicity call
+ codec_set_page_size to set the default */
+ if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, DEFAULT_USE_HMAC)) != SQLITE_OK) return rc;
+
+ if((rc = sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) return rc;
+
+ return SQLITE_OK;
+}
+
+/**
+ * Free and wipe memory associated with a cipher_ctx, including the allocated
+ * read_ctx and write_ctx.
+ */
+void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
+ codec_ctx *ctx = *iCtx;
+ CODEC_TRACE(("codec_ctx_free: entered iCtx=%d\n", iCtx));
+ sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz);
+ sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz);
+ sqlcipher_free(ctx->buffer, 0);
+ sqlcipher_cipher_ctx_free(&ctx->read_ctx);
+ sqlcipher_cipher_ctx_free(&ctx->write_ctx);
+ sqlcipher_free(ctx, sizeof(codec_ctx));
+}
+
+int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
+ 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, sizeof(Pgno));
+ HMAC_Final(&ctx->hctx, out, NULL);
+ HMAC_CTX_cleanup(&ctx->hctx);
+ return SQLITE_OK;
+}
+
+/*
+ * ctx - codec context
+ * pgno - page number in database
+ * size - size in bytes of input and output buffers
+ * mode - 1 to encrypt, 0 to decrypt
+ * in - pointer to input bytes
+ * out - pouter to output bytes
+ */
+int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int page_sz, unsigned char *in, unsigned char *out) {
+ cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+ unsigned char *iv_in, *iv_out, *hmac_in, *hmac_out, *out_start;
+ int tmp_csz, csz, size;
+
+ /* calculate some required positions into various buffers */
+ size = page_sz - c_ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
+ iv_out = out + size;
+ iv_in = in + size;
+
+ /* hmac will be written immediately after the initialization vector. the remainder of the page reserve will contain
+ random bytes. note, these pointers are only valid when use_hmac is true */
+ hmac_in = in + size + c_ctx->iv_sz;
+ hmac_out = out + size + c_ctx->iv_sz;
+ out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */
+
+ CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
+
+ /* just copy raw data from in to out when key size is 0
+ * i.e. during a rekey of a plaintext database */
+ if(c_ctx->key_sz == 0) {
+ memcpy(out, in, size);
+ return SQLITE_OK;
+ }
+
+ if(mode == CIPHER_ENCRYPT) {
+ /* start at front of the reserve block, write random data to the end */
+ if(sqlcipher_random(iv_out, c_ctx->reserve_sz) != 1) return SQLITE_ERROR;
+ } else { /* CIPHER_DECRYPT */
+ memcpy(iv_out, iv_in, c_ctx->iv_sz); /* copy the iv from the input to output buffer */
+ }
+
+ if(c_ctx->use_hmac && (mode == CIPHER_DECRYPT)) {
+ if(sqlcipher_page_hmac(c_ctx, pgno, in, size + c_ctx->iv_sz, hmac_out) != SQLITE_OK) {
+ memset(out, 0, page_sz);
+ CODEC_TRACE(("codec_cipher: hmac operations failed for pgno=%d\n", pgno));
+ return SQLITE_ERROR;
+ }
+
+ CODEC_TRACE(("codec_cipher: comparing hmac on in=%d out=%d hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz));
+ if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) {
+ /* the hmac check failed, which means the data was tampered with or
+ corrupted in some way. we will return an error, and zero out the page data
+ to force an error */
+ memset(out, 0, page_sz);
+ CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d\n", pgno));
+ return SQLITE_ERROR;
+ }
+ }
+
+ 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);
+
+ if(c_ctx->use_hmac && (mode == CIPHER_ENCRYPT)) {
+ sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out);
+ }
+
+ return SQLITE_OK;
+}
+
+/**
+ * Derive an encryption key for a cipher contex key based on the raw password.
+ *
+ * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
+ * the key space (i.e 64 hex chars for a 256 bit key) then the key data will be used directly.
+ *
+ * Otherwise, a key data will be derived using PBKDF2
+ *
+ * returns SQLITE_OK if initialization was successful
+ * returns SQLITE_ERROR if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
+ */
+int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
+ CODEC_TRACE(("codec_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
+ ctx->kdf_salt=%d ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \
+ ctx->hmac_kdf_salt=%d, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n",
+ c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter,
+ ctx->hmac_kdf_salt, c_ctx->fast_kdf_iter, c_ctx->key_sz));
+
+
+ if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null
+ if (c_ctx->pass_sz == ((c_ctx->key_sz*2)+3) && sqlite3StrNICmp(c_ctx->pass ,"x'", 2) == 0) {
+ int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */
+ const char *z = c_ctx->pass + 2; /* adjust lead offset of x' */
+ CODEC_TRACE(("codec_key_derive: using raw key from hex\n"));
+ 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,
+ ctx->kdf_salt, ctx->kdf_salt_sz,
+ c_ctx->kdf_iter, c_ctx->key_sz, c_ctx->key);
+
+ }
+
+ /* if this context is setup to use hmac checks, generate a seperate and different
+ key for HMAC. In this case, we use the output of the previous KDF as the input to
+ this KDF run. This ensures a distinct but predictable HMAC key. */
+ if(c_ctx->use_hmac) {
+ int i;
+
+ /* start by copying the kdf key into the hmac salt slot
+ then XOR it with the fixed hmac salt defined at compile time
+ this ensures that the salt passed in to derive the hmac key, while
+ easy to derive and publically known, is not the same as the salt used
+ to generate the encryption key */
+ memcpy(ctx->hmac_kdf_salt, ctx->kdf_salt, ctx->kdf_salt_sz);
+ for(i = 0; i < ctx->kdf_salt_sz; i++) {
+ ctx->hmac_kdf_salt[i] ^= HMAC_SALT_MASK;
+ }
+
+ 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,
+ ctx->hmac_kdf_salt, ctx->kdf_salt_sz,
+ c_ctx->fast_kdf_iter, c_ctx->key_sz, c_ctx->hmac_key);
+ }
+
+ c_ctx->derive_key = 0;
+ return SQLITE_OK;
+ };
+ return SQLITE_ERROR;
+}
+
+int sqlcipher_codec_key_derive(codec_ctx *ctx) {
+ /* derive key on first use if necessary */
+ if(ctx->read_ctx->derive_key) {
+ if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
+ }
+
+ if(ctx->write_ctx->derive_key) {
+ if(sqlcipher_cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
+ // the relevant parameters are the same, just copy read key
+ if(sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
+ } else {
+ if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->write_ctx) != SQLITE_OK) return SQLITE_ERROR;
+ }
+ }
+ return SQLITE_OK;
+}
+
+int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
+ if(source == CIPHER_READ_CTX) {
+ return sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx);
+ } else {
+ return sqlcipher_cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
+ }
+}
+
+
+#ifndef OMIT_EXPORT
+
+/*
+ * Implementation of an "export" function that allows a caller
+ * to duplicate the main database to an attached database. This is intended
+ * as a conveneince for users who need to:
+ *
+ * 1. migrate from an non-encrypted database to an encrypted database
+ * 2. move from an encrypted database to a non-encrypted database
+ * 3. convert beween the various flavors of encrypted databases.
+ *
+ * This implementation is based heavily on the procedure and code used
+ * in vacuum.c, but is exposed as a function that allows export to any
+ * named attached database.
+ */
+
+/*
+** Finalize a prepared statement. If there was an error, store the
+** text of the error message in *pzErrMsg. Return the result code.
+**
+** Based on vacuumFinalize from vacuum.c
+*/
+static int sqlcipher_finalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
+ int rc;
+ rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
+ if( rc ){
+ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
+ }
+ return rc;
+}
+
+/*
+** Execute zSql on database db. Return an error code.
+**
+** Based on execSql from vacuum.c
+*/
+static int sqlcipher_execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
+ sqlite3_stmt *pStmt;
+ VVA_ONLY( int rc; )
+ if( !zSql ){
+ return SQLITE_NOMEM;
+ }
+ if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
+ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
+ return sqlite3_errcode(db);
+ }
+ VVA_ONLY( rc = ) sqlite3_step(pStmt);
+ assert( rc!=SQLITE_ROW );
+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
+
+/*
+** Execute zSql on database db. The statement returns exactly
+** one column. Execute this as SQL on the same database.
+**
+** Based on execExecSql from vacuum.c
+*/
+static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
+ sqlite3_stmt *pStmt;
+ int rc;
+
+ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ) return rc;
+
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
+ if( rc!=SQLITE_OK ){
+ sqlcipher_finalize(db, pStmt, pzErrMsg);
+ return rc;
+ }
+ }
+
+ return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
+
+/*
+ * copy database and schema from the main database to an attached database
+ *
+ * Based on sqlite3RunVacuum from vacuum.c
+*/
+void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char* attachedDb = (const char*) sqlite3_value_text(argv[0]);
+ int saved_flags; /* Saved value of the db->flags */
+ int saved_nChange; /* Saved value of db->nChange */
+ int saved_nTotalChange; /* Saved value of db->nTotalChange */
+ void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
+ int rc = SQLITE_OK; /* Return code from service routines */
+ char *zSql = NULL; /* SQL statements */
+ char *pzErrMsg = NULL;
+
+ saved_flags = db->flags;
+ saved_nChange = db->nChange;
+ saved_nTotalChange = db->nTotalChange;
+ saved_xTrace = db->xTrace;
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
+ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
+ db->xTrace = 0;
+
+ /* Query the schema of the main database. Create a mirror schema
+ ** in the temporary database.
+ */
+ zSql = sqlite3_mprintf(
+ "SELECT 'CREATE TABLE %s.' || substr(sql,14) "
+ " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+ " AND rootpage>0"
+ , attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ zSql = sqlite3_mprintf(
+ "SELECT 'CREATE INDEX %s.' || substr(sql,14)"
+ " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
+ , attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ zSql = sqlite3_mprintf(
+ "SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) "
+ " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
+ , attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ /* Loop through the tables in the main database. For each, do
+ ** an "INSERT INTO rekey_db.xxx SELECT * FROM main.xxx;" to copy
+ ** the contents to the temporary database.
+ */
+ zSql = sqlite3_mprintf(
+ "SELECT 'INSERT INTO %s.' || quote(name) "
+ "|| ' SELECT * FROM main.' || quote(name) || ';'"
+ "FROM main.sqlite_master "
+ "WHERE type = 'table' AND name!='sqlite_sequence' "
+ " AND rootpage>0"
+ , attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ /* Copy over the sequence table
+ */
+ zSql = sqlite3_mprintf(
+ "SELECT 'DELETE FROM %s.' || quote(name) || ';' "
+ "FROM %s.sqlite_master WHERE name='sqlite_sequence' "
+ , attachedDb, attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ zSql = sqlite3_mprintf(
+ "SELECT 'INSERT INTO %s.' || quote(name) "
+ "|| ' SELECT * FROM main.' || quote(name) || ';' "
+ "FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
+ , attachedDb, attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ /* Copy the triggers, views, and virtual tables from the main database
+ ** over to the temporary database. None of these objects has any
+ ** associated storage, so all we have to do is copy their entries
+ ** from the SQLITE_MASTER table.
+ */
+ zSql = sqlite3_mprintf(
+ "INSERT INTO %s.sqlite_master "
+ " SELECT type, name, tbl_name, rootpage, sql"
+ " FROM main.sqlite_master"
+ " WHERE type='view' OR type='trigger'"
+ " OR (type='table' AND rootpage=0)"
+ , attachedDb);
+ rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql);
+ if( rc!=SQLITE_OK ) goto end_of_export;
+ sqlite3_free(zSql);
+
+ zSql = NULL;
+end_of_export:
+ db->flags = saved_flags;
+ db->nChange = saved_nChange;
+ db->nTotalChange = saved_nTotalChange;
+ db->xTrace = saved_xTrace;
+
+ sqlite3_free(zSql);
+
+ if(rc) {
+ if(pzErrMsg != NULL) {
+ sqlite3_result_error(context, pzErrMsg, -1);
+ sqlite3DbFree(db, pzErrMsg);
+ } else {
+ sqlite3_result_error(context, sqlite3ErrStr(rc), -1);
+ }
+ }
+}
+
+#endif
+#endif