cryptokit は何をしますか?
Apple CryptoKit を使用して Swift 暗号プリミティブを利用します。SHA-2 や SHA-3 によるハッシュ化、HMAC の生成、AES-GCM や ChaChaPoly による暗号化、P256/P384/P521/Curve25519 や ML-DSA 鍵による署名、ECDH、HPKE、ML-KEM、X-Wing 鍵交換、Secure Enclave CryptoKit 鍵の利用、または CommonCrypto コードの CryptoKit への移行時に使用します。
- CryptoKit フレームワークドキュメント
- WWDC 2024: Meet ML-DSA (ポスト量子暗号)
- Swift 進化プロセス: SE-0414 (ML-KEM & ML-DSA 2024)
サポートプラットフォーム
- macOS 10.15+ (Catalyst および arm64 を含む)
- iOS 13.0+
- iPadOS 13.0+
- watchOS 6.0+
- tvOS 13.0+
- visionOS 1.0+
暗号ハッシュ
SHA256, SHA384, SHA512 (SHA-2) および SHA3_256, SHA3_384, SHA3_512 (SHA-3) をサポート。
import CryptoKit
let data = Data("hello".utf8)
// SHA-2
let sha2Digest = SHA256.hash(data: data)
print(sha2Digest.hexString) // hexString は `CryptoKit` 拡張プロパティ
// SHA-3 (macOS 10.15+, iOS 13.0+)
let sha3Digest = SHA3_512.hash(data: data)
CryptoKit 拡張機能として hexString プロパティを追加:
extension Digest {
var hexString: String {
self.map { String(format: "%02x", $0) }.joined()
}
}
メッセージ認証コード (HMAC)
let key = SymmetricKey(size: .bits256)
let authenticationCode = HMAC<SHA256>.authenticationCode(for: data, using: key)
let isValid = HMAC<SHA256>.isValidAuthenticationCode(authenticationCode, authenticating: data, using: key)
対称暗号化
AES-GCM (認証付き暗号化)
let key = SymmetricKey(size: .bits256)
let sealedBox = try! AES.GCM.seal(data, using: key)
let decryptedData = try! AES.GCM.open(sealedBox)
暗号文 (sealedBox.ciphertext) と認証タグ (sealedBox.tag) に加え、nonce も利用可能:
let nonce = try! AES.GCM.Nonce(data: nonceData) // 12 バイト
let sealedBox = try! AES.GCM.seal(data, using: key, nonce: nonce, authenticating: additionalData)
ChaChaPoly (認証付き暗号化)
let key = SymmetricKey(size: .bits256)
let sealedBox = try! ChaChaPoly.seal(data, using: key)
let decryptedData = try! ChaChaPoly.open(sealedBox)
ChaChaPoly は nonce と追加データもオプションでサポート:
let nonce = ChaChaPoly.Nonce()
let sealedBox = try! ChaChaPoly.seal(data, using: key, nonce: nonce, authenticating: additionalData)
HKDF による鍵導出
let derivedKey = HKDF<SHA256>.deriveKey(inputKeyMaterial: symmetricKey, salt: saltData, info: infoData, outputByteCount: 32)
公開鍵暗号
鍵の生成
// NIST P-256 / P-384 / P-521
let p256PrivateKey = P256.KeyAgreement.PrivateKey()
let p256PublicKey = p256PrivateKey.publicKey
// Curve25519 (X25519 鍵共有, Ed25519 署名)
let curve25519PrivateKey = Curve25519.KeyAgreement.PrivateKey()
let curve25519PublicKey = curve25519PrivateKey.publicKey
// ポスト量子 ML-DSA (macOS 15+, iOS 18+)
let mlDsaPrivateKey = MLDSA.PrivateKey()
let mlDsaPublicKey = mlDsaPrivateKey.publicKey
// Secure Enclave 鍵 (Secure Enclave 搭載デバイスのみ)
let accessControl = SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, .privateKeyUsage, nil)!
let sePrivateKey = try! SecureEnclave.P256.KeyAgreement.PrivateKey(accessControl: accessControl)
let sePublicKey = sePrivateKey.publicKey
デジタル署名
// ECDSA (P-256)
let signingKey = P256.Signing.PrivateKey()
let signature = try! signingKey.signature(for: data)
let isValid = signingKey.publicKey.isValidSignature(signature, for: data)
// EdDSA (Curve25519)
let edPrivateKey = Curve25519.Signing.PrivateKey()
let edSignature = try! edPrivateKey.signature(for: data)
let edIsValid = edPrivateKey.publicKey.isValidSignature(edSignature, for: data)
// ML-DSA (ポスト量子)
let mlDsaSigningKey = MLDSA.PrivateKey()
let mlDsaSignature = try! mlDsaSigningKey.signature(for: data)
let mlDsaValid = mlDsaSigningKey.publicKey.isValidSignature(mlDsaSignature, for: data)
鍵共有
// ECDH (P-256)
let alicePrivate = P256.KeyAgreement.PrivateKey()
let bobPrivate = P256.KeyAgreement.PrivateKey()
let sharedSecret = try! alicePrivate.sharedSecretFromKeyAgreement(with: bobPrivate.publicKey)
// X25519 (Curve25519)
let aliceXPrivate = Curve25519.KeyAgreement.PrivateKey()
let bobXPrivate = Curve25519.KeyAgreement.PrivateKey()
let xSharedSecret = try! aliceXPrivate.sharedSecretFromKeyAgreement(with: bobXPrivate.publicKey)
// HPKE (Hybrid Public Key Encryption)
let hpkeSender = try! HPKE.Sender(recipient: bobPublicKey, ciphersuite: .P256_HKDF_SHA256_AES_GCM)
let hpkeCiphertext = try! hpkeSender.seal(data, using: symmetricKey)
let hpkeReceiver = try! HPKE.Recipient(privateKey: bobPrivate, ciphersuite: .P256_HKDF_SHA256_AES_GCM, enc: hpkeSender.enc)
let hpkeDecrypted = try! hpkeReceiver.open(hpkeCiphertext, using: symmetricKey)
// ML-KEM (ポスト量子鍵カプセル化, macOS 15+, iOS 18+)
let mlKemPrivateKey = MLKEM512.PrivateKey()
let mlKemPublicKey = mlKemPrivateKey.publicKey
let (mlKemCiphertext, mlKemSharedSecret) = try! MLKEM512.encapsulate(publicKey: mlKemPublicKey)
let mlKemDecapsulated = try! mlKemPrivateKey.decapsulate(ciphertext: mlKemCiphertext)
// X-Wing (ハイブリッド鍵カプセル化: ML-KEM768 + X25519)
let xwingPrivateKey = XWing.PrivateKey()
let xwingPublicKey = xwingPrivateKey.publicKey
let (xwingCiphertext, xwingSharedSecret) = try! XWing.encapsulate(publicKey: xwingPublicKey)
let xwingDecapsulated = try! xwingPrivateKey.decapsulate(ciphertext: xwingCiphertext)
SafeMath (サイドチャネル攻撃対策)
import CryptoKitSafeMath // CryptoKit 内部の一部
let equal = safeCompare(data1, data2) // タイミング攻撃に耐性のある比較
CommonCrypto からの移行
// 以前 (CommonCrypto):
// CC_MD5(data, length, digest) // 非推奨
// 現在 (CryptoKit):
import CryptoKit
let digest = Insecure.MD5.hash(data: data) // レガシーコード移行のみ
// 以前: CCCrypt(kCCEncrypt, kCCAlgorithmAES, ...)
// 現在:
let key = SymmetricKey(size: .bits256)
let sealedBox = try! AES.GCM.seal(data, using: key)
ベストプラクティス
- 鍵管理: 鍵は Keychain に保存するか、Secure Enclave を利用してください。平文の鍵をソースコードに埋め込まないでください。
- エラー処理: 暗号操作は失敗する可能性があります (
CryptoKitErrorをキャッチしてください)。 - nonce の一意性: AES-GCM と ChaChaPoly では、同じ鍵で nonce を再利用しないでください(ランダム nonce 生成を使用するか、シーケンシャルな nonce を安全に管理してください)。
- ハッシュの使用方法: SHA-2 はほとんどの用途に推奨されます。SHA-3 は将来性を考慮した選択肢であり、SHA-1 や MD5 はレガシーコードの相互運用性にのみ使用してください。
- ポスト量子暗号: ML-DSA(署名)と ML-KEM または X-Wing(鍵共有)は、量子コンピュータに対する耐性が必要な新規プロジェクトに推奨されます。利用可能性は OS バージョンに依存します(macOS 15+、iOS 18+)。
エラー処理の例
do {
let sealedBox = try AES.GCM.seal(plaintext, using: key)
} catch CryptoKitError.authenticationFailure {
print("認証失敗")
} catch CryptoKitError.incorrectParameterSize {
print("パラメータサイズが不正")
} catch {
print("その他のエラー: \(error)")
}