SQLite 3.7.13的加密解密(四)―― 挂接加密解密函数

前端之家收集整理的这篇文章主要介绍了SQLite 3.7.13的加密解密(四)―― 挂接加密解密函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

把crypt.c中实现的加密解密函数挂接到sqlite3.c中,并且实现前面编译提示的未实现的函数。在sqlite3.c的最后一行的后面,添加如下代码
#ifdef@H_403_20@ sqlITE_HAS_CODEC
#include@H_403_20@ "crypt.h"
/***
加密结构
***/
#define@H_403_20@ CRYPT_OFFSET 8
typedef@H_403_20@ struct@H_403_20@ _CryptBlock {
BYTE* ReadKey; // 读数据库和写入事务的密钥
BYTE* WriteKey; // 写入数据库的密钥
int@H_403_20@ PageSize; // 页的大小
BYTE* Data;
} CryptBlock,*LPCryptBlock;
#ifndef@H_403_20@DB_KEY_LENGTH_BYTE /*密钥长度*/
#define@H_403_20@DB_KEY_LENGTH_BYTE 16 /*密钥长度*/
#endif@H_403_20@
#ifndef@H_403_20@DB_KEY_PADDING /*密钥位数不足时补充的字符*/
#define@H_403_20@DB_KEY_PADDING 0x33/*密钥位数不足时补充的字符*/
#endif@H_403_20@
/*** 下面是编译时提示缺少的函数 ***/
/** 这个函数不需要做任何处理,获取密钥的部分在下面 DeriveKey 函数里实现 **/
void@H_403_20@ sqlite3CodecGetKey@H_403_20@(sqlite3* db,int@H_403_20@ nDB,void@H_403_20@** Key,int@H_403_20@* nKey) {
return@H_403_20@;
}
/*被 sqlitesqlite3_key_interop 调用,附加密钥到数据库.*/
int@H_403_20@ sqlite3CodecAttach@H_403_20@(sqlite3 *db,int@H_403_20@ nDb,const@H_403_20@ void@H_403_20@ *pKey,int@H_403_20@ nKeyLen);
/**
这个函数好像是 sqlite 3.3.17前不久才加的,以前版本的 sqlite里没有看到这个函数
这个函数我还没有搞清楚是做什么的,它里面什么都不做直接返回,对加解密没有影响
**/
void@H_403_20@ sqlite3_activate_see@H_403_20@( const@H_403_20@ char@H_403_20@* right) {
return@H_403_20@;
}
int@H_403_20@ sqlite3_key@H_403_20@(sqlite3 *db,int@H_403_20@ nKey);
int@H_403_20@ sqlite3_rekey@H_403_20@(sqlite3 *db,int@H_403_20@ nKey);
/***
下面是上面的函数的辅助处理函数
***/
// 从用户提供的缓冲区中得到一个加密密钥
// 用户提供的密钥可能位数上满足不了要求,使用这个函数来完成密钥扩展
static@H_403_20@ unsigned@H_403_20@ char@H_403_20@ * DeriveKey@H_403_20@( const@H_403_20@ void@H_403_20@ *pKey,int@H_403_20@ nKeyLen);
//创建或更新一个页的加密算法索引.此函数会申请缓冲区.

static@H_403_20@ LPCryptBlock CreateCryptBlock@H_403_20@(unsigned@H_403_20@ char@H_403_20@* hKey,Pager *pager,

LPCryptBlock pExisting);
//加密/解密函数,被pager调用

void@H_403_20@ * sqlite3Codec@H_403_20@(void@H_403_20@ *pArg,unsigned@H_403_20@ char@H_403_20@ *data,Pgno nPageNum,int@H_403_20@ nMode);

//设置密码函数
int@H_403_20@ __stdcall sqlite3_key_interop@H_403_20@(sqlite3 *db,int@H_403_20@ nKeySize);
int@H_403_20@ __stdcall sqlite3_rekey_interop@H_403_20@(sqlite3 *db,int@H_403_20@ nKeySize);
//销毁一个加密块及相关的缓冲区,密钥.
static@H_403_20@ void@H_403_20@ DestroyCryptBlock@H_403_20@(LPCryptBlock pBlock);

static@H_403_20@ void@H_403_20@ * sqlite3pager_get_codecarg@H_403_20@(Pager *pPager);

