Skip to content

Commit 2ca488c

Browse files
committed
Support AES128.
1 parent e1851f1 commit 2ca488c

File tree

2 files changed

+160
-55
lines changed

2 files changed

+160
-55
lines changed

ceshim.c

Lines changed: 159 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
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);

ceshim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#define CESHIM_ERROR 400
1313
#define CESHIM_ERROR_PAGE_SIZE_TOO_SMALL (CESHIM_ERROR | (1<<8))
14+
#define CESHIM_ERROR_MALFORMED_KEY (CESHIM_ERROR | (2<<8))
1415

1516
int ceshim_register(
1617
const char *zName, /* Name of the newly constructed VFS */

0 commit comments

Comments
 (0)