// Reference: // - https://developer.apple.com/documentation/swift/commandline/arguments // - https://git.hatter.ink/hatter/card-cli/src/branch/master/swift-lib/src/lib.swift // - https://developer.apple.com/documentation/security/secaccesscontrolcreateflags // - https://gist.github.com/monsoir/cc06c298c9c37d629942d87b14a202fc // - https://developer.apple.com/documentation/foundation/jsonencoder import CryptoKit import Foundation import LocalAuthentication extension Data { var hexEncodedString: String { return map { String(format: "%02x", $0) }.joined() } } struct GenerateSecureEnclaveKeyPairRequest { var controlFlag: String } func parseGenerateSecureEnclaveKeyPairRequest() -> GenerateSecureEnclaveKeyPairRequest? { var controlFlagOpt: String? let len = CommandLine.arguments.count; if CommandLine.arguments.count > 2 { var i = 2 while i < len { let k = CommandLine.arguments[i]; if (k == "--control-flag") { controlFlagOpt = CommandLine.arguments[i + 1] i += 2 } else { i += 1 } } } guard let controlFlag = controlFlagOpt else { exitError("parameter --control-flag required.") return nil } return GenerateSecureEnclaveKeyPairRequest( controlFlag: controlFlag ) } struct ComputeP256EcSignRequest { var dataRepresentationBase64: String var messageBase64: String var messageType: String } func parseComputeP256EcSignRequest() -> ComputeP256EcSignRequest? { var dataRepresentationBase64Opt: String? var messageBase64Opt: String? var messageTypeOpt: String? let len = CommandLine.arguments.count; if CommandLine.arguments.count > 2 { var i = 2 while i < len { let k = CommandLine.arguments[i]; if (k == "--data-representation-base64" || k == "--private-key") { dataRepresentationBase64Opt = CommandLine.arguments[i + 1] i += 2 } else if (k == "--message-base64") { messageBase64Opt = CommandLine.arguments[i + 1] i += 2 } else if (k == "--message-type") { messageTypeOpt = CommandLine.arguments[i + 1] i += 2; } else { i += 1 } } } guard let dataRepresentationBase64 = dataRepresentationBase64Opt else { exitError("parameter --data-representation-base64 or --private-key required.") return nil } guard let messageBase64 = messageBase64Opt else { exitError("parameter --message-base64 required.") return nil } return ComputeP256EcSignRequest( dataRepresentationBase64: dataRepresentationBase64, messageBase64: messageBase64, messageType: messageTypeOpt ?? "raw" ) } func parseExternalSignRequest() -> ComputeP256EcSignRequest? { var algOpt: String? var dataRepresentationBase64Opt: String? var messageBase64Opt: String? var messageTypeOpt: String? let len = CommandLine.arguments.count; if CommandLine.arguments.count > 2 { var i = 2 while i < len { let k = CommandLine.arguments[i]; if (k == "--parameter") { dataRepresentationBase64Opt = CommandLine.arguments[i + 1] i += 2 } else if (k == "--message-base64") { messageBase64Opt = CommandLine.arguments[i + 1] i += 2 } else if (k == "--alg") { algOpt = CommandLine.arguments[i + 1] i += 2 } else if (k == "--message-type") { messageTypeOpt = CommandLine.arguments[i + 1] i += 2; } else { i += 1 } } } guard let alg = algOpt else { exitError("parameter --alg required.") return nil } if alg != "ES256" { exitError("parameter --alg MUST be ES256.") return nil } guard let dataRepresentationBase64 = dataRepresentationBase64Opt else { exitError("parameter --parameter required.") return nil } guard let messageBase64 = messageBase64Opt else { exitError("parameter --message-base64 required.") return nil } return ComputeP256EcSignRequest( dataRepresentationBase64: dataRepresentationBase64, messageBase64: messageBase64, messageType: messageTypeOpt ?? "raw" ) } struct ComputeEcdhRequest { var dataRepresentationBase64: String var ephemeraPublicKeyBase64: String } func parseComputeEcdhRequest() -> ComputeEcdhRequest? { var dataRepresentationBase64Opt: String? var ephemeraPublicKeyBase64Opt: String? let len = CommandLine.arguments.count; if CommandLine.arguments.count > 2 { var i = 2 while i < len { let k = CommandLine.arguments[i]; if (k == "--data-representation-base64" || k == "--private-key") { dataRepresentationBase64Opt = CommandLine.arguments[i + 1] i += 2 } else if (k == "--ephemera-public-key-base64" || k == "--ephemera-public-key") { ephemeraPublicKeyBase64Opt = CommandLine.arguments[i + 1] i += 2 } else { i += 1 } } } guard let dataRepresentationBase64 = dataRepresentationBase64Opt else { exitError("parameter --data-representation-base64 or --private-key required.") return nil } guard let ephemeraPublicKeyBase64 = ephemeraPublicKeyBase64Opt else { exitError("parameter --ephemera-public-key-base64 required.") return nil } return ComputeEcdhRequest( dataRepresentationBase64: dataRepresentationBase64, ephemeraPublicKeyBase64: ephemeraPublicKeyBase64 ) } struct RecoverSecureEnclavePublicKeyRequest { var dataRepresentationBase64: String } func parseRecoverSecureEnclavePublicKeyRequest() -> RecoverSecureEnclavePublicKeyRequest? { var dataRepresentationBase64Opt: String? let len = CommandLine.arguments.count; if CommandLine.arguments.count > 2 { var i = 2 while i < len { let k = CommandLine.arguments[i]; if (k == "--data-representation-base64" || k == "--private-key") { dataRepresentationBase64Opt = CommandLine.arguments[i + 1] i += 2 } else { i += 1 } } } guard let dataRepresentationBase64 = dataRepresentationBase64Opt else { exitError("parameter --data-representation-base64 or --private-key required.") return nil } return RecoverSecureEnclavePublicKeyRequest( dataRepresentationBase64: dataRepresentationBase64 ) } func parseExternalPublicKeyRequest() -> RecoverSecureEnclavePublicKeyRequest? { var dataRepresentationBase64Opt: String? let len = CommandLine.arguments.count; if CommandLine.arguments.count > 2 { var i = 2 while i < len { let k = CommandLine.arguments[i]; if (k == "--parameter") { dataRepresentationBase64Opt = CommandLine.arguments[i + 1] i += 2 } else { i += 1 } } } guard let dataRepresentationBase64 = dataRepresentationBase64Opt else { exitError("parameter --parameter required.") return nil } return RecoverSecureEnclavePublicKeyRequest( dataRepresentationBase64: dataRepresentationBase64 ) } struct ErrorResponse: Codable { var success: Bool var error: String } struct VersionResponse: Codable { var success: Bool var version: String } struct SupportSecureEnclaveResponse: Codable { var success: Bool var supported: Bool } struct GenerateSecureEnclaveP256KeyPairResponse: Codable { var success: Bool var public_key_point_base64: String var public_key_base64: String var data_representation_base64: String } struct GenerateSecureEnclaveMlKemKeyPairResponse: Codable { var success: Bool var public_key_base64: String var data_representation_base64: String } struct ExternalPublicKeyResponse: Codable { var success: Bool var public_key_base64: String } struct ComputeSecureEnclaveP256EcsignResponse: Codable { var success: Bool var signature_base64: String } struct ComputeSecureEnclaveEcdhResponse: Codable { var success: Bool var shared_secret_hex: String } struct ExternalSpecResponse: Codable { var success: Bool var agent: String var specification: String var commands: Array } // https://developer.apple.com/forums/thread/696715 // https://github.com/apple/swift-crypto/blob/main/Sources/Crypto/Digests/Digests.swift public struct MySHA256Digest: Digest { let bytes: (UInt64, UInt64, UInt64, UInt64) init?(bufferPointer: UnsafeRawBufferPointer) { guard bufferPointer.count == 32 else { return nil } var bytes = (UInt64(0), UInt64(0), UInt64(0), UInt64(0)) withUnsafeMutableBytes(of: &bytes) { targetPtr in targetPtr.copyMemory(from: bufferPointer) } self.bytes = bytes } public static var byteCount: Int { return 32 } public func withUnsafeBytes(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R { return try Swift.withUnsafeBytes(of: bytes) { let boundsCheckedPtr = UnsafeRawBufferPointer(start: $0.baseAddress, count: Self.byteCount) return try body(boundsCheckedPtr) } } private func toArray() -> ArraySlice { var array = [UInt8]() array.appendByte(bytes.0) array.appendByte(bytes.1) array.appendByte(bytes.2) array.appendByte(bytes.3) return array.prefix(upTo: SHA256Digest.byteCount) } public var description: String { return "\("SHA256") digest: \(toArray().map { String(format: "%02x", $0) }.joined())" } public func hash(into hasher: inout Hasher) { self.withUnsafeBytes { hasher.combine(bytes: $0) } } } extension MutableDataProtocol { mutating func appendByte(_ byte: UInt64) { withUnsafePointer(to: byte.littleEndian, { self.append(contentsOf: UnsafeRawBufferPointer(start: $0, count: 8)) }) } } func stringify(_ value: T) -> String? { guard let jsonData = try? JSONEncoder().encode(value) else { return nil } let result = String(data: jsonData, encoding: .utf8) return result } func exitError(_ error: String) { if let response = stringify(ErrorResponse(success: false, error: error)) { print(response) } else { print("{\"success\":false,\"error\":\"JSON stringify erorr, raw error: \(error)\"}") } exit(1) } func exitOkWithJson(_ value: T) { if let response = stringify(value) { print(response) exit(0) } else { print("{\"success\":false,\"error\":\"JSON stringify erorr\"}") exit(1) } } func isSupportSecureEnclave() -> SupportSecureEnclaveResponse { return SupportSecureEnclaveResponse(success: true, supported: SecureEnclave.isAvailable) } func getSecAccessControlCreateWithFlags(controlFlag: String) -> SecAccessControl? { var error: Unmanaged? = nil let accessControlCreateFlags: SecAccessControlCreateFlags if (controlFlag == "none") { accessControlCreateFlags = [.privateKeyUsage] } else if (controlFlag == "userPresence") { accessControlCreateFlags = [.privateKeyUsage, .userPresence] } else if (controlFlag == "devicePasscode") { accessControlCreateFlags = [.privateKeyUsage, .devicePasscode] } else if (controlFlag == "biometryAny") { accessControlCreateFlags = [.privateKeyUsage, .biometryAny] } else if (controlFlag == "biometryCurrentSet") { accessControlCreateFlags = [.privateKeyUsage, .biometryCurrentSet] } else { exitError("invalid control flag: \(controlFlag)") return nil } guard let accessCtrl = SecAccessControlCreateWithFlags( nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, accessControlCreateFlags, &error ) else { exitError(error.debugDescription) return nil } return accessCtrl } func generateSecureEnclaveP256KeyPair(sign: Bool, request: GenerateSecureEnclaveKeyPairRequest) -> GenerateSecureEnclaveP256KeyPairResponse? { guard let accessCtrl = getSecAccessControlCreateWithFlags(controlFlag: request.controlFlag) else { return nil } do { if (sign) { let privateKeyReference = try SecureEnclave.P256.Signing.PrivateKey.init( accessControl: accessCtrl ) return signingPrivateKeyToResponse(privateKeyReference) } else { let privateKeyReference = try SecureEnclave.P256.KeyAgreement.PrivateKey.init( accessControl: accessCtrl ) return keyAgreementPrivateKeyToResponse(privateKeyReference) } } catch { exitError("\(error)") return nil } } #if DISABLE_QPC #else func generateSecureEnclaveMlKemKeyPair(keyLen: Int, request: GenerateSecureEnclaveKeyPairRequest) -> GenerateSecureEnclaveMlKemKeyPairResponse? { guard let accessCtrl = getSecAccessControlCreateWithFlags(controlFlag: request.controlFlag) else { return nil } do { if (keyLen == 768) { let privateKeyReference = try CryptoKit.SecureEnclave.MLKEM768.PrivateKey.init( accessControl: accessCtrl ); return mlKem768PrivateKeyToResponse(privateKeyReference); } else if (keyLen == 1024) { let privateKeyReference = try CryptoKit.SecureEnclave.MLKEM1024.PrivateKey.init( accessControl: accessCtrl ); return mlKem1024PrivateKeyToResponse(privateKeyReference); } else { exitError("Invalid algorithm: ML-KEM-\(keyLen)") return nil } } catch { exitError("\(error)") return nil } } #endif func signingPrivateKeyToResponse(_ privateKeyReference: SecureEnclave.P256.Signing.PrivateKey) -> GenerateSecureEnclaveP256KeyPairResponse { let publicKeyPointBase64 = privateKeyReference.publicKey.x963Representation.base64EncodedString() let publicKeyDerBase64 = privateKeyReference.publicKey.derRepresentation.base64EncodedString() let dataRepresentationBase64 = privateKeyReference.dataRepresentation.base64EncodedString() return GenerateSecureEnclaveP256KeyPairResponse( success: true, public_key_point_base64: publicKeyPointBase64, public_key_base64: publicKeyDerBase64, data_representation_base64: dataRepresentationBase64 ) } func keyAgreementPrivateKeyToResponse(_ privateKeyReference: SecureEnclave.P256.KeyAgreement.PrivateKey) -> GenerateSecureEnclaveP256KeyPairResponse { let publicKeyPointBase64 = privateKeyReference.publicKey.x963Representation.base64EncodedString() let publicKeyDerBase64 = privateKeyReference.publicKey.rawRepresentation.base64EncodedString() let dataRepresentationBase64 = privateKeyReference.dataRepresentation.base64EncodedString() return GenerateSecureEnclaveP256KeyPairResponse( success: true, public_key_point_base64: publicKeyPointBase64, public_key_base64: publicKeyDerBase64, data_representation_base64: dataRepresentationBase64 ) } #if DISABLE_QPC #else func mlKem768PrivateKeyToResponse(_ privateKeyReference: SecureEnclave.MLKEM768.PrivateKey) -> GenerateSecureEnclaveMlKemKeyPairResponse { let publicKeyDerBase64 = privateKeyReference.publicKey.rawRepresentation.base64EncodedString() let dataRepresentationBase64 = privateKeyReference.dataRepresentation.base64EncodedString() return GenerateSecureEnclaveMlKemKeyPairResponse( success: true, public_key_base64: publicKeyDerBase64, data_representation_base64: dataRepresentationBase64 ) } func mlKem1024PrivateKeyToResponse(_ privateKeyReference: SecureEnclave.MLKEM1024.PrivateKey) -> GenerateSecureEnclaveMlKemKeyPairResponse { let publicKeyDerBase64 = privateKeyReference.publicKey.rawRepresentation.base64EncodedString() let dataRepresentationBase64 = privateKeyReference.dataRepresentation.base64EncodedString() return GenerateSecureEnclaveMlKemKeyPairResponse( success: true, public_key_base64: publicKeyDerBase64, data_representation_base64: dataRepresentationBase64 ) } #endif func recoverSecureEnclaveP256PublicKey(request: RecoverSecureEnclavePublicKeyRequest, sign: Bool) -> GenerateSecureEnclaveP256KeyPairResponse? { guard let privateKeyDataRepresentation = Data( base64Encoded: request.dataRepresentationBase64 ) else { exitError("private key base64 decode failed") return nil } do { let context = LAContext() if (sign) { let privateKeyReference = try SecureEnclave.P256.Signing.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) return signingPrivateKeyToResponse(privateKeyReference) } else { let privateKeyReference = try SecureEnclave.P256.KeyAgreement.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) return keyAgreementPrivateKeyToResponse(privateKeyReference) } } catch { exitError("\(error)") return nil } } #if DISABLE_QPC #else func recoverSecureEnclaveMlKemPublicKey(request: RecoverSecureEnclavePublicKeyRequest, keyLen: Int) -> GenerateSecureEnclaveMlKemKeyPairResponse? { guard let privateKeyDataRepresentation = Data( base64Encoded: request.dataRepresentationBase64 ) else { exitError("private key base64 decode failed") return nil } do { let context = LAContext() if (keyLen == 768) { let privateKeyReference = try SecureEnclave.MLKEM768.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) return mlKem768PrivateKeyToResponse(privateKeyReference); } else if (keyLen == 1024) { let privateKeyReference = try SecureEnclave.MLKEM1024.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) return mlKem1024PrivateKeyToResponse(privateKeyReference); } else { exitError("Invalid algorithm: ML-KEM-\(keyLen)") return nil } } catch { exitError("\(error)") return nil } } #endif func computeSecureEnclaveP256Ecsign(request: ComputeP256EcSignRequest) -> ComputeSecureEnclaveP256EcsignResponse? { guard let privateKeyDataRepresentation = Data( base64Encoded: request.dataRepresentationBase64 ) else { exitError("private key base64 decode failed") return nil } guard let contentData = Data( base64Encoded: request.messageBase64 ) else { exitError("content base64 decode failed") return nil } do { let context = LAContext() let p = try SecureEnclave.P256.Signing.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) let signature: P256.Signing.ECDSASignature if (request.messageType == "raw") { let digest = SHA256.hash(data: contentData) signature = try p.signature(for: digest) } else if (request.messageType == "sha256") { let dataAsBufferPointer : UnsafeRawBufferPointer = contentData.withUnsafeBytes { return $0 } guard let dataAsDigest = MySHA256Digest(bufferPointer: dataAsBufferPointer) else { exitError("invalid SHA256 digest") return nil } signature = try p.signature(for: dataAsDigest) } else { exitError("not supported message type: \(request.messageType)") return nil } return ComputeSecureEnclaveP256EcsignResponse( success: true, signature_base64: signature.derRepresentation.base64EncodedString() ) } catch { exitError("\(error)") return nil } } func computeSecureEnclaveP256Ecdh(request: ComputeEcdhRequest) -> ComputeSecureEnclaveEcdhResponse? { guard let privateKeyDataRepresentation = Data( base64Encoded: request.dataRepresentationBase64 ) else { exitError("private key base64 decode failed") return nil } guard let ephemeralPublicKeyRepresentation = Data( base64Encoded: request.ephemeraPublicKeyBase64 ) else { exitError("ephemeral public key base64 decode failed") return nil } do { let context = LAContext() let p = try SecureEnclave.P256.KeyAgreement.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) let ephemeralPublicKey = try P256.KeyAgreement.PublicKey.init(derRepresentation: ephemeralPublicKeyRepresentation) let sharedSecret = try p.sharedSecretFromKeyAgreement( with: ephemeralPublicKey) var shared_secret_hex: String if sharedSecret.description.starts(with: "SharedSecret: ") { let str = sharedSecret.description let startIndex = str.index(str.startIndex, offsetBy: "SharedSecret: ".count) shared_secret_hex = String(str[startIndex...]) } else { shared_secret_hex = sharedSecret.description } return ComputeSecureEnclaveEcdhResponse( success: true, shared_secret_hex: shared_secret_hex ) } catch { exitError("\(error)") return nil } } #if DISABLE_QPC #else func computeSecureEnclaveMlKemEcdh(request: ComputeEcdhRequest, keyLen: Int) -> ComputeSecureEnclaveEcdhResponse? { guard let privateKeyDataRepresentation = Data( base64Encoded: request.dataRepresentationBase64 ) else { exitError("private key base64 decode failed") return nil } guard let ephemeralPublicKeyRepresentation = Data( base64Encoded: request.ephemeraPublicKeyBase64 ) else { exitError("ephemeral public key base64 decode failed") return nil } do { let context = LAContext() if keyLen == 768 { let p = try SecureEnclave.MLKEM768.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) let sharedSecret = try p.decapsulate(ephemeralPublicKeyRepresentation) let sharedSecretData = sharedSecret.withUnsafeBytes { Data($0) } return ComputeSecureEnclaveEcdhResponse( success: true, shared_secret_hex: sharedSecretData.hexEncodedString ) } else if (keyLen == 1024) { let p = try SecureEnclave.MLKEM1024.PrivateKey( dataRepresentation: privateKeyDataRepresentation, authenticationContext: context ) let sharedSecret = try p.decapsulate(ephemeralPublicKeyRepresentation) let sharedSecretData = sharedSecret.withUnsafeBytes { Data($0) } return ComputeSecureEnclaveEcdhResponse( success: true, shared_secret_hex: sharedSecretData.hexEncodedString ) } else { exitError("Invalid algorithm: ML-KEM-\(keyLen)") return nil } } catch { exitError("\(error)") return nil } } #endif func externalSpec() -> ExternalSpecResponse { return ExternalSpecResponse( success: true, agent: "swift-secure-enclave-external-provider/2.0.0-alpha", specification: "External/1.0.0-alpha", commands: ["external_public_key", "external_sign"] ) } if (CommandLine.arguments.count == 1) { exitError("require at least one argument") } let command = CommandLine.arguments[1] if (command == "is_support_secure_enclave") { exitOkWithJson(isSupportSecureEnclave()) } if (command == "generate_p256_ecsign_keypair") { let request = parseGenerateSecureEnclaveKeyPairRequest()!; exitOkWithJson(generateSecureEnclaveP256KeyPair(sign: true, request: request)) } if (command == "generate_p256_ecdh_keypair") { let request = parseGenerateSecureEnclaveKeyPairRequest()!; exitOkWithJson(generateSecureEnclaveP256KeyPair(sign: false, request: request)) } if (command == "recover_p256_ecsign_public_key") { let request = parseRecoverSecureEnclavePublicKeyRequest()! let response = recoverSecureEnclaveP256PublicKey(request: request, sign: true) exitOkWithJson(response) } if (command == "recover_p256_ecdh_public_key") { let request = parseRecoverSecureEnclavePublicKeyRequest()! let response = recoverSecureEnclaveP256PublicKey(request: request, sign: false) exitOkWithJson(response) } if (command == "compute_p256_ecsign") { let request = parseComputeP256EcSignRequest()!; let response = computeSecureEnclaveP256Ecsign(request: request) exitOkWithJson(response) } if (command == "compute_p256_ecdh") { let request = parseComputeEcdhRequest()!; let response = computeSecureEnclaveP256Ecdh(request: request) exitOkWithJson(response) } #if DISABLE_QPC #else if (command == "generate_mlkem768_ecdh_keypair") { let request = parseGenerateSecureEnclaveKeyPairRequest()!; exitOkWithJson(generateSecureEnclaveMlKemKeyPair(keyLen: 768, request: request)) } if (command == "generate_mlkem1024_ecdh_keypair") { let request = parseGenerateSecureEnclaveKeyPairRequest()!; exitOkWithJson(generateSecureEnclaveMlKemKeyPair(keyLen: 1024, request: request)) } if (command == "recover_mlkem768_public_key") { let request = parseRecoverSecureEnclavePublicKeyRequest()! let response = recoverSecureEnclaveMlKemPublicKey(request: request, keyLen: 768) exitOkWithJson(response) } if (command == "recover_mlkem1024_public_key") { let request = parseRecoverSecureEnclavePublicKeyRequest()! let response = recoverSecureEnclaveMlKemPublicKey(request: request, keyLen: 1024) exitOkWithJson(response) } if (command == "compute_mlkem768_ecdh") { let request = parseComputeEcdhRequest()!; let response = computeSecureEnclaveMlKemEcdh(request: request, keyLen: 768) exitOkWithJson(response) } if (command == "compute_mlkem1024_ecdh") { let request = parseComputeEcdhRequest()!; let response = computeSecureEnclaveMlKemEcdh(request: request, keyLen: 1024) exitOkWithJson(response) } #endif if (command == "external_spec") { exitOkWithJson(externalSpec()) } if (command == "external_public_key") { let request = parseExternalPublicKeyRequest()! let response = recoverSecureEnclaveP256PublicKey(request: request, sign: true)! exitOkWithJson(ExternalPublicKeyResponse(success: true, public_key_base64: response.public_key_base64)) } if (command == "external_sign") { let request = parseExternalSignRequest()!; let response = computeSecureEnclaveP256Ecsign(request: request) exitOkWithJson(response) } if (command == "version") { exitOkWithJson(VersionResponse(success: true, version: "2.0.1-20250724")) } if (command == "help" || command == "-h" || command == "--help") { print("swift-secure-enclave-tool-v2 [parameters]") print("help - print help") print("version - print version") print("is_support_secure_enclave - is Secure Enclave supported") print("generate_p256_ecsign_keypair --control-flag <> - generate Secure Enclave P256 EC sign key pair") print("generate_p256_ecdh_keypair --control-flag <> - generate Secure Enclave P256 EC DH key pair") print("recover_p256_ecsign_public_key --private-key <> - recover Secure Enclave P256 EC sign key pair") print("recover_p256_ecdh_public_key --private-key <> - recover Secure Enclave P256 EC DH key pair") print("compute_p256_ecsign --private-key <> --message-base64 <> [--message-type <>] - compure Secure Enclave P256 EC sign") print("compute_p256_ecdh --private-key <> --ephemera-public-key <> - compure Secure Enclave P256 EC DH") #if DISABLE_QPC #else print("generate_mlkem768_ecdh_keypair --control-flag <> - generate Secure Enclave ML-KEM-768 key pair") print("generate_mlkem1024_ecdh_keypair --control-flag <> - generate Secure Enclave ML-KEM-1024 key pair") print("recover_mlkem768_public_key --private-key <> - recover Secure Enclave ML-KEM-768 key pair") print("recover_mlkem1024_public_key --private-key <> - recover Secure Enclave ML-KEM-1024 key pair") print("compute_mlkem768_ecdh --private-key <> --ephemera-public-key <> - compure Secure Enclave ML-KEM-768") print("compute_mlkem1024_ecdh --private-key <> --ephemera-public-key <> - compure Secure Enclave ML-KEM-1024") #endif print("external_spec - external specification") print("external_public_key --parameter <> - external public key") print("external_sign --parameter <> --alg ES256 --message-base64 <> - external sign") print() print("options:") print("> --control-flag - none, userPresence, devicePasscode, biometryAny, biometryCurrentSet") print("> --private-key - private key representation (dataRepresentationBase64)") print("> --message-base64 - content in base64") print("> --message-type - sha256 or raw(default)") print("> --ephemera-public-key - public key der in base64") exit(0) } exitError("invalid command")