SQLite 如何处理 iOS 中的加密?

Sam*_*ill 5 sqlite ios

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

zrz*_*zka 6

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),
  • 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
Run Code Online (Sandbox Code Playgroud)

我不知道 SQLite 的内部结构,但看起来前四个字节代表页码,其余的是一些随机的东西CCCrypt为每个页面调用,后续页面iv0x02 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=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
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压缩流

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