Шифрование основных данных
У меня есть вопрос по поводу основного шифрования данных. Я храню некоторые конфиденциальные пользовательские данные в базе данных Core Data SQLite. Все критические значения являются трансформируемыми, и я использую AES256 для шифрования и дешифрования "на лету", включая индивидуальный IV для каждого значения. Ключ шифрования - это хэш-пароль SHA512, выбранный пользователем. Это работает очень хорошо до сих пор.
Теперь о пароле пользователя. Когда пользователь запускает приложение, его спрашивают его пароль. Пароль хешируется с помощью SHA512 и сохраняется в связке ключей iOS. Для каждой операции записи или чтения NSValueTransformer будет получать пароль из цепочки для ключей. Если приложение закрывается, я удаляю хэш пароля из цепочки для ключей.
В моей базе данных базовых данных у меня есть специальный объект, который имеет случайное число!= 0, поскольку это единственное значение. Чтобы проверить, правильно ли пользователь ввел пароль, я извлекаю эту сущность и читаю число. Если это =! 0, я знаю, что пароль был верным, потому что при неудачном дешифровании NSValueTransformer всегда возвращает 0.
Теперь мои актуальные вопросы: считаете ли вы это хорошим подходом к шифрованию? Как еще вы будете проверять правильность введенного пароля?
Я немного обеспокоен тем, что хранение хэша пароля в цепочке для ключей во время работы приложения делает все медленнее, потому что NSValueTransformer должен постоянно обращаться к цепочке для ключей. Будет ли он достаточно безопасным, чтобы просто хранить хэш пароля в памяти, поэтому он будет удален при закрытии приложения?
2 ответа
Вы не должны использовать хэш пароля, хэши спроектированы так, чтобы быть быстрыми, поэтому (сравнительно) легко осуществить атаку методом перебора. Используйте функцию получения ключа, такую как PBKDF2.
Не используйте ключ, непосредственно полученный из пароля, в качестве ключа шифрования. Если пользователь меняет пароль, вам необходимо перешифровать все данные, и резервные копии становятся бесполезными. Используйте случайно сгенерированный ключ шифрования, который вы шифруете ключом шифрования на основе пароля.
Я не очень уверен насчет хранения хеша в цепочке для ключей вместо того, чтобы просто хранить его в памяти. В прошлый раз, когда я смотрел на это, было сравнительно легко расшифровать цепочку для ключей. И каждый злоумышленник, который может прочитать память вашего работающего приложения, скорее всего, сможет отслеживать доступ к цепочке для ключей или дешифрованные данные. Просто сохраните его в памяти и обязательно сотрите память, если приложение переходит в фоновый режим и т. Д. Это, очевидно, также верно для каждого фрагмента дешифрованных данных.
[EDIT: @JeffLockhart, чтобы уточнить процедуру для главного ключа шифрования] вы генерируете случайный ключ для шифрования ваших данных, давайте назовем его ключом A. Вы можете использовать SecRandomCopyBytes для генерации ключа A, см. Пример использования CryptoExcercise от Apple. Вы используете ключ A для шифрования пользовательских данных. Чтобы сохранить ключ A, вы должны зашифровать ключ A вторым ключом B. Вам не следует использовать пароль непосредственно в качестве ключа B из-за быстрых атак методом перебора или словарной атаки. Таким образом, вы извлекаете ключ из пароля с помощью PBKDF, как в этом ответе stackru. Затем вы шифруете ключ A ключом B, например, используя CCCrypt. Вы сохраняете зашифрованный ключ A и соль, используемую для его получения. Чтобы расшифровать, пользователь вводит пароль, вы получаете ключ B, используя пароль и соль. Вы расшифровываете ключ A, используя производный ключ B. Надежда, которая проясняется.
Вы могли бы взглянуть на это:
Безопасный инкрементный магазин
Они реализовали подкласс NSIncrementalStore, который использует зашифрованную базу данных SQLite. Это замена для Apple Store SQLite. Поставляется с ценником, а также.