【问题标题】:How does sqlite handle encryption in iOS?在 iOS 中 sqlite 如何处理加密?
【发布时间】:2020-10-16 04:32:19
【问题描述】:

iOS 中似乎有一些默认支持 sqlite 加密,但我找不到任何关于它如何工作的文档。在一个新的 iOS 项目中,我创建了一个新数据库,并在创建表之前添加了 key pragma。

import SQLite3

...

sqlite3_open_v2(docStr, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nil)
sqlite3_exec(db, "PRAGMA key = 'abc123';", nil, nil, nil)
sqlite3_exec(db, "CREATE TABLE Breed (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, favorite INTEGER NOT NULL DEFAULT 0 ); INSERT INTO Breed(name) VALUES ('Beagle');", nil, nil, nil);

检查文件系统上的数据库,然后它似乎被加密了。正如我提到的,这是一个干净的项目,我没有添加 SQLCipher 或任何其他库。有没有办法知道什么扩展/库正在使用编译指示,这样我就可以知道使用它是否有意义?

在 iPhone 11 模拟器上运行 iOS 13.2.2

【问题讨论】:

标签: ios sqlite


【解决方案1】:

SQLite 提供encryption extensions,其中有 sqlite3-see-cccrypt.c

此文件是公共域“sqlite3.c”文件的直接替换,增加了对 AES-128 和 AES-256 加密算法的支持,在 OFB 模式下,使用外部 CCCrypt 加密。 CCCrypt 是 MacOS 和 iOS 上的默认加密库,因此建议在这些平台上使用这种 SEE 实现。

see-ccrypt.c 模块通常只进行 AES128 加密。但是,当使用 -DCCCRYPT256 编译 see-cccrypt 时,当且仅当密钥长度正好为 32 字节时,它将使用 AES256。

我不知道这是否是 Apple 使用的。

当您使用abc123 键创建数据库时,会发生以下情况:

* frame #0: 0x00007fff52a041fb libcommonCrypto.dylib`CCCrypt
  frame #1: 0x00007fff21cfca21 libsqlite3.dylib`sqliteCodecCCCrypto + 305
  frame #2: 0x00007fff21bc76d3 libsqlite3.dylib`pager_write_pagelist + 243
  ...  

CCCrypt 被使用。页大小为 4096 字节。 CCrypt函数签名是:

CCCryptorStatus
CCCrypt(CCOperation op, CCAlgorithm alg, CCOptions options, const void *key, size_t keyLength,
    const void *iv, const void *dataIn, size_t dataInLength, void *dataOut, size_t dataOutAvailable,
    size_t *dataOutMoved)

这个函数被调用:

  • op 设置为 0(加密)
  • alg 设置为 0 (AES 128),
  • keyabc123abc123abc1(初始密钥,复制到适合 16 个字节),
  • dataIn 是一个我还不认识的垃圾(不是普通的 SQLite 页面),
  • dataInLength 是 4096,
  • dataOutMoved 返回时设置为 4096。

还有iv的值是:

0x01 0x00 0x00 0x00 0xc0 0xa2 0xe8 0xa8
0x44 0x49 0xef 0xa0 0xa4 0x7b 0xec 0x5f

我不知道 SQLite 的内部结构,但看起来前四个字节代表页码,其余的是一些 随机的东西CCCrypt 被每个页面调用,后续页面 iv0x02 0x00 0x00 0x000x03 0x00 0x00 0x00 等开头。

当你查看加密的 sqlite 文件时,iv 的最后 12 个字节存储在每页的末尾:

% hexdump -C db-enc.sqlite| grep "44 49 ef"
00000ff0  e2 a1 77 2a c0 a2 e8 a8  44 49 ef a0 a4 7b ec 5f
          ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
           |- ?        |- last 12 bytes of iv
  • 0xff0 = 4080
  • 4080 + 16 = 4096(= 页面大小)

有人会说使用了 AES 128,但是......当我打开已经存在的数据库时,再次调用 CCCrypt,但操作设置为 0(加密)。换句话说,CCCrypt 永远不会被解密操作调用。

库存储:

