Decrypting Android M adopted storage
One of the new features Android M introduces is adoptable storage. This feature allows external storage devices such as SD cards or USB drives to be 'adopted' and used in the same manner as internal storage. What this means in practice is that both apps and their private data can be moved to the adopted storage device. In other words, this is another take on everyone's (except for widget authors...) favorite 2010 feature -- AppsOnSD. There are, of course, a few differences, the major one being that while AppsOnSD (just like app Android 4.1 app encryption) creates per-app encrypted containers, adoptable storage encrypts the whole device. This short post will look at how adoptable storage encryption is implemented, and show how to decrypt and use adopted drives on any Linux machine.
It completes with error, so we can now try to mount the mapped device, again guessing that the file system is most probably ext4 (or you can inspect the mapped device and find the superblock first, if you want to be extra diligent).
Adopting an USB drive
In order to enable adoptable storage for devices connected via USB you need to execute the following command in the Android shell (presumably, this is not needed if your device has an internal SD card slot; however there are no such devices that run Android M at present):
Now, if you connect a USB drive to the device's micro USB slot (you can also use an USB OTG cable), Android will give you an option to set it up as 'internal' storage, which requires reformatting and encryption. 'Portable' storage is formatted using VFAT, as before.
After the drive is formatted, it shows up under Device storage in the Storage screen of system Settings. You can now migrate media and application data to the newly added drive, but it appears that there is no option in the system UI that allows you to move applications (APKs).
Adopted devices are mounted via Linux's device-mapper under
You can safely eject an adopted drive by tapping on it in the Storage screen, and the choosing Eject from the overflow menu. Android will show a persistent notification that prompts you to reinsert the device once it's removed. Alternatively, you also can 'forget' the drive, which removes it from the system, and should presumably delete the associated encryption key (which doesn't seem to be the case in the current preview build).
$ adb shell sm set-force-adoptable true
Now, if you connect a USB drive to the device's micro USB slot (you can also use an USB OTG cable), Android will give you an option to set it up as 'internal' storage, which requires reformatting and encryption. 'Portable' storage is formatted using VFAT, as before.
After the drive is formatted, it shows up under Device storage in the Storage screen of system Settings. You can now migrate media and application data to the newly added drive, but it appears that there is no option in the system UI that allows you to move applications (APKs).
Adopted devices are mounted via Linux's device-mapper under
/mnt/expand/
as can be seen below, and can be directly accessed only by system apps.$ mount rootfs / rootfs ro,seclabel,relatime 0 0 ... /dev/block/dm-1 /mnt/expand/a16653c3-... ext4 rw,dirsync,seclabel,nosuid,nodev,noatime 0 0 /dev/block/dm-2 /mnt/expand/0fd7f1a0-... ext4 rw,dirsync,seclabel,nosuid,nodev,noatime 0 0
You can safely eject an adopted drive by tapping on it in the Storage screen, and the choosing Eject from the overflow menu. Android will show a persistent notification that prompts you to reinsert the device once it's removed. Alternatively, you also can 'forget' the drive, which removes it from the system, and should presumably delete the associated encryption key (which doesn't seem to be the case in the current preview build).
Inspecting the drive
Once you've ejected the drive, you can connect it to any Linux box in order to inspect it. Somewhat surprisingly, the drive will be automatically mounted on most modern Linux distributions, which suggests that there is at least one readable partition. If you look at the partition table with
fdisk
or a similar tool, you may see something like this:# fdisk /dev/sdb Disk /dev/sdb: 7811 MB, 7811891200 bytes, 15257600 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: gpt # Start End Size Type Name 1 2048 34815 16M unknown android_meta 2 34816 15257566 7.3G unknown android_expand
As you can see, there is a tiny
android_meta
partition, but the bulk of the device has been assigned to the android_expand
partition. Unfortunately, the full source code of Android M is not available, so we cannot be sure how exactly this partition table is created, or what the contents of each partition is. However, we know that most of Android's storage management functionality is implemented in the vold
system daemon, so we check if there is any mention of android_expand
inside vold
with the following command:$ strings vold|grep -i expand --change-name=0:android_expand %s/expand_%s.key /mnt/expand/%s
Here
expand_%s.key
suspiciously looks like a key filename template, and we already know that adopted drives are encrypted, so our next step is to look for any similar files in the device's /data
partition (you'll need a custom recovery or root access for this). Unsurprisingly, there is a matching file in /data/misc/vold
which looks like this:# ls /data/misc/vold bench expand_8838e738a18746b6e435bb0d04c15ccd.key # ls -l expand_8838e738a18746b6e435bb0d04c15ccd.key -rw------- 1 root root 16 expand_8838e738a18746b6e435bb0d04c15ccd.key # od -t x1 expand_8838e738a18746b6e435bb0d04c15ccd.key 0000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0000020
Decrypting the drive
That's exactly 16 bytes, enough for a 128-bit key. As we know, Android's FDE implementation uses an AES 128-bit key, so it's a good bet that adoptable storage uses a similar (or identical) implementation. Looking at the start and end of ourandroid_expand
partition doesn't reveal any readable info, nor is it similar to Android's crypto footer, or LUKS's header. Therefore, we need to guess the encryption mode and/or any related parameters. Looking once again at Android's FDE implementation (which is based on the dm-crypt target of Linux's device-mapper), we see that the encryption mode used is aes-cbc-essiv:sha256
. After consulting dm-crypt's mapping table reference, we see that the remaining parameters we need are the IV offset and the starting offset of encrypted data. Since the IV offset is usually zero, and most probably the entire android_expand
partition (offset 0) is encrypted, the command we need to map the encrypted partition becomes the following:# dmsetup create crypt1 --table "0 `blockdev --getsize /dev/sdb2` crypt \ aes-cbc-essiv:sha256 00010203040506070809010a0b0c0d0e0f 0 /dev/sdb2 0"
It completes with error, so we can now try to mount the mapped device, again guessing that the file system is most probably ext4 (or you can inspect the mapped device and find the superblock first, if you want to be extra diligent).
# mount -t ext4 /dev/mapper/crypt1 /mnt/1/ # cd /mnt/1 # find ./ -type d ./ ./lost+found ./app ./user ./media ./local ./local/tmp ./misc ./misc/vold ./misc/vold/bench
This reveals a very familiar Android
If you have root access, you can also partition, format, mount, unmount and forget disks/volumes. The full list of supported commands is shown in the following listing.
Most features are also available from the system UI, but
/data
layout, and you should see any media and app data you've moved to the adopted device. If you copy any files to the mounted device, they should be visible when you mount the drive again in Android. Storage manager commands
Back in Android, you can use thesm
command (probably short for 'storage manager') we showed in the first section to list disks and volumes as shown below:$ sm list-disks disk:8,16 disk:8,0 $ sm list-volumes emulated:8,2 unmounted null private mounted null private:8,18 mounted 0fd7f1a0-2d27-48f9-8702-a484cb894a92 emulated:8,18 mounted null emulated unmounted null private:8,2 mounted a16653c3-6f5e-455c-bb03-70c8a74b109e
If you have root access, you can also partition, format, mount, unmount and forget disks/volumes. The full list of supported commands is shown in the following listing.
$ sm usage: sm list-disks sm list-volumes [public|private|emulated|all] sm has-adoptable sm get-primary-storage-uuid sm set-force-adoptable [true|false] sm partition DISK [public|private|mixed] [ratio] sm mount VOLUME sm unmount VOLUME sm format VOLUME sm forget [UUID|all]
Most features are also available from the system UI, but
sm
allows you to customize the ratio of the android_meta
and android_expand
partitions, as well as to create 'mixed' volumes.Summary
Android M allows for adoptable storage, which is implemented similarly to internal storage FDE -- using dm-crypt with a per-volume, static 128-bit AES key, stored in
/data/misc/vold/
. Once the key is extracted from the device, adopted storage can be mounted and read/written on any Linux machine. Adoptable storage encryption is done purely in software (at least in the current preview build), so its performance is likely comparable to encrypted internal storage on devices that don't support hardware-accelerated FDE.
Comments
Could you possibly elaborate a bit more on how adoptable storage is exposed to applications? The preview SDK docs are unfortunately not very helpful.
- Is an encrypted card usable for media files without migrating just like an unencrypted card, i.e. is migration decoupled from encryption?
- Where is the primary shared storage mounted, and does that change after migrating application data? What does Context.getExternalFilesDirs() return in each case?
- After migration, is the internal (emulated) shared storage still accessible (via file managers and/or the external storage APIs), or is it completely shadowed by the external shared storage?
- Where are APK expansion files (OBBs) stored, before and after migration?
You can write a simple app to check how the Contexts methods behave
Many people have been stuck with adopted internal storage, because they then have no SD card to which Google Play Music can store the music; and as Google Play Music won't move to the adopted SD card, all music is stored in the internal memory. For me, I have more music than Apps, so this just makes things worse.
However your reference to "sm" and "mixed" gave me something to work with.
$ adb shell sm list-disks adoptable
disk:179_64
$ sm partition disk:179_64 mixed 75
$
gives me 75% as portable storage.
However I advise a reboot after setting the new music storage location this as Google Music may get the wrong idea about much space is available.
http://blog.sam.liddicott.com/2016/02/android-6-semi-adopted-storage.html
Now I want to use the card as portable in my phone.
Can't seem to format it either as portable card or internal card.
Will this technique help? If yes, then great I'm gonna try it and let you know.
If no please guide me through the way which may help me.
I would say that you probably need a new card.
I would say that you probably need a new card.
I'll apreciate your help since I am really desperate and nobody can give me any solution.
Thanks.
command:
dmsetup create mmc --table "0 62299103 crypt aes-cbc-essiv_sha256 1hereismykey1 0 /dev/mmcblk0p2 0"
the result is
"device-mapper: reload ioctl on mmc failed: Invalid argument
Command failed"
dmesg says:
[119671.798439] device-mapper: table: 252:3: crypt: Invalid IV mode
[119671.798447] device-mapper: ioctl: error adding target to table
Any suggestions?
thx
just for the record:
the filesystem on the encrypted card was "f2fs" in my case.
I am using Marshmellow 6.0.1
Trying to decrypt my SD card so I can expand a partition here, but when I run:
dmsetup create crypt1 --table "0 `blockdev --getsize /dev/mmcblk0p2` crypt \aes-cbc-essiv:sha256 0...f 0 /dev/mmcblk0p2 0"
I get the error:
device-mapper: reload ioctl on crypt1 failed: No such file or directory
and I'm not quite sure what to make of it. Could you point me in the right direction?
Cheers.
Thanks!
I have recently upgraded my phone to Android 6.0
Everything worked fine until i formatted my SD card to Internal.
After the conversion, it was working well. I was pretty much satisfied. With that confidence, i moved all my apps from Internal to SD card.
After some minutes my phone got struck, so i restarted by removing and placing the battery in the back.
When it booted up it didn't detect my SD card and kept showing an error that, i need to Forget my SD card.
i googled the condition and found a post explaining the issue that it is Android 6.0's bug, and it's highly recommended to not move apps from Internal to SD card without a reboot, after converting the SD card to Internal.
The post also explained about wiping the SD card, as the only option left, and instructed to fastboot the device.
For some unknown reasons, the default "hold press Power button and press Volume Down" didn't work in my phone and it took me to a meta mode, where nothing is displayed apart from saying that it is a meta mode.
Then i took a wrong turn by repeating the same by pressing the Power and Volume Up button. It took me to factory mode, where i was displayed with 6 options in Chinese.
I can't read Chinese, and one of the option had an English word "eMMC", i thought this was the option to wipe out the SD card and selected it. It restored my phone to factory settings by erasing the Internal memory instead of the SD card.
Now, my phone detects my SD card, but shows it as "Unsupported" under Storage and USB option. And it asks me to Set Up the SD card by formatting it.
There are two options, "Use as portable storage" and "Use as Internal Storage".
If i select the first option, it says SD card is ready. But it doesn't format or fix the errors . And if i go for the 2nd option, it doesn't format and it displays the following error as a Toast.
Couldn't erase SD card
command '46 volume partition disk: 179,128 private' failed with '400 46 Command failed'
This is a Strontium 32GB class 10 SD Card. Kindly help me to format the SD Card and fix it's errors so i can use it again.
Some months ago, I had to do a hard reset on my phone, since then I have my 32gb sd card encrypted, it was originally set as adopted storage.
After a lot of search, I'm still trying to recover such important files that I have in this sd card, after I fone The hard reset on my phone, is there any way to save the data on The sd? If I lost the encryption key, is there any chance to recover my sd data?
Is it possible to recover data from the old card, if I clicked "forget" the disk and replaced it with a new one. Whether the result of this operation, a new encryption key is created and with it it is impossible to do?
When set adoptable is done to true afyer has adoptable command it again shows false
Unable to set it to true
Please help hard earned money sdcard waste
Tried cmd prompt and all formatters
Adb shell method also fail
Thanks!
But I still get an error when I try the command :
dmsetup create crypt1 --table "0 `blockdev --getsize /dev/mmcblk0` crypt \aes-cbc-essiv:sha256 0180e00...170fe15b73b4f 0 /dev/mmcblk0 0"
device-mapper: reload ioctl on crypt1 failed: No such file or directory
Command failed
in dmesg I get :
[11652.228696] device-mapper: table: 252:0: crypt: Error allocating crypto tfm
[11652.228702] device-mapper: ioctl: error adding target to table
Please help !
I've posted a possible solution in order to retrieve the data (somehow the SD-card got corrupted). I did not have a rooted phone so decryption would take years...
Read how I got it back on:
https://android.stackexchange.com/questions/174799/moto-g3-android-marshmallow-not-detecting-sd-card-anymore-solution
sudo dmsetup create crypt1 --table "0 'blockdev --getsize /dev/sdd2' crypt \aes-cbc-essiv:sha256 63d27a5ac67ec961207eda47f34aa99c 0 /dev/sdd2 0"
Invalid format on line 1 of table
Command failed
My dmesg show:
29213.292481] usb 1-1.2: Product: USB Storage
[29213.292483] usb 1-1.2: Manufacturer: Generic
[29213.292485] usb 1-1.2: SerialNumber: 000000000819
[29213.292997] usb-storage 1-1.2:1.0: USB Mass Storage device detected
[29213.293142] scsi10 : usb-storage 1-1.2:1.0
[29214.290181] scsi 10:0:0:0: Direct-Access Generic STORAGE DEVICE 0819 PQ: 0 ANSI: 6
[29214.290596] sd 10:0:0:0: Attached scsi generic sg4 type 0
[29214.457848] sd 10:0:0:0: [sdd] 61734912 512-byte logical blocks: (31.6 GB/29.4 GiB)
[29214.458941] sd 10:0:0:0: [sdd] Write Protect is off
[29214.458948] sd 10:0:0:0: [sdd] Mode Sense: 23 00 00 00
[29214.459941] sd 10:0:0:0: [sdd] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[29214.497989] sdd: sdd1 sdd2
[29214.501822] sd 10:0:0:0: [sdd] Attached SCSI removable disk
Any idea?
dmsetup create sd1 --table "0 `blockdev --getsize /dev/sdb2` crypt aes-cbc-essiv:sha256 bbbbc2188b3e4a7476148a9411545715 0 /dev/sdb2 0"
device-mapper: reload ioctl on sd1 failed: Invalid argument
Any help is appreciated
Regards
Chinmay
Is that typo or am I missing something?