董淳光SQLITE3?使用总结(5)
<script></script>标签:知识/探索 | ? |
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);
}
?
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), NULL);
??????? sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock);
??????? rc = SQLITE_OK;
??? }
??? return rc;
}
?
// Changes the encryption key for an existing database.
int __stdcall 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);
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, const void *pKey, int nKeySize)
{
? return sqlite3CodecAttach(db, 0, pKey, nKeySize);
}
?
?
// 释放与一个页相关的加密块
void sqlite3pager_free_codecarg(void *pArg)
{
if (pArg)
???? DestroyCryptBlock((LPCryptBlock)pArg);
}
?
#endif //#ifdef SQLITE_HAS_CODEC
?
五、?????? 后记
写此教程,可不是一个累字能解释。
但是我还是觉得欣慰的,因为我很久以前就想写 sqlite 的教程,一来自己备忘,二而已造福大众,大家不用再走弯路。
本人第一次写教程,不足的地方请大家指出。
{
return sqlite3_key_interop(db, pKey, nKey);
}
?
int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey)
{
return sqlite3_rekey_interop(db, pKey, nKey);
}
?
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), NULL);
??????? sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock);
??????? rc = SQLITE_OK;
??? }
??? return rc;
}
?
// Changes the encryption key for an existing database.
int __stdcall 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);
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, const void *pKey, int nKeySize)
{
? return sqlite3CodecAttach(db, 0, pKey, nKeySize);
}
?
?
// 释放与一个页相关的加密块
void sqlite3pager_free_codecarg(void *pArg)
{
if (pArg)
???? DestroyCryptBlock((LPCryptBlock)pArg);
}
?
#endif //#ifdef SQLITE_HAS_CODEC
?
五、?????? 后记
写此教程,可不是一个累字能解释。
但是我还是觉得欣慰的,因为我很久以前就想写 sqlite 的教程,一来自己备忘,二而已造福大众,大家不用再走弯路。
本人第一次写教程,不足的地方请大家指出。