GithubHelp home page GithubHelp logo

agens-no / ellipticcurvekeypair Goto Github PK

View Code? Open in Web Editor NEW
703.0 703.0 114.0 255 KB

Sign, verify, encrypt and decrypt using the Secure Enclave

License: Other

Swift 98.93% Ruby 1.07%
elliptic-curves ios keychain keypair macos secure-enclave-processor security

ellipticcurvekeypair's People

Contributors

0xflotus avatar abjurato avatar alkalim avatar chylis avatar dependabot[bot] avatar dschuetz avatar dwbbytedance avatar haraldson avatar hfossli avatar hfossli-agens avatar keefertaylor avatar kostiakoval avatar raphschwander avatar tommyle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ellipticcurvekeypair's Issues

AccessControl for publicKey doesn't restrict to biometryCurrentSet flag

Hi,

I've found your helper is really useful. Despite, I couldn't understand the AccessControl for publicKey. When I set it to [.biometryCurrentSet, .privateKeyUsage] it doesn't ask me to authenticate with FaceID/TouchID when encrypting data.

Do you know why is it happening?

I believe there is no point to have those flags when create KeyPair manager, we can just provide AccessControl for privateKey.

Thanks,
Roman

concern about userPresence

The code is

EllipticCurveKeyPair.Device.hasSecureEnclave ? [.userPresence, .privateKeyUsage] : [.userPresence]

Will it be able to handle text passcode or should it be only Numeric value? (Other than FaceID if valid)

Not an issue

Turns out I was incorrect on this issue (even though I did check three times before posting).

Error when signing or decrypting on Simulator (iOS 13)

Hi!

If I run the demo project on a simulator on iOS 13, whenever I try to perform a signature or decryption I get this error:

