sqlite3+使用总结 下载本文

函数会在数据库关闭时被调用。参考我的 DeriveKey 函数来申请内存。

这里我给出我已经修改好的 sqlite3.c 和 sqlite3.h 文件。

如果太懒,就直接使用这两个文件,编译肯定能通过,运行也正常。当然,你必须按我前面提的,新建 crypt.h 和 crypt.c 文件,而且函数要按我前面定义的要求来做。

3、 加密使用方法:

现在,你代码已经有了加密功能。

你要把加密功能给用上,除了改 sqlite3.c 文件、给你工程添加 SQLITE_HAS_CODEC 宏,还得修改你的数据库调用函数。

前面提到过,要开始一个数据库操作,必须先 sqlite3_open 。 加解密过程就在 sqlite3_open 后面操作。

假设你已经 sqlite3_open 成功了,紧接着写下面的代码: int i;

//添加、使用密码

i = sqlite3_key( db, \ //修改密码

i = sqlite3_rekey( db, \

用 sqlite3_key 函数来提交密码。

第1个参数是 sqlite3 * 类型变量,代表着用 sqlite3_open 打开的数据库(或新建数据库)。 第2个参数是密钥。 第3个参数是密钥长度。

用 sqlite3_rekey 来修改密码。参数含义同 sqlite3_key。

实际上,你可以在sqlite3_open函数之后,到 sqlite3_close 函数之前任意位置调用 sqlite3_key 来设置密码。 但是如果你没有设置密码,而数据库之前是有密码的,那么你做任何操作都会得到一个返回值:SQLITE_NOTADB,并且得到错误提示:“file is encrypted or is not a database”。

只有当你用 sqlite3_key 设置了正确的密码,数据库才会正常工作。

如果你要修改密码,前提是你必须先 sqlite3_open 打开数据库成功,然后 sqlite3_key 设置密钥成功,之后才能用 sqlite3_rekey 来修改密码。(源码网整理:www.codepub.com)

如果数据库有密码,但你没有用 sqlite3_key 设置密码,那么当你尝试用 sqlite3_rekey 来修改密码时会得到 SQLITE_NOTADB 返回值。

如果你需要清空密码,可以使用: //修改密码

i = sqlite3_rekey( db, NULL, 0 ); 来完成密码清空功能。

4、 sqlite3.c 最后添加代码段

/***

董淳光定义的加密函数 ***/

#ifdef SQLITE_HAS_CODEC /***

加密结构 ***/

#define CRYPT_OFFSET 8 typedef struct _CryptBlock {

BYTE* ReadKey; // 读数据库和写入事务的密钥

BYTE* WriteKey; // 写入数据库的密钥 int PageSize; // 页的大小 BYTE* Data;

} CryptBlock, *LPCryptBlock;

#ifndef DB_KEY_LENGTH_BYTE /*密钥长度*/ #define DB_KEY_LENGTH_BYTE 16 /*密钥长度*/ #endif

#ifndef DB_KEY_PADDING /*密钥位数不足时补充的字符*/ #define DB_KEY_PADDING 0x33 /*密钥位数不足时补充的字符*/ #endif

/*** 下面是编译时提示缺少的函数 ***/

/** 这个函数不需要做任何处理,获取密钥的部分在下面 DeriveKey 函数里实现 **/ void sqlite3CodecGetKey(sqlite3* db, int nDB, void** Key, int* nKey) {

return ; }

/*被sqlite 和 sqlite3_key_interop 调用, 附加密钥到数据库.*/

int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen); /**

这个函数好像是 sqlite 3.3.17前不久才加的,以前版本的sqlite里没有看到

这个函数这个函数我还没有搞清楚是做什么的,它里面什么都不做直接返回,对加解密没有影响 **/

void sqlite3_activate_see(const char* right ) {

return; }

int sqlite3_key(sqlite3 *db, const void *pKey, int nKey); int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey); /***下面是上面的函数的辅助处理函数***/ // 从用户提供的缓冲区中得到一个加密密钥

// 用户提供的密钥可能位数上满足不了要求,使用这个函数来完成密钥扩展 static unsigned char * DeriveKey(const void *pKey, int nKeyLen); //创建或更新一个页的加密算法索引.此函数会申请缓冲区.

static LPCryptBlock CreateCryptBlock(unsigned char* hKey, Pager *pager, LPCryptBlock pExisting); //加密/解密函数, 被pager调用

void * sqlite3Codec(void *pArg, unsigned char *data, Pgno nPageNum, int nMode); //设置密码函数

int __stdcall sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize); // 修改密码函数

int __stdcall sqlite3_rekey_interop(sqlite3 *db, const void *pKey, int nKeySize); //销毁一个加密块及相关的缓冲区,密钥.

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 ); //加密/解密函数, 被pager调用

void * sqlite3Codec(void *pArg, unsigned char *data, Pgno nPageNum, 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 2: //重载一个页 case 3: //载入一个页

if (!pBlock->ReadKey) break; dwPageSize = pBlock->PageSize;

My_DeEncrypt_Func(data, dwPageSize, pBlock->ReadKey, DB_KEY_LENGTH_BYTE ); /*调用我的解密函数*/ break;

case 6: //加密一个主数据库文件的页 if (!pBlock->WriteKey) break;

memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize;

My_Encrypt_Func(data , dwPageSize, pBlock->WriteKey, DB_KEY_LENGTH_BYTE ); /*调用我的加密函数*/ break;

case 7: //加密事务文件的页

/*在正常环境下, 读密钥和写密钥相同. 当数据库是被重新加密的,读密钥和写密钥未必相同.回滚事务必要用数据库文件的原始密钥写入.因此,当一次回滚被写入,总是用数据库的读密钥,这是为了保证与读取原始数据的密钥相同. */

if (!pBlock->ReadKey) break;

memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize;

My_Encrypt_Func( data, dwPageSize, pBlock->ReadKey, 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, pKey, DB_KEY_LENGTH_BYTE ); }

return hKey; }

//创建或更新一个页的加密算法索引.此函数会申请缓冲区.

static LPCryptBlock CreateCryptBlock(unsigned char* hKey, Pager *pager, LPCryptBlock pExisting) {

LPCryptBlock pBlock;

if (!pExisting) //创建新加密块 {

pBlock = sqliteMalloc(sizeof(CryptBlock)); memset(pBlock, 0, sizeof(CryptBlock)); pBlock->ReadKey = hKey; pBlock->WriteKey = hKey;

pBlock->PageSize = pager->pageSize;