void@H_403_20@ sqlite3pager_set_codec@H_403_20@( Pager *pPager,
void@H_403_20@ *(*xCodec)( void@H_403_20@*,void@H_403_20@*,Pgno,int@H_403_20@),void@H_403_20@ *pCodecArg);
//加密/解密函数,int@H_403_20@ nMode) {

LPCryptBlock pBlock = (LPCryptBlock) pArg;
unsigned@H_403_20@ int@H_403_20@ dwPageSize = 0;
if@H_403_20@ (!pBlock)
return@H_403_20@ data;
// 确保pager的页长度和加密块的页长度相等.如果改变,就需要调整.
if@H_403_20@ (nMode != 2) {

PgHdr *pageHeader;

pageHeader = DATA_TO_PGHDR(data);

if@H_403_20@ (pageHeader->pPager->pageSize != pBlock->PageSize) {

CreateCryptBlock(0,pageHeader->pPager,pBlock);

}
}
switch@H_403_20@ (nMode) {

case@H_403_20@ 0: // Undo a "case 7" journal file encryption

case@H_403_20@ 2: //重载一个页
case@H_403_20@ 3: //载入一个页
if@H_403_20@ (!pBlock->ReadKey)
break@H_403_20@;

dwPageSize = pBlock->PageSize;

My_DeEncrypt_Func(data,dwPageSize,pBlock->ReadKey,

DB_KEY_LENGTH_BYTE); /*调用我的解密函数*/

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

memcpy@H_403_20@(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@H_403_20@;
case@H_403_20@ 7: //加密事务文件的页
/*在正常环境下,读密钥和写密钥相同. 当数据库是被重新加密的,读密钥和写密钥未必相同.
回滚事务必要用数据库文件的原始密钥写入.因此,当一次回滚被写入,总是用数据库的读密钥,
这是为了保证与读取原始数据的密钥相同.
*/
if@H_403_20@ (!pBlock->ReadKey)
break@H_403_20@;

memcpy@H_403_20@(pBlock->Data + CRYPT_OFFSET,DB_KEY_LENGTH_BYTE); /*调用我的加密函数*/

break@H_403_20@;
}
return@H_403_20@ data;
}
//销毁一个加密块及相关的缓冲区,密钥.
static@H_403_20@ void@H_403_20@ DestroyCryptBlock@H_403_20@(LPCryptBlock pBlock)
{
//销毁读密钥.
if@H_403_20@ (pBlock->ReadKey) {
sqliteFree(pBlock->ReadKey);
}
//如果写密钥存在并且不等于读密钥,也销毁.

if@H_403_20@ (pBlock->WriteKey && pBlock->WriteKey != pBlock->ReadKey) {

sqliteFree(pBlock->WriteKey);
}
if@H_403_20@ (pBlock->Data) {
sqliteFree(pBlock->Data);
}
//释放加密块.
sqliteFree(pBlock);
}

static@H_403_20@ void@H_403_20@ * sqlite3pager_get_codecarg@H_403_20@(Pager *pPager)

