Sqlite 3.7.14.1 xxtea 加密算法
来源:互联网 发布:飞鱼网络电视tv 编辑:程序博客网 时间:2024/04/27 19:50
http://blog.csdn.net/wzq9706/article/details/8133314
最近在研空Sqlite加密算法,东拼西凑,还没研究出AES怎么用,欢迎指正,交流
1.从官方下载最新版本的Sqlite目前
www.sqlite.org
是:如sqlite-amalgamation-3071401.zip
2.在VS中添加一个空项目
3.解压sqlite-amalgamation-3071401.zip
复制出里面的sqlite3.h和sqlite3.c文件,放在工程目录中,并添加到工程
4.在工程中添加"sqlite3crypt.h",并添加以下代码
#ifndef DCG_SQLITE_CRYPT_FUNC_#define DCG_SQLITE_CRYPT_FUNC_//#ifdef SQLITE_HAS_CODECtypedef unsigned char BYTE;// 加密结构#define CRYPT_OFFSET 8typedef 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// 加密函数int sqlite3_encrypt(unsigned char * pData, unsigned int data_len, unsigned char * key, unsigned int len_of_key); // 解密函数int sqlite3_dencrypt(unsigned char * pData, unsigned int data_len, unsigned char * key, unsigned int len_of_key);// ===// 被sqlite3调用的加/解密函数void* sqlite3Codec(void *pArg, void *data, int nPageNum, int nMode);// 释放而加/密内存的回调void sqlite3CodecFree(void* arg);// 验证密码接口unsigned char* DeriveKey(const void *pKey, int nKeyLen);// 创建或更新一个页的加密算法索引.此函数会申请缓冲区.LPCryptBlock CreateCryptBlock(unsigned char* hKey, int nPageSize, LPCryptBlock pExisting);//#endif // SQLITE_HAS_CODEC#endif5.在工程中添加"sqlite3crypt.c",并添加以下代码
#include "sqlite3crypt.h"#include "sqlite3.h"#include <memory.h>#include <stdlib.h>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 ; } // 其它算法,未实现 // ==============================================================================int sqlite3_encrypt(unsigned char * pData, unsigned int data_len, unsigned char * key, unsigned int len_of_key){return 0;}// 其它算法,未实现// ==============================================================================int sqlite3_dencrypt( unsigned char * pData, unsigned int data_len, unsigned char * key, unsigned int len_of_key){return 0;}// ==============================================================================void * sqlite3Codec(void *pArg, void *data, int nPageNum, int nMode) { LPCryptBlock pBlock = (LPCryptBlock) pArg; unsigned int dwPageSize = 0; int len = 0; if (!pBlock) return data; // 确保pager的页长度和加密块的页长度相等.如果改变,就需要调整. if (nMode != 2) { int a = 0; a++; // 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; memcpy(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; memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; len = pBlock->PageSize / 4; xxtea(data, len, pBlock->ReadKey); break; /* case 3: //载入一个页 if (!pBlock->ReadKey) break; memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize; // 解密 sqlite3_dencrypt((BYTE*)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; // 加密 sqlite3_encrypt((BYTE*)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; sqlite3_encrypt((BYTE*)data, dwPageSize, pBlock->ReadKey, DB_KEY_LENGTH_BYTE);/*调用我的加密函数*/ // break;*/ } return data;}// ==============================================================================void sqlite3CodecFree(void* pArg) {if (pArg){LPCryptBlock pBlock = (LPCryptBlock)pArg;//销毁读密钥.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);}}// =====================================================================================LPCryptBlock CreateCryptBlock(unsigned char* hKey, int nPageSize, LPCryptBlock pExisting){LPCryptBlock pBlock;if (!pExisting) //创建新加密块{pBlock = sqlite3_malloc(sizeof(CryptBlock));memset(pBlock, 0, sizeof(CryptBlock));pBlock->ReadKey = hKey;pBlock->WriteKey = hKey;pBlock->PageSize = nPageSize;pBlock->Data = (unsigned char*) sqlite3_malloc(pBlock->PageSize + CRYPT_OFFSET);}else //更新存在的加密块{pBlock = pExisting;if (pBlock->PageSize != nPageSize && !pBlock->Data) {sqlite3_free(pBlock->Data);pBlock->PageSize = nPageSize;pBlock->Data = (unsigned char*) sqlite3_malloc(pBlock->PageSize + CRYPT_OFFSET);}}memset(pBlock->Data, 0, pBlock->PageSize + CRYPT_OFFSET);return pBlock;}// 从用户提供的缓冲区中得到一个加密密钥// =====================================================================================unsigned char * DeriveKey(const void *pKey, int nKeyLen){unsigned char * hKey = 0;int j;if (pKey == 0 || nKeyLen == 0){return 0;}hKey = sqlite3_malloc(DB_KEY_LENGTH_BYTE + 1);if (hKey == 0){return 0;}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;}
6.在splite3.c文件的最后面添加以下代码
#ifdef SQLITE_HAS_CODEC#include "sqlite3crypt.h"// 得到页所对应的编/解码块static void * sqlite3pager_get_codecarg(struct Pager *pPager){ return (pPager->xCodec) ? pPager->pCodec : 0;}// 设置页所对应的编/解码块// @Param pPager 要加密的页// @Param xCodec 加/解密回调// @Param xCodecFree 释放页对应的加/解密模块回调// @Param pCodecArg 加/解密模块void sqlite3pager_set_codec(Pager *pPager, void *(*xCodec)(void*, void*, Pgno, int), void (*xCodecFree)(void*), void *pCodecArg){ pPager->xCodec = xCodec; pPager->pCodec = pCodecArg; pPager->xCodecFree = xCodecFree;}// 实现Sqlite3接口// ===============================================================================// ===============================================================================// 下面是编译时提示缺少的函数 // 这个函数不需要做任何处理,获取密钥的部分在下面 DeriveKey 函数里实现void sqlite3CodecGetKey(struct sqlite3* db, int nDB, void** Key, int* nKey) {return;}// 这个函数好像是 sqlite 3.3.17前不久才加的,以前版本的sqlite里没有看到这个函数// 这个函数我还没有搞清楚是做什么的,它里面什么都不做直接返回,对加解密没有影响void sqlite3_activate_see(const char* right) {return;} // 实现加密接口int sqlite3_key(sqlite3 *db, const void *pKey, int nKey){return sqlite3CodecAttach(db, 0, pKey, nKey);} // 实现解密接口int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey){Pgno nSkip; void *pPage; Pgno n; Btree *pbt = db->aDb[0].pBt; Pager *p = sqlite3BtreePager(pbt); LPCryptBlock pBlock = (LPCryptBlock) sqlite3pager_get_codecarg(p); unsigned char * hKey = DeriveKey(pKey, nKey); int rc = SQLITE_ERROR; if (!pBlock && !hKey) return SQLITE_OK; //重新加密一个数据库,改变pager的写密钥, 读密钥依旧保留. if (!pBlock) //加密一个未加密的数据库 { pBlock = CreateCryptBlock(hKey, p->pageSize, NULL); pBlock->ReadKey = 0; // 原始数据库未加密 sqlite3pager_set_codec(sqlite3BtreePager(pbt), sqlite3Codec, sqlite3CodecFree, pBlock); } else // 改变已加密数据库的写密钥 { pBlock->WriteKey = hKey; } // 开始一个事务 rc = sqlite3BtreeBeginTrans(pbt, 1); if (!rc) { // 用新密钥重写所有的页到数据库。 //Pgno nPage = sqlite3PagerPagecount(p); int nPage = 0; sqlite3PagerPagecount(p, &nPage); nSkip = PAGER_MJ_PGNO(p); for (n = 1; rc == SQLITE_OK && n <= nPage; n++) { if (n == nSkip) continue; rc = sqlite3PagerGet(p, n, (DbPage**)&pPage); if (!rc) { rc = sqlite3PagerWrite((DbPage*)pPage); sqlite3PagerUnref((DbPage*)pPage); } } } // 如果成功,提交事务。 if (!rc) { rc = sqlite3BtreeCommit(pbt); } // 如果失败,回滚。 if (rc) { sqlite3BtreeRollback(pbt, SQLITE_OK); } // 如果成功,销毁先前的读密钥。并使读密钥等于当前的写密钥。 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) { sqlite3pager_set_codec(p, NULL, NULL, NULL); sqlite3CodecFree(pBlock); } return rc;} // 实现附加密钥到数据库接口// ================================================================================int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen){ int rc = SQLITE_ERROR; unsigned char* 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)->pageSize, NULL); sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, sqlite3CodecFree, pBlock); rc = SQLITE_OK; } return rc;}#endif //#ifdef SQLITE_HAS_CODEC
7.OK,代码部分完成了,但要使用Sqlite的加密前必须要预添加加SQLITE_HAS_CODEC这个宏,怎么加就不详诉了
8.最后,测试代码
#include <stdio.h>#include <stdlib.h>#include <string.h>extern "C" {#include "sqlite3.h"};#define SQLITE3_STATICextern int sqlite3_key(sqlite3 *db, const void *pKey, int nKey);static int _callback_exec(void * notused,int argc, char ** argv, char ** aszColName){int i;for ( i=0; i<argc; i++ ){printf( "%s = %s\r\n", aszColName[i], argv[i] == 0 ? "NUL" : argv[i] );}return 0;}int main(int argc, char * argv[]){const char * sSQL;char * pErrMsg = 0;int ret = 0;sqlite3 * db = 0;//创建数据库ret = sqlite3_open("encrypt.db", &db);//添加密码ret = sqlite3_key( db, "mypass", strlen("mypass"));//在内存数据库中创建表sSQL = "create table class(name varchar(20), student);";sqlite3_exec( db, sSQL, _callback_exec, 0, &pErrMsg );//插入数据sSQL = "insert into class values('mem_52911', 'zhaoyun');";sqlite3_exec( db, sSQL, _callback_exec, 0, &pErrMsg );//取得数据并显示sSQL = "select * from class;";sqlite3_exec( db, sSQL, _callback_exec, 0, &pErrMsg );//关闭数据库sqlite3_close(db);db = 0;return 0;}
- Sqlite 3.7.14.1 xxtea 加密算法
- xxtea 加密算法
- XXTEA加密算法为SQLite 3.3.17实现加密功能
- XXTEA加密算法为SQLite 3.5.3实现加密功能
- Java xxtea加密算法
- XXTEA加密算法C++版
- XXTEA加密算法OC代码
- XXTEA 加密算法的 JavaScript 和 PHP 实现
- 跨平台的加密算法XXTEA的封装
- 跨平台的加密算法XXTEA的封装
- XXTEA 加密算法 C++ C#兼容版本
- TEA和XxTEA跨平台加密算法
- XXTEA 加密算法的 JavaScript 和 PHP 实现
- 加密算法rc4和xxtea的对比
- XXTEA
- XXTEA 加密算法的概述及 Javascript 及 .net (C#) 实现
- [转载]XXTEA加密算法的各种程序实现整理
- xxtea加密算法-忘记是从哪里看到的了
- 彻底解决C#实现DataTable导出EXCEL表格
- 工作总结之指针的引用
- poj 1258 最小代价网络
- 软考复习——操作系统
- 构造方法注入bean 的使用
- Sqlite 3.7.14.1 xxtea 加密算法
- 非常简单的SQLite的Java程序
- linux 的 IP 及网关设置
- 使用BroadCast 使 service 和activity 信息交互
- 关于js关闭窗口的事件和用法
- Python的运算符与用法
- hadoop学习笔记-2-安装
- android 开发环境配置(MyEclipse8.5 + ADT14.0 + android-sdk_r14-windows)
- POJ 1200 Crazy Search