int sqlite3CodecAttach(sqlite3* db, int nDb, const void* zKey, int nKey) { /* Attach a key to a database. */ Codec* codec = (Codec*) sqlite3_malloc(sizeof(Codec)); CodecInit(codec); /* No key specified, could mean either use the main db's encryption or no encryption */ if (zKey == NULL || nKey <= 0) { /* No key specified */ if (nDb != 0 && nKey > 0) { Codec* mainCodec = (Codec*) mySqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt)); /* Attached database, therefore use the key of main database, if main database is encrypted */ if (mainCodec != NULL && CodecIsEncrypted(mainCodec)) { CodecCopy(codec, mainCodec); CodecSetBtree(codec, db->aDb[nDb].pBt); #if (SQLITE_VERSION_NUMBER >= 3006016) mySqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec); #else #if (SQLITE_VERSION_NUMBER >= 3003014) sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec); #else sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec); #endif db->aDb[nDb].pAux = codec; db->aDb[nDb].xFreeAux = sqlite3CodecFree; #endif } else { CodecSetIsEncrypted(codec, 0); sqlite3_free(codec); } } } else { /* Key specified, setup encryption key for database */ CodecSetIsEncrypted(codec, 1); CodecSetHasReadKey(codec, 1); CodecSetHasWriteKey(codec, 1); CodecGenerateReadKey(codec, (char*) zKey, nKey); CodecCopyKey(codec, 1); CodecSetBtree(codec, db->aDb[nDb].pBt); #if (SQLITE_VERSION_NUMBER >= 3006016) mySqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec); #else #if (SQLITE_VERSION_NUMBER >= 3003014) sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec); #else sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, codec); #endif db->aDb[nDb].pAux = codec; db->aDb[nDb].xFreeAux = sqlite3CodecFree; #endif } return SQLITE_OK; }
int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey) { BOTANSQLITE_TRACE("sqlite3CodecAttach"); void *pCodec = NULL; if (!zKey || nKey <= 0) { Pager *pager = sqlite3BtreePager(db->aDb[nDb].pBt); // No key specified, could mean either use the main db's encryption or no encryption if (nDb != 0 && nKey < 0) { // Is an attached database, therefore use the key of main database, if main database is encrypted void *pMainCodec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt)); if (pMainCodec) { pCodec = InitializeFromOtherCodec(pMainCodec, db); sqlite3PagerSetCodec( pager, Codec, CodecSizeChange, PagerFreeCodec, pCodec); } } else { // No encryption requested sqlite3PagerSetCodec(pager, NULL, NULL, NULL, NULL); } } else { // Key specified, setup encryption key for database pCodec = InitializeNewCodec(db); assert(nKey >= 0); SetWriteKey(pCodec, (const char*) zKey, (size_t) nKey); if (HandleError(pCodec)) { DeleteCodec(pCodec); return SQLITE_ERROR; } SetReadIsWrite(pCodec); sqlite3PagerSetCodec( sqlite3BtreePager(db->aDb[nDb].pBt), Codec, CodecSizeChange, PagerFreeCodec, pCodec); } if (HandleError(pCodec)) return SQLITE_ERROR; return SQLITE_OK; }
void mySqlite3PagerSetCodec( Pager *pPager, void *(*xCodec)(void*,void*,Pgno,int), void (*xCodecSizeChng)(void*,int,int), void (*xCodecFree)(void*), void *pCodec ){ sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec); }
int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) { struct Db *pDb = &db->aDb[nDb]; if(nKey && zKey && pDb->pBt) { codec_ctx *ctx; Pager *pPager = pDb->pBt->pBt->pPager; int prepared_key_sz; ctx = sqlite3Malloc(sizeof(codec_ctx)); 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 */ /* 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 = sqlite3Malloc(sqlite3BtreeGetPageSize(ctx->pBt)); if(ctx->buffer == NULL) return SQLITE_NOMEM; ctx->key_sz = EVP_CIPHER_key_length(CIPHER); ctx->iv_sz = EVP_CIPHER_iv_length(CIPHER); /* allocate space for salt data */ ctx->salt = sqlite3Malloc(FILE_HEADER_SZ); if(ctx->salt == NULL) return SQLITE_NOMEM; /* allocate space for salt data */ ctx->key = sqlite3Malloc(ctx->key_sz); if(ctx->key == NULL) return SQLITE_NOMEM; /* allocate space for raw key data */ ctx->pass = sqlite3Malloc(nKey); if(ctx->pass == NULL) return SQLITE_NOMEM; memcpy(ctx->pass, zKey, nKey); ctx->pass_sz = nKey; /* read the first 16 bytes directly off the database file. This is the salt. */ sqlite3_file *fd = sqlite3Pager_get_fd(pPager); if(fd == NULL || sqlite3OsRead(fd, ctx->salt, 16, 0) != SQLITE_OK) { /* if unable to read the bytes, generate random salt */ RAND_pseudo_bytes(ctx->salt, FILE_HEADER_SZ); } codec_prepare_key(db, zKey, nKey, ctx->salt, FILE_HEADER_SZ, ctx->key, &prepared_key_sz); assert(prepared_key_sz == ctx->key_sz); sqlite3BtreeSetPageSize(ctx->pBt, sqlite3BtreeGetPageSize(ctx->pBt), ctx->iv_sz, 0); sqlite3PagerSetCodec(sqlite3BtreePager(pDb->pBt), sqlite3Codec, (void *) ctx); return SQLITE_OK; } return SQLITE_ERROR; }
// Called by sqlite and sqlite3_key_interop to attach a key to a database. int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen) { int rc = SQLITE_ERROR; HCRYPTKEY hKey = 0; // No key specified, could mean either use the main db's encryption or no encryption if (!pKey || !nKeyLen) { if (!nDb) { return SQLITE_OK; // Main database, no key specified so not encrypted } else // Attached database, use the main database's key { // Get the encryption block for the main database and attempt to duplicate the key // for use by the attached database Pager *p = sqlite3BtreePager(db->aDb[0].pBt); LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(p); if (!pBlock) return SQLITE_OK; // Main database is not encrypted so neither will be any attached database if (!pBlock->hReadKey) return SQLITE_OK; // Not encrypted if (!CryptDuplicateKey(pBlock->hReadKey, NULL, 0, &hKey)) return rc; // Unable to duplicate the key } } else // User-supplied passphrase, so create a cryptographic key out of it { hKey = DeriveKey(pKey, nKeyLen); if (hKey == MAXDWORD) { sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER); return rc; } } // Create a new encryption block and assign the codec to the new attached database if (hKey) { Pager *p = sqlite3BtreePager(db->aDb[nDb].pBt); LPCRYPTBLOCK pBlock = CreateCryptBlock(hKey, p, -1, NULL); if (!pBlock) return SQLITE_NOMEM; sqlite3PagerSetCodec(p, sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, pBlock); //db->aDb[nDb].pAux = pBlock; //db->aDb[nDb].xFreeAux = DestroyCryptBlock; rc = SQLITE_OK; } return rc; }
int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey) { void *pCodec; if (zKey == NULL || nKey <= 0) { // No key specified, could mean either use the main db's encryption or no encryption if (nDb != 0 && nKey < 0) { //Is an attached database, therefore use the key of main database, if main database is encrypted void *pMainCodec = sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt)); if (pMainCodec != NULL) { pCodec = InitializeFromOtherCodec(pMainCodec, db); sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, pCodec); } } } else { // Key specified, setup encryption key for database pCodec = InitializeNewCodec(db); GenerateWriteKey(pCodec, (const char*) zKey, nKey); SetReadIsWrite(pCodec); sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, pCodec); } if (HandleError(pCodec)) return SQLITE_ERROR; return SQLITE_OK; }
int sqlite3CodecAttach(sqlite3* db, int nDb, const void *pKey, int nKey) { struct Db *pDb = &db->aDb[nDb]; //RAWLOG_INFO("sqlite3CodecAttach"); if ( nKey && pKey && pDb->pBt ) { Pager *pPager = sqlite3BtreePager(pDb->pBt); sqlite3_file *fd; CRhoSqliteCodecCtx* pRhoCtx = sqlite3Malloc(sizeof(CRhoSqliteCodecCtx)); memset(pRhoCtx, 0, sizeof(CRhoSqliteCodecCtx)); pRhoCtx->m_szPartition = sqlite3Malloc(nKey); memcpy(pRhoCtx->m_szPartition, pKey, nKey); pRhoCtx->m_nPartLen = nKey; pRhoCtx->m_pPageBuffer = sqlite3Malloc(SQLITE_DEFAULT_PAGE_SIZE); sqlite3PagerSetCodec( pPager, sqlite3Codec, NULL, sqlite3FreeCodecArg, (void *)pRhoCtx ); fd = (isOpen(pPager->fd)) ? pPager->fd : NULL; sqlite3_mutex_enter(db->mutex); /* 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 Note: before forcing the page size we need to force pageSizeFixed to 0, else sqliteBtreeSetPageSize will block the change */ pDb->pBt->pBt->pageSizeFixed = 0; sqlite3BtreeSetPageSize( pDb->pBt, SQLITE_DEFAULT_PAGE_SIZE, EVP_MAX_IV_LENGTH, 0 ); /* if fd is null, then this is an in-memory database and we dont' want to overwrite the AutoVacuum settings if not null, then set to the default */ if ( fd != NULL ) sqlite3BtreeSetAutoVacuum(pDb->pBt, SQLITE_DEFAULT_AUTOVACUUM); sqlite3_mutex_leave(db->mutex); } return SQLITE_OK; }
int sqlite3_rekey_v2(sqlite3 *db, const char *zDbName, const void *zKey, int nKey) { /* Changes the encryption key for an existing database. */ int dbIndex = dbFindIndex(db, zDbName); int rc = SQLITE_ERROR; Btree* pbt = db->aDb[dbIndex].pBt; Pager* pPager = sqlite3BtreePager(pbt); Codec* codec = (Codec*) mySqlite3PagerGetCodec(pPager); if ((zKey == NULL || nKey == 0) && (codec == NULL || !CodecIsEncrypted(codec))) { /* // Database not encrypted and key not specified // therefore do nothing */ return SQLITE_OK; } if (codec == NULL || !CodecIsEncrypted(codec)) { /* // Database not encrypted, but key specified // therefore encrypt database */ if (codec == NULL) { codec = (Codec*) sqlite3_malloc(sizeof(Codec)); CodecInit(codec); } CodecSetIsEncrypted(codec, 1); CodecSetHasReadKey(codec, 0); /* Original database is not encrypted */ CodecSetHasWriteKey(codec, 1); CodecGenerateWriteKey(codec, (char*) zKey, nKey); CodecSetBtree(codec, pbt); #if (SQLITE_VERSION_NUMBER >= 3006016) mySqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec); #else #if (SQLITE_VERSION_NUMBER >= 3003014) sqlite3PagerSetCodec(pPager, sqlite3Codec, codec); #else sqlite3pager_set_codec(pPager, sqlite3Codec, codec); #endif db->aDb[dbIndex].pAux = codec; db->aDb[dbIndex].xFreeAux = sqlite3CodecFree; #endif } else if (zKey == NULL || nKey == 0) { /* // Database encrypted, but key not specified // therefore decrypt database // Keep read key, drop write key */ CodecSetHasWriteKey(codec, 0); } else { /* // Database encrypted and key specified // therefore re-encrypt database with new key // Keep read key, change write key to new key */ CodecGenerateWriteKey(codec, (char*) zKey, nKey); CodecSetHasWriteKey(codec, 1); } sqlite3_mutex_enter(db->mutex); /* Start transaction */ rc = sqlite3BtreeBeginTrans(pbt, 1); if (!rc) { int pageSize = sqlite3BtreeGetPageSize(pbt); Pgno nSkip = WX_PAGER_MJ_PGNO(pageSize); #if (SQLITE_VERSION_NUMBER >= 3003014) DbPage *pPage; #else void *pPage; #endif Pgno n; /* Rewrite all pages using the new encryption key (if specified) */ #if (SQLITE_VERSION_NUMBER >= 3007001) Pgno nPage; int nPageCount = -1; sqlite3PagerPagecount(pPager, &nPageCount); nPage = nPageCount; #elif (SQLITE_VERSION_NUMBER >= 3006000) int nPageCount = -1; int rc = sqlite3PagerPagecount(pPager, &nPageCount); Pgno nPage = (Pgno) nPageCount; #elif (SQLITE_VERSION_NUMBER >= 3003014) Pgno nPage = sqlite3PagerPagecount(pPager); #else Pgno nPage = sqlite3pager_pagecount(pPager); #endif for (n = 1; rc == SQLITE_OK && n <= nPage; n++) { if (n == nSkip) continue; #if (SQLITE_VERSION_NUMBER >= 3003014) rc = sqlite3PagerGet(pPager, n, &pPage); #else rc = sqlite3pager_get(pPager, n, &pPage); #endif if (!rc) { #if (SQLITE_VERSION_NUMBER >= 3003014) rc = sqlite3PagerWrite(pPage); sqlite3PagerUnref(pPage); #else rc = sqlite3pager_write(pPage); sqlite3pager_unref(pPage); #endif } } } if (rc == SQLITE_OK) { /* Commit transaction if all pages could be rewritten */ rc = sqlite3BtreeCommit(pbt); } if (rc != SQLITE_OK) { /* Rollback in case of error */ #if (SQLITE_VERSION_NUMBER >= 3007011) sqlite3BtreeRollback(pbt, SQLITE_OK); #else sqlite3BtreeRollback(pbt); #endif } sqlite3_mutex_leave(db->mutex); if (rc == SQLITE_OK) { /* Set read key equal to write key if necessary */ if (CodecHasWriteKey(codec)) { CodecCopyKey(codec, 0); CodecSetHasReadKey(codec, 1); } else { CodecSetIsEncrypted(codec, 0); } } else { /* Restore write key if necessary */ if (CodecHasReadKey(codec)) { CodecCopyKey(codec, 1); } else { CodecSetIsEncrypted(codec, 0); } } if (!CodecIsEncrypted(codec)) { /* Remove codec for unencrypted database */ #if (SQLITE_VERSION_NUMBER >= 3006016) mySqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); #else #if (SQLITE_VERSION_NUMBER >= 3003014) sqlite3PagerSetCodec(pPager, NULL, NULL); #else sqlite3pager_set_codec(pPager, NULL, NULL); #endif db->aDb[dbIndex].pAux = NULL; db->aDb[dbIndex].xFreeAux = NULL; sqlite3CodecFree(codec); #endif } return rc; }
int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey) { BOTANSQLITE_TRACE("sqlite3_rekey"); // Changes the encryption key for an existing database. int rc = SQLITE_ERROR; Btree *pbt = db->aDb[0].pBt; Pager *pPager = sqlite3BtreePager(pbt); void *pCodec = sqlite3PagerGetCodec(pPager); if ((!zKey || nKey <= 0) && !pCodec) { // Database not encrypted and key not specified. Do nothing return SQLITE_OK; } if (!pCodec) { // Database not encrypted, but key specified. Encrypt database pCodec = InitializeNewCodec(db); assert(nKey >= 0); SetWriteKey(pCodec, (const char*) zKey, (size_t) nKey); if (HandleError(pCodec)) { DeleteCodec(pCodec); return SQLITE_ERROR; } sqlite3PagerSetCodec(pPager, Codec, CodecSizeChange, PagerFreeCodec, pCodec); } else if (!zKey || nKey <= 0) { // Database encrypted, but key not specified. Decrypt database // Keep read key, drop write key DropWriteKey(pCodec); } else { // Database encrypted and key specified. Re-encrypt database with new key // Keep read key, change write key to new key assert(nKey >= 0); SetWriteKey(pCodec, (const char*) zKey, (size_t) nKey); if (HandleError(pCodec)) return SQLITE_ERROR; } // Start transaction rc = sqlite3BtreeBeginTrans(pbt, 1); if (rc == SQLITE_OK) { // Rewrite all pages using the new encryption key (if specified) int nPageCount = -1; sqlite3PagerPagecount(pPager, &nPageCount); Pgno nPage = (Pgno) nPageCount; Pgno nSkip = PAGER_MJ_PGNO(pPager); DbPage *pPage; Pgno n; for (n = 1; rc == SQLITE_OK && n <= nPage; n++) { if (n == nSkip) continue; rc = sqlite3PagerGet(pPager, n, &pPage, 0); if (rc == SQLITE_OK) { rc = sqlite3PagerWrite(pPage); sqlite3PagerUnref(pPage); } else { sqlite3ErrorWithMsg(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled."); } } } else { sqlite3ErrorWithMsg(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct."); } if (rc == SQLITE_OK) { // All good, commit rc = sqlite3BtreeCommit(pbt); if (rc == SQLITE_OK) { //Database rekeyed and committed successfully, update read key if (HasWriteKey(pCodec)) { SetReadIsWrite(pCodec); } else //No write key == no longer encrypted { sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); } } else { //FIXME: can't trigger this, not sure if rollback is needed, reference implementation didn't rollback sqlite3ErrorWithMsg(db, SQLITE_ERROR, "%s", "Could not commit rekey transaction."); } } else { // Rollback, rekey failed sqlite3BtreeRollback(pbt, SQLITE_ERROR, 0); // go back to read key if (HasReadKey(pCodec)) { SetWriteIsRead(pCodec); } else //Database wasn't encrypted to start with { sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); } } return rc; }
// Changes the encryption key for an existing database. int sqlite3_rekey(sqlite3 *db, const unsigned char *pKey, int nKeySize) { Btree *pbt = db->aDb[0].pBt; Pager *p = sqlite3BtreePager(pbt); LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(p); HCRYPTKEY hKey = DeriveKey(pKey, nKeySize); int rc = SQLITE_ERROR; if (hKey == MAXDWORD) { sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER); return rc; } if (!pBlock && !hKey) return SQLITE_OK; // Wasn't encrypted to begin with // To rekey a database, we change the writekey for the pager. The readkey remains // the same if (!pBlock) // Encrypt an unencrypted database { pBlock = CreateCryptBlock(hKey, p, -1, NULL); if (!pBlock) return SQLITE_NOMEM; pBlock->hReadKey = 0; // Original database is not encrypted sqlite3PagerSetCodec(sqlite3BtreePager(pbt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, pBlock); //db->aDb[0].pAux = pBlock; //db->aDb[0].xFreeAux = DestroyCryptBlock; } else // Change the writekey for an already-encrypted database { pBlock->hWriteKey = hKey; } // Start a transaction rc = sqlite3BtreeBeginTrans(pbt, 1); if (!rc) { // Rewrite all the pages in the database using the new encryption key Pgno nPage; Pgno nSkip = PAGER_MJ_PGNO(p); DbPage *pPage; Pgno n; rc = sqlite3PagerPagecount(p, &nPage); for(n = 1; rc == SQLITE_OK && n <= nPage; n ++) { if (n == nSkip) continue; rc = sqlite3PagerGet(p, n, &pPage); if(!rc) { rc = sqlite3PagerWrite(pPage); sqlite3PagerUnref(pPage); } } } // If we succeeded, try and commit the transaction if (!rc) { rc = sqlite3BtreeCommit(pbt); } // If we failed, rollback if (rc) { sqlite3BtreeRollback(pbt); } // If we succeeded, destroy any previous read key this database used // and make the readkey equal to the writekey if (!rc) { if (pBlock->hReadKey) { CryptDestroyKey(pBlock->hReadKey); } pBlock->hReadKey = pBlock->hWriteKey; } // We failed. Destroy the new writekey (if there was one) and revert it back to // the original readkey else { if (pBlock->hWriteKey) { CryptDestroyKey(pBlock->hWriteKey); } pBlock->hWriteKey = pBlock->hReadKey; } // If the readkey and writekey are both empty, there's no need for a codec on this // pager anymore. Destroy the crypt block and remove the codec from the pager. if (!pBlock->hReadKey && !pBlock->hWriteKey) { sqlite3PagerSetCodec(p, NULL, NULL, NULL, NULL); } return rc; }