/** * 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 */ static int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) { void *key = target->key; void *hmac_key = target->hmac_key; void *provider = target->provider; void *provider_ctx = target->provider_ctx; CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source)); sqlcipher_free(target->pass, target->pass_sz); sqlcipher_free(target->keyspec, target->keyspec_sz); memcpy(target, source, sizeof(cipher_ctx)); target->key = key; //restore pointer to previously allocated key data 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, CIPHER_MAX_KEY_SZ); target->provider = provider; // restore pointer to previouly allocated provider; memcpy(target->provider, source->provider, sizeof(sqlcipher_provider)); target->provider_ctx = provider_ctx; // restore pointer to previouly allocated provider context; target->provider->ctx_copy(target->provider_ctx, source->provider_ctx); if(source->pass && source->pass_sz) { target->pass = sqlcipher_malloc(source->pass_sz); if(target->pass == NULL) return SQLITE_NOMEM; memcpy(target->pass, source->pass, source->pass_sz); } if(source->keyspec && source->keyspec_sz) { target->keyspec = sqlcipher_malloc(source->keyspec_sz); if(target->keyspec == NULL) return SQLITE_NOMEM; memcpy(target->keyspec, source->keyspec, source->keyspec_sz); } 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=%p\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_register_provider(sqlcipher_provider *p) { sqlite3_mutex_enter(sqlcipher_provider_mutex); if(default_provider != NULL && default_provider != p) { /* only free the current registerd provider if it has been initialized and it isn't a pointer to the same provider passed to the function (i.e. protect against a caller calling register twice for the same provider) */ sqlcipher_free(default_provider, sizeof(sqlcipher_provider)); } default_provider = p; sqlite3_mutex_leave(sqlcipher_provider_mutex); return SQLITE_OK; }
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; }
/** * Set the passphrase for the cipher_ctx * * returns SQLITE_OK if assignment was successfull * returns SQLITE_NOMEM if an error occured allocating memory */ static int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) { /* free, zero existing pointers and size */ sqlcipher_free(ctx->pass, ctx->pass_sz); ctx->pass = NULL; ctx->pass_sz = 0; if(zKey && nKey) { /* if new password is provided, copy it */ ctx->pass_sz = nKey; ctx->pass = sqlcipher_malloc(nKey); if(ctx->pass == NULL) return SQLITE_NOMEM; memcpy(ctx->pass, zKey, nKey); } return SQLITE_OK; }
/** * Free and wipe memory associated with a cipher_ctx */ static void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) { cipher_ctx *ctx = *iCtx; CODEC_TRACE(("cipher_ctx_free: entered iCtx=%p\n", iCtx)); ctx->provider->ctx_free(&ctx->provider_ctx); sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider)); 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->keyspec, ctx->keyspec_sz); sqlcipher_free(ctx, sizeof(cipher_ctx)); }
/** * Set the keyspec for the cipher_ctx * * returns SQLITE_OK if assignment was successfull * returns SQLITE_NOMEM if an error occured allocating memory */ static int sqlcipher_cipher_ctx_set_keyspec(cipher_ctx *ctx, const unsigned char *key, int key_sz, const unsigned char *salt, int salt_sz) { /* free, zero existing pointers and size */ sqlcipher_free(ctx->keyspec, ctx->keyspec_sz); ctx->keyspec = NULL; ctx->keyspec_sz = 0; /* establic a hex-formated key specification, containing the raw encryption key and the salt used to generate it */ ctx->keyspec_sz = ((key_sz + salt_sz) * 2) + 3; ctx->keyspec = sqlcipher_malloc(ctx->keyspec_sz); if(ctx->keyspec == NULL) return SQLITE_NOMEM; ctx->keyspec[0] = 'x'; ctx->keyspec[1] = '\''; cipher_bin2hex(key, key_sz, ctx->keyspec + 2); cipher_bin2hex(salt, salt_sz, ctx->keyspec + (key_sz * 2) + 2); ctx->keyspec[ctx->keyspec_sz - 1] = '\''; return SQLITE_OK; }
void sqlcipher_deactivate() { sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); sqlcipher_activate_count--; /* if no connections are using sqlcipher, cleanup globals */ if(sqlcipher_activate_count < 1) { sqlite3_mutex_enter(sqlcipher_provider_mutex); if(default_provider != NULL) { sqlcipher_free(default_provider, sizeof(sqlcipher_provider)); default_provider = NULL; } sqlite3_mutex_leave(sqlcipher_provider_mutex); /* last connection closed, free provider mutex*/ sqlite3_mutex_free(sqlcipher_provider_mutex); sqlcipher_provider_mutex = NULL; sqlcipher_activate_count = 0; /* reset activation count */ } sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)); }
int sqlcipher_codec_add_random(codec_ctx *ctx, const char *zRight, int random_sz){ const char *suffix = &zRight[random_sz-1]; int n = random_sz - 3; /* adjust for leading x' and tailing ' */ if (n > 0 && sqlite3StrNICmp((const char *)zRight ,"x'", 2) == 0 && sqlite3StrNICmp(suffix, "'", 1) == 0 && n % 2 == 0) { int rc = 0; int buffer_sz = n / 2; unsigned char *random; const unsigned char *z = (const unsigned char *)zRight + 2; /* adjust lead offset of x' */ CODEC_TRACE(("sqlcipher_codec_add_random: using raw random blob from hex\n")); random = sqlcipher_malloc(buffer_sz); memset(random, 0, buffer_sz); cipher_hex2bin(z, n, random); rc = ctx->read_ctx->provider->add_random(ctx->read_ctx->provider_ctx, random, buffer_sz); sqlcipher_free(random, buffer_sz); return rc; } return SQLITE_ERROR; }
static int sqlcipher_openssl_ctx_free(void **ctx) { sqlcipher_openssl_deactivate(*ctx); sqlcipher_free(*ctx, sizeof(openssl_ctx)); return SQLITE_OK; }
int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) { u32 meta; int rc = 0; int command_idx = 0; int password_sz; int saved_flags; int saved_nChange; int saved_nTotalChange; void (*saved_xTrace)(void*,const char*); Db *pDb = 0; sqlite3 *db = ctx->pBt->db; const char *db_filename = sqlite3_db_filename(db, "main"); char *migrated_db_filename = sqlite3_mprintf("%s-migrated", db_filename); char *pragma_hmac_off = "PRAGMA cipher_use_hmac = OFF;"; char *pragma_4k_kdf_iter = "PRAGMA kdf_iter = 4000;"; char *pragma_1x_and_4k; char *set_user_version; char *key; int key_sz; int user_version = 0; int upgrade_1x_format = 0; int upgrade_4k_format = 0; static const unsigned char aCopy[] = { BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_USER_VERSION, 0, /* Preserve the user version */ BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; key_sz = ctx->read_ctx->pass_sz + 1; key = sqlcipher_malloc(key_sz); memset(key, 0, key_sz); memcpy(key, ctx->read_ctx->pass, ctx->read_ctx->pass_sz); if(db_filename){ const char* commands[5]; char *attach_command = sqlite3_mprintf("ATTACH DATABASE '%s-migrated' as migrate KEY '%q';", db_filename, key); int rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, "", &user_version); if(rc == SQLITE_OK){ CODEC_TRACE(("No upgrade required - exiting\n")); goto exit; } // Version 2 - check for 4k with hmac format rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, pragma_4k_kdf_iter, &user_version); if(rc == SQLITE_OK) { CODEC_TRACE(("Version 2 format found\n")); upgrade_4k_format = 1; } // Version 1 - check both no hmac and 4k together pragma_1x_and_4k = sqlite3_mprintf("%s%s", pragma_hmac_off, pragma_4k_kdf_iter); rc = sqlcipher_check_connection(db_filename, key, ctx->read_ctx->pass_sz, pragma_1x_and_4k, &user_version); sqlite3_free(pragma_1x_and_4k); if(rc == SQLITE_OK) { CODEC_TRACE(("Version 1 format found\n")); upgrade_1x_format = 1; upgrade_4k_format = 1; } if(upgrade_1x_format == 0 && upgrade_4k_format == 0) { CODEC_TRACE(("Upgrade format not determined\n")); goto handle_error; } set_user_version = sqlite3_mprintf("PRAGMA migrate.user_version = %d;", user_version); commands[0] = upgrade_4k_format == 1 ? pragma_4k_kdf_iter : ""; commands[1] = upgrade_1x_format == 1 ? pragma_hmac_off : ""; commands[2] = attach_command; commands[3] = "SELECT sqlcipher_export('migrate');"; commands[4] = set_user_version; for(command_idx = 0; command_idx < ArraySize(commands); command_idx++){ const char *command = commands[command_idx]; if(strcmp(command, "") == 0){ continue; } rc = sqlite3_exec(db, command, NULL, NULL, NULL); if(rc != SQLITE_OK){ break; } } sqlite3_free(attach_command); sqlite3_free(set_user_version); sqlcipher_free(key, key_sz); if(rc == SQLITE_OK){ Btree *pDest; Btree *pSrc; int i = 0; if( !db->autoCommit ){ CODEC_TRACE(("cannot migrate from within a transaction")); goto handle_error; } if( db->nVdbeActive>1 ){ CODEC_TRACE(("cannot migrate - SQL statements in progress")); goto handle_error; } /* Save the current value of the database flags so that it can be ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ 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; pDest = db->aDb[0].pBt; pDb = &(db->aDb[db->nDb-1]); pSrc = pDb->pBt; rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL); rc = sqlite3BtreeBeginTrans(pSrc, 2); rc = sqlite3BtreeBeginTrans(pDest, 2); assert( 1==sqlite3BtreeIsInTrans(pDest) ); assert( 1==sqlite3BtreeIsInTrans(pSrc) ); sqlite3CodecGetKey(db, db->nDb - 1, (void**)&key, &password_sz); sqlite3CodecAttach(db, 0, key, password_sz); sqlite3pager_get_codec(pDest->pBt->pPager, (void**)&ctx); ctx->skip_read_hmac = 1; for(i=0; i<ArraySize(aCopy); i+=2){ sqlite3BtreeGetMeta(pSrc, aCopy[i], &meta); rc = sqlite3BtreeUpdateMeta(pDest, aCopy[i], meta+aCopy[i+1]); if( NEVER(rc!=SQLITE_OK) ) goto handle_error; } rc = sqlite3BtreeCopyFile(pDest, pSrc); ctx->skip_read_hmac = 0; if( rc!=SQLITE_OK ) goto handle_error; rc = sqlite3BtreeCommit(pDest); db->flags = saved_flags; db->nChange = saved_nChange; db->nTotalChange = saved_nTotalChange; db->xTrace = saved_xTrace; db->autoCommit = 1; if( pDb ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; } sqlite3ResetAllSchemasOfConnection(db); remove(migrated_db_filename); sqlite3_free(migrated_db_filename); } else { CODEC_TRACE(("*** migration failure** \n\n")); } } goto exit; handle_error: CODEC_TRACE(("An error occurred attempting to migrate the database\n")); rc = SQLITE_ERROR; exit: return rc; }
static int sqlcipher_ltc_ctx_free(void **ctx) { sqlcipher_ltc_deactivate(&ctx); sqlcipher_free(*ctx, sizeof(ltc_ctx)); return SQLITE_OK; }