Криптография в Swift: шифрование и хеширование для iOS/macOS

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

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

Начать курс

Криптография в Swift (iOS/macOS): шифрование и хеширование

В современной разработке под iOS и macOS безопасность данных — один из ключевых приоритетов. Apple предоставляет мощные встроенные инструменты для криптографической защиты: от простого хеширования до асимметричного шифрования. В этой статье мы рассмотрим, как использовать CryptoKit (рекомендованный фреймворк начиная с iOS 13 / macOS 10.15) и классический CommonCrypto для решения типовых задач: шифрование, хеширование и аутентификация данных.

Основные понятия

Прежде чем перейти к коду, разберёмся с терминами:

  • Симметричное шифрование — один ключ используется и для шифрования, и для расшифровки (например, AES).
  • Асимметричное шифрование — пара ключей: публичный (для шифрования) и приватный (для расшифровки).
  • Хеширование — необратимое преобразование данных в строку фиксированной длины (SHA-256).
  • HMAC — код аутентификации сообщения на основе хеша с использованием ключа.

1. Хеширование с помощью CryptoKit

CryptoKit — современный Swift-фреймворк, который делает криптографию простой и безопасной. Для хеширования используется структура SHA256.

import CryptoKit

func hashString(_ input: String) -> String {
    let inputData = Data(input.utf8)
    let hashed = SHA256.hash(data: inputData)
    return hashed.compactMap { String(format: "%02x", $0) }.joined()
}

// Пример использования
let password = "MySecurePass123"
let hash = hashString(password)
print("SHA-256 хеш: \(hash)")

Также доступны SHA384, SHA512 и SHA1 (последний — только для совместимости).

2. HMAC (аутентификация сообщения)

HMAC добавляет ключ к хешу, что защищает от подделки. В CryptoKit это реализовано через HMAC с указанием алгоритма:

import CryptoKit

func hmacSHA256(key: SymmetricKey, message: String) -> String {
    let messageData = Data(message.utf8)
    let code = HMAC<SHA256>.authenticationCode(for: messageData, using: key)
    return code.compactMap { String(format: "%02x", $0) }.joined()
}

// Генерация ключа
let key = SymmetricKey(size: .bits256)
let hmac = hmacSHA256(key: key, message: "Важное сообщение")
print("HMAC: \(hmac)")

3. Симметричное шифрование (AES-GCM)

AES-GCM — современный режим шифрования, который обеспечивает как конфиденциальность, так и аутентификацию (предотвращает подмену данных). CryptoKit поддерживает его из коробки.

import CryptoKit

func encryptAESGCM(plainText: String, key: SymmetricKey) throws -> Data {
    let plainData = Data(plainText.utf8)
    let sealedBox = try AES.GCM.seal(plainData, using: key)
    return sealedBox.combined! // combined = nonce + ciphertext + tag
}

func decryptAESGCM(encryptedData: Data, key: SymmetricKey) throws -> String {
    let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)
    let decryptedData = try AES.GCM.open(sealedBox, using: key)
    return String(data: decryptedData, encoding: .utf8)!
}

// Пример
let key = SymmetricKey(size: .bits256)
let originalText = "Секретные данные"

do {
    let encrypted = try encryptAESGCM(plainText: originalText, key: key)
    let decrypted = try decryptAESGCM(encryptedData: encrypted, key: key)
    print("Расшифровано: \(decrypted)")
} catch {
    print("Ошибка: \(error)")
}

Важно: combined включает всё необходимое для расшифровки (nonce, ciphertext, tag). Храните его вместе с зашифрованными данными.

4. Асимметричное шифрование (RSA) через CommonCrypto

Для RSA CryptoKit не предоставляет прямого API, но можно использовать Security.framework и CommonCrypto. Ниже — пример шифрования публичным ключом.

import Security

func encryptRSA(plainText: String, publicKey: SecKey) -> Data? {
    guard let plainData = plainText.data(using: .utf8) else { return nil }
    
    var error: Unmanaged<CFError>?
    guard let cipherData = SecKeyCreateEncryptedData(
        publicKey,
        .rsaEncryptionPKCS1,
        plainData as CFData,
        &error
    ) as Data? else {
        print("О                    

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