[Xiaomi Mi A3 ROMs, Kernels, Recoveries, & Other De] axon7fan:
How To Support Phone/Device Encryption

So you want to go to Settings > Security > Encryption & credentials > Encrypt phone ... but when you do you get a green outline of the Android robot on a black background for a few seconds and then your phone seems to go back into the system as if nothing happened!

Well here's the reason why. If you connect with "adb shell" and run "logcat" while you attempt the encryption you get the following messages:

12-02 19:07:25.890 457 479 D vold : fdeEnable(3, *, 0)
12-02 19:07:25.891 457 479 D vold : !fscrypt_is_native, spawning fdeEnableInternal
12-02 19:07:25.894 457 13837 E Cryptfs : Bad magic for real block device /dev/block/bootdevice/by-name/userdata
12-02 19:07:25.895 457 13837 E Cryptfs : Not a valid ext4 superblock
12-02 19:07:25.895 457 13837 E Cryptfs : Orig filesystem overlaps crypto footer region. Cannot encrypt in place.

...

12-02 19:07:26.248 457 13837 E Cryptfs : Bad magic for real block device /dev/block/bootdevice/by-name/userdata
12-02 19:07:26.248 457 13837 E Cryptfs : Not a valid ext4 superblock
12-02 19:07:26.248 457 13837 E Cryptfs : Orig filesystem overlaps crypto footer region. Cannot encrypt in place.

What's the issue? It turns out you needs 32 kilobytes at the end of the data partition for encryption to work. In order to support this we must format the /data filesystem to be slightly smaller than the partition size!

What this means is that you're going to lose all your data. So BACK IT UP (You may read posts that suggest you can use resize2fs - but this only works if your /data partition is/was formatted as ext4, whereas the f2fs filesystem cannot be shrunk - I tried formatting as ext4 but PixelExperience assumed the unencrypted partition was encrypted, which it wasn't, so that didn't work)!

