99#include "btreeInt.h"
1010#include "ceshim.h"
1111
12+ #include <CommonCrypto/CommonDigest.h>
13+ #include <CommonCrypto/CommonCryptor.h>
14+
15+
1216// Size of standard Sqlite3 pager header
1317#define CESHIM_DB_HEADER1_SZ 100
1418// Size of ceshim-specific pager header
@@ -116,6 +120,9 @@ struct ceshim_info {
116120 u16 pgMapMaxCnt ; // Max entries for a page map, based on page size
117121 u16 pgMapSz ; // Size in bytes for the page map allocation
118122 u32 nBytesPerPgMap ; // Performance optimization premultiplication store
123+ char * key ; // Encryption key blob
124+ int key_sz ; // Key size in bytes
125+ int iv_sz ; // IV blob size in bytes
119126
120127 // bools
121128 u8 bPgMapDirty :1 ; // Curr page map needs to be persisted
@@ -424,7 +431,7 @@ static int ceshimLoadMMTbl(ceshim_file *p){
424431 ceshim_info * pInfo = p -> pInfo ;
425432 ceshim_header * header = & pInfo -> ceshimHeader ;
426433 assert ( pInfo -> mmTbl == NULL );
427-
434+
428435 // Header must have already been loaded
429436 assert ( header -> mmTblCurrCnt > 0 );
430437
@@ -618,7 +625,7 @@ static u16 ceshimSwitchPageMap(ceshim_file *p, sqlite_int64 iUppOfst){
618625
619626 // switch
620627 if ( rc == SQLITE_OK && ix != pInfo -> mmTblCurrIx ){
621- ceshim_printf (pInfo , "\nSwitching to map #%u for offset %lld\n" , (unsigned )ix , iUppOfst );
628+ ceshim_printf (pInfo , "Switching to map #%u for offset %lld\n" , (unsigned )ix , iUppOfst );
622629 // save
623630 if ( (rc = ceshimSavePagemapData (p ))== SQLITE_OK ){
624631 // reset
@@ -857,7 +864,7 @@ static int ceshimClose(sqlite3_file *pFile){
857864 p -> nTransactions = 0 ;
858865 }
859866 }
860-
867+
861868 if ( rc == SQLITE_OK ){
862869 ceshimReleasePage1 (p );
863870 if ( (rc = sqlite3PagerClose (p -> pPager ))== SQLITE_OK ){
@@ -878,6 +885,10 @@ static int ceshimClose(sqlite3_file *pFile){
878885 sqlite3_free (pInfo -> pBigEndianPgMap );
879886 pInfo -> pBigEndianPgMap = NULL ;
880887 }
888+ if ( pInfo -> key ){
889+ sqlite3_free (pInfo -> key );
890+ pInfo -> key = NULL ;
891+ }
881892 }
882893 }
883894 }
@@ -891,6 +902,17 @@ static int ceshimClose(sqlite3_file *pFile){
891902 return rc ;
892903}
893904
905+ static void random_bytes (unsigned char * buf , int num ) {
906+ int i ;
907+ int j = num /4 ;
908+ uint32_t * dwbuf = (uint32_t * )buf ;
909+
910+ srandomdev ();
911+ for (i = 0 ;i < j ;i ++ ) {
912+ * (dwbuf + i ) = (u_int32_t )random ();
913+ }
914+ }
915+
894916/*
895917** Read data from a ceshim-file.
896918*/
@@ -917,23 +939,46 @@ static int ceshimRead(
917939 pInfo -> zVfsName , p -> zFName , uppPgno , mappedPgno , iOfst , cmprPgOfst , iAmt , uCmpPgSz );
918940 assert ( uCmpPgSz > 0 );
919941 int iDstAmt = uppPgSz ;
920- void * pBuf = sqlite3_malloc (iDstAmt );
921- pInfo -> xUncompress (
922- NULL ,
923- pBuf ,
924- & iDstAmt ,
925- (char * )pMemPage -> aData
926- + pMemPage -> dbHdrOffset
927- + pMemPage -> pgHdrOffset
928- + cmprPgOfst ,
929- uCmpPgSz
930- );
931- u16 uBufOfst = iOfst % uppPgSz ;
932- memcpy (zBuf , pBuf + uBufOfst , iAmt );
933- sqlite3_free (pBuf );
942+ void * pUncBuf = sqlite3_malloc (iDstAmt );
943+
944+ if ( pUncBuf ){
945+ // decrypt
946+ void * iv =
947+ (char * )pMemPage -> aData
948+ + pMemPage -> dbHdrOffset
949+ + pMemPage -> pgHdrOffset
950+ + cmprPgOfst ;
951+ void * srcData = iv + pInfo -> iv_sz ;
952+ size_t tmp_csz ;
953+ CCCryptorStatus ccStatus ;
954+
955+ void * pCmpBuf = sqlite3_malloc (uCmpPgSz );
956+ ccStatus = CCCrypt (
957+ kCCDecrypt , // enc/dec
958+ kCCAlgorithmAES128 , // algorithm
959+ 0 , // options: kCCOptionPKCS7Padding, kCCOptionECBMode, 0 = no padding
960+ pInfo -> key , // 256-bit (32-byte) key
961+ pInfo -> key_sz , // key length (bytes)
962+ iv , // const void *iv
963+ srcData , // const void *dataIn
964+ uCmpPgSz - pInfo -> iv_sz , // data-in length
965+ pCmpBuf , // dataOut; result is written here.
966+ uCmpPgSz , // The size of the dataOut buffer in bytes
967+ & tmp_csz // On successful return, the number of bytes written to dataOut.
968+ );
969+
970+ if ( ccStatus == kCCSuccess ){
971+ pInfo -> xUncompress (NULL , pUncBuf , & iDstAmt , pCmpBuf , (int )tmp_csz );
972+ assert ( iDstAmt == uppPgSz );
973+ u16 uBufOfst = iOfst % uppPgSz ;
974+ memcpy (zBuf , pUncBuf + uBufOfst , iAmt );
975+ } else rc = ccStatus ;
976+ sqlite3_free (pUncBuf );
977+ }else rc = SQLITE_NOMEM ;
934978 sqlite3PagerUnref (pPage );
935979 }
936980 }else {
981+ ceshim_printf (pInfo , "%s.xRead(%s,ofst=%08lld,amt=%d)" , pInfo -> zVfsName , p -> zFName , iOfst , iAmt );
937982 memset (zBuf , 0 , iAmt );
938983 rc = SQLITE_OK ;
939984 }
@@ -956,50 +1001,80 @@ static int ceshimWrite(
9561001){
9571002 ceshim_file * p = (ceshim_file * )pFile ;
9581003 ceshim_info * pInfo = p -> pInfo ;
959- int rc = SQLITE_OK ;
1004+ int rc ;
9601005
9611006 if ( p -> pPager ){
9621007 DbPage * pPage ;
9631008 Pgno uppPgno , mappedPgno ;
9641009
965- if ( rc == SQLITE_OK ){
966- // compress
967- int pnDest = pInfo -> xCompressBound (NULL , iAmt );
968- void * pBuf = sqlite3_malloc (pnDest );
969- if ( pBuf ){
970- CeshimCmpOfst cmprPgOfst ;
971- pInfo -> xCompress (NULL , pBuf , & pnDest , (void * )zBuf , iAmt );
972- ceshimPageMapSet (p , iOfst , pnDest , & uppPgno , & mappedPgno , & cmprPgOfst );
973- if ( rc == SQLITE_OK && (rc = sqlite3PagerGet (p -> pPager , mappedPgno , & pPage , 0 ))== SQLITE_OK ){
1010+ // compress
1011+ int pnDest = pInfo -> xCompressBound (NULL , iAmt );
1012+ void * pCmpBuf = sqlite3_malloc (pnDest );
1013+ if ( pCmpBuf ){
1014+ CeshimCmpOfst cmprPgOfst ;
1015+ pInfo -> xCompress (NULL , pCmpBuf , & pnDest , (void * )zBuf , iAmt );
1016+
1017+ // encrypt
1018+ size_t nOutSz = pnDest + kCCBlockSizeAES128 + 1 ;
1019+ void * pEncBuf = sqlite3_malloc ((int )nOutSz );
1020+ if ( pEncBuf ){
1021+ void * iv ; // initialization vector
1022+ CCCryptorStatus ccStatus ;
1023+ iv = pEncBuf ;
1024+ pEncBuf += pInfo -> iv_sz ;
1025+ random_bytes (iv , pInfo -> iv_sz );
1026+ size_t tmp_csz ;
1027+
1028+ ccStatus = CCCrypt (
1029+ kCCEncrypt , // enc/dec
1030+ kCCAlgorithmAES128 , // algorithm
1031+ kCCOptionPKCS7Padding , // options: kCCOptionPKCS7Padding, kCCOptionECBMode, 0 = no padding
1032+ pInfo -> key , // 256-bit (32-byte) key
1033+ pInfo -> key_sz , // key length (bytes)
1034+ iv , // const void *iv
1035+ pCmpBuf , // const void *dataIn
1036+ pnDest , // data-in length
1037+ pEncBuf , // dataOut; result is written here.
1038+ nOutSz , // The size of the dataOut buffer in bytes
1039+ & tmp_csz // On successful return, the number of bytes written to dataOut.
1040+ );
1041+
1042+ if ( ccStatus == kCCSuccess ){
1043+ tmp_csz += pInfo -> iv_sz ;
1044+ ceshimPageMapSet (p , iOfst , tmp_csz , & uppPgno , & mappedPgno , & cmprPgOfst );
1045+
9741046 // write
975- CeshimMemPage * pMemPage = memPageFromDbPage (pPage , mappedPgno );
976- if ( (rc = ceshimPagerWrite (p , pPage ))== SQLITE_OK ){
977- ceshim_printf (
978- pInfo ,
979- "%s.xWrite(%s, pgno=%u->%u, offset=%08lld->%06lu, amt=%06d->%06d)" ,
980- pInfo -> zVfsName , p -> zFName ,
981- uppPgno , mappedPgno ,
982- iOfst , (long unsigned )(pMemPage -> dbHdrOffset + pMemPage -> pgHdrOffset + cmprPgOfst ),
983- iAmt , pnDest
984- );
985- memcpy (
986- pMemPage -> aData
987- + pMemPage -> dbHdrOffset
988- + pMemPage -> pgHdrOffset
989- + cmprPgOfst ,
990- pBuf ,
991- pnDest
992- );
993-
994- // Keep track of sizes of upper and lower pagers
995- if ( pInfo -> ceshimHeader .uppPageFile < uppPgno ) pInfo -> ceshimHeader .uppPageFile = uppPgno ;
996- if ( pInfo -> lwrPageFile < mappedPgno ) pInfo -> lwrPageFile = mappedPgno ;
1047+ if ( (rc = sqlite3PagerGet (p -> pPager , mappedPgno , & pPage , 0 ))== SQLITE_OK ){
1048+ CeshimMemPage * pMemPage = memPageFromDbPage (pPage , mappedPgno );
1049+ if ( (rc = ceshimPagerWrite (p , pPage ))== SQLITE_OK ){
1050+ ceshim_printf (
1051+ pInfo ,
1052+ "%s.xWrite(%s, pgno=%u->%u, offset=%08lld->%06lu, amt=%06d->%06d)" ,
1053+ pInfo -> zVfsName , p -> zFName ,
1054+ uppPgno , mappedPgno ,
1055+ iOfst , (unsigned long )(pMemPage -> dbHdrOffset + pMemPage -> pgHdrOffset + cmprPgOfst ),
1056+ iAmt , tmp_csz
1057+ );
1058+ memcpy (
1059+ pMemPage -> aData
1060+ + pMemPage -> dbHdrOffset
1061+ + pMemPage -> pgHdrOffset
1062+ + cmprPgOfst ,
1063+ iv ,
1064+ tmp_csz
1065+ );
1066+
1067+ // Keep track of sizes of upper and lower pagers
1068+ if ( pInfo -> ceshimHeader .uppPageFile < uppPgno ) pInfo -> ceshimHeader .uppPageFile = uppPgno ;
1069+ if ( pInfo -> lwrPageFile < mappedPgno ) pInfo -> lwrPageFile = mappedPgno ;
1070+ }
1071+ sqlite3PagerUnref (pPage );
9971072 }
998- sqlite3PagerUnref ( pPage ) ;
999- }
1000- sqlite3_free ( pBuf ) ;
1001- }
1002- }
1073+ } else rc = ccStatus ;
1074+ sqlite3_free ( iv );
1075+ } else rc = SQLITE_NOMEM ;
1076+ sqlite3_free ( pCmpBuf );
1077+ }else rc = SQLITE_NOMEM ;
10031078 }else {
10041079 ceshim_printf (pInfo , "%s.xWrite(%s, offset=%08lld, amt=%06d)" , pInfo -> zVfsName , p -> zFName , iOfst , iAmt );
10051080 rc = p -> pReal -> pMethods -> xWrite (p -> pReal , zBuf , iAmt , iOfst );
@@ -1280,6 +1355,29 @@ static void pageReinit(DbPage *pData) {
12801355
12811356}
12821357
1358+ static int ceshimSetKey (ceshim_file * p , const char * pExpr ){
1359+ int i , n ;
1360+ int rc = SQLITE_OK ;
1361+ const char * z ;
1362+ ceshim_info * pInfo = p -> pInfo ;
1363+
1364+ if ( (pExpr [0 ]== 'x' || pExpr [0 ]== 'X' ) && pExpr [1 ]== '\'' ){
1365+ z = & pExpr [2 ];
1366+ n = sqlite3Strlen30 (z ) - 1 ;
1367+ if ( z [n ]== '\'' ){
1368+ pInfo -> key = (char * )sqlite3_malloc (n /2 + 1 );
1369+ n -- ;
1370+ if ( pInfo -> key ){
1371+ for (i = 0 ; i < n ; i += 2 ){
1372+ pInfo -> key [i /2 ] = (sqlite3HexToInt (z [i ])<<4 ) | sqlite3HexToInt (z [i + 1 ]);
1373+ }
1374+ pInfo -> key [i /2 ] = 0 ;
1375+ }else rc = SQLITE_NOMEM ;
1376+ }else rc = CESHIM_ERROR_MALFORMED_KEY ;
1377+ }else rc = CESHIM_ERROR_MALFORMED_KEY ;
1378+ return rc ;
1379+ }
1380+
12831381
12841382/*
12851383** Open a ceshim file handle.
@@ -1307,8 +1405,12 @@ static int ceshimOpen(
13071405
13081406 // Process URI parameters
13091407 if ( flags & SQLITE_OPEN_URI ){
1408+ // block_size
13101409 const char * zParamBlockSize = sqlite3_uri_parameter (_zName , "block_size" );
13111410 if ( zParamBlockSize ) nParamBlockSz = (u32 )sqlite3Atoi (zParamBlockSize );
1411+ // key
1412+ const char * zParamKey = sqlite3_uri_parameter (_zName , "key" );
1413+ if ( zParamKey ) rc = ceshimSetKey (p , zParamKey );
13121414 }
13131415
13141416 // open file
@@ -1395,7 +1497,7 @@ static int ceshimDelete(sqlite3_vfs *pVfs, const char *_zPath, int dirSync){
13951497 sqlite3_vfs * pRoot = pInfo -> pRootVfs ;
13961498 int rc ;
13971499 const char * zPath = ceshimMapPath (pInfo , _zPath );
1398- ceshim_printf (pInfo , "%s.xDelete(\"%s\",%d) BYPASS " , pInfo -> zVfsName , zPath , dirSync );
1500+ ceshim_printf (pInfo , "%s.xDelete(\"%s\",%d)" , pInfo -> zVfsName , zPath , dirSync );
13991501 rc = pRoot -> xDelete (pRoot , zPath , dirSync );
14001502 ceshim_print_errcode (pInfo , " -> %s\n" , rc );
14011503 return rc ;
@@ -1641,6 +1743,8 @@ int ceshim_register(
16411743 pInfo -> ceshimHeader .schema = CESHIM_FILE_SCHEMA_NO ;
16421744 pInfo -> ceshimHeader .currPgno = CESHIM_FIRST_MAPPED_PAGE ;
16431745 pInfo -> ceshimHeader .uppPgSz = SQLITE_DEFAULT_PAGE_SIZE ;
1746+ pInfo -> key_sz = kCCKeySizeAES256 ; // 32
1747+ pInfo -> iv_sz = kCCBlockSizeAES128 ; // 16
16441748
16451749 ceshim_printf (pInfo , "%s.enabled_for(\"%s\")\n" , pInfo -> zVfsName , pRoot -> zName );
16461750 return sqlite3_vfs_register (pNew , 0 );
0 commit comments