Login Spec Here: https://github.com/18F/identity-idp/blob/master/docs/encrypt... Many aspects of this make no sense to me... so IF this is actually what they are doing... hash(user, password) { salt = CS-PRNG(160bit) s = scrypt(salt, password) z1 = s[0:32] z2 = s[32:64] R = CS-PRNG(256bit) d = HSM(R) XOR (pad_right(z1, 0x00, 32 bytes)) cek = SHA256(z2 || d) hash = SHA256(cek) save_record(user, d, salt, hash) } First…
Without having looked at the actual implementation, here's one option that could work: Upon account creation, the server generates a key pair and a random string - the recovery code. The server stores the public key and an encrypted version of the private key, with the encryption key being the recovery code. Any changes to PII can be encrypted using the public key. The server does not need to store the recovery code (which would beat the whole point of this exercise). Instead, it can simply attempt to decrypt the PII with the user-provided recovery code, and if it succeeds, the server knows the entered recovery code was valid.