Adam's blog: Saving photos on an unencrypted smartphone SD card

12 Sep 2022, 1296 words

When I have bought my Sony Xperia XA2, my main goal was to buy a phone that can run a (mostly) open-source OS – LineageOS. My last smartphone, the Xiaomi Redmi 4X, has supported a feature in which an SD card could be encrypted and extend the internal phone storage. It has newer occurred to me that this newer phone may not support this. Now I am stuck with my 32 GB of internal storage, where 29 GB is already occupied by the system and apps. Where can I keep my photos?

Internal storage

By default, all photos taken with the preinstalled LineageOS camera are saved to a fixed location inside the internal storage, and there is no option to change that behavior. Other applications, like OpenCamera, do not work as well with the device’s camera. As stated before, the internal storage is already quite occupied and would not stand a chance against a longer 4K video. I have to store it somewhere else.

External storage

My phone supports only an unencrypted ex-FAT formatted SD card, which limits my options by a large margin. On my previous phone, I had an option to format the SD card as a part of the encrypted internal storage. Unfortunately, as I have learned perhaps too late, my phone does not support this method. There are many applications on the Google Play Store, that claim to encrypt and protect your photos, but I see four main deal-breakers with this approach:

  1. they are not open-source
  2. they use an unspecified encryption algorithm
  3. they mostly do not allow you to select where to store the encrypted photos
  4. storing photos cannot be automatized

DroidFS

On the other hand, on the F-Droid, I have found a neat application called DroidFS. This application internally creates a gocryptfs volume(s) with a custom location and passphrases (with an optional fingerprint unlock). This application is open source, uses a known encryption algorithm, and lets you select where to store the photos. The only problem is with the automation of the encryption process – if you would want to add photos through an external app, you would have to first mount the gocryptfs volume, which depends on /dev/fuse, which is not available without rooting the phone, which is something I do not want to do, as this could break my SafetyNet.

The only implementation without the requirement for fuse device that I have found is gocryptfs-inspect, but this works only for a decryption of files, not encryption.

I am certain that it would be possible to create a custom project in Python that would also work for encrypting files, but I would rather find an easier solution.

RCX - Rclone for Android

Rclone is an application that I have already mentioned on this blog at least once. Its center point are so called “Storage systems”, which can be a real type of storage – e.g. local drive, SFTP, Google Drive – or a virtual one – e.g. a crypt storage that takes another storage and performs a transparent encryption upon it.

RCX - Rclone for Android is an open-source Android application that can manage and connect to the rclone “Storage systems”. Furthermore, it also integrates well with the Android’s SAF, so that I can access the content from the Total Commander application.

Even better, when saved into a shared directory on a SD card, I can gain a full control with Termux bash shell! The shared directory on the SD card, to which all applications can both read and write, is located at /storage/<sd-id>/Android/media/. With the RCX we can create a new directory – /storage/<sd-id>/Android/media/photos.crypt – and a corresponding crypt remote. Then we can export the configuration from the RCX and import it into Termux.

Automating the process

Now I have a rclone remote called Photos both in RCX and Termux. This remote is a crypt wrapper over a physical /storage/<sd-id>/Android/media/photos.crypt directory. The Photos remote has disabled filename obfuscation.

The thing that I do want to do now is for the photos and videos from my internal storage to be encrypted and copied to the SD card, where they will be sorted by their year and month for easier browsing. This task can be achieved with a following script:

#!/bin/bash

# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euo pipefail

# Set the initial directory to the scripts location
cd "$(dirname "$(realpath "$0")")"

# All picures and videos start with IMG_ or VID_, followed by year, month and day
template='^((IMG_)|(VID_))([0-9]{4})([0-9]{2})([0-9]{2})_.*?$'

# Where to look for original files
directories=( "$HOME/storage/pictures/" "$HOME/storage/movies/" )

# Encrypt all files
for directory in "${directories[@]}"; do
    echo "Encrypting $directory"
    cd "$directory"
    for f in *; do
        if [ ! -f "$f" ]; then
            continue
        fi
        echo "$f" | grep -qE "$template" || continue

        echo "... $f"
        rclone moveto --progress "$f" "Photos:/$f"
    done
done

# Move the encrypted files into coorrect sub-directories by year and month
echo "Moving"
cd /storage/sdcard/Android/media/photos.crypt

for f in *; do
    if [ ! -f "$f" ]; then
        continue
    fi
    echo "$f" | grep -qE "$template" || continue

    echo "... $f"
    year="$(echo "$f" | sed -Ee "s/$template/\\4/")"
    month="$(echo "$f" | sed -Ee "s/$template/\\5/")"
    day="$(echo "$f" | sed -Ee "s/$template/\\6/")"

    directory="$year/$month"
    mkdir -p "$directory"
    mv "$f" "$directory/"
    echo "$f -> $directory"
done

Optionally, if I would want to synchronize the content of Photos remote with my cloud storage, the process would be fairly easy – I just have to add a new rclone remote and then sync them by adding the following lines at the end of the script:

# Optionally synchronize with cloud
set +u
if [ -n "$1" ] && [ "$1" == "--sync" ]; then
    echo "Syncing"
    rclone sync --progress Photos:/ cloud:/Photos/
fi

Final words

I have tried several options on how to securely store photos on an unencrypted SD card. In the end, I have settled for a script that takes care of the encryption for me and also can synchronize my files with my cloud storage. Now I can set up a cron job inside the Termux or use something like Tasker or Automate to have it run in periodical intervals. My internal storage space is saved!