2013年5月27日 星期一

Andorid Sqlite 加密功能

因為我們應用的需求,資料庫需要加密(不想被別人用adb pull 就取得資料庫)
Andorid 已經有使用sqlite 來超作資料庫,但是sqlite 沒有加密功能,所以只要自行處理 !!
不過 sqlite 有預留加密的進入點 !!

就一步一步來吧 !!

A.首先先打開 SQLITE_HAS_CODEC 這個 define.

--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/dist/Android.mk    2013-05-27 13:37:12.767651814 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/dist/Android.mk    2013-05-24 18:55:23.884236340 +0800
@@ -27,7 +27,8 @@
        -DSQLITE_OMIT_BUILTIN_TEST \
        -DSQLITE_OMIT_COMPILEOPTION_DIAGS \
        -DSQLITE_OMIT_LOAD_EXTENSION \
-       -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600
+       -DSQLITE_DEFAULT_FILE_PERMISSIONS=0600\
+       -DSQLITE_HAS_CODEC=1

 common_src_files := sqlite3.c


B.Modify sqlite3.c file.
  sqlite在編譯之前(Standard method) 會將所有 .c file 合併成為一個 .C file ( 我不知道為何要這樣 )
  所以在BSP 內找到對應的檔案, 並且開始修改 !!

  在 "Begin file attach.c" 之前開始插入修加密所需要的 code ;

  詳細加密的功能可以參考下列網址 :
    http://lancelot.blog.51cto.com/393579/940816
  這網頁說的蠻清楚的 , 不過因為之前我們舊機種就已經有使用 (linux + GTK 架構 ) , 所以
  就移植過來.

  因為兩個版本不同,移植過來有些問題 , 所以需要修改一些小東西 , 可以參考下列網址 , 還蠻清楚的 !!
    http://lancelot.blog.51cto.com/393579/940814
   
  修改後的 diff 內容如下 , 不過太長加上有些機密問題 (加密方式 ) 所以我只列出一小部份:
 

diff -Nuraw TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/dist/sqlite3.c TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/dist/sqlite3.c
--- TI-Android-JB-4.1.2_AM335x_4.0.1-orignal/external/sqlite/dist/sqlite3.c    2013-05-27 13:37:12.802652106 +0800
+++ TI-Android-JB-4.1.2_AM335x_4.0.1/external/sqlite/dist/sqlite3.c    2013-05-27 13:33:06.551572993 +0800
@@ -80395,6 +80395,501 @@
 #endif /* SQLITE_OMIT_ANALYZE */

 /************** End of analyze.c *********************************************/
+/************** Begin file key.c ******************************************/
+
+#ifdef  SQLITE_HAS_CODEC
+
+//======== main codec function.
+typedef struct _CryptBlock
+{
+    char    *ReadKey;
+    char    *WriteKey;
+    int     PageSize;
+    char    *Data;
+
+} CryptBlock, *LPCryptBlock;
+
+#ifndef  DB_KEY_LENGTH_BYTE
+ #define  DB_KEY_LENGTH_BYTE   16
+#endif
+
+#ifndef  DB_KEY_PADDING
 ..........