Error: authentication(error: __C_Synthesized.related decl 'e' for LAError(_nsError: Error Domain=com.apple.LocalAuthentication Code=-1 "Found public key, but couldn't find or access private key. The errSecItemNotFound error is sometimes wrongfully reported when LAContext authentication fails" UserInfo={NSLocalizedFailureReason=Found public key, but couldn't find or access private key. The errSecItemNotFound error is sometimes wrongfully reported when LAContext authentication fails, NSUnderlyingError=0x600003c582a0 {Error Domain=NSOSStatusErrorDomain Code=-25300 "Could not get key for query: ["r_Ref": true, "u_OpPrompt": "Sign transaction", "labl": "no.agens.sign.private", "kcls": 1, "class": keys, "u_AuthCtx": <LAContext: 0x60000275a040>]" UserInfo={NSLocalizedRecoverySuggestion=See https://www.osstatus.com/search/results?platform=all&framework=all&search=-25300, NSLocalizedDescription=Could not get key for query: ["r_Ref": true, "u_OpPrompt": "Sign transaction", "labl": "no.agens.sign.private", "kcls": 1, "class": keys, "u_AuthCtx": <LAContext: 0x60000275a040>]}}}))

Can it be related to the discussion in this thread?
https://stackoverflow.com/questions/56700680/keychain-query-always-returns-errsecitemnotfound-after-upgrading-to-ios-13

Encryption on MacOS

I want to learn any encryption/decryption or generate keypair operation on MacOS which has Secure Enclave?

no prompts shown for face id auth on simulator

Thank you for great library. Learned a lot.

I am trying the sample on iOS simulator via XCode Version 10.1 (10B61). I configured Face ID in simulator. But I can't get Face ID prompt working for both sign or decrypt operations. Has anything changed recently in simulator behavior?

iOS device I selected in simulator: iPhoneXS Max
Xcode version: 10.1 (10B61)
Mac OSX version: macOS High Siera Version 10.13.6

Create a better API for handling various devices better

It should be easy to configure for

  • devices with SE & with passcode & with biometry
  • devices with SE & with passcode & without biometry
  • devices with SE & without passcode & with biometry (is this possible?)
  • devices with SE & without passcode & without biometry
  • devices without SE & with passcode
  • devices without SE & without passcode

Fallback to .applicationPassword etc should be easy to do and it should be hard to forget devices / setups.

#25

No prompts for Touch ID when accessing private key

It's probably me, but with master-code I experience the following problems:
I won't be prompted for touch-id, when accessing the private key. In addition to that the signature I am creating is different all the time (for the same digest).

So it seems that the private key isn't accessed at all - and the keypair is regenerated every time (therefore no prompt). Though the logs say: SecItemCopyMatching: ["kcls": 1, "class": keys, "labl": "my.key", "u_OpPrompt": "Auth", "u_AuthCtx": <LAContext: 0x1c5861900>, "r_Ref": true]

I followed your great tutorial, but didn't get it to work :(
https://github.com/agens-no/EllipticCurveKeyPair/blob/master/Demo-iOS/SignatureViewController.swift

Here is my code:

  struct KeyPair {
    static let manager: EllipticCurveKeyPair.Manager = {
      EllipticCurveKeyPair.logger = { print($0) }
      let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAlwaysThisDeviceOnly, flags: [])
      let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, flags: {
        return EllipticCurveKeyPair.Device.hasSecureEnclave ? [.userPresence, .privateKeyUsage] : [.userPresence]
      }())
      let config = EllipticCurveKeyPair.Config(
        publicLabel: "my.key.public",
        privateLabel: "my.key",
        operationPrompt: "Auth",
        publicKeyAccessControl: publicAccessControl,
        privateKeyAccessControl: privateAccessControl,
        token: .secureEnclaveIfAvailable)
      return EllipticCurveKeyPair.Manager(config: config)
    }()
  }

  var context: LAContext! = LAContext()

  DispatchQueue.global(qos: .background).async {
    do {
      let digest = givenDigest.data(using: .utf8)!
      signature = try KeyPair.manager.sign(digest, hash: .sha256, context: self.context)

      signature.base64EncodedString() // different every time
    } else {
      // ...
    }
  }

What am I doing wrong?

Signature validates locally but not on remote server

Hi, I wanto to use your library for my project which uses JSON Web Token
JWT = base64(header) + "." + base64(payload) + "." + base64(signature)

In the documentation of my project I have an example

eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJ0ZXN0dXNlcm5hbWUiLCJzdWIiOiJ0ZXN0Y2xpZW50aWQiLCJpYXQiOjE1MDE1MDk3ODIsImV4cCI6MTUwMTUwOTg0Mn0.SGNpyl3zRA_ptRhA0lFH0o7-nhf3mpxE95ss37_jHYbCnwlRb4zDvVaYCj9DlpppU4U0y3vIPEqM44vV2UZ5Iw

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7u8bg5nOOsxZvkdmK+Zcvx+byi93
iQ+lMWHsAcOaOAwbmcSU3lKEXKu3gp/ymiXUhIyFuw2Pkxfe7T1e4HSmqA==
-----END PUBLIC KEY-----

And when I paste that token here https://jwt.io/ with the public key - it validates.
However when I use your library to sign the header and payload I get info about invalid signature (on JWT page)

let signatureInput = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJ0ZXN0dXNlcm5hbWUiLCJzdWIiOiJ0ZXN0Y2xpZW50aWQiLCJpYXQiOjE1MDE1MDk3ODIsImV4cCI6MTUwMTUwOTg0Mn0"
let signature = createSignature(signatureInput)
let token = signatureInput + "." + signature


func createSignature(_ input: String) -> String {
        guard
            let data = input.data(using: .utf8),
            let signature = try? keysManager.sign(data, hash: .sha256)
        else {
            fatalError("Cannot create signature")
        }
        return signature.base64EncodedString(options: .init(rawValue: 0))
    }

The verification passes your method

do {
    try keysManager.verify(signature: Data(base64Encoded: signature)!,
         originalDigest: signatureInput.data(using: .utf8)!,
         hash: .sha256)
     print("valid")
}
catch {
     print("error \(error)")
}

Unbased content of header and payload are

header // eyJhbGciOiJFUzI1NiJ9
{
  "alg": "ES256"
}

payload // eyJpc3MiOiJ0ZXN0dXNlcm5hbWUiLCJzdWIiOiJ0ZXN0Y2xpZW50aWQiLCJpYXQiOjE1MDE1MDk3ODIsImV4cCI6MTUwMTUwOTg0Mn0
{
  "iss": "testusername",
  "sub": "testclientid",
  "iat": 1501509782,
  "exp": 1501509842
}

Am I doing something wrong with signing?

iOS 13+

Hi @hfossli-agens,

Thank you for creating this library. I have been using this in some of my projects.

I was wondering if you had an interest in bumping the minimum project version to iOS 13+ as this will allow the project to use CryptoKit and potentially simplify some parts of the library. I am happy to open a pr.

Here is an example of some improvements:

SHA256.swift: This whole file can be replaced with:

import Foundation
import CryptoKit

extension Data {
    func sha256() -> Data {
        Data(SHA256.hash(data: self))
    }
}

Device Token Type

After

import CryptoKit

public enum Token {
    case secureEnclave
    case keychain

    public static var secureEnclaveIfAvailable: Token {
        SecureEnclave.isAvailable ? .secureEnclave : .keychain
    }
}

Before

public enum Token {
    case secureEnclave
    case keychain
    
    public static var secureEnclaveIfAvailable: Token {
        return Device.hasSecureEnclave ? .secureEnclave : .keychain
    }
}

public enum Device {
    public static var hasTouchID: Bool {
        if #available(macOS 10.12.2, *) {
            var error: NSError?
            let result = LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
            EllipticCurveKeyPair.logger?(String(describing: error))
            return result
        } else {
            return false
        }
    }

    public static var isSimulator: Bool {
        return TARGET_OS_SIMULATOR != 0
    }

    public static var hasSecureEnclave: Bool {
        return hasTouchID && !isSimulator
    }   
}

