zoukankan      html  css  js  c++  java
  • Sqlite xxteacrypt.c代码

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


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

    sqlite3PagerSetCodec变化非常大
    static void sqlite3PagerSetCodec(
      Pager *pPager,
      void *(*xCodec)(void*,void*,Pgno,int),
      void (*xCodecSizeChng)(void*,int,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*,Pgno,int),
      void (*xCodecSizeChng)(void*,int,int),
      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 , 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)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), sqlite3Codec, pBlock);
      #else
            sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock);
      #endif
            db->aDb[nDb].pAux = pBlock;
            db->aDb[nDb].xFreeAux = sqlite3CodecFree;
    #endif
            rc = SQLITE_OK;
        }
        return rc;
    }
    
    
    //不保存用户的原始密码.返回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 *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, sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, pBlock);
    #else
      #if (SQLITE_VERSION_NUMBER >= 3003014)
              sqlite3PagerSetCodec(sqlite3BtreePager(pbt), sqlite3Codec, pBlock);
      #else
            sqlite3pager_set_codec(pPager, sqlite3Codec, 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, n, &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, NULL, NULL);
    #else
      #if (SQLITE_VERSION_NUMBER >= 3003014)
              sqlite3PagerSetCodec(pPager, NULL, NULL);
      #else
        sqlite3pager_set_codec(pPager, NULL, NULL);
      #endif
            db->aDb[0].pAux = NULL;
            db->aDb[0].xFreeAux = NULL;
            sqlite3CodecFree(pBlock);
    #endif
        }
        return rc;
    }
    
    SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
    {
        return sqlite3_key_interop(db, pKey, nKey);
    }
    
    SQLITE_API 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
    


  • 相关阅读:
    项目中 2个或者多个EF模型 表名称相同会导致生成的实体类 覆盖的解决方法
    Validation failed for one or more entities. See ‘EntityValidationErrors’解决方法;关于如何查看 EntityValidationErrors 详细信息的解决方法
    深夜杳杳
    我在学习
    IIS下新建虚拟目录
    Win10资源管理器异常
    Docker笔记三:Docker数据卷和DockerFile
    Docker笔记二:Docker拷贝,提交,进入容器和阿里云加速
    ElasticSearch7.x系列三:Logstash的使用
    ElasticSearch7.x系列二:Kibana的使用和C#的Nest客户端
  • 原文地址:https://www.cnblogs.com/iapp/p/3631766.html
Copyright © 2011-2022 走看看