{"id":13588373,"url":"https://github.com/agens-no/EllipticCurveKeyPair","last_synced_at":"2025-04-08T03:33:45.077Z","repository":{"id":17438336,"uuid":"81981636","full_name":"agens-no/EllipticCurveKeyPair","owner":"agens-no","description":"Sign, verify, encrypt and decrypt using the Secure Enclave","archived":false,"fork":false,"pushed_at":"2022-07-22T08:59:43.000Z","size":255,"stargazers_count":715,"open_issues_count":28,"forks_count":120,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-04-03T14:13:00.659Z","etag":null,"topics":["elliptic-curves","ios","keychain","keypair","macos","secure-enclave-processor","security"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agens-no.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-14T19:35:33.000Z","updated_at":"2025-03-14T09:07:17.000Z","dependencies_parsed_at":"2022-08-20T19:50:37.326Z","dependency_job_id":null,"html_url":"https://github.com/agens-no/EllipticCurveKeyPair","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agens-no%2FEllipticCurveKeyPair","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agens-no%2FEllipticCurveKeyPair/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agens-no%2FEllipticCurveKeyPair/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agens-no%2FEllipticCurveKeyPair/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agens-no","download_url":"https://codeload.github.com/agens-no/EllipticCurveKeyPair/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247772763,"owners_count":20993627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elliptic-curves","ios","keychain","keypair","macos","secure-enclave-processor","security"],"created_at":"2024-08-01T15:06:40.312Z","updated_at":"2025-04-08T03:33:44.785Z","avatar_url":"https://github.com/agens-no.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"Elliptic Curve Key Pair\n=======================\n\nSign, verify, encrypt and decrypt using the Secure Enclave on iOS and MacOS.\n\n![](https://raw.githubusercontent.com/wiki/agens-no/EllipticCurveKeyPair/iphonex-decrypt-w-background.gif)\n\n![macOS 10.12.1 support](https://img.shields.io/badge/macOS-10.12.1%2B-brightgreen.svg)\n![iOS 9 support](https://img.shields.io/badge/iOS-9.0%2B-brightgreen.svg)\n![Swift 3 and 4 support](https://img.shields.io/badge/swift-3%20|%204-brightgreen.svg)\n![Carthage compatible](https://img.shields.io/badge/carthage-compatible-brightgreen.svg)\n![Cocoapods compatible](https://img.shields.io/badge/cocoapods-compatible-brightgreen.svg)\n\n## Features\n\n- create a private public keypair\n- store the private key on the secure enclave\n- store the public key in keychain\n- each time you use the private key the user will be prompted with FaceID, TouchID, device pass code or application password\n- export the public key as X.509 DER with proper ASN.1 header / structure\n- verify the signature with openssl in command line easily\n\nSupports FaceID, TouchID, device pass code and application password.\n\n\n## About\n\nUsing the Security Framework can be a little bit confusing. That’s why I created this. You may use it as example code and guidance or you may use it as a micro framework.\n\nI found it tricky to figure out how to use the `SecKeyRawVerify`, `SecKeyGeneratePair` and `SecItemCopyMatching` C APIs in Swift 3, but the implementation is quite straight forward thanks to awesome Swift features.\n\n\n\n## Installation\n\n#### Manual\n\nJust drag [`Sources/EllipticCurveKeyPair.swift`](Sources/EllipticCurveKeyPair.swift) and [`Sources/SHA256.swift`](Sources/SHA256.swift) file into your Xcode project.\n\n#### Cocoapods\n\n```ruby\npod EllipticCurveKeyPair\n```\n\n#### Carthage\n\n```ruby\ngithub \"agens-no/EllipticCurveKeyPair\"\n```\n\n\n## Use cases\n\nThere are lots of great possibilities with Secure Enclave. Here are some examples\n\n### Encrypting\n\n1. Encrypt a message using the public key\n1. Decrypt the message using the private key – only accessible with FaceID / TouchID / device pin\n\nOnly available on iOS 10 and above\n\n### Signing\n\n1. Sign some data received by server using the private key – only accessible with FaceID / TouchID / device pin\n1. Verify that the signature is valid using the public key\n\nA use case could be\n\n1. User is requesting a new agreement / purchase\n1. Server sends a push with a session token that should be signed\n1. On device we sign the session token using the private key - prompting the user to confirm with touch id\n1. The signed token is then sent to server\n1. Server already is in possession of the public key and verifies the signature using the public key\n1. Server is now confident that user signed this agreement with touch id\n\n\n\n## Examples\n\nFor more examples see demo app.\n\n### Creating a keypair manager\n\n```swift\nstruct KeyPair {\n    static let manager: EllipticCurveKeyPair.Manager = {\n        let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAlwaysThisDeviceOnly, flags: [])\n        let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: [.userPresence, .privateKeyUsage])\n        let config = EllipticCurveKeyPair.Config(\n            publicLabel: \"payment.sign.public\",\n            privateLabel: \"payment.sign.private\",\n            operationPrompt: \"Confirm payment\",\n            publicKeyAccessControl: publicAccessControl,\n            privateKeyAccessControl: privateAccessControl,\n            token: .secureEnclave)\n        return EllipticCurveKeyPair.Manager(config: config)\n    }()\n}\n```\n\nYou can also gracefully fallback to use keychain if Secure Enclave is not available by using different access control flags:\n```swift\nlet privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: {\n    return EllipticCurveKeyPair.Device.hasSecureEnclave ? [.userPresence, .privateKeyUsage] : [.userPresence]\n}())\n```\n\nIn that case you need to remember to set `token` variable in `Config` object to `.secureEnclaveIfAvailable`.\n\n### Getting the public key in DER format\n\n```swift\ndo {\n    let key = try KeyPair.manager.publicKey().data().DER // Data\n} catch {\n    // handle error\n}\n```\nSee demo app for working example\n\n### Getting the public key in PEM format\n\n```swift\ndo {\n    let key = try KeyPair.manager.publicKey().data().PEM // String\n} catch {\n    // handle error\n}\n```\n\n### Signing\n\n```swift\ndo {\n    let digest = \"some text to sign\".data(using: .utf8)!\n    let signature = try KeyPair.manager.sign(digest, hash: .sha256)\n} catch {\n    // handle error\n}\n```\nYou may also pass a LAContext object when signing\n\n### Encrypting\n\n```swift\ndo {\n    let digest = \"some text to encrypt\".data(using: .utf8)!\n    let encrypted = try KeyPair.manager.encrypt(digest, hash: .sha256)\n} catch {\n    // handle error\n}\n```\n\n### Encrypting on a different device/OS/platform\n\nYou can also encrypt on a different device/OS/platform using the public key. If you want to know all the details about how to encrypt in a format the Secure Enclave understands, then you need definitely need to read this great write up by [@dschuetz](https://github.com/dschuetz)!\n\nhttps://darthnull.org/security/2018/05/31/secure-enclave-ecies/\n\n### Decrypting\n\n```swift\ndo {\n    let encrypted = ...\n    let decrypted = try KeyPair.manager.decrypt(encrypted, hash: .sha256)\n    let decryptedString = String(data: decrypted, encoding: .utf8)\n} catch {\n    // handle error\n}\n```\nYou may also pass a LAContext object when decrypting\n\n## Error handling\n\nThe most common thing is to catch error related to\n- Secure Enclave not being available\n- User cancels fingerprint dialog\n- No fingerprints enrolled\n\nWith `do/catch`:\n```swift\ndo {\n    let decrypted = try KeyPair.manager.decrypt(encrypted)\n} catch EllipticCurveKeyPair.Error.underlying(_, let underlying) where underlying.code == errSecUnimplemented {\n    print(\"Unsupported device\")\n} catch EllipticCurveKeyPair.Error.authentication(let authenticationError) where authenticationError.code == .userCancel {\n    print(\"User cancelled/dismissed authentication dialog\")\n} catch {\n    print(\"Some other error occurred. Error \\(error)\")\n}\n```\n\nWith `if let`:\n```swift\nif case let EllipticCurveKeyPair.Error.underlying(_, underlying) = error, underlying.code == errSecUnimplemented {\n    print(\"Unsupported device\")\n} else if case let EllipticCurveKeyPair.Error.authentication(authenticationError), authenticationError.code == .userCancel {\n  print(\"User cancelled/dismissed authentication dialog\")\n} else {\n  print(\"Some other error occurred. Error \\(error)\")\n}\n```\n\n\n## Debugging\n\nIn order to inspect the queries going back and forth to Keychain you may print to console every mutation this library does on Keychain like this\n```swift\nEllipticCurveKeyPair.logger = { print($0) }\n```\n\n\n\n## Verifying a signature\n\nIn the demo app you’ll see that each time you create a signature some useful information is logged to console.\n\nExample output\n\n```sh\n#! /bin/sh\necho 414243 | xxd -r -p \u003e dataToSign.dat\necho 3046022100842512baa16a3ec9b977d4456923319442342e3fdae54f2456af0b7b8a09786b022100a1b8d762b6cb3d85b16f6b07d06d2815cb0663e067e0b2f9a9c9293bde8953bb | xxd -r -p \u003e signature.dat\ncat \u003e key.pem \u003c\u003cEOF\n-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdDONNkwaP8OhqFTmjLxVcByyPa19\nifY2IVDinFei3SvCBv8fgY8AU+Fm5oODksseV0sd4Zy/biSf6AMr0HqHcw==\n-----END PUBLIC KEY-----\nEOF\n/usr/local/opt/openssl/bin/openssl dgst -sha256 -verify key.pem -signature signature.dat dataToSign.dat\n```\n\nIn order to run this script you can\n\n1. Paste it in to a file: `verify.sh`\n1. Make the file executable: `chmod u+x verify.sh`\n1. Run it: `./verify.sh`\n\nThen you should see\n```sh\nVerified OK\n```\n\nPS: This script will create 4 files in your current directory.\n\n\n\n## Keywords\nSecurity framework, Swift 3, Swift 4, Swift, SecKeyRawVerify, SecKeyGeneratePair, SecItemCopyMatching, secp256r1, Elliptic Curve Cryptography, ECDSA, ECDH, ASN.1, Apple, iOS, Mac OS, kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyTypeEC, kSecAttrTokenIDSecureEnclave, LAContext, LocalAuthentication, FaceID, Face ID, TouchID, Touch ID, Application Password, Device Pin, Devicepin\n\n\n\n## Acknowledgements and credits\n\n### TrailOfBits\n\n[TrailOfBits](https://github.com/trailofbits/) published some objective-c code a while back which was to great help! Thanks for [sharing](https://blog.trailofbits.com/2016/06/28/start-using-the-secure-enclave-crypto-api/) Tidas and [SecureEnclaveCrypto](https://github.com/trailofbits/SecureEnclaveCrypto). They also got some other most interesting projects. Check them out!\n\n### Quinn “the Eskimo!”, Apple\n\nHe shared som [very valuable insights](https://forums.developer.apple.com/message/84684#84684) with regards to exporting the public key in the proper DER X.509 format.\n\n### SHA256\n\nThe `SHA256` class (originally `SHA2.swift`) is found in the invaluable [CryptoSwift](https://github.com/krzyzanowskim/CryptoSwift) library by [Marcin Krzyżanowski](http://www.krzyzanowskim.com/). The class has been heavily altered in order to strip it down to its bare minimum for what we needed in this project.\n\n\n\n## FAQ\n\n**Why am I not being prompted with touch id / device pin on simulator?**  \n\u003e The simulator doesn’t possess any secure enclave and therefore trying to access it would just lead to errors. If you set `fallbackToKeychainIfSecureEnclaveIsNotAvailable` to `true` then the private key will be stored in keychain on simulator making it easy to test your application on simulator as well.\n\n**Where can I learn more?**  \n\u003e Check out this video on [WWDC 2015](https://developer.apple.com/videos/play/wwdc2015/706/) about Security in general or [click here](https://developer.apple.com/videos/play/wwdc2015/706/?time=2069) to skip right to the section about the Secure Enclave.\n\n**Why is it wrapped in an enum?**\n\u003e I try to balance drag-and-drop the files you need into xcode and supporting dependency managers like carthage and cocoapods at the same time. If you have better ideas or don't agree with this decision I'm happy to discuss alternatives :)\n\n\n\n## Feedback\n\nWe would 😍 to hear your opinion about this library. Wether you like or don’t. Please file an issue if there’s something you would like to see improved. You can reach me as [@hfossli](https://twitter.com/hfossli) on twitter and elsewhere. 😀\n\n[\u003cimg src=\"http://static.agens.no/images/agens_logo_w_slogan_avenir_medium.png\" width=\"340\" /\u003e](http://agens.no/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagens-no%2FEllipticCurveKeyPair","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagens-no%2FEllipticCurveKeyPair","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagens-no%2FEllipticCurveKeyPair/lists"}