Thanks!

Possible bug in encryptionEciesEdh: SecKeyAlgorithm?

I'm trying to figure out how to generate a message from another tool (right now, I'm working in python) and then decrypt it inside the demo app. In the process of working all this out (which is far more complicated and poorly-documented than I'd expected :( ), I may have found a pair of typos.

In the encryptionEciesEcdh: SecKeyAlgorithm switch statement, the algorithms returned for .sha256 and .sha384 seem to have been swapped. That is, case .sha256 returns SecKeyAlgorithm....SHA384AESGCM, while .sha384 returns ....SHA256AESGCM.

I want to export the public key as X.509 DER with proper ASN.1 header / structure

I need to export the public key as X.509 DER with proper ASN.1 header / structure

please give me an example.

I have a public key with format

-----BEGIN CERTIFICATE-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbEicao0J2djMo1Q3ECOuprI+XdZPJ13NeYyr1t/hp2VFe90SEAdv+LaJ6Qcffq7EdLUXCVekev7tBmAzEAU6FTYbjrWUeXFvsstWlUi+HfCowmRBzemCzMe7lzMiIZ49FTlVqxXHp2QWeummVHnZpLnzYSI/aQIZl9vf14cDKxQIDAQAB-----END CERTIFICATE-----

How to convert this in X.509 DER with proper ASN.1 header / structure

any help will be appreciated.
thanks

Better support for `operationPrompt`

Continuing the discussion from #17.

I think it is a good idea, but I am still conflicted. I don't want to make the API and code more complicated than it is.

I would love to just use the LAContext under the hood, but sadly the localizedReason property was introduced on iOS 11... Thus forcing us to instead send operationPrompt parameter all the way down to the query.

Example of what's needed to change.

Current code

public final class Manager {

    ...1
        
    public func privateKey(context: LAContext? = nil) throws -> PrivateKey {
        ...2
    }
    enum Prompt {
        case context(LAContext)
        case string(String)
    }

    public final class Manager {

        ...1
            
        public func privateKey(context: LAContext? = nil) throws -> PrivateKey {    
            return privateKey(prompt: .context(context))
        }

        public func privateKey(operationPrompt: String) throws -> PrivateKey {    
            return privateKey(prompt: .string(operationPrompt))
        }

        private func privateKey(prompt: Prompt) throws -> PrivateKey {    
            ...2 
            - let key = try helper.getPrivateKey(context: context)
            + let key = try helper.getPrivateKey(prompt: prompt)
        }

errSecItemNotFound after iCloud backup

Hi,
after a backup from one iPhone to other, my app, throw this exception:

> Found public key, but couldn't find or access private key. The errSecItemNotFound error is sometimes wrongfully reported when LAContext authentication fails

I can not understand what the problem is.
Some advice? thank you.

deinitialize() and deallocate() causing Compiler Error in SHA256.swift

Installed via cocoapods and got these errors when building:

'deinitialize()' is unavailable: the default argument to deinitialize(count:) has been removed, please specify the count explicitly
'deallocate(capacity:)' is unavailable: Swift currently only supports freeing entire heap blocks, use deallocate() instead

'deinitialize()' was obsoleted in Swift 5.0
'deallocate(capacity:)' was obsoleted in Swift 5.0

SecItemCopyMatching not works in iphone 12

I face issue with Face Id in some of iphone 12 pro and pro max the issue happen in SecKeyCreateSignature not generate signature but it works fine in different iphones like iphone 11.

even I cannot get the Face Id prompt.

my app not show in Face id & Passcode -> other apps.

In iphone 12 pro not in all device happen only a few devices.

Publish new version in CocoaPods?

Hi,

The last publish / tagged version of this library was in November 2017 and there's been a lot of updates and helpful functionality pushed since then. While Carthage will let me consume the library from head, CocoaPods won't let another Pod consume an arbitrary version of a library. Is it possible to publish a new version of this library in CocoaPods / Carthage?

You should just be able to update the version numbers in the podspec, run git tag and pod truck push.

Support application password

Hey, it's me again :-)

Still happily using the master-branch.
Lately, I wanted to try the application password method for devices that haven't set fingerprint or passcode.

I added the flag .applicationPassword resulting in: flags: EllipticCurveKeyPair.Device.hasSecureEnclave ? [.applicationPassword, .privateKeyUsage] : [.applicationPassword].

My understanding is, that I'd have to provide the actual password to the LAContext before key creation. Something like this:
context.setCredential("passwordFromServer".data(using:String.Encoding.utf8)!, type: LACredentialType.applicationPassword)

Though, I don't pass the LAContext to key creation. Regarding your API I can only provide it when decrypting or signing.

Create access control with only [.privateKeyUsage]

Hi, thanks for providing this library. Makes my live less complicated :)

I have a follow up question on the matter of issue #15: I do as you suggest (using only .privateKeyUsage as flags, which results in that error: throw EllipticCurveKeyPair.Error.inconcistency(message: "Couldn't create access control flag. Keychain chokes if you try to create access control with only [.privateKeyUsage] on devices older than iOS 11 and macOS 10.13.x")

Is that meant to throw? I'm running this on iOS 12+ (getting it actually on iOS 14) and am wondering whether this should only throw for the iOS / macOS versions mentioned in the crash description.

Commenting those lines out that check if only .privateKeyUsage is set, everything works fine...

That's my code:

static let manager: EllipticCurveKeyPair.Manager = {
            let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: [])
            let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: {
                return EllipticCurveKeyPair.Device.hasSecureEnclave ? [.privateKeyUsage] : []
            }())
            let config = EllipticCurveKeyPair.Config(
                publicLabel: "public",
                privateLabel: "private",
                operationPrompt: "",
                publicKeyAccessControl: publicAccessControl,
                privateKeyAccessControl: privateAccessControl,
                token: .secureEnclaveIfAvailable)
            return EllipticCurveKeyPair.Manager(config: config)
        }()

