Disclaimer: This is a PoC of an SGX-based application, but is insecure as it is. To build secure SGX-based applications, you'll need to perform the remote attestation step after being approved as an SGX licensee. Even if you managed to get an attested release-mode enclave from our code you shouldn't use it to protect real stuff; neither the architecture nor the code have been properly reviewed, hence they're probably not secure.
SGX-reencrypt is an SGX-based application that performs symmetric-key proxy reencryption: SGX-reencrypt runs as a service that receives encrypted requests containing
-
A nonce
N
unique for this request -
A ciphertext
C
encrypted and authenticated with key with key idi
-
The key id
i
of the original ciphertext -
A key id
j
for the new ciphertext
The SGX-reencrypt service then
- Decrypts and verifies the request
- Verifies that the policy allows to reencrypt from key id
i
to key idj
. Upon failure, returnsN || 0x01 || C
- Decrypt and verifies the ciphertext
C
using key with key idi
, returning a plaintextP
. Upon failure, returnsN || 0x02 || C
- Encrypt and authenticate
P
using key idj
to get a ciphertextC0
, returnsN || 0x00 || C0
Requests are encrypted using the crypto_box()
function from TweetNaCl
(public-key authenticated encryption). Plaintexts are encrypted using
AES-GCM.
Responses are encrypted too using crypto_box()
, and error responses
include C
to make them indistinguishable from success responses.
This assumes that keys and a policy have been sealed to the reencrypt enclave, as well as the enclave's Curve25519 private key.
A enclave's TweetNaCl keypair needs to be generated before using it.
The enclave provides the trusted call generate_keypair
, that will
generate a new keypair and output the public key on success. This
information can be sealed to the filesystem using the trusted call
seal_keypair
. After service restart, unseal_keypair
will try to
recover the previously sealed keypair.
Once an enclave keypair has been generated, the returned public key can be distributed amongst clients; it will be used to encrypt each request and authenticate responses.
The SGX-reencrypt functionality is accessed through two trusted calls
(ecalls): register_key()
and reencrypt()
. Both accept an encrypted
request and returns an encrypted response that can be opened using the
client private key and the enclave public key.
Key registration is the process by which symmetric keys are provisioned to the enclave. These keys can later be used during reencryption requests to decrypt and encrypt given ciphertexts.
Each key registration request is composed by an encrypted datagram, using the enclave public key, containing these fields:
key
, 16 bytesexpiration_date
, 8 bytespolicy_from
, 1 byten_keys_from
, 4 bytespolicy_to
, 1 byten_keys_to
, 4 bytesn_authorized_clients
, 4 byteskeys_from
, [16 bytes]keys_to
, [16 bytes]authorized_clients
, [32 bytes]
On success, the enclave response contains the 16-byte key ID assigned.
At the moment, 16-byte value BLAKE2b(key || expiration_date)
. See security note 1.
Each authorized client is authenticated using its TweetNaCl public key.
Reencryption is the process by which, given a ciphertext, c
, and a
pair of previously registered key identifiers, k1id
, k2id
, the user
gets the new ciphertext encrypt(k2, decrypt(k1, c))
. This process
allows to reencrypt a given ciphertext without exposing the plaintext
nor the keys to observers out of the enclave.
Each key reencryption request is composed by an encrypted datagram, using the enclave public key, containing these fields:
[K1ID (16B)][K2ID (16B)][IV (12B)]
[MAC (16B)][ciphertext (...)]
On success, the enclave response contains a new ciphertext.
Given a reencryption request, a set of policies is enforced:
-
Does key-in allows encryption to key-out?
-
Does key-out allows encryption from key-in?
-
Is the client authorized to use key-in and key-out?
-
Is the current timestamp lower than key-in and key-out exp. date? See security note 2.
Only when every policy is passed the reencryption is computed.
-
An eavesdropper on the channel shouldn't be able to extract clear information about the requests nor the responses (only relative data, as request size).
-
An attacker that interacts with the enclave shouldn't be able to extract the keys.
-
Non-authorized users shouldn't be able to use registered keys.
-
Ciphertexts should be indistinguishable.
-
As Key ID is deterministic, a party knowing a symmetric key and expiration date could overwrite the registered key and replace the policy with a malicious one without the user noticing it.
-
At the moment, there's no trusted absolute time source inside the enclave, and the timestamp is requested through an untrusted call to the system, rendering the expiration date policy forgeable by a malicious enclave host.
Copyright (c) 2016, Nagravision S.A.
Code under GPLv3