jbp.io Archive
17 January 2016

Using SGX to harden password hashing

SGX is a way of running security-sensitive user-mode code in an ‘enclave’. Code running in an enclave has its memory encrypted and authenticated, and cannot be observed by code running anywhere else. It’s able to use device-specific keys to encrypt (‘seal’) data to future executions of itself or enclaves signed by the same key.

We can use SGX to harden password hashing, by imposing the restriction that it is only possible on our hardware. That means offline attack is no longer possible, and a database leak only contains undecryptable ciphertext.


This is a demo, and the result of me playing with SGX for a day. You shouldn’t deploy this without understanding everything yourself first.


It would be easy to hash a password in an enclave and then seal it to itself for verification later. Unfortunately, that means only that physical CPU will ever be able to check a user password. That’s not a sensible approach; backups would be worthless.

So we’ll have a logical grouping of enclaves, all of which can check passwords – a ‘region’. A region is implemented as an AES key available to all such enclaves. ‘Enrolling’ an enclave into a region involves the enclave learning the region key, and sealing the key material to itself for later use.

diagram showing simple region concept

When we’re not enrolling an enclave into our region, the region key can be kept offline, in a hardware security module, or written down in a safe.


We need only two operations: setting a password and checking a guess. These look like:

diagram showing password setup flow

Here, we generate a random salt (using laundered hardware entropy from the RDRAND instruction) and pass the password into PBKDF2. The result and salt are encrypted using the region key, producing a ciphertext which can be stored alongside the user record in a database or password file.

diagram showing password guess flow

Here we decrypt the ciphertext to obtain the salt and correct hash. We hash the purported password and compare with the correct hash.

The code

The code is here. The main enclave code is in pwenclave/pwenclave.c. The interface to it is in pwenclave/pwenclave.edl, in Intel’s “Enclave Description Language”, which tells the tooling which function calls you want remoted into (an ‘ecall’) and out of (an ‘ocall’) the enclave.

There’s a test program in smoketest/smoketest.c which should product output like this:

pw_region_enroll took 0ms
pw_setup took 78ms
setup worked, blob is 84 bytes
pw_check+ took 78ms
pw_check worked (positive case)
pw_check- took 78ms
pw_check worked (negative case)