#ifdef
sqlITE_HAS_CODEC
#include "crypt.h"
/***
加密结构
***/
#define CRYPT_OFFSET 8
typedef
struct _CryptBlock {
BYTE* ReadKey; // 读数据库和写入事务的密钥
BYTE* WriteKey; // 写入数据库的密钥
int PageSize; // 页的大小
BYTE* Data;
} CryptBlock,*LPCryptBlock;
#ifndefDB_KEY_LENGTH_BYTE
/*密钥长度*/
#defineDB_KEY_LENGTH_BYTE
16 /*密钥长度*/
#endif
#ifndefDB_KEY_PADDING
/*密钥位数不足时补充的字符*/
#defineDB_KEY_PADDING
0x33/*密钥位数不足时补充的字符*/
#endif
return;
}
/**
这个函数我还没有搞清楚是做什么的,它里面什么都不做直接返回,对加解密没有影响
**/
void
sqlite3_activate_see(
const
char* right) {
return;
}
/***
***/
static
unsigned
char *
DeriveKey(
const
void *pKey,int nKeyLen);
static LPCryptBlock CreateCryptBlock(unsigned char* hKey,Pager *pager,
LPCryptBlock pExisting);
void * sqlite3Codec(void *pArg,unsigned char *data,Pgno nPageNum,int nMode);
//设置密码函数
//销毁一个加密块及相关的缓冲区,密钥.
static
void
DestroyCryptBlock(LPCryptBlock pBlock);
static void * sqlite3pager_get_codecarg(Pager *pPager);
void
sqlite3pager_set_codec(
Pager *pPager,
void *(*xCodec)(
void*,void*,Pgno,int),void *pCodecArg);
//加密/解密函数,int nMode) {
LPCryptBlock pBlock = (LPCryptBlock) pArg;
unsigned
int dwPageSize = 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;
dwPageSize = pBlock->PageSize; My_DeEncrypt_Func(data,dwPageSize,pBlock->ReadKey, DB_KEY_LENGTH_BYTE); /*调用我的解密函数*/
break;
if (!pBlock->WriteKey)
break;
memcpy(pBlock->Data + CRYPT_OFFSET,data,pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize; My_Encrypt_Func(data,pBlock->WriteKey,DB_KEY_LENGTH_BYTE); /*调用我的加密函数*/
break;
case 7: //加密事务文件的页
/*在正常环境下,读密钥和写密钥相同. 当数据库是被重新加密的,读密钥和写密钥未必相同.
这是为了保证与读取原始数据的密钥相同.
*/
if (!pBlock->ReadKey)
break;
memcpy(pBlock->Data + CRYPT_OFFSET,DB_KEY_LENGTH_BYTE); /*调用我的加密函数*/
break;
}
return data;
}
//销毁一个加密块及相关的缓冲区,密钥.
static
void
DestroyCryptBlock(LPCryptBlock pBlock)
{
//销毁读密钥.
if (pBlock->ReadKey) {
sqliteFree(pBlock->ReadKey);
}
//如果写密钥存在并且不等于读密钥,也销毁.
if (pBlock->WriteKey && pBlock->WriteKey != pBlock->ReadKey) {
sqliteFree(pBlock->WriteKey);
}
if (pBlock->Data) {
sqliteFree(pBlock->Data);
}
//释放加密块.
sqliteFree(pBlock);
}
static void * sqlite3pager_get_codecarg(Pager *pPager)
{
return (pPager->xCodec) ? pPager->pCodecArg : NULL;
}
static
unsigned
char *
DeriveKey(
const
void *pKey,int nKeyLen)
{
unsigned
char * hKey =
NULL;
int j;
if (pKey == NULL || nKeyLen == 0)
{
return
NULL;
}
hKey = sqliteMalloc(DB_KEY_LENGTH_BYTE + 1);
if (hKey ==
NULL)
{
return
NULL;
}
hKey[DB_KEY_LENGTH_BYTE] = 0; if (nKeyLen < DB_KEY_LENGTH_BYTE)
{
memcpy(hKey,pKey,nKeyLen); //先拷贝得到密钥前面的部分 j = DB_KEY_LENGTH_BYTE - nKeyLen;
//补充密钥后面的部分
memset(hKey + nKeyLen,DB_KEY_PADDING,j);
}
else
{
//密钥位数已经足够,直接把密钥取过来
memcpy(hKey,DB_KEY_LENGTH_BYTE);
}
return hKey;
}
static LPCryptBlock CreateCryptBlock(unsigned char* hKey,
LPCryptBlock pExisting)
{
LPCryptBlock pBlock;
if (!pExisting) //创建新加密块
{
pBlock = sqliteMalloc(sizeof(CryptBlock));
memset(pBlock,sizeof(CryptBlock));
pBlock->ReadKey = hKey;
pBlock->WriteKey = hKey;
pBlock->PageSize = pager->
pageSize;
pBlock->Data = (
unsigned
char*) sqliteMalloc(
pBlock->PageSize + CRYPT_OFFSET);
}
else //更新存在的加密块
{
pBlock = pExisting; if (pBlock->PageSize != pager->pageSize && !pBlock->Data) {
sqliteFree(pBlock->Data);
pBlock->PageSize = pager->
pageSize;
pBlock->Data = (
unsigned
char*) sqliteMalloc(
pBlock->PageSize + CRYPT_OFFSET);
}
}
memset(pBlock->Data,pBlock->PageSize + CRYPT_OFFSET);
return pBlock;
}
/*
** Set the codec for this pager
*/
void
sqlite3pager_set_codec(
Pager *pPager,void *(*xCodec)(
void*,void *pCodecArg)
{
pPager->xCodec = xCodec; pPager->pCodecArg = pCodecArg;
}
{
return sqlite3_key_interop(db,nKey);
}
{
return sqlite3_rekey_interop(db,nKey);
}
{
int rc =
sqlITE_ERROR;
unsigned
char* hKey = 0;
//如果没有指定密匙,可能标识用了主数据库的加密或没加密.
if (!pKey || !nKeyLen)
{
if (!nDb)
{
}
{
LPCryptBlock pBlock = (LPCryptBlock) sqlite3pager_get_codecarg(
sqlite3BtreePager(db->aDb[0].pBt));
if (!pBlock)
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);
sqlite3Codec,pBlock);
rc = sqlITE_OK;
}
return rc;
}
// Changes the encryption key for an existing database.
{
Btree *pbt = db->aDb[0].pBt; Pager *p = sqlite3BtreePager(pbt); LPCryptBlock pBlock = (LPCryptBlock) sqlite3pager_get_codecarg(p); unsigned char * hKey = DeriveKey(pKey,nKeySize);
int rc =
sqlITE_ERROR;
if (!pBlock && !hKey)
return
sqlITE_OK;
{
pBlock = CreateCryptBlock(hKey,p,NULL);
pBlock->ReadKey = 0; // 原始数据库未加密
sqlite3pager_set_codec(sqlite3BtreePager(pbt),sqlite3Codec,pBlock);
}
else // 改变已加密数据库的写密钥
{
pBlock->WriteKey = hKey;
}
// 开始一个事务
rc = sqlite3BtreeBeginTrans(pbt,1);
if (!rc)
{
// 用新密钥重写所有的页到数据库。
Pgno nPage = sqlite3PagerPagecount(p); Pgno nSkip = PAGER_MJ_PGNO(p);
void *pPage;
Pgno n; 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)
{
sqliteFree(pBlock->ReadKey);
}
pBlock->ReadKey = pBlock->WriteKey;
}
else // 如果失败,销毁当前的写密钥,并恢复为当前的读密钥。
{
if (pBlock->WriteKey)
{
sqliteFree(pBlock->WriteKey);
}
pBlock->WriteKey = pBlock->ReadKey;
}
// 如果读密钥和写密钥皆为空,就不需要再对页进行编解码。
// 销毁加密块并移除页的编解码器
if (!pBlock->ReadKey && !pBlock->WriteKey)
{
sqlite3pager_set_codec(p,NULL,NULL);
DestroyCryptBlock(pBlock);
}
return rc;
}
/***
下面是加密函数的主体
***/
{
return sqlite3CodecAttach(db,nKeySize);
}
// 释放与一个页相关的加密块
void
sqlite3pager_free_codecarg(
void *pArg)
{
if (pArg)
DestroyCryptBlock((LPCryptBlock) pArg);
}
#endif //#
ifdef sqlITE_HAS_CODEC
|
DeriveKey 函数就是做这个扩展的。有人把接收到的密钥求md5,这也是一个办法,因为md5运算结果固定16字节,不论你有多少字符,最后就是16字节。这是md5算法的特点。但是我不想用md5,因为还得为它添加包含一些 md5 的.c或.cpp文件。我不想这么做。我自己写了一个算法来扩展密钥,很简单的算法。当然,你也可以使用你的扩展方法,也而可以使用 md5 算法。只要修改 DeriveKey 函数就可以了。
在 DeriveKey 函数里,只管申请空间构造所需要的密钥,不需要释放,因为在另一个函数里有释放过程,而那个函数会在数据库关闭时被调用。参考上面 DeriveKey 函数来申请内存。