Reboot into TWRP recovery (hold the VOLUME UP key as you're rebooting).

Find the /data partition mount to discover what device should be formatted.

$ adb shell
laurel_sprout:/ # mount |grep /data
/dev/block/sda15 on /data type f2fs (rw,lazytime,seclabel,relatime,background_gc=on,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,alloc_mode=default,fsync_mode=posix)

In this case it is the /dev/block/sda15 device that needs to be formatted.

Umount this (it is used by both /data and /sdcard mounts for some reason).

laurel_sprout:/ # umount /dev/block/sda15
laurel_sprout:/ # umount /dev/block/sda15
laurel_sprout:/ # umount /dev/block/sda15
umount: /dev/block/sda15: Invalid argument

Find the current partition size:

### get partition size (in 1 kilobyte blocks)
laurel_sprout:/ # cat /proc/partitions |grep sda15
8 15 50681692 sda15

For my 64GB phone the partition size is 50,681,692 1-kilobyte blocks.

Now it is important for me to find out what the block size of the device is.

### get block size of device (needed for mkfs later)
laurel_sprout:/ # blockdev --getbsz /dev/block/sda15
4096

On my device the block size is 4 kilobytes.

I can now calculate how many blocks (sectors) are 32 kilobytes smaller than the partition size. I use awk because there are not many tools on TWRP that can do math.

### calculate 32 kilobytes less than the partition size, in blocks
laurel_sprout:/ awk 'BEGIN { print ( ( 50681692 * 1024 ) - 32768 ) / 4096 }'
12670415

So I need to format /data as 12,670,415 sectors in size.

laurel_sprout:/ # mkfs.f2fs -l "mycustomdata" /dev/block/sda15 12670415

F2FS-tools: mkfs.f2fs Ver: 1.10.0 (2018-01-30)

Info: Disable heap-based policy
Info: Debug level = 0
Info: Label = mycustomdata
Info: Trim is enabled
Info: No support kernel version!
Info: wanted sectors = 12670415 (in 18446744073709551615 bytes)
Info: total device sectors = 12670423 (in 4096 bytes)
Info: Segments per section = 1
Info: Sections per zone = 1
Info: sector size = 4096
Info: total sectors = 12670415 (49493 MB)
Info: zone aligned segment0 blkaddr: 512
Info: [/dev/block/sda15] Discarding device
Info: This device doesn't support BLKSECDISCARD
Info: Discarded 49493 MB
Info: Overprovision ratio = 0.900%
Info: Overprovision segments = 449 (GC reserved = 230)
Info: format successful

Reboot into recovery (to remount /data).

Set the active slot to be the slot that you're NOT wanting to put PixelExperience on (because TWRP flashes ROMs to the other slot!!!).

Next, adb push PixelExperience and TWRP zip files onto /sdcard/. Then install PixelExperience and TWRP zips files.

Now set the active slot to the other slot, the one you're wanting PixelExperience on (so we can root it).

Next, adb push Magisk zip and apk, and patch_no_fde10 zip files onto /sdcard/. Then install Magisk and patch_no_fde10 zip files.

Reboot into system.

After the initial phone setup, go to Settings > Security > Encryption & credentials > Encrypt phone.

The screen will display the green Android robot logo on a black background for a few short seconds, then the phone will restart and display the "android ONE" logo for a very long time. For my 64GB Xiaomi Mi A3 it sat there for over 40 minutes before I gave up and just rebooted the phone. After which the system asked me for my PIN and I was able to boot the phone with the encrypted /data mount. Actually I tried the whole installation process a second time and restarted the phone after about a single minute after the reboot from enabling phone encryption but everything seems okay.

Just before the reboot the following messages appeared from the logcat:

12-02 21:59:08.508 460 460 D vold : fdeEnable(3, *, 0)
12-02 21:59:08.509 460 460 D vold : !fscrypt_is_native, spawning fdeEnableInternal
12-02 21:59:08.519 460 23938 E Cryptfs : Not a valid ext4 superblock
12-02 21:59:08.524 460 23938 D Cryptfs : Just asked init to shut down class main
12-02 21:59:08.914 460 23938 I vold : List of Keymaster HALs found:
12-02 21:59:08.914 460 23938 I vold : Keymaster HAL #1: Keymaster HAL: 4 from QTI SecurityLevel: TRUSTED_ENVIRONMENT HAL: android.hardware.keymaster@4.0::IKeymasterDevice/default
12-02 21:59:08.919 460 23938 D vold : Computing HMAC with params { (seed: 1234567890aaaabbbbccccddddeeeeffff111133335555777799990000222257, nonce: 1234567890aaaabbbbccccddddeeeeffff111133335555777799990000222) }
12-02 21:59:08.919 460 23938 D vold : Computing HMAC for Keymaster HAL: 4 from QTI SecurityLevel: TRUSTED_ENVIRONMENT HAL: android.hardware.keymaster@4.0::IKeymasterDevice/default
12-02 21:59:08.932 460 23938 I vold : Using Keymaster HAL: 4 from QTI for encryption. Security level: TRUSTED_ENVIRONMENT, HAL: android.hardware.keymaster@4.0::IKeymasterDevice/default
12-02 21:59:08.943 460 23938 I vold : List of Keymaster HALs found:
12-02 21:59:08.944 460 23938 I vold : Keymaster HAL #1: Keymaster HAL: 4 from QTI SecurityLevel: TRUSTED_ENVIRONMENT HAL: android.hardware.keymaster@4.0::IKeymasterDevice/default
12-02 21:59:08.944 460 23938 I vold : Using Keymaster HAL: 4 from QTI for encryption. Security level: TRUSTED_ENVIRONMENT, HAL: android.hardware.keymaster@4.0::IKeymasterDevice/default

Once rebooted the data mount appears as follows:

$ adb shell
laurel_sprout:/ $ mount |grep "on /data "
/dev/block/dm-0 on /data type f2fs (rw,lazytime,seclabel,nosuid,nodev,noatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,extent_cache,mode=adaptive,active_logs=6,reserve_root=24712,resuid=0,resgid=1065,alloc_mode=default,fsync_mode=nobarrier)

Note that TWRP can no longer see the encrypted partition.

After this I tried installing a later version of PixelExperience using TWRP. I installed PixelExperience ROM, followed by TWRP zip, then switched to the slot I was using, and installed Magisk zip again, but did not install patch_no_fde10.zip, it is no longer necessary after phone has been encrypted.

Now you've got an encrypted partition, want to take a copy from TWRP, and mount it in Linux? Do the following.

While you're in the system ROM run the following command to discover your encryption key:

$ adb shell
laurel_sprout:/ $ su
laurel_sprout:/ # dmctl list devices
Available Device Mapper Devices:
userdata : 253:0

laurel_sprout:/ # dmctl list targets
Available Device Mapper Targets:
verity : 1.4.0
default-key : 1.0.0
crypt : 1.18.1
striped : 1.6.0
linear : 1.4.0
error : 1.5.0

laurel_sprout:/ # dmctl table userdata
Targets in the device-mapper table for userdata:
0-101363352: crypt, aes-cbc-essiv:sha256 aabbccddeeff00112233445566778899 0 8:15 0 1 allow_discards

Okay that 32 character hex string is your encryption key. It is 16 bytes (256 bits) in length.

Restart the phone in recovery (TWRP). Pull the entire partition (approx 64GB or 128GB depending on your phone model) to your desktop/laptop:

$ adb pull -p /dev/block/sda15 android-encrypted-data-partition.img

Now to mount we first have to open the file as a local device:

$ losetup --list
$ sudo losetup /dev/loop7 android-encrypted-data-partition.img

Next we want to decrypt this local device using the hex encryption key we gathered above (including the offsets from the same entry):

$ sudo dmsetup ls
$ sudo dmsetup create crypt7 --table "0 101363352 crypt aes-cbc-essiv:sha256 aabbccddeeff00112233445566778899 0 /dev/loop7 0"

Now it is time to mount the decrypted partition (you may need to install the f2fs-tools package if you use Ubuntu):

# mount dirty partition
# noexec - do not allow direct execution of binaries on mount
# norecovery - do not attempt to replay dirty log which requires read-write
# ro - read only
$ sudo mount -o ro,norecovery,noexec -t f2fs /dev/mapper/crypt7 /mnt/android

You can now view the mounted partition in /mnt/android.

Then it is time to clean up:

# unmount and clean up
$ sudo umount /dev/mapper/crypt7
$ sudo dmsetup remove crypt7
$ sudo losetup --detach /dev/loop7