diff --git a/swift-secure-enclave-tool.swift b/swift-secure-enclave-tool.swift index c72d1cd..06d1c8f 100644 --- a/swift-secure-enclave-tool.swift +++ b/swift-secure-enclave-tool.swift @@ -42,22 +42,165 @@ func generateSecureEnclaveP256KeyPair(sign: Bool) -> String { } } +func recoverSecureEnclaveP256PublicKeyEcsign(privateKeyDataRepresentation: String) -> String { + return recoverSecureEnclaveP256PublicKey(privateKeyDataRepresentation: privateKeyDataRepresentation, sign: true); +} + +func recoverSecureEnclaveP256PublicKey(privateKeyDataRepresentation: String, sign: Bool) -> String { + guard let privateKeyDataRepresentation = Data( + base64Encoded: privateKeyDataRepresentation + ) else { + return "err:private key base64 decode failed" + } + do { + let context = LAContext(); + if (sign) { + let privateKeyReference = try SecureEnclave.P256.Signing.PrivateKey( + dataRepresentation: privateKeyDataRepresentation, + authenticationContext: context + ) + let publicKeyBase64 = privateKeyReference.publicKey.x963Representation.base64EncodedString() + let publicKeyPem = privateKeyReference.publicKey.derRepresentation.base64EncodedString() + let dataRepresentationBase64 = privateKeyReference.dataRepresentation.base64EncodedString() + return "ok:\(publicKeyBase64),\(publicKeyPem),\(dataRepresentationBase64)" + } else { + let privateKeyReference = try SecureEnclave.P256.KeyAgreement.PrivateKey( + dataRepresentation: privateKeyDataRepresentation, + authenticationContext: context + ) + let publicKeyBase64 = privateKeyReference.publicKey.x963Representation.base64EncodedString() + let publicKeyPem = privateKeyReference.publicKey.derRepresentation.base64EncodedString() + let dataRepresentationBase64 = privateKeyReference.dataRepresentation.base64EncodedString() + return "ok:\(publicKeyBase64),\(publicKeyPem),\(dataRepresentationBase64)" + } + } catch { + return "err:\(error)" + } +} + +func computeSecureEnclaveP256Ecsign(privateKeyDataRepresentation: String, content: String) -> String { + guard let privateKeyDataRepresentation = Data( + base64Encoded: privateKeyDataRepresentation + ) else { + return "err:private key base64 decode failed" + } + guard let contentData = Data( + base64Encoded: content + ) else { + return "err:content base64 decode failed" + } + do { + let context = LAContext(); + let p = try SecureEnclave.P256.Signing.PrivateKey( + dataRepresentation: privateKeyDataRepresentation, + authenticationContext: context + ) + + let digest = SHA256.hash(data: contentData) + let signature = try p.signature(for: digest) + + return "ok:\(signature.derRepresentation.base64EncodedString())" + } catch { + return "err:\(error)" + } +} + +func computeSecureEnclaveP256Ecdh(privateKeyDataRepresentation: String, ephemeraPublicKey: String) -> String { + guard let privateKeyDataRepresentation = Data( + base64Encoded: privateKeyDataRepresentation + ) else { + return "err:private key base64 decode failed" + } + guard let ephemeralPublicKeyRepresentation = Data( + base64Encoded: ephemeraPublicKey + ) else { + return "err:ephemeral public key base64 decode failed" + } + 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) + + return "ok:\(sharedSecret.description)" + } catch { + return "err:\(error)" + } +} + +func exitWith(response: String) { + print(response); + if (response.hasPrefix("ok:")) { + exit(0) + } else { + exit(1) + } +} + + if (CommandLine.arguments.count == 1) { - print("err:requireArguments") - exit(1) + exitWith(response: "err:require one argument") } let action = CommandLine.arguments[1]; -if (action == "checkSecureEnclaveEnabled") { - print("ok:\(isSupportSecureEnclave())") - exit(0); +if (action == "is_support_secure_enclave") { + exitWith(response: "ok:\(isSupportSecureEnclave())") } -if (action == "generateSecureEnclaveP256SingingKeyPair") { - print(generateSecureEnclaveP256KeyPair(sign: true)) - exit(0); +if (action == "generate_secure_enclave_p256_ecsign_keypair") { + exitWith(response: generateSecureEnclaveP256KeyPair(sign: true)) } -print("err:unknownAction") +if (action == "generate_secure_enclave_p256_ecdh_keypair") { + exitWith(response: generateSecureEnclaveP256KeyPair(sign: false)) +} + +if (action == "recover_secure_enclave_p256_ecsign_public_key") { + if (CommandLine.arguments.count != 3) { + exitWith(response: "err:require two arguments") + } + let response = recoverSecureEnclaveP256PublicKey( + privateKeyDataRepresentation: CommandLine.arguments[2], sign: true); + exitWith(response: response) +} + +if (action == "recover_secure_enclave_p256_ecdh_public_key") { + if (CommandLine.arguments.count != 3) { + exitWith(response: "err:require two arguments") + } + let response = recoverSecureEnclaveP256PublicKey( + privateKeyDataRepresentation: CommandLine.arguments[2], sign: false); + exitWith(response: response) +} + +if (action == "compute_secure_enclave_p256_ecsign") { + if (CommandLine.arguments.count != 4) { + exitWith(response: "err:require three arguments") + } + let response = computeSecureEnclaveP256Ecsign( + privateKeyDataRepresentation: CommandLine.arguments[2], + content: CommandLine.arguments[3] + ); + exitWith(response: response) +} + +if (action == "compute_secure_enclave_p256_ecdh") { + if (CommandLine.arguments.count != 4) { + exitWith(response: "err:require three arguments") + } + let response = computeSecureEnclaveP256Ecdh( + privateKeyDataRepresentation: CommandLine.arguments[2], + ephemeraPublicKey: CommandLine.arguments[3] + ); + exitWith(response: response) +} + +print("err:unknown action") exit(1) \ No newline at end of file