{

return@H_403_20@ (pPager->xCodec) ? pPager->pCodecArg : NULL;

}
// 从用户提供的缓冲区中得到一个加密密钥
static@H_403_20@ unsigned@H_403_20@ char@H_403_20@ * DeriveKey@H_403_20@( const@H_403_20@ void@H_403_20@ *pKey,int@H_403_20@ nKeyLen)
{
unsigned@H_403_20@ char@H_403_20@ * hKey = NULL;
int@H_403_20@ j;

if@H_403_20@ (pKey == NULL || nKeyLen == 0)

{
return@H_403_20@ NULL;
}

hKey = sqliteMalloc(DB_KEY_LENGTH_BYTE + 1);

if@H_403_20@ (hKey == NULL)
{
return@H_403_20@ NULL;
}

hKey[DB_KEY_LENGTH_BYTE] = 0;

if@H_403_20@ (nKeyLen < DB_KEY_LENGTH_BYTE)

{

memcpy@H_403_20@(hKey,pKey,nKeyLen); //先拷贝得到密钥前面的部分

j = DB_KEY_LENGTH_BYTE - nKeyLen;

//补充密钥后面的部分

memset@H_403_20@(hKey + nKeyLen,DB_KEY_PADDING,j);

}
else@H_403_20@
{
//密钥位数已经足够,直接把密钥取过来

memcpy@H_403_20@(hKey,DB_KEY_LENGTH_BYTE);

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

static@H_403_20@ LPCryptBlock CreateCryptBlock@H_403_20@(unsigned@H_403_20@ char@H_403_20@* hKey,

LPCryptBlock pExisting)
{
LPCryptBlock pBlock;
if@H_403_20@ (!pExisting) //创建新加密块
{

pBlock = sqliteMalloc(sizeof@H_403_20@(CryptBlock));

memset@H_403_20@(pBlock,sizeof@H_403_20@(CryptBlock));
pBlock->ReadKey = hKey;
pBlock->WriteKey = hKey;
pBlock->PageSize = pager-> pageSize;
pBlock->Data = ( unsigned@H_403_20@ char@H_403_20@*) sqliteMalloc(
pBlock->PageSize + CRYPT_OFFSET);
}
else@H_403_20@ //更新存在的加密块
{

pBlock = pExisting;

if@H_403_20@ (pBlock->PageSize != pager->pageSize && !pBlock->Data) {

sqliteFree(pBlock->Data);
pBlock->PageSize = pager-> pageSize;
pBlock->Data = ( unsigned@H_403_20@ char@H_403_20@*) sqliteMalloc(
pBlock->PageSize + CRYPT_OFFSET);
}
}
memset@H_403_20@(pBlock->Data,pBlock->PageSize + CRYPT_OFFSET);
return@H_403_20@ pBlock;
}
/*

** Set the codec for this pager

*/
void@H_403_20@ sqlite3pager_set_codec@H_403_20@( Pager *pPager,void@H_403_20@ *(*xCodec)( void@H_403_20@*,void@H_403_20@ *pCodecArg)
{

pPager->xCodec = xCodec;

pPager->pCodecArg = pCodecArg;

}
int@H_403_20@ sqlite3_key@H_403_20@(sqlite3 *db,int@H_403_20@ nKey)
{

return@H_403_20@ sqlite3_key_interop(db,nKey);

}
int@H_403_20@ sqlite3_rekey@H_403_20@(sqlite3 *db,int@H_403_20@ nKey)
{

return@H_403_20@ sqlite3_rekey_interop(db,nKey);

}
/*被 sqlitesqlite3_key_interop 调用,int@H_403_20@ nKeyLen)
{
int@H_403_20@ rc = sqlITE_ERROR;
unsigned@H_403_20@ char@H_403_20@* hKey = 0;
//如果没有指定密匙,可能标识用了主数据库的加密或没加密.

if@H_403_20@ (!pKey || !nKeyLen)

{
if@H_403_20@ (!nDb)
{
return@H_403_20@ sqlITE_OK; //主数据库,没有指定密钥所以没有加密.
}
else@H_403_20@ //附加数据库,使用主数据库的密钥.
{
//获取数据库的加密块并复制密钥给附加数据库使用

LPCryptBlock pBlock = (LPCryptBlock) sqlite3pager_get_codecarg(

sqlite3BtreePager(db->aDb[0].pBt));
if@H_403_20@ (!pBlock)
return@H_403_20@ sqlITE_OK; //主数据库没有加密
if@H_403_20@ (!pBlock->ReadKey)
return@H_403_20@ sqlITE_OK; //没有加密
memcpy@H_403_20@(pBlock->ReadKey,&hKey,16);
}
}
else@H_403_20@ //用户提供了密码,从中创建密钥.
{

hKey = DeriveKey(pKey,nKeyLen);

}
//创建一个新的加密块,并将解码器指向新的附加数据库.
if@H_403_20@ (hKey)
{

LPCryptBlock pBlock = CreateCryptBlock(hKey,

sqlite3BtreePager(db->aDb[nDb].pBt),NULL);
sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt),

sqlite3Codec,pBlock);

rc = sqlITE_OK;
}
return@H_403_20@ rc;
}
// Changes the encryption key for an existing database.
int@H_403_20@ __stdcall sqlite3_rekey_interop@H_403_20@(sqlite3 *db,int@H_403_20@ nKeySize)
{

Btree *pbt = db->aDb[0].pBt;

Pager *p = sqlite3BtreePager(pbt);

LPCryptBlock pBlock = (LPCryptBlock) sqlite3pager_get_codecarg(p);

unsigned@H_403_20@ char@H_403_20@ * hKey = DeriveKey(pKey,nKeySize);

int@H_403_20@ rc = sqlITE_ERROR;

if@H_403_20@ (!pBlock && !hKey)

return@H_403_20@ sqlITE_OK;
//重新加密一个数据库,改变pager的写密钥,读密钥依旧保留.
if@H_403_20@ (!pBlock) //加密一个未加密的数据库
{

pBlock = CreateCryptBlock(hKey,p,NULL);

pBlock->ReadKey = 0; // 原始数据库未加密

sqlite3pager_set_codec(sqlite3BtreePager(pbt),sqlite3Codec,pBlock);

}
else@H_403_20@ // 改变已加密数据库的写密钥
{
pBlock->WriteKey = hKey;
}
// 开始一个事务

rc = sqlite3BtreeBeginTrans(pbt,1);

if@H_403_20@ (!rc)
{
// 用新密钥重写所有的页到数据库

Pgno nPage = sqlite3PagerPagecount(p);

Pgno nSkip = PAGER_MJ_PGNO(p);

void@H_403_20@ *pPage;

Pgno n;

for@H_403_20@ (n = 1; rc == sqlITE_OK && n <= nPage; n++)

{
if@H_403_20@ (n == nSkip)
continue@H_403_20@;
rc = sqlite3PagerGet(p,n,&pPage);
if@H_403_20@ (!rc)
{

rc = sqlite3PagerWrite(pPage);

sqlite3PagerUnref(pPage);
}
}
}
// 如果成功,提交事务。
if@H_403_20@ (!rc)
{

rc = sqlite3BtreeCommit(pbt);

}
// 如果失败,回滚。
if@H_403_20@ (rc)
{
sqlite3BtreeRollback(pbt);
}
// 如果成功,销毁先前的读密钥。并使读密钥等于当前的写密钥。
if@H_403_20@ (!rc)
{
if@H_403_20@ (pBlock->ReadKey)
{
sqliteFree(pBlock->ReadKey);
}
pBlock->ReadKey = pBlock->WriteKey;
}
else@H_403_20@ // 如果失败,销毁当前的写密钥,并恢复为当前的读密钥。
{
if@H_403_20@ (pBlock->WriteKey)
{
sqliteFree(pBlock->WriteKey);
}
pBlock->WriteKey = pBlock->ReadKey;
}
// 如果读密钥和写密钥皆为空,就不需要再对页进行编解码。
// 销毁加密块并移除页的编解码器

if@H_403_20@ (!pBlock->ReadKey && !pBlock->WriteKey)

{

sqlite3pager_set_codec(p,NULL,NULL);

DestroyCryptBlock(pBlock);
}
return@H_403_20@ rc;
}
/***
下面是加密函数的主体
***/
int@H_403_20@ __stdcall sqlite3_key_interop@H_403_20@(sqlite3 *db,int@H_403_20@ nKeySize)
{

return@H_403_20@ sqlite3CodecAttach(db,nKeySize);

}
// 释放与一个页相关的加密块
void@H_403_20@ sqlite3pager_free_codecarg@H_403_20@( void@H_403_20@ *pArg)
{
if@H_403_20@ (pArg)
DestroyCryptBlock((LPCryptBlock) pArg);
}
#endif@H_403_20@ //# ifdef sqlITE_HAS_CODEC
特别说明:
DeriveKey 函数,这个函数是对密钥的扩展。比如,你要求密钥是128位,即是16字节,但是如果用户只输入 1个字节呢?2个字节呢?或输入50个字节呢?你得对密钥进行扩展,使之符合16字节的要求。

DeriveKey 函数就是做这个扩展的。有人把接收到的密钥求md5,这也是一个办法,因为md5运算结果固定16字节,不论你有多少字符,最后就是16字节。这是md5算法的特点。但是我不想用md5,因为还得为它添加包含一些 md5 的.c或.cpp文件。我不想这么做。我自己写了一个算法来扩展密钥,很简单的算法。当然,你也可以使用你的扩展方法,也而可以使用 md5 算法。只要修改 DeriveKey 函数就可以了。

在 DeriveKey 函数里,只管申请空间构造所需要的密钥,不需要释放,因为在另一个函数里有释放过程,而那个函数会在数据库关闭时被调用。参考上面 DeriveKey 函数来申请内存。

猜你在找的Sqlite相关文章