SQLite3使用详解之三
/*** 下面是上面的函数的辅助处理函数 ***/ // 从用户提供的缓冲区中得到一个加密密钥 // 用户提供的密钥可能位数上满足不了要求,使用这个函数来完成密钥扩展 static unsigned char * DeriveKey(const void *pKey,int nKeyLen); //创建或更新一个页的加密算法索引.此函数会申请缓冲区. static LPCryptBlock CreateCryptBlock(unsigned char* hKey,Pager *pager,LPCryp tBlock 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,int nKeySiz e); //销毁一个加密块及相关的缓冲区,密钥. 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; 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,pBlock->WriteKey,DB_KEY_LENGTH_BYTE ) ; /*调用我的加密函数*/ break; case 7: //加密事务文件的页 /*在正常环境下,读密钥和写密钥相同. 当数据库是被重新加密的,读密钥和写密钥 未必相同. 回滚事务必要用数据库文件的原始密钥写入.因此,当一次回滚被写入,总是用数据库 的读密钥, 这是为了保证与读取原始数据的密钥相同. */ if (!pBlock->ReadKey) break; memcpy(pBlock->Data + CRYPT_OFFSET,pBlock->PageSize); data = pBlock->Data + CRYPT_OFFSET; dwPageSize = pBlock->PageSize; My_Encrypt_Func( data,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,LPCryp tBlock 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_OFFS ET); } 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*,int), void *pCodecArg ) { pPager->xCodec = xCodec; pPager->pCodecArg = pCodecArg; } int sqlite3_key(sqlite3 *db,int nKey) { return sqlite3_key_interop(db,nKey); } int sqlite3_rekey(sqlite3 *db,int nKey) { return sqlite3_rekey_interop(db,nKey); } /*被sqlite 和 sqlite3_key_interop 调用,附加密钥到数据库.*/ int sqlite3CodecAttach(sqlite3 *db,int nDb,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(sqli te3BtreePager(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); sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt),sqlite3Cod ec,pBlock); rc = SQLITE_OK; } return rc; } // Changes the encryption key for an existing database. int __stdcall sqlite3_rekey_interop(sqlite3 *db,int nKeySiz e) { 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; //重新加密一个数据库,改变pager的写密钥,读密钥依旧保留. if (!pBlock) //加密一个未加密的数据库 { 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; } /*** 下面是加密函数的主体 ***/ int __stdcall sqlite3_key_interop(sqlite3 *db,int nKeySize) { return sqlite3CodecAttach(db,nKeySize); } // 释放与一个页相关的加密块 void sqlite3pager_free_codecarg(void *pArg) { if (pArg) DestroyCryptBlock((LPCryptBlock)pArg); } #endif //#ifdef SQLITE_HAS_CODEC 五、 后记 写此教程,可不是一个累字能解释。 但是我还是觉得欣慰的,因为我很久以前就想写 sqlite 的教程,一来自己备忘,二而已 造福大众,大家不用再走弯路。 本人第一次写教程,不足的地方请大家指出。 本文可随意转载、修改、引用。但无论是转载、修改、引用,都请附带我的名字:董淳光 。以示对我劳动的肯定 (源码网整理:www.codepub.com) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- c# – ASP.NET MVC – 缓慢的初始加载
- oracle数据库表结构及数据的导出
- AJAX技术解读
- ios – UIButton从静态库触发时单击“不工作”
- flash_recovery_area空间压力导致ORA-01033:ORACLE 正在初
- ruby – connect:SSL_connect returned = 1 errno = 0 sta
- cocos2dx之实现扑克牌翻转效果的三种方法
- 正则表达式 – 在蒙古不区分大小写搜索
- resource net/sf/antcontrib/antlib.xml. It could not be
- 如何从C#运行PowerShell脚本作为非高级用户