参考

サンプル実装

  • EntitlementのKeychain Access Groupsに$(AppIdentifierPrefix)[あなたのBundle Identifierの文字列]を書いておく必要がある
  • Secure Enclave特有のバグかはわからないが、ApplicationTagが長すぎるとキーは作成できてもSecItemCopyMatchingで取ってこれないことがある
import Foundation
import CryptoKit
import Security
 
@main
class KeyTestApp {
    static func main() {
        // Secure Enclaveが使えるかチェックする
        let isSecureEnclaveAvailable: Bool = SecureEnclave.isAvailable
        if !isSecureEnclaveAvailable {
            NSLog("No Secure enclave...")
            exit(1)
        }
        NSLog("Secure Enclave is detected")
 
 
 
        // アクセス権限の設定
        let access = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, .privateKeyUsage, nil)!
 
 
        // 鍵のAttributesの設定
        let attributes: NSDictionary = [
            kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
            kSecAttrKeySizeInBits: 256,
            kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,  // ここでSecure Enclaveに格納されることを指示
            kSecPrivateKeyAttrs: [
                kSecAttrIsPermanent: false,  // これがtrueだと、ちゃんとOSのキーチェーンに保存される?
                kSecAttrApplicationTag: "UNKO".data(using: .utf8)!,
                kSecAttrAccessControl: access,
            ],
        ]
 
 
        // Secure Enclave内に秘密鍵を生成・公開鍵の導出
        var error: Unmanaged<CFError>?
        guard let privateKey: SecKey = SecKeyCreateRandomKey(attributes, &error) else {
            NSLog(error!.takeRetainedValue().localizedDescription)
            exit(1)
        }
        let pubKey: SecKey = SecKeyCopyPublicKey(privateKey)!;
 
 
        // サポートチェック
        if !SecKeyIsAlgorithmSupported(pubKey, .encrypt, .eciesEncryptionStandardX963SHA256AESGCM) {
            NSLog("暗号化できない")
            exit(1)
        }
        if !SecKeyIsAlgorithmSupported(privateKey, .decrypt, .eciesEncryptionStandardX963SHA256AESGCM) {
            NSLog("復号できない")
            exit(1)
        }
        
 
 
        // 暗号化
        let data: Data = "Hello, Secure Enclave!".data(using: .utf8)!
        var encryptError: Unmanaged<CFError>?
        let encryptedData: Data = SecKeyCreateEncryptedData(pubKey, .eciesEncryptionStandardX963SHA256AESGCM, data as CFData, &encryptError)! as Data
 
        if let encryptError = error {
            NSLog(encryptError.takeRetainedValue().localizedDescription)
            NSLog("暗号化に失敗")
            exit(1)
        }
 
        // 復号
        var decryptError: Unmanaged<CFError>?
        let decryptedData: Data = SecKeyCreateDecryptedData(privateKey, .eciesEncryptionStandardX963SHA256AESGCM, encryptedData as CFData, &decryptError)! as Data
        if let decryptError = error {
            NSLog(decryptError.takeRetainedValue().localizedDescription)
            NSLog("復号に失敗")
            exit(1)
        }
 
        print("Result: ")
        print(String(data: decryptedData, encoding: .utf8)!)  // ちゃんとHello, Secure Enclave!と表示されるはず
    }
}
 

その他実装例