iOS 中似乎有一些对 sqlite 加密的默认支持,但我找不到任何有关其工作原理的文档。在一个新的 iOS 项目中,我创建了一个新的 db 并key在创建表之前添加了编译指示。
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);
Run Code Online (Sandbox Code Playgroud)
检查文件系统上的数据库,然后它似乎被加密了。正如我提到的,这是一个干净的项目,我没有添加 SQLCipher 或任何其他库。有没有办法知道使用 pragma 的扩展名/lib 以便我知道使用它是否有意义?
在 iPhone 11 模拟器上运行 iOS 13.2.2
SQLite 提供加密扩展,其中有sqlite3-see-cccrypt.c:
该文件是公共域“sqlite3.c”filef 的直接替代品,添加了对 AES-128 和 AES-256 加密算法的支持,在 OFB 模式下,使用外部 CCCrypt 加密。CCCrypt 是 MacOS 和 iOS 上的默认加密库,因此建议这些平台使用 SEE 的这种实现。
see-ccrypt.c 模块通常只进行 AES128 加密。但是,当使用 -DCCCRYPT256 编译 see-cccrypt 时,当且仅当密钥长度正好为 32 字节时,它才会使用 AES256。
我不知道苹果是否使用这个。
当您使用 key 创建数据库时,abc123会发生以下情况:
* frame #0: 0x00007fff52a041fb libcommonCrypto.dylib`CCCrypt
frame #1: 0x00007fff21cfca21 libsqlite3.dylib`sqliteCodecCCCrypto + 305
frame #2: 0x00007fff21bc76d3 libsqlite3.dylib`pager_write_pagelist + 243
...
Run Code Online (Sandbox Code Playgroud)
CCCrypt被利用。页面大小为 4096 字节。CCrypt函数签名是:
* frame #0: 0x00007fff52a041fb libcommonCrypto.dylib`CCCrypt
frame #1: 0x00007fff21cfca21 libsqlite3.dylib`sqliteCodecCCCrypto + 305
frame #2: 0x00007fff21bc76d3 libsqlite3.dylib`pager_write_pagelist + 243
...
Run Code Online (Sandbox Code Playgroud)
该函数的调用方式为:
op设置为0(加密)alg设置为0(AES 128),key是abc123abc123abc1(初始密钥,复制以适合 16 字节),dataIn是一个我还不认识的垃圾(不是一个普通的 SQLite 页面),dataInLength是 4096,dataOutMoved返回时设置为 4096。还有iv价值是:
0x01 0x00 0x00 0x00 0xc0 0xa2 0xe8 0xa8
0x44 0x49 0xef 0xa0 0xa4 0x7b 0xec 0x5f
Run Code Online (Sandbox Code Playgroud)
我不知道 SQLite 的内部结构,但看起来前四个字节代表页码,其余的是一些随机的东西。CCCrypt为每个页面调用,后续页面iv以0x02 0x00 0x00 0x00,0x03 0x00 0x00 0x00等开头。
当您查看加密的 sqlite 文件时,最后 12 个字节iv存储在每个页面的末尾:
% 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
Run Code Online (Sandbox Code Playgroud)
0xff0=40804080 + 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
Run Code Online (Sandbox Code Playgroud)
需要关注的符号:
_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
Run Code Online (Sandbox Code Playgroud)
dlopen呼叫:
/usr/lib/libcompression.dylib压缩流这就是我到目前为止所发现的。如果有人想继续,请随意,我没有更多时间来讨论这个兔子洞:)