Originally posted by @b00tsy in #15 (comment)

How to use ECKeyPair without local authentication

Not a bug report but rather a usage question:

I'd like to generate a key pair that is stored in the enclave, except where the private key can be used whenever the genuine app is running to sign/encrypt data, no local auth required. Could you provide guidance on the best way to achieve this?

iPad Mini 2 Crash

I'm getting a crash when trying to generate keys on an iPad Mini 2 running 11.0.0 with the log:

crash_info_entry_0
Fatal error: 'try!' expression unexpectedly raised an error: EllipticCurveKeyPair.EllipticCurveKeyPair.Error.underlying(message: "Could not generate keypair. Security probably doesn't like the access flags you provided. Specifically if this device doesn't have secure enclave and you pass .privateKeyUsage. it will produce this error.", error: Error Domain=NSOSStatusErrorDomain Code=-25293 "Could not generate keypair. Security probably doesn't like the access flags you provided. Specifically if this device doesn't have secure enclave and you pass .privateKeyUsage. it will produce this error." UserInfo={NSLocalizedRecoverySuggestion=See https://www.osstatus.com/search/results?platform=all&framework=all&search=-25293, NSLocalizedDescription=Could not generate keypair. Security probably doesn't like the access flags you provided. Specifically if this device doesn't have secure enclave and you pass .privateKeyUsage. it will produce this error.}): file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-902.0.48/src/swift/stdlib/public/core/ErrorType.swift, line 184

This device does not have touchID from what I see, so I guess also no secure enclave?

The config I'm using is:

static let handler: EllipticCurveKeyPair.Manager = { EllipticCurveKeyPair.logger = { DDLogDebug($0) } let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAlwaysThisDeviceOnly, flags: []) let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: { return EllipticCurveKeyPair.Device.hasSecureEnclave ? [.userPresence, .privateKeyUsage] : [.userPresence] }()) let config = EllipticCurveKeyPair.Config( publicLabel: PUBLIC_KEY_LABEL, privateLabel:PRIVATE_KEY_LABEL, operationPrompt: "Decrypt message", publicKeyAccessControl: publicAccessControl, privateKeyAccessControl: privateAccessControl, token: .secureEnclaveIfAvailable) return EllipticCurveKeyPair.Manager(config: config) }()

