Of the files you mentioned above, locksettings.db
is actually the least relevant to the decryption process. And, as a result, the easiest to recreate if corrupted or lost. It's simply an SQLite database. It contains the following tables:
CREATE TABLE android_metadata (locale TEXT)
CREATE TABLE locksettings (_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,user INTEGER,value TEXT)
CREATE TABLE sqlite_sequence(name,seq)
The table android_metadata
contains a single row, e.g. locale=en_US
. The table sqlite_sequence
is a counter for the rows in locksettings
, and should therefore contain a single row name='locksettings',seq=9
In the table locksettings
, only one row is actually relevant to the decryption process. That row is name='sp-handle'
. It's matching value
is the decimal representation of the hexadecimal value represented by XXXXX
in XXXXX.spblob
. Put more simply, the only thing locksettings.db
does in practice during the decryption process is point at the correct spblob
file. This is particularly important if you have several, as each might correspond with a different unlock password.
The spblob
file contains something called the "Synthetic Password", which is used to generate the decryption key for the Key Encrypted Key in /data/misc/vold/user_keys/ce/0/current/encrypted_key
. encrypted_key
is basically an AES-256-GCM encrypted key. The first 12 bytes is the GCM IV, the last 16 bytes is the GCM authentication tag, and everything in between is the cypher text. Once successfully decrypted, the key is added to fscrypt
's keychain, and used to decrypt files in user-locked areas of the drive, like /data/data
or /data/media
. This also involves reading xattribute (9, 'c')
on each encrypted file/directory, but this is already down to the filesystem driver. The important point is that you need to decrypt spblob
to decrypt /data/misc/vold/user_keys/ce/0/current/encrypted_key
to decrypt the rest of the drive.
Not to be confused with /data/misc/vold/user_keys/de/0/encrypted_key
which is used to decrypt files/directories that don't require the PIN, such as /data/app
or /data/system_de/0
. The matching keymaster_key_blob
contains the key to decrypt encrypted_key
, in bytes 5 through 36 (The rest is header, metadata, and authentication tag), making it significantly easier to decrypt. Naturally, the CE key does not have a matching keymaster_key_blob
.
spblob
itself starts with 2 bytes representing version and "token type" respectively. The "token type" is 0 for lock screen, 1 for strong hardware token, and 2 for weak hardware token. Generally, it should be 0. The remainder of the bytes are the double AES-256-GCM encrypted synthetic password. The same general format as encrypted_key
applies, i.e. First 12 bytes are IV and last 16 are authentication tag. As a result, the size of spblob
is the size of the synthetic password plus 2+12*2+16*2=58
bytes.
The "outer" GCM encryption is generated from a hardware-encrypted key, with the application id synthetic_password_XXXXX
where XXXXX
is the name of the blob with leading 0
s trimmed (Comments inside the Android code suggests the 0
trimming might be a bug that was left in because "fixing" it would break the decryption process). An encrypted version of this key should be present in the file /data/misc/keystore/persistent.sqlite
, which is also an SQLite database. Decrypting it would require files from the /metadata
partition, which is hardware-protected.
Fully describing persistent.sqlite
would make this already long answer even longer, so here's the query for getting the encrypted key:
SELECT blob FROM keyentry, blobentry WHERE keyentry.id=blobentry.keyentryid AND keyentry.alias='synthetic_password_XXXXX'
Where XXXXX
is the matching spblob
file name with leading 0
s trimmed.
The most important part is that so long as the phone hasn't been hardware-reset, it should be able to recover the hardware-encrypted key without problem.
The inner encryption of the spblob
is where the user PIN comes in. And also where the other files come in. First the file pwd
is parsed to get parameters for scrypt KDF algorithm. The user-input PIN is put through scrypt with the parameters extracted from pwd
to produce a 32 byte hash called "stretched LSKF". This is combined with a hash of the contents of the secdis
file, and then hashed again, to produce the key for decrypting the partially decrypted spblob
. The exact formula is:
prefixhash(prefix, message) = sha512(prefix.padEnd(128, '\0') + message)
inner_key = prefixhash('application-id', stretchedLskf + prefixhash('secdiscardable-transform', file-contents('XXXXX.secdis')))
synthetic_password = gcm-decrypt(inner_key, gcm-decrypt(keystore_get('synthetic_password_XXXXX'), file-contents('XXXXX.spblob')[2..]))
So, to answer the original question, to properly decrypt the files, you need:
locksettings.db
to point at the correct spblob
- The
pwd
and secdis
matching the spblob
to be present
- The correct PIN matching the
spblob
synthetic_password_XXXXX
to be present in persistence.sqlite
- The
/metadata
partition to contain the correct key for decrypting synthetic_password_XXXXX
. Note that factory reset or flashing a new ROM will very likely wipe the /metadata
partition.
- The encrypted key
/data/misc/vold/user_keys/ce/0/current/encrypted_key
, as well as the matching secdiscardable
and stretching
files, which are used along with the synthetic password in spblob
to generate the key necessary to decrypt encrypted_key
.
Changing your PIN is most likely to create a new spblob
file, and change locksettings.db
to point at it. It may delete the old spblob
file. It's unlikely to touch the CE encrypted_key
as any modification to it runs the risk of corrupting it, rendering all files encrypted with it inaccessible. It would absolutely not attempt to re-encrypt all of the files, as that would both carry a risk of corruption, and also take a very long time. Much longer than anyone would wait for just a PIN change. Also, according to the comments within the code, "A user's SP never changes, but SP protectors can be added and removed", so even if you get new spblob
files, the decrypted content of each of them should be the same.
As an aside, I do suggest creating backups of all of these files before doing any more messing around. If at all possible, try to create a backup of the /metadata
partition as well, although the hardware may attempt to prevent that. That way, if messing around or guessing wrong PINs causes one of these files to become corrupt or disappear, you can potentially restore it from backup.