加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Sqlite xxteacrypt.c代码

发布时间:2020-12-12 20:24:48 所属栏目:百科 来源:网络整理
导读:http://bbs.2ccc.com/topic.asp?topicid=337891 今天刚好改风铃兄的sqlite,随便说说,不对的请大家指正. sqlite3PagerSetCodec变化非常大 staticvoidsqlite3PagerSetCodec( Pager*pPager, void*(*xCodec)(void*,void*,Pgno,int), void(*xCodecSizeChng)(void*

http://bbs.2ccc.com/topic.asp?topicid=337891


今天刚好改风铃兄的sqlite,随便说说,不对的请大家指正.

sqlite3PagerSetCodec变化非常大
staticvoidsqlite3PagerSetCodec(
Pager*pPager,
void*(*xCodec)(void*,void*,Pgno,int),
void(*xCodecSizeChng)(void*,int,//新加的
void(*xCodecFree)(void*),//新加的
void*pCodec//对应原来的pCodecArg

xCodecSizeChng更改page大小时候调用的函数,暂时没用上直接NULL
xCodecFree其实就是代替了xFreeAux的作用,现在释放page,不用我们自己做了。

DestroyCryptBlock函数要改一下参数类型,不然编译不过。

用20M的Demo测试,未发现明显问题。


#ifdef SQLITE_SOURCESTD
  #include <pager.c>
#else
  #include <sqlite3.c>
#endif

#ifndef SQLITE_OMIT_DISKIO
#ifdef SQLITE_HAS_CODEC

#include "md5c.c"

#define CRYPT_OFFSET 8
#define BYTE unsigned char
#define WX_PAGER_MJ_PGNO(x) ((PENDING_BYTE/(x))+1)
Btree *m_bt;

typedef 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 sqlite3_activate_see(const char *info)
{
}

void sqlite3CodecSizeChange(void *pArg,int pageSize,int reservedSize)
{
}

/*
** Get the codec argument for this pager
*/
void* mySqlite3PagerGetCodec(
  Pager *pPager
){
#if (SQLITE_VERSION_NUMBER >= 3006016)
  return sqlite3PagerGetCodec(pPager);
#else
  return (pPager->xCodec) ? pPager->pCodecArg : NULL;
#endif
}

/*
** Set the codec argument for this pager
*/
void mySqlite3PagerSetCodec(
  Pager *pPager,void *(*xCodec)(void*,void (*xCodecSizeChng)(void*,void (*xCodecFree)(void*),void *pCodec
){
  sqlite3PagerSetCodec(pPager,xCodec,xCodecSizeChng,xCodecFree,pCodec);
}

//创建或更新一个页的加密算法索引.此函数会申请缓冲区.
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);
}

// 释放与一个页相关的加密块
void sqlite3CodecFree(void *pArg)
{
    if (pArg)
        DestroyCryptBlock((LPCryptBlock)pArg);
}

//加密/解密函数,被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)
    {
    Pager *pageHeader = sqlite3BtreePager(m_bt);
        if (pageHeader->pageSize != pBlock->PageSize)  //适用旧版
        {
          CreateCryptBlock(0,pageHeader,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,pBlock->WriteKey);
        break;
    case 7: //加密事务文件的页
        /*在正常环境下,读密钥和写密钥相同. 当数据库是被重新加密的,读密钥和写密钥未必相同.
        回滚事务必要用数据库文件的原始密钥写入.因此,当一次回滚被写入,总是用数据库的读密钥,这是为了保证与读取原始数据的密钥相同.
        */
        if (!pBlock->ReadKey) break;

        CopyMemory(pBlock->Data + CRYPT_OFFSET,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)mySqlite3PagerGetCodec(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);
        m_bt = db->aDb[nDb].pBt;
#if (SQLITE_VERSION_NUMBER >= 3006016)
    mySqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),sqlite3Codec,sqlite3CodecSizeChange,sqlite3CodecFree,pBlock);
#else
  #if (SQLITE_VERSION_NUMBER >= 3003014)
    sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt),pBlock);
  #else
        sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt),pBlock);
  #endif
        db->aDb[nDb].pAux = pBlock;
        db->aDb[nDb].xFreeAux = sqlite3CodecFree;
#endif
        rc = SQLITE_OK;
    }
    return rc;
}


//不保存用户的原始密码.返回NULL.
void sqlite3CodecGetKey(sqlite3 *db,void **ppKey,int *pnKeyLen)
{
    *ppKey = NULL;
    *pnKeyLen = 0;
}