Running latest commit of master.

Is secp256k1 curve supported?

I have generated the public and private keys of the secp256k1 curve. Currently, I only need to use the generated public and private keys to encrypt data with ECC encryption. Does the library support this?

Document how to use on macOS

Can't quite get the basic examples working on macOS, it's complaining about the parameters being incorrect.

I'll update here my findings when I figure it out.

Deprecation Warnings and Making export() Method of PublicKey Public

First, THANK YOU for developing this library. We used it to develop a
VPN solution for our company.

While working with EllipticCurveKeyPair.swift, We noticed that there
are several places where the code now generates deprecation warnings.
Also, the export() method of the PublicKey class is marked private.
For our application, I needed to export the public key to generate a
CSR. I can't think of a reason why this method should be private.

I would be happy to provide a PR for these issues. I thought it would
be more friendly to start with an issue (instead of doing a drive by
PR).

iOS 13 and CryptoKit

Apple seems to have broken Security.framework in iOS 13+ simulators, while at the same releasing CryptoKit as a standard way of doing crypto operations, limited to iOS 13 and higher.

It would be really nice if the library could transparently implement operations with Cryptokit where available while keeping the same pleasant API.

Sign twice strings

Hello,

How can I sign two strings like (blaBla1) then (BlaBla2) in one call of

Shared.keypair.sign(digest, hash: .sha256) and return two signatures

Thank you in advance?

Dismiss TouchID authentication

Hi

I am not sure if this is possible.
Can we cancel TouchID authentication happening on decrypt operation if we dont want to proceed?
LAContext has a method "invalidate" which invalidates LAContext and throws LAErrorAppCancel error.

e.g. We prompt user to authenticate using TouchID as soon as app is opened. We also make a background call to check if user is running on latest app.
If user is running on old version then we cancel TouchID operation and show a message which says "Please update app to latest version."

LAContext passed when decrypting will not be respected

I'd like to decrypt multiple things in a short amount of time. I don't want to prompt the user for authentication every time.

