CryptoKit для Swift: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое CryptoKit и зачем она нужна?

CryptoKit — это фреймворк для криптографических операций, разработанный компанией Apple и встроенный непосредственно в экосистему Swift. Он доступен начиная с iOS 13, macOS 10.15, watchOS 6 и tvOS 13. В отличие от сторонних библиотек, CryptoKit является нативным решением, что гарантирует высокую производительность, безопасность и полную интеграцию с системой управления ключами Secure Enclave.

Зачем нужна CryptoKit? В современной разработке приложений безопасность данных выходит на первый план. CryptoKit предоставляет разработчикам простой, но мощный интерфейс для:

  • Хеширования данных (SHA-256, SHA-384, SHA-512)
  • Симметричного шифрования (AES-GCM, ChaCha20-Poly1305)
  • Асимметричного шифрования (Curve25519, P-256, P-384, P-521)
  • Цифровых подписей (EdDSA, ECDSA)
  • Генерации криптостойких случайных чисел
  • Обмена ключами (Diffie-Hellman на эллиптических кривых)

Библиотека спроектирована так, чтобы минимизировать ошибки разработчика: она использует безопасные реализации по умолчанию, автоматически управляет памятью и не позволяет использовать устаревшие или небезопасные алгоритмы (например, MD5 или SHA-1 для подписей).

Установка CryptoKit

Так как CryptoKit является частью стандартной библиотеки Apple, не требуется установка через менеджеры пакетов (CocoaPods, Swift Package Manager или Carthage). Всё, что нужно — это проект с минимальной целью развертывания iOS 13+ или macOS 10.15+.

Важно: Если вы разрабатываете под более старые версии ОС, CryptoKit недоступен. В таком случае используйте CommonCrypto (C-уровень) или сторонние библиотеки (например, CryptoSwift).

Для проверки доступности CryptoKit в коде используйте:

import CryptoKit

if #available(iOS 13.0, macOS 10.15, *) {
    // Ваш код с CryptoKit
} else {
    // Fallback на CommonCrypto
}

Быстрый старт с примером кода

Рассмотрим простейший пример: хеширование строки и симметричное шифрование.

import CryptoKit
import Foundation

// 1. Хеширование
let inputString = "Hello, CryptoKit!"
let inputData = Data(inputString.utf8)
let hash = SHA256.hash(data: inputData)
print("SHA256 хеш: \(hash.compactMap { String(format: "%02x", $0) }.joined())")

// 2. Симметричное шифрование (AES-GCM)
let key = SymmetricKey(size: .bits256) // Генерация 256-битного ключа
let plaintext = "Секретное сообщение".data(using: .utf8)!

do {
    let sealedBox = try AES.GCM.seal(plaintext, using: key)
    print("Зашифрованные данные: \(sealedBox.ciphertext.base64EncodedString())")
    
    // Расшифровка
    let openedBox = try AES.GCM.open(sealedBox, using: key)
    let decryptedString = String(data: openedBox, encoding: .utf8)!
    print("Расшифрованное сообщение: \(decryptedString)")
} catch {
    print("Ошибка шифрования: \(error)")
}

Основные методы и функции CryptoKit

Ниже представлены 10 ключевых функций CryptoKit с подробным описанием, параметрами и примерами.

1. SHA256.hash(data:)

Описание: Вычисляет SHA-256 хеш от переданных данных. Возвращает объект SHA256Digest.

Параметры:

  • data: Data — исходные данные для хеширования.

Пример:

let data = "Пример данных".data(using: .utf8)!
let digest = SHA256.hash(data: data)
print(digest.description) // Вывод: SHA256 digest: 8f4343... (64 символа)

2. SHA384.hash(data:)

Описание: Аналогично SHA256, но использует 384-битный дайджест. Более безопасен, но медленнее.

Параметры: те же, что и SHA256.

Пример:

let digest384 = SHA384.hash(data: data)
print("SHA384: \(digest384)")

3. SHA512.hash(data:)

Описание: 512-битный хеш. Максимальная безопасность среди SHA-2 семейства.

Пример:

let digest512 = SHA512.hash(data: data)
print("SHA512: \(digest512)")

4. AES.GCM.seal(_:using:nonce:)

Описание: Шифрует данные с использованием алгоритма AES в режиме GCM (Galois/Counter Mode). Обеспечивает аутентификацию данных.

Параметры:

  • plaintext: Data — открытый текст.
  • using: SymmetricKey — симметричный ключ (128, 192 или 256 бит).
  • nonce: AES.GCM.Nonce? — опциональный nonce (12 байт). Если не указан, генерируется автоматически.

Возвращает: AES.GCM.SealedBox — содержит зашифрованный текст, тег аутентификации и nonce.

Пример:

let key = SymmetricKey(size: .bits256)
let plaintext = Data("Конфиденциально".utf8)
let sealedBox = try AES.GCM.seal(plaintext, using: key)
// sealedBox.ciphertext, sealedBox.tag, sealedBox.nonce

5. AES.GCM.open(_:using:)

