[Перевод] Шифрование SQLite с помощью SQLCipher (iOS/Mac)

Оригинал на английском (disclaimer: перевод вольный)

SQLite является самым распространенным средством  для хранения данных на iPhone со стабильным API и хорошей документацией. Очевидно, что не хотелось бы мешать код приложения с собственно шифрованием, а делать это как можно прозрачней.

Такую функциональность предоставляют SQLCipher и OpenSSL. Оба проекта замечательны своим открытым исходным кодом, а также поддержкой Mac/Windows/Linux.

Итак, что нам потребуется…

[](http://sqlcipher.net/documentation/ios#iphone-tutorial)** SQLCipher (http://zetetic.net/software/sqlcipher)**

SQLCipher представляет собой специализированную сборку SQLite, поддерживающую прозрачное шифрование на лету. При использовании этой библиотеки доступ к БД осуществляется с помощью стандартного SQLite API. Все, связанное с шифрованием, происходит за сценой, разработчику не требуется ни о чем заботиться.

Первый шаг - получаем исходники проекта с GitHub (https://github.com/sjlombardo/sqlcipher)

Либо сразу клонируем: git clone git://github.com/sjlombardo/sqlcipher.git

OpenSSL (http://www.openssl.org) Для всех криптографических функций (AES256, генератор псевдослучайных чисел, PBKDF2 ключи), SQLCipher использует достаточно провернную библиотеку OpenSSL. OpenSSL не является фреймворком, поэтому для использования на iPhone нам нужно настроить проект для линковки в статическую библиотеку.

Скачайте исходники http://www.openssl.org/source/ (либо можете клонировать с неофициального GitHub-зеркала git clone git://github.com/mkrautz/openssl-mirror.git)

OpenSSL-XCode Скомпилировать OpenSSL из исходников может быть далеко не простым занятием, учитывая что вам надо будет разбираться с несколькими архитектурами (i386 для симулятора и arm6/arm7 для устройства).

OpenSSL-XCode содержит шаблон проекта, который сам подгоняет настройки сборки OpenSSL в зависимости от архитектуры и выбранного SDK. Чем существенно облегчает использование в iOS проектах.

Исходники берем либо здесь: http://github.com/sjlombardo/openssl-xcode, либо сразу клонируем git clone git://github.com/sjlombardo/openssl-xcode.git

После этого необходимо скопировать openssl.xcodeproj в корень исходников OpenSSL.

Настройка Теперь, когда все исходники скачаны, остается только настроить XCode и ваш проект.

Самый простой способ включить SQLCipher в приложение - это использовать XCode project reference.

Для линковки нужно настройть XCode, чтобы сборка происходила в одну центральную “локацию”. Откройте XCode/Preferences. Во вкладке “Building” переключите “Place Build Products in” с “Project directory” на “Customized location”. Выберите подходящую папку. Building Preferences

Переключитесь на вкладку Source Trees. Добавьте SQLCIPHER_SRC и OPENSSL_SRC, которые будут указывать на папки с исходникам SQLCipher и OpenSSL соответственно. Должно получиться что-то вроде: Source Tree Preferences

Перейдем к настройкам конкретного проекта.

Добавьте ссылку на openssl.xcodeproj и sqlcipher.xcodeproj (просто drag’n’drop на проект в дереве проекта). Убедитесь, что “Copy items” выключена.

Теперь настроим пути для работы в команде. Использование относительных путей позволит каждому разработчику располагать исходники OpenSSL и SQLCipher в удобных для них местах.

Выберите sqlcipher.xcodeproj в дереве и нажмите Option-i (или правой - Get Info). Измените “Path Type” на “Relative to SQLCIPHER_SRC”. relative paths

Выберите openssl.xcodeproj в дереве и нажмите Option-i (или правой - Get Info). Измените “Path Type” на “Relative to OPENSSL_SRC”.

Следующим шагом добавим build-зависимости, чтобы SQLCipher и OpenSSL собирались до приложения. Выберите target вашего приложения, правой, Get Info и на вкладке “General” добавьте 2 зависимости: одну для openssl.xcodeproj/crypto и одну для sqlcipher.xcodeproj/sqlcipher. Project dependencies

После этого переключитесь на вкладку “Build”, в качестве Configuration выберите “All Configurations” и найдите в списке “Header Search Path”. Добавьте туда $(SQLCIPHER_SRC) и $(OPENSSL_SRC), включите рекурсивный поиск на обоих. Header Search Paths

Последний шаг - нужно добавить библиотеки для линковки. Раскройте в дереве sqlcipher.xcodeproj и openssl.xcodeproj, перенесите libsqlcipher.a и libcrypto.a на “Link Binary With Libraries” вашего target’а Link Binaries

После этого ваше приложение должно собираться без каких-либо ошибок. Первая компиляция может идти очень долго, но ничего страшного в этом нет.

SQLCipher подключен, после открытия базы использовать его можно двумя способами: 1) функция sqlite3_key

sqlite3 *db;
const char *dbFile = [@"/path/to/database" UTF8String];
if (sqlite3_open(dbFile, &db) == SQLITE_OK) {
  const char* key = [@"BIGSecret" UTF8String];
  sqlite3_key(db, key, strlen(key));
  if (sqlite3_exec(db, (const char*) "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
    // password is correct, or, database has been initialized
  } else {
    // incorrect password!
  }
}

2) PRAGMA

sqlite3 *db;
const char *dbFile = [@"/path/to/database" UTF8String];
if (sqlite3_open(dbFile, &db) == SQLITE_OK) {
  sqlite3_exec(db, "PRAGMA key = 'BIGsecret'", NULL, NULL, NULL);
  if (sqlite3_exec(db, (const char*) SELECT count(*) FROM sqlite_master;, NULL, NULL, NULL) == SQLITE_OK) {
    // password is correct, or, database has been initialized
  } else {
    // incorrect password!
  }
}

Важно: и PRAGMA, и sqlite_key должны быть первыми операциями после открытия БД.

В большинстве случаев SQLCipher использует PBKDF2 для получения ключа шифрования. Но вы можете указать бинарный ключ (в BLOB нотации, ровно 256 бит) ` PRAGMA key = “x’2DD29CA851E7B56E4697B0E1F08507293D761A05CE4D1B628663F411A8086D99’”; `

Как только ключ установлен, SQLCipher будет шифровать все данные в вашей БД. Если ключ не указан, SQLCipher будет работать абсолютно идентично стандартной SQLite базе.

После этого можно запустить приложение в симулятор и проверить, что все настроено правильно. Найдите базу

Без шифрования она будет выглядеть так:

new-host-2:sqlcipher sjlombardo$ hexdump -C plaintext.db
00000000  53 51 4c 69 74 65 20 66  6f 72 6d 61 74 20 33 00  |SQLite format 3.|
00000010  04 00 01 01 00 40 20 20  00 00 00 04 00 00 00 00  |.....@  ........|
...
000003b0  00 00 00 00 24 02 06 17  11 11 01 35 74 61 62 6c  |....$......5tabl|
000003c0  65 74 32 74 32 03 43 52  45 41 54 45 20 54 41 42  |et2t2.CREATE TAB|
000003d0  4c 45 20 74 32 28 61 2c  62 29 24 01 06 17 11 11  |LE t2(a,b)$.....|
000003e0  01 35 74 61 62 6c 65 74  31 74 31 02 43 52 45 41  |.5tablet1t1.CREA|
000003f0  54 45 20 54 41 42 4c 45  20 74 31 28 61 2c 62 29  |TE TABLE t1(a,b)|
...
000007d0  00 00 00 14 02 03 01 2d  02 74 77 6f 20 66 6f 72  |.......-.two for|
000007e0  20 74 68 65 20 73 68 6f  77 15 01 03 01 2f 01 6f  | the show..../.o|
000007f0  6e 65 20 66 6f 72 20 74  68 65 20 6d 6f 6e 65 79  |ne for the money|

С шифрованием должно быть что-то такое:

new-host-2:Documents sjlombardo$ hexdump -C encrypted.db
00000000  84 d1 36 18 eb b5 82 90  c4 70 0d ee 43 cb 61 87  |.?6.?..?p.?C?a.|
00000010  91 42 3c cd 55 24 ab c6  c4 1d c6 67 b4 e3 96 bb  |.B?..?|
00000bf0  8e 99 ee 28 23 43 ab a4  97 cd 63 42 8a 8e 7c c6  |..?(#C??.?cB..|?|
00000c00

Отдельного упоминания стоит то, что при использовании криптографии Apple будет требовать с вас дополнительных документов. По этой ссылке описание как через это все пройти (english).

Comments