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

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

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

Начать курс

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

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

1. Настройка проекта

Для использования CryptoKit дополнительных настроек не требуется — он входит в стандартную библиотеку Foundation. Если вы работаете с CommonCrypto, добавьте в Bridging-Header (для Swift + ObjC) или импортируйте модуль напрямую:

// Для CommonCrypto в Swift 5+ можно использовать:
import CommonCrypto
// Или настроить модульный мост (modulemap)

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

CryptoKit предоставляет высокоуровневый API для AES в режиме GCM (Galois/Counter Mode) — безопасный и простой способ шифрования.

import CryptoKit
import Foundation

// Функция шифрования строки
func encryptString(_ plaintext: String, using key: SymmetricKey) throws -> Data {
    let plaintextData = plaintext.data(using: .utf8)!
    let sealedBox = try AES.GCM.seal(plaintextData, using: key)
    return sealedBox.combined! // combined = nonce + ciphertext + tag
}

// Функция дешифрования
func decryptData(_ combinedData: Data, using key: SymmetricKey) throws -> String {
    let sealedBox = try AES.GCM.SealedBox(combined: combinedData)
    let decryptedData = try AES.GCM.open(sealedBox, using: key)
    return String(data: decryptedData, encoding: .utf8)!
}

// Пример использования
let key = SymmetricKey(size: .bits256) // 256-битный ключ
let original = "Секретное сообщение для iOS"
let encrypted = try encryptString(original, using: key)
print("Зашифровано: \(encrypted.base64EncodedString())")

let decrypted = try decryptData(encrypted, using: key)
print("Расшифровано: \(decrypted)")

Важно: SymmetricKey генерируется случайным образом. Для реального приложения ключ нужно хранить в Keychain или использовать Secure Enclave.

3. Хеширование (SHA-256) и HMAC

Хеширование — односторонняя функция, незаменимая для проверки целостности данных и хранения паролей. CryptoKit поддерживает SHA-256, SHA-384, SHA-512.

import CryptoKit

func sha256Hash(of data: Data) -> String {
    let digest = SHA256.hash(data: data)
    return digest.compactMap { String(format: "%02x", $0) }.joined()
}

// Пример для строки
let message = "Hello, Swift Crypto!"
let hash = sha256Hash(of: message.data(using: .utf8)!)
print("SHA-256: \(hash)")

Для аутентификации сообщений (HMAC) используйте HMAC с ключом:

func hmacSHA256(key: SymmetricKey, data: Data) -> Data {
    let authenticationCode = HMAC<SHA256>.authenticationCode(for: data, using: key)
    return Data(authenticationCode)
}

let hmacKey = SymmetricKey(size: .bits256)
let hmacResult = hmacSHA256(key: hmacKey, data: "Важные данные".data(using: .utf8)!)
print("HMAC: \(hmacResult.base64EncodedString())")

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

Для RSA используйте фреймворк Security (SecKey). CryptoKit не поддерживает RSA напрямую, но вы можете комбинировать подходы.

import Security

// Генерация пары ключей RSA (2048 бит)
func generateRSAKeyPair() -> (privateKey: SecKey, publicKey: SecKey)? {
    let attributes: [String: Any] = [
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecAttrKeySizeInBits as String: 2048,
        kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false],
        kSecPublicKeyAttrs as String: [kSecAttrIsPermanent as String: false]
    ]
    var error: Unmanaged<CFError>?
    guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
        print("Ошибка генерации: \(error!.takeRetainedValue())")
        return nil
    }
    let publicKey = SecKeyCopyPublicKey(privateKey)!
    return                    

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