网上有个3.3.7的xxtea加密,但3.61起,内部有代码变化了
解决方案 »
- delphi怎样将入库、出库、库存三个表的内容融合到一张表做成详细查询页面!
- Delphi7虽然经典,但是对我而言,有个最大的缺陷
- TDBGrid如何增加一行内容
- 求教,如何用delphi读取xml
- 看看这个错误,实在不懂啊!
- sunnf接分,原因见里面url
- 不明白...;不明白...请指教串口卡问题:打开几个串口后程序变慢或死机???
- 超急恐怖,求救:我的程序已经投入使用,但是发现用户信息互相覆盖。。。。。。。
- 怎样显示一个“浏览”对话框?
- 如何实现:当鼠标在某按钮上停留一到两秒时显示解释框(鼠标下黄色小框)!
- 请问这个属性怎样赋?RzPanel1.BorderOuter:=fsflat;这样错的
- 结婚那天,坐在角落里象乞丐的人,居然是我的公婆!(转)
以下代码为修改后的xxtea,适用最新的sqlite 3个文件源码的版本#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1])
#include "sqlite3.c"
#ifndef SQLITE_OMIT_DISKIO
#ifdef SQLITE_HAS_CODEC
#include "md5.h"#define CRYPT_OFFSET 8
#define BYTE unsigned chartypedef 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)
{
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 = 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)
{
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;
}int sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
{
return sqlite3_key_interop(db, pKey, nKey);
}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
Delphi 有个免费的控件 ASQSQLite ,在源代码中自己实现 SQLite3_Key 和 SQLite3_ReKey ,只要加很少几行代码就可以支持加密了ODBC驱动也有