trailofbits / SecureEnclaveCrypto

Demonstration library for using the Secure Enclave on iOS
Apache License 2.0
279 stars 41 forks source link

Add ECIES encryption and decryption support. #10

Closed iangcarroll closed 7 years ago

iangcarroll commented 7 years ago

The decryption API only works on iOS 10.3 and above. I was told it being broken was a bug (rdar://problem/29438764), and it appears to work in the latest beta.

Usage is pretty straightforward:

let encrypted = try Manager.shared.encrypt("Hello!".data(using: .utf8)!)
let decrypted = try Manager.shared.decrypt(encrypted) // "Hello!"

Uses SHA256 for the KDF which should be a sane default.

hfossli commented 7 years ago

Hey! Thanks for sending this pull request.

The decryption API only works on iOS 10.3 and above. I was told it being broken was a bug (rdar://problem/29438764), and it appears to work in the latest beta.

Can you tell me more about this?

withzombies commented 7 years ago

nice @iangcarroll. I didn't know they added this API. It seems like Apple really wants to make the SE comparable to HSMs.

Since it's not available in the latest production release (10.2). Could you add #available guards around the feature?

iangcarroll commented 7 years ago

Can you tell me more about this?

SecKeyCreateDecryptedData was returning an unsupported operation error, so I used a technical support incident to report it and ask if it was a bug. They confirmed SecKeyCreateDecryptedData should work with Secure Enclave keys and that the error was a bug. iOS 10.3 fixes the bug, and SecKeyCreateDecryptedData can now decrypt data encrypted against a SEP-backed key.

Technically, I've been told you can still do ECDH with a SEP key in previous iOS versions, so you could do ECIES yourself. But that would be pretty annoying.

Since it's not available in the latest production release (10.2). Could you add #available guards around the feature?

Sure; didn't know that was a thing.

hfossli commented 7 years ago

I have very little knowledge about security and elliptic curves etc etc. Even though there's a lot of material about ECDH, ECIES and friends on internet I find it hard to comprehend. When is it useful to encrypt and decrypt? Is it used in combination with signature? Or is the server encrypting with public key and client decrypting with private key? Maybe demo project or readme should describe its use case in some way.

iangcarroll commented 7 years ago

My knowledge about this is a bit high level, but I'll try to explain. ECIES is essentially how you can encrypt data with an elliptic curve key. There is no "native" encryption functionality with elliptic curves like there is with RSA. But you have ECDH, a key exchange that allows you to generate a shared secret from two keypairs (a public key from a distinct keypair and a private key from a distinct keypair).

ECIES essentially creates a random key, K2, and performs ECDH against it with your key, K1: ECDH(K1_Private, K2_Public). Here, the ECDH operation happens in the Secure Enclave. This generates a shared secret which is fed into something like AES as a symmetric key. You save the public part of K2 along with your encrypted data and discard its private key.

When you want to decrypt it, you again perform ECDH against the saved public key with your private key, which gives you the symmetric key previously used for AES.

ECIES does a few other things, like running the shared secret through a KDF, but that is the gist.

This would allow an iOS app to, as an example, encrypt your username and password before it is saved to the filesystem, though this is already possible via other means.

iangcarroll commented 7 years ago

I'll try to make a PR that adds some documentation, and also fixes the variable names in this commit (I forgot to change them from digest).

hfossli commented 7 years ago

Awesome :)

hfossli commented 7 years ago

Is it possible to export a public key which can be used to encrypt server side and then decrypt locally on device with the private key? How should that key be exported?

iangcarroll commented 7 years ago

Yes, if you know the device public key you can perform ECIES with it on your server. You would then send the encrypted blob and the second public key you generated for ECIES to the device.

In practice, this is tricky, because I don't know if SecKeyCreateEncryptedData uses a standard output format (in other words, how does your server format the data when it's passed to SecKeyCreateDecryptedData). If it doesn't, and you don't figure out how to save your data according to its format, you will have to completely re-implement ECIES, which is a bit of a minefield.

hukl commented 7 years ago

@hfossli I think if you're at that stage, that you want to use ECIES/EC* with a API or backend you for a communication session, you should use TLS directly rather than re-implementing it yourself. For crypting small chunks/messages which are not session based the simpler RSA is more suitable - or in theory something like GPG I guess.

iangcarroll commented 7 years ago

Well, this repository is about the Secure Enclave, which supports a total of one ECC curve, so RSA is out of the question in that context. But I agree TLS is a good idea for many use cases.

hfossli commented 7 years ago

Yep, I agree, but would be awesome to know how to decrypt a message only available with biometry. Maybe there's no real use case for this (that the server encrypts)?

Basically what I'm asking is how can I with openssl cli do this serverside?

let result = SecKeyCreateDecryptedData(privateKey.underlying, SecKeyAlgorithm.eciesEncryptionStandardX963SHA256AESGCM, digest as CFData, &error)