?? xxteacrypt.c
字號:
#ifdef SQLITE_SOURCESTD
#include <pager.c>
#else
#include <sqlite3.c>
#endif
//#define DATA_TO_PGHDR(D) (&((PgHdr*)(D)))
//舊版
//#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
#ifndef SQLITE_OMIT_DISKIO
#ifdef SQLITE_HAS_CODEC
#include "md5c.c"
#define CRYPT_OFFSET 8
#define BYTE unsigned char
typedef struct _CryptBlock
{
BYTE* ReadKey; // 讀數據庫和寫入事務的密鑰
BYTE* WriteKey; // 寫入數據庫的密鑰
int PageSize; // 頁的大小
BYTE* Data;
} CryptBlock, *LPCryptBlock;
int xxtea( int * v, int n , int * k ) {
unsigned int z/*=v[n-1]*/, y=v[0], sum=0, e, DELTA=0x9e3779b9 ;
int m, p, q ;
if ( n>1) {
/* Coding Part */
z = v[n-1];
q = 6+52/n ;
while ( q-- > 0 ) {
sum += DELTA ;
e = sum >> 2&3 ;
for ( p = 0 ; p < n-1 ; p++ ){
y = v[p+1],
z = v[p] += (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
}
y = v[0] ;
z = v[n-1] += (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
}
return 0 ;
/* Decoding Part */
}else if ( n <-1 ) {
n = -n ;
q = 6+52/n ;
sum = q*DELTA ;
while (sum != 0) {
e = sum>>2 & 3 ;
for (p = n-1 ; p > 0 ; p-- ){
z = v[p-1],
y = v[p] -= (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
}
z = v[n-1] ;
y = v[0] -= (z>>5^y<<2)+(y>>3^z<<4)^(sum^y)+(k[p&3^e]^z);
sum -= DELTA ;
}
return 0 ;
}
return 1 ;
} /* Signal n=0,1,-1 */
void * sqlite3pager_get_codecarg(Pager *pPager)
{
return (pPager->xCodec) ? pPager->pCodecArg: NULL;
}
void sqlite3_activate_see(const char *info)
{
}
//創建或更新一個頁的加密算法索引.此函數會申請緩沖區.
static LPCryptBlock CreateCryptBlock(BYTE* hKey, Pager *pager, LPCryptBlock pExisting)
{
LPCryptBlock pBlock;
if (!pExisting) //創建新加密塊
{
pBlock = sqlite3_malloc(sizeof(CryptBlock));
ZeroMemory(pBlock, sizeof(CryptBlock));
pBlock->ReadKey = hKey;
pBlock->WriteKey = hKey;
pBlock->PageSize = pager->pageSize;
pBlock->Data = (BYTE*)sqlite3_malloc(pBlock->PageSize + CRYPT_OFFSET);
}
else //更新存在的加密塊
{
pBlock = pExisting;
if ( pBlock->PageSize != pager->pageSize && !pBlock->Data){
sqlite3_free(pBlock->Data);
pBlock->PageSize = pager->pageSize;
pBlock->Data = (BYTE*)sqlite3_malloc(pBlock->PageSize + CRYPT_OFFSET);
}
}
ZeroMemory(pBlock->Data, pBlock->PageSize + CRYPT_OFFSET);
return pBlock;
}
//銷毀一個加密塊及相關的緩沖區,密鑰.
static void DestroyCryptBlock(LPCryptBlock pBlock)
{
//銷毀讀密鑰.
if (pBlock->ReadKey){
sqlite3_free(pBlock->ReadKey);
}
//如果寫密鑰存在并且不等于讀密鑰,也銷毀.
if (pBlock->WriteKey && pBlock->WriteKey != pBlock->ReadKey){
sqlite3_free(pBlock->WriteKey);
}
if(pBlock->Data){
sqlite3_free(pBlock->Data);
}
//釋放加密塊.
sqlite3_free(pBlock);
}
//加密/解密函數, 被pager調用
void * sqlite3Codec(void *pArg, BYTE *data, Pgno nPageNum, int nMode, PgHdr *pageHeader)
{
LPCryptBlock pBlock = (LPCryptBlock)pArg;
int len = 0;
if (!pBlock) return data;
// 確保pager的頁長度和加密塊的頁長度相等.如果改變,就需要調整.
if (nMode != 2)
{
//PgHdr *pageHeader;
//pageHeader = DATA_TO_PGHDR(data);
if (pageHeader->pPager->pageSize != pBlock->PageSize) //適用舊版
{
CreateCryptBlock(0, pageHeader->pPager, pBlock);
}
}
switch(nMode)
{
case 0: // Undo a "case 7" journal file encryption
case 2: //重載一個頁
case 3: //載入一個頁
if (!pBlock->ReadKey) break;
len = 0 - (pBlock->PageSize/4);
xxtea(data, len, pBlock->ReadKey);
break;
case 6: //加密一個主數據庫文件的頁
if (!pBlock->WriteKey) break;
CopyMemory(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize);
data = pBlock->Data + CRYPT_OFFSET;
len = pBlock->PageSize/4;
xxtea(data , len, pBlock->WriteKey);
break;
case 7: //加密事務文件的頁
/*在正常環境下, 讀密鑰和寫密鑰相同. 當數據庫是被重新加密的,讀密鑰和寫密鑰未必相同.
回滾事務必要用數據庫文件的原始密鑰寫入.因此,當一次回滾被寫入,總是用數據庫的讀密鑰,
這是為了保證與讀取原始數據的密鑰相同.
*/
if (!pBlock->ReadKey) break;
CopyMemory(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize);
data = pBlock->Data + CRYPT_OFFSET;
len = pBlock->PageSize/4;
xxtea(data, len, pBlock->ReadKey);
break;
}
return data;
}
// 從用戶提供的緩沖區中得到一個加密密鑰
static BYTE * DeriveKey(const void *pKey, int nKeyLen)
{
BYTE * hKey = NULL;
BYTE * digest = NULL;
MD5_CTX md5ctx;
if ((pKey == NULL) || (nKeyLen <1 ))
{
return NULL;
}
digest = sqlite3_malloc(16);
MD5Init(&md5ctx);
MD5Update(&md5ctx, (unsigned char*)pKey, nKeyLen);
MD5Final(digest, &md5ctx);
hKey = digest;
return hKey;
}
//被sqlite 和 sqlite3_key_interop 調用, 附加密鑰到數據庫.
int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen)
{
int rc = SQLITE_ERROR;
BYTE* hKey = 0;
//如果沒有指定密匙,可能標識用了主數據庫的加密或沒加密.
if (!pKey || !nKeyLen)
{
if (!nDb)
{
return SQLITE_OK; //主數據庫, 沒有指定密鑰所以沒有加密.
}
else //附加數據庫,使用主數據庫的密鑰.
{
//獲取主數據庫的加密塊并復制密鑰給附加數據庫使用
LPCryptBlock pBlock = (LPCryptBlock)sqlite3pager_get_codecarg(sqlite3BtreePager(db->aDb[0].pBt));
if (!pBlock) return SQLITE_OK; //主數據庫沒有加密
if (!pBlock->ReadKey) return SQLITE_OK; //沒有加密
memcpy(pBlock->ReadKey, &hKey, 16);
}
}
else //用戶提供了密碼,從中創建密鑰.
{
hKey = DeriveKey(pKey, nKeyLen);
}
//創建一個新的加密塊,并將解碼器指向新的附加數據庫.
if (hKey)
{
LPCryptBlock pBlock = CreateCryptBlock(hKey, sqlite3BtreePager(db->aDb[nDb].pBt), NULL);
sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock);
db->aDb[nDb].pAux = pBlock;
db->aDb[nDb].xFreeAux = DestroyCryptBlock;
rc = SQLITE_OK;
}
return rc;
}
// 釋放與一個頁相關的加密塊
void sqlite3pager_free_codecarg(void *pArg)
{
if (pArg)
DestroyCryptBlock((LPCryptBlock)pArg);
}
//不保存用戶的原始密碼.返回NULL.
void sqlite3CodecGetKey(sqlite3 *db, int nDb, void **ppKey, int *pnKeyLen)
{
*ppKey = NULL;
*pnKeyLen = 0;
}
//密鑰并不保留到臨時空間,僅保存于主數據庫.
int sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize)
{
return sqlite3CodecAttach(db, 0, pKey, nKeySize);
}
//改變已有數據庫的加密密鑰
int sqlite3_rekey_interop(sqlite3 *db, const void *pKey, int nKeySize)
{
Btree *pbt = db->aDb[0].pBt;
Pager *p = sqlite3BtreePager(pbt);
LPCryptBlock pBlock = (LPCryptBlock)sqlite3pager_get_codecarg(p);
BYTE * hKey = DeriveKey(pKey, nKeySize);
int rc = SQLITE_ERROR;
if (!pBlock && !hKey) return SQLITE_OK;
//重新加密一個數據庫,改變pager的寫密鑰, 讀密鑰依舊保留.
if (!pBlock) //加密一個未加密的數據庫
{
pBlock = CreateCryptBlock(hKey, p, NULL);
pBlock->ReadKey = 0; // 原始數據庫未加密
sqlite3PagerSetCodec(sqlite3BtreePager(pbt), sqlite3Codec, pBlock);
db->aDb[0].pAux = pBlock;
db->aDb[0].xFreeAux = DestroyCryptBlock;
}
else // 改變已加密數據庫的寫密鑰
{
pBlock->WriteKey = hKey;
}
// 開始一個事務
rc = sqlite3BtreeBeginTrans(pbt, 1);
if (!rc)
{
// 用新密鑰重寫所有的頁到數據庫。
Pgno nPage = 0;
Pgno nSkip = PAGER_MJ_PGNO(p);
void *pPage;
Pgno n;
if (sqlite3PagerPagecount(p, &nPage) == SQLITE_OK)
{
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 (!rc)
{
rc = sqlite3BtreeCommit(pbt);
}
// 如果失敗,回滾。
if (rc)
{
sqlite3BtreeRollback(pbt);
}
// 如果成功,銷毀先前的讀密鑰。并使讀密鑰等于當前的寫密鑰。
if (!rc)
{
if (pBlock->ReadKey)
{
sqlite3_free(pBlock->ReadKey);
}
pBlock->ReadKey = pBlock->WriteKey;
}
else// 如果失敗,銷毀當前的寫密鑰,并恢復為當前的讀密鑰。
{
if (pBlock->WriteKey)
{
sqlite3_free(pBlock->WriteKey);
}
pBlock->WriteKey = pBlock->ReadKey;
}
// 如果讀密鑰和寫密鑰皆為空,就不需要再對頁進行編解碼。
// 銷毀加密塊并移除頁的編解碼器
if (!pBlock->ReadKey && !pBlock->WriteKey)
{
sqlite3PagerSetCodec(p, NULL, NULL);
db->aDb[0].pAux = NULL;
db->aDb[0].xFreeAux = NULL;
DestroyCryptBlock(pBlock);
}
return rc;
}
SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
{
return sqlite3_key_interop(db, pKey, nKey);
}
SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey)
{
return sqlite3_rekey_interop(db, pKey, nKey);
}
#endif // SQLITE_HAS_CODEC
#endif // SQLITE_OMIT_DISKIO
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -