Profile cover photo
Profile photo
Ethan Yonker (Dees Troy)
3,220 followers -
Lead Developer of TWRP.
Lead Developer of TWRP.

3,220 followers
About
Ethan Yonker (Dees Troy)'s posts

Post has shared content
#TWRP 3.1.1 is out now. Get the latest from https://twrp.me

Changelog:
Backups will now include adopted storage keys (Dees_Troy)
Fixed an adb restore issue (bigbiff)
Fixed rebooting when no OS is present (Dees_Troy)
Fixed line wrapping in the GUI terminal (_that)
Updated TWRP source code to AOSP 7.1.2 (Dees_Troy)

Post has attachment
#TWRP 3.1.1 is out now. Get the latest from https://twrp.me

Changelog:
Backups will now include adopted storage keys (Dees_Troy)
Fixed an adb restore issue (bigbiff)
Fixed rebooting when no OS is present (Dees_Troy)
Fixed line wrapping in the GUI terminal (_that)
Updated TWRP source code to AOSP 7.1.2 (Dees_Troy)

Post has attachment
The issue that I reported to Google back in November has (finally) been fixed. Forevermore (or at least for a while) Google's acknowledgements pages will include a mention of my name, Team Win Recovery Project, and a link to our website.

I stumbled upon the issue while working on decrypting FBE in TWRP. I was testing on the Nexus 5X so I could use the Pixel as my main phone for a while before subjecting it to TWRP development.

https://source.android.com/security/bulletin/2017-05-01#id-in-file-based-encryption

https://issuetracker.google.com/issues/37126260

In Android there is a /data/system/device_policies.xml file which contains stats about your password like:
<active-password quality="131072" length="4" uppercase="0" lowercase="0" letters="0" numeric="4" symbols="0" nonletter="4" />

On full device encryption, this kind of data would only be accessible after entering the correct pin/pattern/password, but on devices using file based encryption, this data is readily accessible after completing the password-less Device Encryption process. This data could then be used by an attacker to significantly improve their chances of brute forcing the user's password.

At the very least, this data should be stored inside a CE folder and only accessible after the user enters a password. A better design would probably involve storing this kind of data inside TZ and allow apps to query TZ and have TZ return a calculated password quality.

Post has shared content
Reshare here:
Here's a write up about some work that I did while trying to recovery some lost encrypted data on an LG G4:

Note that I am not especially well versed in reverse engineering or working with TZ / QSEE environments. I am definitely not an expert at these things, though I do have some experience working with Android encryption having developed decrypt support within TWRP. Some of the information in this article may be incomplete or completely wrong. I worked on this particular case in blocks of a few hours at a time over the course of several months, so my memory of things may be a little fuzzy.

Some time ago, an Android user asked me for help retrieving some encrypted data from an LG G4. In this case, the user had unlocked the bootloader on his LG G4 H811 T-Mobile USA model phone and had rooted the device. The user was using root to send various commands to the device to manually change the decryption password on the device. Normally the lock screen password and the password to decrypt the device on first boot are one and the same. The user was following an older version of the guide found here:
https://github.com/nelenkov/cryptfs-password-manager
The intent was to set a much stronger password for decrypting data while using a simpler password at the lock screen. At the earlier time, the guide did not contain the clear warnings about using the correct syntax that it does today.

Using root, you can communicate with vold using vdc, which is a binary included on most recent Android devices. Specifically, you can do things like:
vdc cryptfs checkpw 0000
All vold commands related to encryption use the “cryptfs” parameter. The checkpw command in this case would attempt to decrypt the data partition with a password of 0000. Note that the password type (pin/pattern/password) does not matter as all types boil down to a string of characters. The type of password is stored in the crypto footer, in the case of the G4, in the encrypt partition. The type is read by the device during boot and tells the device whether to display the pattern input, a simple numeric pad for pin, or a regular keyboard for passwords.

You can also use vdc to change your password and password type. Normally you would use a command like this:
vdc cryptfs changepw pin 0000 1111
In this case, we tell vold that we want to change the password with changepw and that we want the new password to be a pin. The 0000 is the old password and the 1111 is the new pin.

In this particular case, the user had supplied a different set of parameters. Specifically, the user had supplied something like:
vdc cryptfs changepw pin 1111
This syntax is actually the correct syntax on some devices and firmwares. Unfortunately in the case of the G4, the user ended up in a bad state where decrypt was no longer possible using any password, old or new. Ultimately the user ended up in the situation discussed here:
https://github.com/nelenkov/cryptfs-password-manager/issues/14
We will go into a deeper dive later to discuss exactly what happened and what we were able to do to ultimately decrypt the data on the device and successfully retrieve that data.

I purchased a LG G4 H811 from a local T-Mobile store. I OTA’ed the device up to the (at the time) latest Android 6.0 (marshmallow) 20i which can be found here:
https://forum.xda-developers.com/tmobile-g4/development/stock-h811-20i-images-kdz-flashable-t3308227

One of the first steps that I work towards when dealing with encryption is to obtain a root shell at or before the encryption prompt. On Nexus/Pixel devices, this is relatively easy as I can just download AOSP and make an engineering boot image. This approach isn’t possible on the G4 though. Instead, I modified the init scripts in the stock boot image to make adb start by default and set a slightly different set of USB settings. At this point I was able to obtain a non-root shell at the decrypt prompt. Further, I copied the adb_keys file out of an unencrypted data partition and placed the adb_keys file in the ramdisk so that my attempts to use adb would be authorized.

Next, I reached out to phh who develops his own open source superuser tools and asked if it was possibly to create a version of his su binary that did not require the user to grant root privileges via an app. He graciously supplied me with such a binary that I then included in the /sbin folder in the modified boot image. Now I was able to get a root shell at the decrypt prompt. This root access allows us to push files anywhere we want to the device, grab logcats and dmesgs, and even run vdc commands manually.

Based on past experience and looking at logcats, I was able to determine a few things about the encryption methods used on the LG G4. It appears to be fairly close to CAF using Qualcomm’s “hardware” encryption that I have seen used by Cyanogen Inc on the OnePlus One and by Motorola on various Moto G models. Specifically in the logcat, we see “HW based disk encryption is enabled”.
https://github.com/LineageOS/android_device_qcom_common/blob/cm-12.0/cryptfs_hw/cryptfs_hw.c#L181
The LG firmware includes a libcryptfs_hw.so in the system partition. I used the source code that we have available for this library from:
https://github.com/TeamWin/android_device_qcom_common/blob/android-6.0/cryptfs_hw/cryptfs_hw.c
I compiled my own libcryptfs_hw.so and replaced the one in the stock firmware with my own. It appears that LG made no changes to this library, as my own version of the library worked flawlessly for encrypting, decrypting, and changing passwords.

In addition, it appears that the G4 uses some modifications to CAF. Specifically, LG uses a TZ module named secureks. Perhaps this is short for secure keystore. LG has also replaced the key derivation from PIN/password with their own key manager library (km_, in liblgkm.so).

Before we go any further, I want to briefly highlight some of the relevant partitions on the G4 and try to explain each partition’s role. All of the partitions will be referred to here by name and may be found in /dev/block/platform/f9824900.sdhci/by-name/
userdata – The actual data partition in encrypted form
encrypt – contains encryption information. On the G4 this includes the counter which tells us how many tries we have left before we trigger a wipe. It also tells the device what input method to display (pin/pattern/password). I will also refer to this data as the “crypto footer”. On some devices this data is stored in the last 16KB of the data partition (hence the term footer) instead of in its own separate partition.
drm – appears to contain some password key/hash data used by LG’s secureks module
dm-0 – (full path is /dev/block/dm-0) which is created by the device mapper in the kernel when the encrypted data is successfully unencrypted.

Since I was able to supply my own libcryptfs_hw.so library, I added some additional logging to my library to log what password parameters were being sent and to get a better idea of what functions were being called and what values they were returning.

Nikolay (https://twitter.com/kapitanpetko) helped us out by supplying some information about what goes on in the vold change password function. The order of operations are found below. Note that function calls that begin with km_ are calls into liblgkm.so.
Call km_get_km_meta which we assume retrieves the current password information
Next km_encrypt_key and km_get_key_mac_by_password which appears to prepare the new password and put it in the proper format for saving
Call km_put_km_meta which saves the new password data (later we determine that this data is saved in the drm partition)
Call put_crypt_ftr_and_key which would update the password information in the encrypt partition
Finally call update_hw_device_encryption_key which updates the password that is saved in QSEE for Qualcomm’s hardware encryption

Here is a logcat of vdc cryptfs changepw pin 0000 1111:
01-08 00:25:16.132 368 412 E VoldCryptCmdListener: [LGE][VOLD][CommandListener.cpp][CryptfsCmd::runCommand()] argv[0]:cryptfs, argv[1]:changepw
01-08 00:25:16.132 368 412 D VoldCryptCmdListener: cryptfs changepw pin {}
01-08 00:25:16.132 368 412 I Ext4Crypt: ext4 crypto complete called on /data
01-08 00:25:16.132 368 412 I Ext4Crypt: No master key, so not ext4enc
01-08 00:25:16.134 368 412 I : Keymaster partition does not exists
01-08 00:25:16.134 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.134 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.180 368 412 D QSEECOMAPI: : Loaded image: APP id = 18
01-08 00:25:16.182 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.207 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.207 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 18
01-08 00:25:16.207 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 00:25:16.235 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.235 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.273 368 412 D QSEECOMAPI: : Loaded image: APP id = 19
01-08 00:25:16.274 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.288 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.288 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 19
01-08 00:25:16.289 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 00:25:16.305 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.305 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.342 368 412 D QSEECOMAPI: : Loaded image: APP id = 20
01-08 00:25:16.343 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.358 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.358 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 20
01-08 00:25:16.358 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 00:25:16.358 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.358 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.395 368 412 D QSEECOMAPI: : Loaded image: APP id = 21
01-08 00:25:16.396 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.537 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.537 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 21
01-08 00:25:16.537 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_encryption:: File_write success !!!
01-08 00:25:16.577 368 412 I : Keymaster partition does not exists
01-08 00:25:16.577 368 412 D : HW based disk encryption is enabled
01-08 00:25:16.577 368 412 E : set_key called with operation: 2
01-08 00:25:16.577 368 412 D : HW based disk encryption is enabled
01-08 00:25:16.577 368 412 E : get_tmp_passwd: Passed argument is '1111'
01-08 00:25:16.577 368 412 E : get_tmp_passwd: Passed argument is '0000'
01-08 00:25:16.963 368 412 E QSEECOMAPI: : SUCCESS::ioctl call to update the encryption key for usage 1 success with ret = 0
01-08 00:25:16.963 368 412 I Cryptfs : Encryption hardware key updated

In this case, the password was changed successfully from 0000 to 1111.

Now here is the output of vdc cryptfs changepw pin 0000:
01-08 02:08:31.589 367 402 E VoldCryptCmdListener: [LGE][VOLD][CommandListener.cpp][CryptfsCmd::runCommand()] argv[0]:cryptfs, argv[1]:changepw
01-08 02:08:31.589 367 402 D VoldCryptCmdListener: cryptfs changepw pin {}
01-08 02:08:31.589 367 402 I Ext4Crypt: ext4 crypto complete called on /data
01-08 02:08:31.590 367 402 I Ext4Crypt: No master key, so not ext4enc
01-08 02:08:31.595 367 402 I : Keymaster partition does not exists
01-08 02:08:31.595 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.595 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:31.670 367 402 D QSEECOMAPI: : Loaded image: APP id = 16
01-08 02:08:31.681 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:31.711 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:31.711 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 16
01-08 02:08:31.711 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 02:08:31.748 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.748 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:31.828 367 402 D QSEECOMAPI: : Loaded image: APP id = 17
01-08 02:08:31.836 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:31.863 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:31.863 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 17
01-08 02:08:31.863 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 02:08:31.887 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.887 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:31.964 367 402 D QSEECOMAPI: : Loaded image: APP id = 18
01-08 02:08:31.968 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:31.992 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:31.992 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 18
01-08 02:08:31.992 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 02:08:31.992 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.992 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:32.057 367 402 D QSEECOMAPI: : Loaded image: APP id = 19
01-08 02:08:32.064 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:32.216 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:32.216 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 19
01-08 02:08:32.216 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_encryption:: File_write success !!!
01-08 02:08:32.223 367 402 I : Keymaster partition does not exists
01-08 02:08:32.223 367 402 D : HW based disk encryption is enabled
01-08 02:08:32.223 367 402 E : set_key called with operation: 2
01-08 02:08:32.223 367 402 D : HW based disk encryption is enabled
01-08 02:08:32.223 367 402 E : get_tmp_passwd: Passed argument is ''
01-08 02:08:32.223 367 402 E : get_tmp_passwd: Passed argument is ''
01-08 02:08:32.522 367 402 E QSEECOMAPI: : Error::ioctl call to update the encryption key for usage 1 failed with ret = -1, errno = 22
01-08 02:08:32.522 367 402 E Cryptfs : Error updating device encryption hardware key ret -9

In this case we end up in a bad state where we can no longer decrypt the device. (It may be worth noting that the device will register a change in the password type, e.g. pin to password, and display the new input method at the decrypt screen meaning that the crypto footer has been updated.) The new password that is being supplied to libcryptfs_hw.so is an empty string based on get_tmp_passwd: Passed argument is '' which we obtained by adding more logging to our libcryptfs_hw.so library in the set_key function here:
https://github.com/TeamWin/android_device_qcom_common/blob/android-6.0/cryptfs_hw/cryptfs_hw.c#L165

The set_key function calls a function in libQSEEComAPI.so which just calls an ioctl. I traced the ioctl through the G4 kernel all the way down to where the kernel passes the information to TZ to verify that it really was TZ that was supplying the error when trying to change the password to an empty string and that there was not some function in the kernel that was not handling an empty string.

During another test cycle, I backed up various partitions on the G4, then changed the password. I compared md5 outputs from the backups and the partitions and determined that the drm partition was apparently responsible for storing the password data that was being saved by liblgkm.so. I ran the “bad” vdc cryptfs changepw pin 0000 command again and placed the device in the state where it could no longer be decrypted. I restored the drm partition from the backup, then entered the old pin from before the bad vdc command and the device was able to be decrypted again.

So from the above test case, we learn some very valuable information. First, it is possible to potentially recover the encrypted data. It appears that if we can restore the drm partition to a working state, we will be back in good shape. Secondly, there appears to be a separation between the data that is stored by liblgkm.so and the data that is stored by Qualcomm’s hardware encryption routines. These two sets of data end up out of sync when we try to change the password using the bad vdc command.

At first, I thought long and hard about how I might go about trying to restore the drm partition to a working state. Finally, it dawned on me that a much simpler solution might be available. I compiled another libcryptfs_hw.so and hard coded the password in the set_key function to the old password. I ran vdc cryptfs checkpw ‘’ and device successfully decrypted!

So, let’s step back to our change password function calls from vold:
Call km_get_km_meta which we assume retrieves the current password information
Next km_encrypt_key and km_get_key_mac_by_password which appears to prepare the new password and put it in the proper format for saving
Call km_put_km_meta which saves the new password data (later we determine that this data is saved in the drm partition)
Call put_crypt_ftr_and_key which would update the password information in the encrypt partition
Finally call update_hw_device_encryption_key which updates the password that is saved in QSEE for Qualcomm’s hardware encryption

From the function calls and our logcats, we can now see that vold will save the new password data to the drm partition first, then update the Qualcomm hardware encryption data later. There is no code in vold to roll back the changes made to the drm partition by km_put_km_meta if the call to update_hw_device_encryption_key fails. The km_* functions will allow you to set an empty password and saves the new data as evidenced in the logcats by “QSEECOM_SEUCREKS_CLIENT: : sksc_encryption:: File_write success !!!”. The same empty password will fail to be saved by update_hw_device_encryption_key leaving the 2 sets of data out of sync.

After successfully decrypting the data partition, we were able to retrieve the data by using dd to dump the entire /dev/block/dm-0 partition, which is the device-mapped decrypted data. After dumping the data, we were able to mount the dumped image on a PC to view and retrieve individual files. Further, we were able to boot into TWRP, format the data partition, then use dd again to write the backed up data back to the data partition unecrypted and boot the device up with working, decrypted data, though we did have some troubles with the lock screen.

There are some other takeaways that I’d like to note. Using root to mess around with vdc can be dangerous. Either work with data that you don’t care if you lose, or make a good backup. The vdc commands in this case were only accessible by root. Ideally LG and even Google should improve error handling and roll back changes if some part of the password change process fails. The same type of issue potentially exists in AOSP, though I’m not aware of any Google devices using hardware disk encryption. See https://android.googlesource.com/platform/system/vold/+/android-7.1.1_r28/cryptfs.c#3360 and line 3370.

I believe that LG’s implementation of encryption and password handling to be potentially less secure than it would otherwise could be. Storing the password related data in the drm partition provides a larger attack surface. While I didn’t do an extensive dive into LG’s liblgkm.so, I don’t get the impression that liblgkm.so is using any hardware backing from TZ on the G4. Further, in more recent TZ implementations from Google, there is a rate limit. The rate limit is intended to make brute forcing a strong password impossible by limiting the number of password attempts in a given time frame. Some may say that the device will wipe itself after 10 or 30 failed attempts, but the counter for this forced wipe is stored in plain text in the crypto footer and it is easy to reset the counter. Further, I believe that the wipe is triggered by rebooting the device into recovery mode. An attacker could replace or remove the recovery to thwart attempts to wipe the data or simply reset the counter in the crypto footer. While I’m no expert, it seems likely that an attacker could utilize the weaker attack surface in LG’s liblgkm.so and drm partition to attempt to brute force the user’s password.

Here's a write up about some work that I did while trying to recover some lost encrypted data on an LG G4:

Note that I am not especially well versed in reverse engineering or working with TZ / QSEE environments. I am definitely not an expert at these things, though I do have some experience working with Android encryption having developed decrypt support within TWRP. Some of the information in this article may be incomplete or completely wrong. I worked on this particular case in blocks of a few hours at a time over the course of several months, so my memory of things may be a little fuzzy.

Some time ago, an Android user asked me for help retrieving some encrypted data from an LG G4. In this case, the user had unlocked the bootloader on his LG G4 H811 T-Mobile USA model phone and had rooted the device. The user was using root to send various commands to the device to manually change the decryption password on the device. Normally the lock screen password and the password to decrypt the device on first boot are one and the same. The user was following an older version of the guide found here:
https://github.com/nelenkov/cryptfs-password-manager
The intent was to set a much stronger password for decrypting data while using a simpler password at the lock screen. At the earlier time, the guide did not contain the clear warnings about using the correct syntax that it does today.

Using root, you can communicate with vold using vdc, which is a binary included on most recent Android devices. Specifically, you can do things like:
vdc cryptfs checkpw 0000
All vold commands related to encryption use the “cryptfs” parameter. The checkpw command in this case would attempt to decrypt the data partition with a password of 0000. Note that the password type (pin/pattern/password) does not matter as all types boil down to a string of characters. The type of password is stored in the crypto footer, in the case of the G4, in the encrypt partition. The type is read by the device during boot and tells the device whether to display the pattern input, a simple numeric pad for pin, or a regular keyboard for passwords.

You can also use vdc to change your password and password type. Normally you would use a command like this:
vdc cryptfs changepw pin 0000 1111
In this case, we tell vold that we want to change the password with changepw and that we want the new password to be a pin. The 0000 is the old password and the 1111 is the new pin.

In this particular case, the user had supplied a different set of parameters. Specifically, the user had supplied something like:
vdc cryptfs changepw pin 1111
This syntax is actually the correct syntax on some devices and firmwares. Unfortunately in the case of the G4, the user ended up in a bad state where decrypt was no longer possible using any password, old or new. Ultimately the user ended up in the situation discussed here:
https://github.com/nelenkov/cryptfs-password-manager/issues/14
We will go into a deeper dive later to discuss exactly what happened and what we were able to do to ultimately decrypt the data on the device and successfully retrieve that data.

I purchased a LG G4 H811 from a local T-Mobile store. I OTA’ed the device up to the (at the time) latest Android 6.0 (marshmallow) 20i which can be found here:
https://forum.xda-developers.com/tmobile-g4/development/stock-h811-20i-images-kdz-flashable-t3308227

One of the first steps that I work towards when dealing with encryption is to obtain a root shell at or before the encryption prompt. On Nexus/Pixel devices, this is relatively easy as I can just download AOSP and make an engineering boot image. This approach isn’t possible on the G4 though. Instead, I modified the init scripts in the stock boot image to make adb start by default and set a slightly different set of USB settings. At this point I was able to obtain a non-root shell at the decrypt prompt. Further, I copied the adb_keys file out of an unencrypted data partition and placed the adb_keys file in the ramdisk so that my attempts to use adb would be authorized.

Next, I reached out to phh who develops his own open source superuser tools and asked if it was possibly to create a version of his su binary that did not require the user to grant root privileges via an app. He graciously supplied me with such a binary that I then included in the /sbin folder in the modified boot image. Now I was able to get a root shell at the decrypt prompt. This root access allows us to push files anywhere we want to the device, grab logcats and dmesgs, and even run vdc commands manually.

Based on past experience and looking at logcats, I was able to determine a few things about the encryption methods used on the LG G4. It appears to be fairly close to CAF using Qualcomm’s “hardware” encryption that I have seen used by Cyanogen Inc on the OnePlus One and by Motorola on various Moto G models. Specifically in the logcat, we see “HW based disk encryption is enabled”.
https://github.com/LineageOS/android_device_qcom_common/blob/cm-12.0/cryptfs_hw/cryptfs_hw.c#L181
The LG firmware includes a libcryptfs_hw.so in the system partition. I used the source code that we have available for this library from:
https://github.com/TeamWin/android_device_qcom_common/blob/android-6.0/cryptfs_hw/cryptfs_hw.c
I compiled my own libcryptfs_hw.so and replaced the one in the stock firmware with my own. It appears that LG made no changes to this library, as my own version of the library worked flawlessly for encrypting, decrypting, and changing passwords.

In addition, it appears that the G4 uses some modifications to CAF. Specifically, LG uses a TZ module named secureks. Perhaps this is short for secure keystore. LG has also replaced the key derivation from PIN/password with their own key manager library (km_, in liblgkm.so).

Before we go any further, I want to briefly highlight some of the relevant partitions on the G4 and try to explain each partition’s role. All of the partitions will be referred to here by name and may be found in /dev/block/platform/f9824900.sdhci/by-name/
userdata – The actual data partition in encrypted form
encrypt – contains encryption information. On the G4 this includes the counter which tells us how many tries we have left before we trigger a wipe. It also tells the device what input method to display (pin/pattern/password). I will also refer to this data as the “crypto footer”. On some devices this data is stored in the last 16KB of the data partition (hence the term footer) instead of in its own separate partition.
drm – appears to contain some password key/hash data used by LG’s secureks module
dm-0 – (full path is /dev/block/dm-0) which is created by the device mapper in the kernel when the encrypted data is successfully unencrypted.

Since I was able to supply my own libcryptfs_hw.so library, I added some additional logging to my library to log what password parameters were being sent and to get a better idea of what functions were being called and what values they were returning.

Nikolay (https://twitter.com/kapitanpetko) helped us out by supplying some information about what goes on in the vold change password function. The order of operations are found below. Note that function calls that begin with km_ are calls into liblgkm.so.
Call km_get_km_meta which we assume retrieves the current password information
Next km_encrypt_key and km_get_key_mac_by_password which appears to prepare the new password and put it in the proper format for saving
Call km_put_km_meta which saves the new password data (later we determine that this data is saved in the drm partition)
Call put_crypt_ftr_and_key which would update the password information in the encrypt partition
Finally call update_hw_device_encryption_key which updates the password that is saved in QSEE for Qualcomm’s hardware encryption

Here is a logcat of vdc cryptfs changepw pin 0000 1111:
01-08 00:25:16.132 368 412 E VoldCryptCmdListener: [LGE][VOLD][CommandListener.cpp][CryptfsCmd::runCommand()] argv[0]:cryptfs, argv[1]:changepw
01-08 00:25:16.132 368 412 D VoldCryptCmdListener: cryptfs changepw pin {}
01-08 00:25:16.132 368 412 I Ext4Crypt: ext4 crypto complete called on /data
01-08 00:25:16.132 368 412 I Ext4Crypt: No master key, so not ext4enc
01-08 00:25:16.134 368 412 I : Keymaster partition does not exists
01-08 00:25:16.134 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.134 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.180 368 412 D QSEECOMAPI: : Loaded image: APP id = 18
01-08 00:25:16.182 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.207 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.207 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 18
01-08 00:25:16.207 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 00:25:16.235 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.235 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.273 368 412 D QSEECOMAPI: : Loaded image: APP id = 19
01-08 00:25:16.274 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.288 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.288 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 19
01-08 00:25:16.289 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 00:25:16.305 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.305 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.342 368 412 D QSEECOMAPI: : Loaded image: APP id = 20
01-08 00:25:16.343 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.358 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.358 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 20
01-08 00:25:16.358 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 00:25:16.358 368 412 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 00:25:16.358 368 412 D QSEECOMAPI: : App is not loaded in QSEE
01-08 00:25:16.395 368 412 D QSEECOMAPI: : Loaded image: APP id = 21
01-08 00:25:16.396 368 412 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 00:25:16.537 368 412 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 00:25:16.537 368 412 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 21
01-08 00:25:16.537 368 412 D QSEECOM_SEUCREKS_CLIENT: : sksc_encryption:: File_write success !!!
01-08 00:25:16.577 368 412 I : Keymaster partition does not exists
01-08 00:25:16.577 368 412 D : HW based disk encryption is enabled
01-08 00:25:16.577 368 412 E : set_key called with operation: 2
01-08 00:25:16.577 368 412 D : HW based disk encryption is enabled
01-08 00:25:16.577 368 412 E : get_tmp_passwd: Passed argument is '1111'
01-08 00:25:16.577 368 412 E : get_tmp_passwd: Passed argument is '0000'
01-08 00:25:16.963 368 412 E QSEECOMAPI: : SUCCESS::ioctl call to update the encryption key for usage 1 success with ret = 0
01-08 00:25:16.963 368 412 I Cryptfs : Encryption hardware key updated

In this case, the password was changed successfully from 0000 to 1111.

Now here is the output of vdc cryptfs changepw pin 0000:
01-08 02:08:31.589 367 402 E VoldCryptCmdListener: [LGE][VOLD][CommandListener.cpp][CryptfsCmd::runCommand()] argv[0]:cryptfs, argv[1]:changepw
01-08 02:08:31.589 367 402 D VoldCryptCmdListener: cryptfs changepw pin {}
01-08 02:08:31.589 367 402 I Ext4Crypt: ext4 crypto complete called on /data
01-08 02:08:31.590 367 402 I Ext4Crypt: No master key, so not ext4enc
01-08 02:08:31.595 367 402 I : Keymaster partition does not exists
01-08 02:08:31.595 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.595 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:31.670 367 402 D QSEECOMAPI: : Loaded image: APP id = 16
01-08 02:08:31.681 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:31.711 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:31.711 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 16
01-08 02:08:31.711 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 02:08:31.748 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.748 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:31.828 367 402 D QSEECOMAPI: : Loaded image: APP id = 17
01-08 02:08:31.836 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:31.863 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:31.863 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 17
01-08 02:08:31.863 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 02:08:31.887 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.887 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:31.964 367 402 D QSEECOMAPI: : Loaded image: APP id = 18
01-08 02:08:31.968 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:31.992 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:31.992 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 18
01-08 02:08:31.992 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_decryption:: file_read success~!!!
01-08 02:08:31.992 367 402 D QSEECOMAPI: : QSEECom_get_handle sb_length = 0x1c00
01-08 02:08:31.992 367 402 D QSEECOMAPI: : App is not loaded in QSEE
01-08 02:08:32.057 367 402 D QSEECOMAPI: : Loaded image: APP id = 19
01-08 02:08:32.064 367 402 D QSEECOM_SECUREKS_TZ_CMD: : Loading app secureks succeded
01-08 02:08:32.216 367 402 D QSEECOMAPI: : QSEECom_dealloc_memory
01-08 02:08:32.216 367 402 D QSEECOMAPI: : QSEECom_shutdown_app, app_id = 19
01-08 02:08:32.216 367 402 D QSEECOM_SEUCREKS_CLIENT: : sksc_encryption:: File_write success !!!
01-08 02:08:32.223 367 402 I : Keymaster partition does not exists
01-08 02:08:32.223 367 402 D : HW based disk encryption is enabled
01-08 02:08:32.223 367 402 E : set_key called with operation: 2
01-08 02:08:32.223 367 402 D : HW based disk encryption is enabled
01-08 02:08:32.223 367 402 E : get_tmp_passwd: Passed argument is ''
01-08 02:08:32.223 367 402 E : get_tmp_passwd: Passed argument is ''
01-08 02:08:32.522 367 402 E QSEECOMAPI: : Error::ioctl call to update the encryption key for usage 1 failed with ret = -1, errno = 22
01-08 02:08:32.522 367 402 E Cryptfs : Error updating device encryption hardware key ret -9

In this case we end up in a bad state where we can no longer decrypt the device. (It may be worth noting that the device will register a change in the password type, e.g. pin to password, and display the new input method at the decrypt screen meaning that the crypto footer has been updated.) The new password that is being supplied to libcryptfs_hw.so is an empty string based on get_tmp_passwd: Passed argument is '' which we obtained by adding more logging to our libcryptfs_hw.so library in the set_key function here:
https://github.com/TeamWin/android_device_qcom_common/blob/android-6.0/cryptfs_hw/cryptfs_hw.c#L165

The set_key function calls a function in libQSEEComAPI.so which just calls an ioctl. I traced the ioctl through the G4 kernel all the way down to where the kernel passes the information to TZ to verify that it really was TZ that was supplying the error when trying to change the password to an empty string and that there was not some function in the kernel that was not handling an empty string.

During another test cycle, I backed up various partitions on the G4, then changed the password. I compared md5 outputs from the backups and the partitions and determined that the drm partition was apparently responsible for storing the password data that was being saved by liblgkm.so. I ran the “bad” vdc cryptfs changepw pin 0000 command again and placed the device in the state where it could no longer be decrypted. I restored the drm partition from the backup, then entered the old pin from before the bad vdc command and the device was able to be decrypted again.

So from the above test case, we learn some very valuable information. First, it is possible to potentially recover the encrypted data. It appears that if we can restore the drm partition to a working state, we will be back in good shape. Secondly, there appears to be a separation between the data that is stored by liblgkm.so and the data that is stored by Qualcomm’s hardware encryption routines. These two sets of data end up out of sync when we try to change the password using the bad vdc command.

At first, I thought long and hard about how I might go about trying to restore the drm partition to a working state. Finally, it dawned on me that a much simpler solution might be available. I compiled another libcryptfs_hw.so and hard coded the password in the set_key function to the old password. I ran vdc cryptfs checkpw ‘’ and device successfully decrypted!

So, let’s step back to our change password function calls from vold:
Call km_get_km_meta which we assume retrieves the current password information
Next km_encrypt_key and km_get_key_mac_by_password which appears to prepare the new password and put it in the proper format for saving
Call km_put_km_meta which saves the new password data (later we determine that this data is saved in the drm partition)
Call put_crypt_ftr_and_key which would update the password information in the encrypt partition
Finally call update_hw_device_encryption_key which updates the password that is saved in QSEE for Qualcomm’s hardware encryption

From the function calls and our logcats, we can now see that vold will save the new password data to the drm partition first, then update the Qualcomm hardware encryption data later. There is no code in vold to roll back the changes made to the drm partition by km_put_km_meta if the call to update_hw_device_encryption_key fails. The km_* functions will allow you to set an empty password and saves the new data as evidenced in the logcats by “QSEECOM_SEUCREKS_CLIENT: : sksc_encryption:: File_write success !!!”. The same empty password will fail to be saved by update_hw_device_encryption_key leaving the 2 sets of data out of sync.

After successfully decrypting the data partition, we were able to retrieve the data by using dd to dump the entire /dev/block/dm-0 partition, which is the device-mapped decrypted data. After dumping the data, we were able to mount the dumped image on a PC to view and retrieve individual files. Further, we were able to boot into TWRP, format the data partition, then use dd again to write the backed up data back to the data partition unecrypted and boot the device up with working, decrypted data, though we did have some troubles with the lock screen.

There are some other takeaways that I’d like to note. Using root to mess around with vdc can be dangerous. Either work with data that you don’t care if you lose, or make a good backup. The vdc commands in this case were only accessible by root. Ideally LG and even Google should improve error handling and roll back changes if some part of the password change process fails. The same type of issue potentially exists in AOSP, though I’m not aware of any Google devices using hardware disk encryption. See https://android.googlesource.com/platform/system/vold/+/android-7.1.1_r28/cryptfs.c#3360 and line 3370.

I believe that LG’s implementation of encryption and password handling to be potentially less secure than it would otherwise could be. Storing the password related data in the drm partition provides a larger attack surface. While I didn’t do an extensive dive into LG’s liblgkm.so, I don’t get the impression that liblgkm.so is using any hardware backing from TZ on the G4. Further, in more recent TZ implementations from Google, there is a rate limit. The rate limit is intended to make brute forcing a strong password impossible by limiting the number of password attempts in a given time frame. Some may say that the device will wipe itself after 10 or 30 failed attempts, but the counter for this forced wipe is stored in plain text in the crypto footer and it is easy to reset the counter. Further, I believe that the wipe is triggered by rebooting the device into recovery mode. An attacker could replace or remove the recovery to thwart attempts to wipe the data or simply reset the counter in the crypto footer. While I’m no expert, it seems likely that an attacker could utilize the weaker attack surface in LG’s liblgkm.so and drm partition to attempt to brute force the user’s password.

Email from a user titled "SM-A720F":

Why you guys show no interest at all for Samsung's A series? I see you have never made TWRP for the first two generations of the A series, and I'm not that hopeful you'll patch the 2017 (3rd gen) models.

So, bloatwares be damned, screw the users, is that your attitude?

Samsung is the top player in the Android market, and is the one which releases new models the most, per year. For these reasons, and regardless of your personal preferences, I think Samsung is the brand you should be focusing on the most.

I'm tired of not having SuperSU on my device because you hackers are either selective or not knowledgeable enough to patch certain models, or both.

-------- And my reply --------
[START SARCASM]

Thanks for your email. I had no idea what device you were going to buy this year and I totally am going to take my hard earned money to buy the same device that you bought so I can spend my free time porting TWRP to your device and provide it to you free of charge. Please send me an email before you buy your next device so I can also buy it (with my own money) and make sure we support (again free of charge) in advance of your next purchase. Thank you for providing us with an attitude adjustment. Clearly we've been wrong all these years and should be spending more of our money buying the devices that you're buying and spending our free time on trying to support you free of charge.

[END SARCASM]

In the future, if you want TWRP, you have 3 options:
1) Look at our website before you buy a device and buy something we already support.
2) Buy 2 of the devices, and send us one.
3) We are open source. You can download our source code and port it yourself. Seriously! We even wrote a guide: https://forum.xda-developers.com/showthread.php?t=1943625 We know that porting is difficult though, so if you find it too difficult, you can always use one of the other 2 options.

Also, seriously, it's you that needs the attitude adjustment. If you think I'm wrong on this front, please send me a copy of your receipt for your purchase of TWRP, and I'll be happy to provide you with a full refund.

Post has shared content
Reshare with the TWRP community:
#TWRP 3.1.0 is out now for most supported devices.

Install the TWRP app now to easily download and install the new version and get notified when we release future versions for your device:
https://play.google.com/store/apps/details?id=me.twrp.twrpapp

Or, grab the latest from our website at https://twrp.me

Rough changelog:
vold decrypt on a few select HTC devices, TWRP will now attempt to use the system partition's vold and vdc binaries and libraries to decrypt the data partition (nkk71 and CaptainThrowback)
adb backup to stream a backup directly to or from your PC, see documentation here: https://github.com/omnirom/android_bootable_recovery/commit/ce8f83c48d200106ff61ad530c863b15c16949d9 (bigbiff)
tweak MTP startup routines (mdmower)
support new Android 7.x xattrs for backup and restore to fix loss of data after a restore (Dees_Troy)
support POSIX file capabilities backup and restore to fix VoLTE on HTC devices and possibly other issues (Dees_Troy)
better indicate to users that internal storage is not backed up (Dees_Troy)
improve automatic determination of TW_THEME (mdmower)
minimal getcap and setcap support (_that)
try mounting both ext4 and f2fs during decrypt (jcadduono and Dees_Troy)
shut off backlight with power key (mdmower)
timeout during FDE decrypt (Dees_Troy and nkk71)
support for FBE decrypt and backing up and restoring FBE policies (Dees_Troy)
boot slot support (Dees_Troy)
TWRP app install prompt during reboot (Dees_Troy)
support for AB OTA zips (Dees_Troy)
support new Android 7.x log command (Dees_Troy)
update recovery sources to AOSP 7.1 (Dees_Troy)
numerous bugfixes and improvements by too many people to mention


#TWRP 3.1.0 is out now for most supported devices.

Install the TWRP app now to easily download and install the new version and get notified when we release future versions for your device:
https://play.google.com/store/apps/details?id=me.twrp.twrpapp

Or, grab the latest from our website at https://twrp.me

Rough changelog:
vold decrypt on a few select HTC devices, TWRP will now attempt to use the system partition's vold and vdc binaries and libraries to decrypt the data partition (nkk71 and CaptainThrowback)
adb backup to stream a backup directly to or from your PC, see documentation here: https://github.com/omnirom/android_bootable_recovery/commit/ce8f83c48d200106ff61ad530c863b15c16949d9 (bigbiff)
tweak MTP startup routines (mdmower)
support new Android 7.x xattrs for backup and restore to fix loss of data after a restore (Dees_Troy)
support POSIX file capabilities backup and restore to fix VoLTE on HTC devices and possibly other issues (Dees_Troy)
better indicate to users that internal storage is not backed up (Dees_Troy)
improve automatic determination of TW_THEME (mdmower)
minimal getcap and setcap support (_that)
try mounting both ext4 and f2fs during decrypt (jcadduono and Dees_Troy)
shut off backlight with power key (mdmower)
timeout during FDE decrypt (Dees_Troy and nkk71)
support for FBE decrypt and backing up and restoring FBE policies (Dees_Troy)
boot slot support (Dees_Troy)
TWRP app install prompt during reboot (Dees_Troy)
support for AB OTA zips (Dees_Troy)
support new Android 7.x log command (Dees_Troy)
update recovery sources to AOSP 7.1 (Dees_Troy)
numerous bugfixes and improvements by too many people to mention


Post has attachment

Walmart is out of shopping carts right now.
Wait while more posts are being loaded