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
    


  • 相关阅读:
    LeetCode OJ 112. Path Sum
    LeetCode OJ 226. Invert Binary Tree
    LeetCode OJ 100. Same Tree
    LeetCode OJ 104. Maximum Depth of Binary Tree
    LeetCode OJ 111. Minimum Depth of Binary Tree
    LeetCode OJ 110. Balanced Binary Tree
    apache-jmeter-3.1的简单压力测试使用方法(下载和安装)
    JMeter入门教程
    CentOS6(CentOS7)设置静态IP 并且 能够上网
    分享好文:分享我在阿里8年,是如何一步一步走向架构师的
  • 原文地址:https://www.cnblogs.com/iapp/p/3631766.html
Copyright © 2011-2022 走看看