//密钥并不保留到临时空间,仅保存于主数据库.
int sqlite3_key_interop(sqlite3 *db,int nKeySize)
{
    return sqlite3CodecAttach(db,pKey,nKeySize);
}

//改变已有数据库的加密密钥
int sqlite3_rekey_interop(sqlite3 *db,int nKeySize)
{
    Btree *pbt = db->aDb[0].pBt;
    Pager *pPager = sqlite3BtreePager(pbt);
    LPCryptBlock pBlock = (LPCryptBlock)mySqlite3PagerGetCodec(pPager);
    BYTE * hKey = DeriveKey(pKey,nKeySize);
    int rc = SQLITE_ERROR;


    if (!pBlock && !hKey) return SQLITE_OK; 

    //重新加密一个数据库,改变pager的写密钥,读密钥依旧保留.
    if (!pBlock) //加密一个未加密的数据库
    {
        pBlock = CreateCryptBlock(hKey,pPager,NULL);
        pBlock->ReadKey = 0; // 原始数据库未加密
  m_bt = db->aDb[0].pBt;
#if (SQLITE_VERSION_NUMBER >= 3006016)
    mySqlite3PagerSetCodec(pPager,pBlock);
#else
  #if (SQLITE_VERSION_NUMBER >= 3003014)
          sqlite3PagerSetCodec(sqlite3BtreePager(pbt),pBlock);
  #else
        sqlite3pager_set_codec(pPager,pBlock);
  #endif
        db->aDb[0].pAux = pBlock;
        db->aDb[0].xFreeAux = sqlite3CodecFree;
#endif
    }
    else // 改变已加密数据库的写密钥
    {
        pBlock->WriteKey = hKey;
    }

    // 开始一个事务
    rc = sqlite3BtreeBeginTrans(pbt,1);

    if (!rc)
    {
        // 用新密钥重写所有的页到数据库。
  #if (SQLITE_VERSION_NUMBER >= 3006000)
          int nPageCount = -1;
          int rc = sqlite3PagerPagecount(pPager,&nPageCount);
    Pgno nPage = (Pgno) nPageCount;
  #elif (SQLITE_VERSION_NUMBER >= 3003014)
    Pgno nPage = sqlite3PagerPagecount(pPager);
  #else
    Pgno nPage = sqlite3pager_pagecount(pPager);
  #endif
  int pageSize = sqlite3BtreeGetPageSize(pbt);
        Pgno nSkip = WX_PAGER_MJ_PGNO(pageSize);
  #if (SQLITE_VERSION_NUMBER >= 3003014)
      DbPage *pPage;
  #else
      void *pPage;
  #endif
        Pgno n;

        for(n = 1; rc == SQLITE_OK && n <= nPage; n ++)
        {
          if (n == nSkip) continue;
      #if (SQLITE_VERSION_NUMBER >= 3003014)
          rc = sqlite3PagerGet(pPager,n,&pPage);
      #else
          rc = sqlite3pager_get(pPager,&pPage);
      #endif
          if(!rc)
          {
    #if (SQLITE_VERSION_NUMBER >= 3003014)
          rc = sqlite3PagerWrite(pPage);
          sqlite3PagerUnref(pPage);
    #else
        rc = sqlite3pager_write(pPage);
        sqlite3pager_unref(pPage);
    #endif
          }
        }
    }

    // 如果成功,提交事务。
    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)
    {
#if (SQLITE_VERSION_NUMBER >= 3006016)
    mySqlite3PagerSetCodec(pPager,NULL,NULL);
#else
  #if (SQLITE_VERSION_NUMBER >= 3003014)
          sqlite3PagerSetCodec(pPager,NULL);
  #else
    sqlite3pager_set_codec(pPager,NULL);
  #endif
        db->aDb[0].pAux = NULL;
        db->aDb[0].xFreeAux = NULL;
        sqlite3CodecFree(pBlock);
#endif
    }
    return rc;
}

SQLITE_API int sqlite3_key(sqlite3 *db,int nKey)
{
    return sqlite3_key_interop(db,nKey);
}

SQLITE_API int sqlite3_rekey(sqlite3 *db,int nKey)
{
    return sqlite3_rekey_interop(db,nKey);
}

#endif // SQLITE_HAS_CODEC

#endif // SQLITE_OMIT_DISKIO

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读