Описание: Расшифровывает данные, проверяя аутентификацию. Если данные были изменены, выбрасывает ошибку.

Параметры:

  • sealedBox: AES.GCM.SealedBox — зашифрованный контейнер.
  • using: SymmetricKey — тот же ключ, что использовался при шифровании.

Пример:

let decryptedData = try AES.GCM.open(sealedBox, using: key)
print(String(data: decryptedData, encoding: .utf8)!)

6. ChaChaPoly.seal(_:using:nonce:)

Описание: Шифрование с использованием алгоритма ChaCha20-Poly1305. Альтернатива AES-GCM, часто быстрее на мобильных устройствах.

Параметры: аналогичны AES.GCM.seal.

Пример:

let chachaKey = SymmetricKey(size: .bits256)
let chachaBox = try ChaChaPoly.seal(plaintext, using: chachaKey)

7. Curve25519.KeyAgreement.privateKey

Описание: Генерирует закрытый ключ для обмена ключами по протоколу X25519 (Diffie-Hellman на Curve25519).

Параметры: нет (инициализатор).

Пример:

let alicePrivateKey = Curve25519.KeyAgreement.PrivateKey()
let alicePublicKey = alicePrivateKey.publicKey
// Отправляем alicePublicKey Бобу

8. Curve25519.KeyAgreement.sharedSecretFromKeyAgreement(with:)

Описание: Вычисляет общий секрет на основе своего закрытого ключа и публичного ключа другой стороны.

Параметры:

  • publicKeyShare: Curve25519.KeyAgreement.PublicKey — публичный ключ собеседника.

Пример:

let bobPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let sharedSecret = try alicePrivateKey.sharedSecretFromKeyAgreement(with: bobPrivateKey.publicKey)
// sharedSecret — это SharedSecret, из которого можно получить симметричный ключ

9. P256.Signing.PrivateKey() и signature(for:)

Описание: Создание цифровой подписи с использованием эллиптической кривой P-256 (ECDSA).

Параметры:

  • for: Data — данные для подписи (обычно хеш).

Пример:

let signingKey = P256.Signing.PrivateKey()
let message = Data("Важный документ".utf8)
let signature = try signingKey.signature(for: message)
// signature — объект P256.Signing.ECDSASignature

10. P256.Signing.PublicKey. isValidSignature(_:for:)

Описание: Проверяет подпись для переданных данных.

Параметры:

  • signature: P256.Signing.ECDSASignature — подпись для проверки.
  • for: Data — исходные данные.

Пример:

let publicKey = signingKey.publicKey
let isValid = publicKey.isValidSignature(signature, for: message)
print("Подпись валидна: \(isValid)")

Реальный практический пример использования

Рассмотрим сценарий: приложение для обмена зашифрованными сообщениями между двумя пользователями (Алисой и Бобом). Используем асимметричное шифрование для обмена ключами и симметричное — для самих сообщений.

import CryptoKit
import Foundation

// Шаг 1: Алиса генерирует свою пару ключей
let alicePrivateKey = Curve25519.KeyAgreement.PrivateKey()
let alicePublicKeyData = alicePrivateKey.publicKey.rawRepresentation

// Шаг 2: Боб генерирует свою пару ключей
let bobPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let bobPublicKeyData = bobPrivateKey.publicKey.rawRepresentation

// Шаг 3: Обмен публичными ключами (в реальности через сеть)
// Алиса получает публичный ключ Боба
let bobPublicKey = try Curve25519.KeyAgreement.PublicKey(rawRepresentation: bobPublicKeyData)

// Шаг 4: Вычисление общего секрета
let sharedSecret = try alicePrivateKey.sharedSecretFromKeyAgreement(with: bobPublicKey)

// Шаг 5: Получение симметричного ключа из общего секрета
let symmetricKey = sharedSecret.hkdfDerivedSymmetricKey(
    using: SHA256.self,
    salt: Data(),
    sharedInfo: Data(),
    outputByteCount: 32
)

// Шаг 6: Шифрование сообщения
let message = "Привет, Боб! Это секретное сообщение."
let messageData = Data(message.utf8)
let sealedBox = try AES.GCM.seal(messageData, using: symmetricKey)

// Передача sealedBox (ciphertext + nonce + tag) Бобу
// Шаг 7: Боб расшифровывает
let bobSymmetricKey = sharedSecret.hkdfDerivedSymmetricKey(
    using: SHA256.self,
    salt: Data(),
    sharedInfo: Data(),
    outputByteCount: 32
)
let decryptedData = try AES.GCM.open(sealedBox, using: bobSymmetricKey)
let decryptedMessage = String(data: decryptedData, encoding: .utf8)!
print("Боб получил: \(decryptedMessage)")

Советы и типичные ошибки

Советы

  • Всегда используйте аутентифицированное шифрование: AES-GCM и ChaCha20-Poly1305 проверяют целостность данных. Никогда не используйте режимы типа ECB или CBC, если не уверены в необходимости.
  • Храните ключи в Keychain: Никогда не храните криптографи

Рекомендаций