美文网首页
sqlcipher代码阅读

sqlcipher代码阅读

作者: 赵海洋 | 来源:发表于2020-05-19 13:10 被阅读0次

    解码

    使用控制台模式启动sqlcipher并打开一个加密的db文件后,使用以下指令进行测试。

    sqlcipher ./sqlcipher.db
    # 下面是直接在sqlcipher的控制台中输入指令:
    PRAGMA key ='936329a';
    PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
    PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
    PRAGMA cipher_use_hmac = OFF;
    PRAGMA cipher_page_size = 1024;
    PRAGMA kdf_iter = 4000;
    .databases
    

    在.database指令执行时,触发了打开数据库并解密的动作。

    image.png

    上图可见,由 process_input 处理指令,最终执行到static int readDbPage(PgHdr *pPg){(page.c),在此函数中,先使用sqlite3OsRead从db文件中读取一页 或 使用sqlite3WalReadFrame从wal文件中读取缓存页。

    拿到数据后使用了这么一行代码:CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);来对读取到内存中的数据进行处理,CODEC1是个宏定义,在有SQLITE_HAS_CODEC宏的情况下(也就是编码为sqlcipher,如果没有宏则只有sqlite的功能)会调用 pPager中的xCodec成员(函数指针),此函数指针对应函数static void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode)(crypto.c)。

    sqlite3Codec函数中调用openssl对这块内存进行解密。

    数据解析

    由page.c读取出来的数据是对应sqlite的物理页(页内有cell)结构,在上层由btree.c定义的MemPage、Btree、CellInfo等相关数据结构来管理。

    通过static int lockBtree(BtShared *pBt)函数来获取第一页,同时起到锁定整个数据表的功能。

    然后对sqlite的文件头进行格式验证后,如果第19个字节是2(File format read version. 1 for legacy; 2 for WAL.)则使用sqlite3PagerOpenWal,再调用pagerOpenWal来打开日志文件。

    最终wal日志文件由wal.c中的sqlite3WalOpen函数来创建或打开,内部使用sqlite3OsOpen来创建wal文件。

    其它页面的读取由Btree的结点遍历来触发,如下图堆栈:

    image.png

    Cell解析

    读取出来的Page结构MemPage有一个成员函数xParseCell,根据page的类型不同,在初使化时设置为了不同的函数:

    • btreeParseCellPtr() => table btree leaf nodes
    • btreeParseCellNoPayload() => table btree internal nodes
    • btreeParseCellPtrIndex() => index btree nodes

    每个Cell根据页类型不同,cell的结构也不一样,详见:https://www.sqlite.org/fileformat2.html#b_tree_pages

    image.png

    可见,除了类型为5的b树的Cell,其它 Cell都可能带有数据(PlayLoad),但每种cell所能包含的数据是有大小限制,超出这个大小的数据就要存放在其它页中了。这种页的前4个字节是个大端序的数字,表明有效数据的大小。页号由cell尾部的4字节大端序保存。

    相关文章

      网友评论

          本文标题:sqlcipher代码阅读

          本文链接:https://www.haomeiwen.com/subject/veuvohtx.html