I am aware of the bug concerning touchIDAuthenticationAllowableReuseDuration (#9). Though I'd like to use the default time-limit (10 minutest) when passing an already authentified LAContext.

When passing the LAContext I am still prompted for authentication. I guess that's because the context is not regarded by the library:

@available(iOS 10.3, *) // API available at 10.0, but bugs made it unusable on versions lower than 10.3
public func decrypt(_ encrypted: Data, hash: Hash = .sha256, context: LAContext? = nil) throws -> Data {
  return try helper.decrypt(encrypted, privateKey: privateKey(), hash: hash)
}

Document (in comments or notes) signature algorithm

ecdsaSignatureDigestX962SHA256 is used to sign data; however, it appears to sign data that has already been digested into sha-256.

We should document what's going on here (double digest?) and also how to verify it in OpenSSL. The demo app outputs some weird code to do with hexdumps and simple sha256 verification, as opposed to OpenSSL's -ecdsa-with-SHA1 (I think this is something I don't personally understand about crypto, so it's my problem, but I'd like to elucidate it further).

Authenticate only with Biometrics

Im trying to authenticate only with biometric with no passcode but, just like context .deviceOwnerAuthenticationWithBiometrics., but no success.
Always when the Touch ID fails, show the modal with the possibility to enter code.

"Could not generate keypair." when running on simulator

Hi! :)

thanks for developing and maintaining this library - this is great!

I just added some code to generate a keypair and sign a digest with it. While this works perfectly on my device (using secure enclave), I have some trouble getting it to run on simulator (using the keychain).

I get this error:

underlying(message: "Could not generate keypair.", error: Error Domain=NSOSStatusErrorDomain Code=-25293 "Could not generate keypair." UserInfo={NSLocalizedRecoverySuggestion=See https://www.osstatus.com/search/results?platform=all&framework=all&search=-25293, NSLocalizedDescription=Could not generate keypair.})

Here is my code:

struct KeyPair {
  static let manager: EllipticCurveKeyPair.Manager = {
    let publicAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAlwaysThisDeviceOnly, flags: [])
    let privateAccessControl = EllipticCurveKeyPair.AccessControl(protection: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, flags: [.userPresence, .privateKeyUsage])
    let config = EllipticCurveKeyPair.Config(
      publicLabel: "n.sign.public",
      privateLabel: "n.sign.private",
      operationPrompt: "N SecureElement",
      publicKeyAccessControl: publicAccessControl,
      privateKeyAccessControl: privateAccessControl,
      publicKeyAccessGroup: nil,
      privateKeyAccessGroup: nil,
      fallbackToKeychainIfSecureEnclaveIsNotAvailable: true
    )
    return EllipticCurveKeyPair.Manager(config: config)
  }()
}

and

do {
      let digest = "some_digest".data(using: .utf8)!
      signature = try KeyPair.manager.sign(digest)
} catch {
...
}

Any ideas what I am doing wrong?
Thank you.

Access control is not respected

Hi,
I faced issues when using your code with a kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly protection level.

        let protection = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
        let config = EllipticCurveKeyPair.Config(
            publicLabel: self.publicLabel,
            privateLabel: self.privateLabel,
            operationPrompt: "",
            accessControl: try! SecAccessControl.create(protection: protection, flags: [.privateKeyUsage]),
            fallbackToKeychainIfSecureEnclaveIsNotAvailable: true)
        return EllipticCurveKeyPair.Manager(config: config)

If you lock the device, wait a few seconds (10+), and you try to decrypt (I found it useful to trigger the decrypt method with a notification), you get this error:

decode keys,rowid=760 failed (-25308): Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 6, bag: 0) Access to item attempted while keychain is locked." UserInfo={NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 6, bag: 0) Access to item attempted while keychain is locked.}

Class 6 is: kSecAttrAccessibleWhenUnlocked (see this thread on SO)

The item should not belong to Class 6.

I managed to solve this issue by applying this change:

        static func forceSavePublicKey(_ publicKey: PublicKey, label: String) throws {
            // I will create a SecAccessControl
            var error: Unmanaged<CFError>?
            
            let sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, [], &error)
            //
            
            let query: [String: Any] = [
                kSecClass as String: kSecClassKey,
                kSecAttrLabel as String: label,
                kSecValueRef as String: publicKey.underlying,
                /* I will apply the SecAccessControl object to the public key */
                kSecAttrAccessControl as String: sacObject!,
            ]
            
            var raw: CFTypeRef?
            var status = SecItemAdd(query as CFDictionary, &raw)
            if status == errSecDuplicateItem {
                status = SecItemDelete(query as CFDictionary)
                status = SecItemAdd(query as CFDictionary, &raw)
            }
            guard status == errSecSuccess else {
                throw Error.osStatus(message: "Could not save public key", osStatus: status)
            }
        }
    } 

This is a rough patch, imho you should re-use what you already have in the Config object.

Can I export the EC Private key ?

I need to export the EC Private Key as I need to send the private key to my server in encrypted format?
Any help is appreciated. Thanks

Demo Project Error

Getting an error in the init for the Manager class. The how do you pass the config to the Helper method?

EllipticCurveKeyPair.swift:99:42: Argument passed to call that takes no arguments
self.helper = Helper(config: config)

Should we drop iOS 9 support

Let me know in comments or with reactions what you prefer

๐Ÿ‘ = drop support (minimum required iOS version will be 10)
๐Ÿ‘Ž = please support iOS 9

Encrypting messages using CLI Open SSL

I'm playing around with both signing and ecrypting. The example project provides a way to verify signatures using openssl (by printing the statements in the debug log), which is working perfectly fine in the POC i'm working on.

I was wondering if you can assist in doing the same for encrypting messages using the public key from the device. Can openssl CLI encrypt messages which the device can decrypt using it's private key (which is stored in the secure enclave)?

Thanks in advance

Jim

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.