/** * 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_NOMEM if the key could't be derived (for instance if pass is NULL or pass_sz is 0) */ static int codec_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 c_ctx->key_sz=%d\n", c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->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: deriving key from hex\n")); cipher_hex2bin(z, n, c_ctx->key); } else { CODEC_TRACE(("codec_key_derive: deriving key using PBKDF2\n")); 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); } return SQLITE_OK; }; return SQLITE_ERROR; }
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; }
int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const char *zRight) { struct Db *pDb = &db->aDb[iDb]; codec_ctx *ctx = NULL; int rc; if(pDb->pBt) { sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx); } CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db, iDb, pParse, zLeft, zRight, ctx)); if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && zRight ) { sqlcipher_codec_set_store_pass(ctx, sqlite3GetBoolean(zRight, 1)); } else if( sqlite3StrICmp(zLeft, "cipher_store_pass")==0 && !zRight ) { char *store_pass_value = sqlite3_mprintf("%d", sqlcipher_codec_get_store_pass(ctx)); codec_vdbe_return_static_string(pParse, "cipher_store_pass", store_pass_value); sqlite3_free(store_pass_value); } if( sqlite3StrICmp(zLeft, "cipher_profile")== 0 && zRight ){ char *profile_status = sqlite3_mprintf("%d", sqlcipher_cipher_profile(db, zRight)); codec_vdbe_return_static_string(pParse, "cipher_profile", profile_status); sqlite3_free(profile_status); } else if( sqlite3StrICmp(zLeft, "cipher_add_random")==0 && zRight ){ if(ctx) { char *add_random_status = sqlite3_mprintf("%d", sqlcipher_codec_add_random(ctx, zRight, sqlite3Strlen30(zRight))); codec_vdbe_return_static_string(pParse, "cipher_add_random", add_random_status); sqlite3_free(add_random_status); } } else if( sqlite3StrICmp(zLeft, "cipher_migrate")==0 && !zRight ){ if(ctx){ char *migrate_status = sqlite3_mprintf("%d", sqlcipher_codec_ctx_migrate(ctx)); codec_vdbe_return_static_string(pParse, "cipher_migrate", migrate_status); sqlite3_free(migrate_status); } } else if( sqlite3StrICmp(zLeft, "cipher_provider")==0 && !zRight ){ if(ctx) { codec_vdbe_return_static_string(pParse, "cipher_provider", sqlcipher_codec_get_cipher_provider(ctx)); } } else if( sqlite3StrICmp(zLeft, "cipher_version")==0 && !zRight ){ codec_vdbe_return_static_string(pParse, "cipher_version", codec_get_cipher_version()); }else if( sqlite3StrICmp(zLeft, "cipher")==0 ){ if(ctx) { if( zRight ) { sqlcipher_codec_ctx_set_cipher(ctx, zRight, 2); // change cipher for both }else { codec_vdbe_return_static_string(pParse, "cipher", sqlcipher_codec_ctx_get_cipher(ctx, 2)); } } }else if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){ if(ctx) sqlcipher_codec_ctx_set_cipher(ctx, zRight, 1); // change write cipher only }else if( sqlite3StrICmp(zLeft,"cipher_default_kdf_iter")==0 ){ if( zRight ) { sqlcipher_set_default_kdf_iter(atoi(zRight)); // change default KDF iterations } else { char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_get_default_kdf_iter()); codec_vdbe_return_static_string(pParse, "cipher_default_kdf_iter", kdf_iter); sqlite3_free(kdf_iter); } }else if( sqlite3StrICmp(zLeft, "kdf_iter")==0 ){ if(ctx) { if( zRight ) { sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight), 2); // change of RW PBKDF2 iteration } else { char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_kdf_iter(ctx, 2)); codec_vdbe_return_static_string(pParse, "kdf_iter", kdf_iter); sqlite3_free(kdf_iter); } } }else if( sqlite3StrICmp(zLeft, "fast_kdf_iter")==0){ if(ctx) { if( zRight ) { sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight), 2); // change of RW PBKDF2 iteration } else { char *fast_kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_fast_kdf_iter(ctx, 2)); codec_vdbe_return_static_string(pParse, "fast_kdf_iter", fast_kdf_iter); sqlite3_free(fast_kdf_iter); } } }else if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){ if(ctx) sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight), 1); // write iterations only }else if( sqlite3StrICmp(zLeft,"cipher_page_size")==0 ){ if(ctx) { if( zRight ) { int size = atoi(zRight); rc = sqlcipher_codec_ctx_set_pagesize(ctx, size); if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx); if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); } else { char * page_size = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_pagesize(ctx)); codec_vdbe_return_static_string(pParse, "cipher_page_size", page_size); sqlite3_free(page_size); } } }else if( sqlite3StrICmp(zLeft,"cipher_default_use_hmac")==0 ){ if( zRight ) { sqlcipher_set_default_use_hmac(sqlite3GetBoolean(zRight,1)); } else { char *default_use_hmac = sqlite3_mprintf("%d", sqlcipher_get_default_use_hmac()); codec_vdbe_return_static_string(pParse, "cipher_default_use_hmac", default_use_hmac); sqlite3_free(default_use_hmac); } }else if( sqlite3StrICmp(zLeft,"cipher_use_hmac")==0 ){ if(ctx) { if( zRight ) { rc = sqlcipher_codec_ctx_set_use_hmac(ctx, sqlite3GetBoolean(zRight,1)); if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); /* since the use of hmac has changed, the page size may also change */ rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx); if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc); } else { char *hmac_flag = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_use_hmac(ctx, 2)); codec_vdbe_return_static_string(pParse, "cipher_use_hmac", hmac_flag); sqlite3_free(hmac_flag); } } }else if( sqlite3StrICmp(zLeft,"cipher_hmac_pgno")==0 ){ if(ctx) { if(zRight) { // clear both pgno endian flags if(sqlite3StrICmp(zRight, "le") == 0) { sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO); sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_LE_PGNO); } else if(sqlite3StrICmp(zRight, "be") == 0) { sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO); sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_BE_PGNO); } else if(sqlite3StrICmp(zRight, "native") == 0) { sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO); sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO); } } else { if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_LE_PGNO, 2)) { codec_vdbe_return_static_string(pParse, "cipher_hmac_pgno", "le"); } else if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_BE_PGNO, 2)) { codec_vdbe_return_static_string(pParse, "cipher_hmac_pgno", "be"); } else { codec_vdbe_return_static_string(pParse, "cipher_hmac_pgno", "native"); } } } }else if( sqlite3StrICmp(zLeft,"cipher_hmac_salt_mask")==0 ){ if(ctx) { if(zRight) { if (sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlite3Strlen30(zRight) == 5) { unsigned char mask = 0; const unsigned char *hex = (const unsigned char *)zRight+2; cipher_hex2bin(hex,2,&mask); sqlcipher_set_hmac_salt_mask(mask); } } else { char *hmac_salt_mask = sqlite3_mprintf("%02x", sqlcipher_get_hmac_salt_mask()); codec_vdbe_return_static_string(pParse, "cipher_hmac_salt_mask", hmac_salt_mask); sqlite3_free(hmac_salt_mask); } } }else { return 0; } return 1; }
/** * 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 (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. * Else, if the raw key data is formated as x'hex' and there are exactly enough hex chars to fill * the key and the salt (i.e 92 hex chars for a 256 bit key and 16 byte salt) then it will be unpacked * as the key followed by the salt. * * 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) */ static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) { int rc; CODEC_TRACE(("cipher_ctx_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \ ctx->kdf_salt=%p ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \ ctx->hmac_kdf_salt=%p, 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(ctx->need_kdf_salt) { if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) return SQLITE_ERROR; ctx->need_kdf_salt = 0; } if (c_ctx->pass_sz == ((c_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */ const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ CODEC_TRACE(("cipher_ctx_key_derive: using raw key from hex\n")); cipher_hex2bin(z, n, c_ctx->key); } else if (c_ctx->pass_sz == (((c_ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */ CODEC_TRACE(("cipher_ctx_key_derive: using raw key from hex\n")); cipher_hex2bin(z, (c_ctx->key_sz * 2), c_ctx->key); cipher_hex2bin(z + (c_ctx->key_sz * 2), (ctx->kdf_salt_sz * 2), ctx->kdf_salt); } else { CODEC_TRACE(("cipher_ctx_key_derive: deriving key using full PBKDF2 with %d iterations\n", c_ctx->kdf_iter)); c_ctx->provider->kdf(c_ctx->provider_ctx, 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); } /* set the context "keyspec" containing the hex-formatted key and salt to be used when attaching databases */ if((rc = sqlcipher_cipher_ctx_set_keyspec(c_ctx, c_ctx->key, c_ctx->key_sz, ctx->kdf_salt, ctx->kdf_salt_sz)) != SQLITE_OK) return rc; /* 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->flags & CIPHER_FLAG_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(("cipher_ctx_key_derive: deriving hmac key from encryption key using PBKDF2 with %d iterations\n", c_ctx->fast_kdf_iter)); c_ctx->provider->kdf(c_ctx->provider_ctx, 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; }