/Applications/Xcode-beta.app/Contents/Developer/Platforms/
  iPhoneOS.platform/Library/Developer/CoreSimulator/
  Profiles/Runtimes/iOS.simruntime/Contents/Resources/
  RuntimeRoot/usr/lib/libsqlite3.dylib

要关注的符号:

  • _sqlite3CodecAttach
    • _sqliteCodecCCCrypto
    • _sqliteCodecCCCryptoSizeChng
    • _sqliteCodecCCCryptoFree
  • _loadKeyCCCrypt

相关外部符号:

                     _CCCrypt:
00000000001ce000         extern function code                                   ; in /usr/lib/libSystem.B.dylib, CODE XREF=imp___stubs__CCCrypt, DATA XREF=_CCCrypt_ptr
                     _CC_SHA256_Final:
00000000001ce008         extern function code                                   ; in /usr/lib/libSystem.B.dylib, CODE XREF=imp___stubs__CC_SHA256_Final, DATA XREF=_CC_SHA256_Final_ptr
                     _CC_SHA256_Init:
00000000001ce010         extern function code                                   ; in /usr/lib/libSystem.B.dylib, CODE XREF=imp___stubs__CC_SHA256_Init, DATA XREF=_CC_SHA256_Init_ptr
                     _CC_SHA256_Update:
00000000001ce018         extern function code    

dlopen 来电:

  • 为压缩流打开 /usr/lib/libcompression.dylib

这就是我目前所发现的。如果有人想继续,请随意,我没有更多时间玩这个兔子洞了:)

【讨论】:

    【解决方案2】:

    我尝试在模拟器中运行您的代码,并且数据库似乎已加密。

    然后我尝试列出所有导出的sqlite3_ 函数:

    (lldb) image lookup -r -s "sqlite3_"
    
    ....
    Summary: libsqlite3.dylib`_sqlite3_lockstate        Address: libsqlite3.dylib[0x0000000000010ee0] (libsqlite3.dylib.__TEXT.__text + 66704)
    Summary: libsqlite3.dylib`_sqlite3_purgeEligiblePagerCacheMemory        Address: libsqlite3.dylib[0x000000000002a590] (libsqlite3.dylib.__TEXT.__text + 170816)
    Summary: libsqlite3.dylib`_sqlite3_system_busy_handler        Address: libsqlite3.dylib[0x0000000000038e40] (libsqlite3.dylib.__TEXT.__text + 230384)
    Summary: libsqlite3.dylib`sqlite3_activate_see        Address: libsqlite3.dylib[0x0000000000016750] (libsqlite3.dylib.__TEXT.__text + 89344)
    Summary: libsqlite3.dylib`sqlite3_aggregate_context        Address: libsqlite3.dylib[0x00000000000169d0] (libsqlite3.dylib.__TEXT.__text + 89984)
    Summary: libsqlite3.dylib`sqlite3_aggregate_count        Address: libsqlite3.dylib[0x000000000001df70] (libsqlite3.dylib.__TEXT.__text + 120096)
    ...
    

    其中一个是sqlite3_activate_see,所以它必须来自SQLite Encryption Extensions

    请参阅文档:https://www.sqlite.org/see/doc/release/www/readme.wiki

    我找不到在 iOS 中使用 SSE 的其他证明。正如sqlite3.h 所说

    #define SQLITE_SOURCE_ID      "2019-04-15 14:49:49 378230ae7f4b721c8b8d83c8ceb891449685cd23b1702a57841f1be40b5daapl"
    

    它指向https://sqlite.org/src/info/378230ae7f4b721c,但原来的哈希是

    378230ae7f4b721c8b8d83c8ceb891449685cd23b1702a57841f1be40b5db63e
    

    和来自 iOS SDK 的 sqlite3.h

    378230ae7f4b721c8b8d83c8ceb891449685cd23b1702a57841f1be40b5daapl
    

    ...如果源代码有 自上次签入以来以任何方式进行了编辑,然后是最后一次 可以修改散列的四位十六进制数字。

    sqlite3.haapl 后缀,表示源代码已被修改。其中一个模块可能是 SSE 集成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-25
      • 2017-02-13
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      相关资源
      最近更新 更多