void* mySqlite3PagerGetCodec( Pager *pPager ){ #if (SQLITE_VERSION_NUMBER >= 3006016) return sqlite3PagerGetCodec(pPager); #else return (pPager->xCodec) ? pPager->pCodecArg : NULL; #endif }
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 sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) { BOTANSQLITE_TRACE("sqlite3CodecGetKey"); Btree *pbt = db->aDb[nDb].pBt; Pager *pPager = sqlite3BtreePager(pbt); assert(pPager); void *pCodec = sqlite3PagerGetCodec(pPager); if (pCodec) { size_t nKeySize; GetWriteKey(pCodec, (char**)zKey, &nKeySize); *nKey = (int)nKeySize; } else { *zKey = NULL; *nKey = 0; } }
void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) { struct Db *pDb = &db->aDb[nDb]; //RAWLOG_INFO("sqlite3CodecGetKey"); if( pDb->pBt ) { Pager *pPager = sqlite3BtreePager(pDb->pBt); CRhoSqliteCodecCtx *pRhoCtx = (CRhoSqliteCodecCtx *) sqlite3PagerGetCodec(pPager); if ( pRhoCtx ) { /* if the codec has an attached codec_context user the raw key data */ *zKey = pRhoCtx->m_szPartition; *nKey = pRhoCtx->m_nPartLen; } else { *zKey = NULL; *nKey = 0; } } }
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 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; }
/* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage( sqlite3_backup *p, /* Backup handle */ Pgno iSrcPg, /* Source database page to backup */ const u8 *zSrcData, /* Source database page data */ int bUpdate /* True for an update, false otherwise */ ){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; #ifdef SQLITE_HAS_CODEC /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is ** guaranteed that the shared-mutex is held by this thread, handle ** p->pSrc may not actually be the owner. */ int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest); #endif int rc = SQLITE_OK; i64 iOff; assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 ); assert( p->bDestLocked ); assert( !isFatalError(p->rc) ); assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); assert( zSrcData ); /* Catch the case where the destination is an in-memory database and the ** page sizes of the source and destination differ. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ rc = SQLITE_READONLY; } #ifdef SQLITE_HAS_CODEC /* Backup is not possible if the page size of the destination is changing ** and a codec is in use. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ rc = SQLITE_READONLY; } /* Backup is not possible if the number of bytes of reserve space differ ** between source and destination. If there is a difference, try to ** fix the destination to agree with the source. If that is not possible, ** then the backup cannot proceed. */ if( nSrcReserve!=nDestReserve ){ u32 newPgsz = nSrcPgsz; rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; } #endif /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. */ for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){ DbPage *pDestPg = 0; Pgno iDest = (Pgno)(iOff/nDestPgsz)+1; if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue; if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0)) && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg)) ){ const u8 *zIn = &zSrcData[iOff%nSrcPgsz]; u8 *zDestData = sqlite3PagerGetData(pDestPg); u8 *zOut = &zDestData[iOff%nDestPgsz]; /* Copy the data from the source page into the destination page. ** Then clear the Btree layer MemPage.isInit flag. Both this module ** and the pager code use this trick (clearing the first byte ** of the page 'extra' space to invalidate the Btree layers ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; if( iOff==0 && bUpdate==0 ){ sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc)); } } sqlite3PagerUnref(pDestPg); } return rc; }
/* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; int rc = SQLITE_OK; i64 iOff; assert( p->bDestLocked ); assert( !isFatalError(p->rc) ); assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); assert( zSrcData ); /* Catch the case where the destination is an in-memory database and the ** page sizes of the source and destination differ. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ rc = SQLITE_READONLY; } #ifdef SQLITE_HAS_CODEC /* Backup is not possible if the page size of the destination is changing ** a a codec is in use. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ rc = SQLITE_READONLY; } #endif /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset ** of the destination page. */ for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){ DbPage *pDestPg = 0; Pgno iDest = (Pgno)(iOff/nDestPgsz)+1; if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue; if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg)) && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg)) ){ const u8 *zIn = &zSrcData[iOff%nSrcPgsz]; u8 *zDestData = sqlite3PagerGetData(pDestPg); u8 *zOut = &zDestData[iOff%nDestPgsz]; /* Copy the data from the source page into the destination page. ** Then clear the Btree layer MemPage.isInit flag. Both this module ** and the pager code use this trick (clearing the first byte ** of the page 'extra' space to invalidate the Btree layers ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; } sqlite3PagerUnref(pDestPg); } return rc; }