+#endif
+
+#define     CRYPT_OFFSET    8
+#define     CRYPT_ROW_SIZE  32
+
+int getSBoxValue(int num)
+{
  .........................
+   return sbox[num];
+}
+
+int getSBoxInvert(int num)
+{
  .................
+return rsbox[num];
+}
+
+int Encrypt_Func( unsigned char * pData, unsigned int data_len, const char * key, unsigned int len_of_key )
+{
+unsigned int i,j;
+//unsigned char *temp1,*temp2,
+unsigned char *sData;
+
+//Encode functino
    ............................
+    free(sData);
+    return 0;
+}
+
+int DeEncrypt_Func( unsigned char * pData, unsigned int data_len, const char * key, unsigned int len_of_key )
+{
+unsigned int i,j;
+//unsigned char *temp1,*temp2,
+unsigned char  *sData;
+
+//Decode functino
+
+
+    //change  by row
+//    temp1 = (unsigned char*)malloc(CRYPT_ROW_SIZE);
+//    temp2 = (unsigned char*)malloc(CRYPT_ROW_SIZE);
+    sData = (unsigned char*)malloc(data_len);
+    memcpy(sData,pData,data_len);
+
+    j = 1;
+    for ( i = 0 ; i < 32 ; i ++)
+    {
+        if ( j >= 32 )
+            j = 0;
+        memcpy(pData+(j*CRYPT_ROW_SIZE),sData+(i*CRYPT_ROW_SIZE),CRYPT_ROW_SIZE);
+        j += 2;
+    }
+
+    //replase by other word
+    for ( i = 0 ; i < data_len ; i++ )
+    {
+        *(pData+i) = getSBoxInvert(*(pData+i));
+    }
+
+    //mask by key
+    for ( i = 0 ; i < data_len ; i++ )
+    {
+        *(pData+i) ^=(*(key+(i%len_of_key)) );
+    }
+
+//    free(temp1);
+//    free(temp2);
+    free(sData);
+    return 0;
+}
+
+void * sqlite3Codec(void *pArg, void *pdata, Pgno nPageNum, int nMode)
+{
+LPCryptBlock    pBlock;
+PgHdr           *pageHeader;
+unsigned int dwPageSize = 0;
+unsigned char *data=(unsigned char *)(pdata);
+
+
+    pBlock = (LPCryptBlock)pArg;
+
+    if (!pBlock)
+        return data;
+
+    switch(nMode)
+    {
+        case 0: // Undo a "case 7" journal file encryption
+        case 2: //reload one page
+        case 3: //loading one page
+            if (!pBlock->ReadKey)
+                break;
+
+            dwPageSize = pBlock->PageSize;
+
+            DeEncrypt_Func(data, dwPageSize, pBlock->ReadKey, DB_KEY_LENGTH_BYTE );
+
+        break;
+
+        case 6: //Encrypt one page
+            if (!pBlock->WriteKey)
+                break;
+
+            memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize);
+            data = pBlock->Data + CRYPT_OFFSET;
+            dwPageSize = pBlock->PageSize;
+
+            Encrypt_Func(data , dwPageSize, pBlock->WriteKey, DB_KEY_LENGTH_BYTE ); /*?£Y?[K*/
+
+        break;
+
+        case 7:
+            if (!pBlock->ReadKey)
+                break;
+
+            memcpy(pBlock->Data + CRYPT_OFFSET, data, pBlock->PageSize);
+            data = pBlock->Data + CRYPT_OFFSET;
+            dwPageSize = pBlock->PageSize;
+
+            Encrypt_Func( data, dwPageSize, pBlock->ReadKey, DB_KEY_LENGTH_BYTE ); /*?£Y?[K*/
+
+        break;
+
+    }
+
+    return data;
+
+}
+
+
+//==========================
+static LPCryptBlock CreateCryptBlock(unsigned char* hKey, Pager *pager, LPCryptBlock pExisting)
+{
+LPCryptBlock pBlock;
+
+    if (!pExisting)
+    {
+        pBlock =(CryptBlock *)sqlite3_malloc(sizeof(CryptBlock));
+
+        memset(pBlock, 0, sizeof(CryptBlock));
+        pBlock->ReadKey = hKey;
+        pBlock->WriteKey = hKey;
+        pBlock->PageSize = pager->pageSize;
+        pBlock->Data = (unsigned char*)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 = (unsigned char*)sqlite3_malloc(pBlock->PageSize + CRYPT_OFFSET);
+        }
+
+    }
+
+    memset(pBlock->Data, 0, pBlock->PageSize + CRYPT_OFFSET);
+
+    return pBlock;
+
+}
+
+void sqlite3pager_set_codec(Pager *pPager,
+        void *(*xCodec)(void*,void*,Pgno,int),void *pCodecArg)
+{
+    pPager->xCodec = xCodec;
+    pPager->pCodec = pCodecArg;
+}
+
+
+static unsigned char *DeriveKey(const void *pKey, int nKeyLen)
+{
+unsigned char *hKey;
+
+    if( pKey == NULL || nKeyLen == 0 )
+    {
+        return NULL;
+    }
+
+    hKey = NULL;
+    hKey = (unsigned char *)sqlite3_malloc(DB_KEY_LENGTH_BYTE + 1);
+
+    if( hKey == NULL )
+    {
+        return NULL;
+    }
+
+    memset( hKey ,DB_KEY_PADDING, DB_KEY_LENGTH_BYTE + 1  );
+
+    hKey[DB_KEY_LENGTH_BYTE] = '\0';
+
+    if( nKeyLen < DB_KEY_LENGTH_BYTE )
+    {
+        memcpy( hKey, pKey, nKeyLen );
+        memcpy( (hKey+nKeyLen), pKey , (DB_KEY_LENGTH_BYTE-nKeyLen) );
+    }
+    else
+    {
+        memcpy(  hKey, pKey, DB_KEY_LENGTH_BYTE );
+    }
+
+    return hKey;
+
+}
+
+
+static void * sqlite3pager_get_codecarg(Pager *pPager)
+{
+    return (pPager->xCodec) ? pPager->pCodec: NULL;
+}
+
+//======== getkey function.
+void sqlite3CodecGetKey(sqlite3 *db, int cnt, void **zKey, int *nKey)
+{
+    return ;
+}
+
+
+
+//======== rekey function.
+
+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);
+
+}
+
+
+int 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;
+Pgno nPage;
+
+    if (!pBlock && !hKey)
+        return SQLITE_OK;
+
+    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)
+    {
+
+        sqlite3PagerPagecount(p,&nPage);
+        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, (DbPage **)&pPage);
+
+            if(!rc)
+            {
+                rc = sqlite3PagerWrite(pPage);
+                sqlite3PagerUnref(pPage);
+            }
+        }
+    }
+
+    if (!rc)
+    {
+        rc = sqlite3BtreeCommit(pbt);
+    }
+
+
+    if (rc)
+    {
+        sqlite3BtreeRollback(pbt,SQLITE_OK);
+    }
+
+    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)
+    {
+        sqlite3pager_set_codec(p, NULL, NULL);
+        DestroyCryptBlock(pBlock);
+    }
+
+return rc;
+
+}
+
+int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey)
+{
+    return sqlite3_rekey_interop(db, pKey, nKey);;
+}
+
+//======== acitvate see function.
+void sqlite3_activate_see(const char *zRight)
+{
+    return ;
+}
+
+
+//======== key function.
+
+
+int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *zKey, int nKey)
+{
+int              rc;
+unsigned char   *hKey;
+LPCryptBlock     pBlock;
+
+    rc = SQLITE_ERROR;
+    if (db == NULL)
+        return rc;
+
+    hKey = 0;
+
+    if (!zKey || !nKey)
+    {
+    // not inpute code
+        if (!nDb)
+        {
+            return SQLITE_OK;
+        }
+        else
+        {
+            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(zKey, nKey);
+    }
+
+    if (hKey)
+    {
+        pBlock = CreateCryptBlock(hKey,sqlite3BtreePager(db->aDb[nDb].pBt), NULL);
+        sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock);
+
+        rc = SQLITE_OK;
+    }
+
+    return rc;
+}
+
+int sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize)
+{
+  return sqlite3CodecAttach(db, 0, pKey, nKeySize);
+}
+
+int sqlite3_key(sqlite3 *db, const void *pKey, int nKey)
+{
+    return sqlite3_key_interop(db, pKey, nKey);;
+}
+
+
+#endif
+
+
+/************** End of key.c *********************************************/
 /************** Begin file attach.c ******************************************/
 /*
 ** 2003 April 6



大功告成 , 接著 ...... 寫一個程式測試看看吧 ....... (下一篇..... )

沒有留言:

張貼留言