Yoctoで暗号化ディレクトリを使う

2024/03/26に公開

ディレクトリの内容を暗号化したい

昨今のIoTデバイスはいろいろな情報を暗号化などして保護することを要求されるケースが多々あります。Linuxではいくつか暗号化する仕組みがありますが、今回はYoctoでecryptfsを使って情報を保護する方法を試してみます。
方針としては独自のレイヤーを作って対応してみます。

layerの追加

以下のコマンドでlayerを追加します。

bitbake-layers create-layer meta-myapp

※pokyディレクトリ以下で実行します。

レシピの作成

まずrecipiesを格納するディレクトリを作成します。サンプルで作られたレシピは不要なので消しておきます。

cd meta-myapp/
rm -rf recipes-example

次に暗号化に使うレシピ名でディレクトリを作成します。今回はecryptfs-autoとecryptfs-auto-serviceという名前でレシピを作成します。ecryptfs-autoは必要なスクリプト類、ecryptfs-auto-serviceはsystemdで起動するための設定ファイルです。

mkdir recipes-ecryptfs-auto
mkdir recipes-ecryptfs-auto/ecryptfs-auto
mkdir recipes-ecryptfs-auto/ecryptfs-auto/files

mkdir recipes-ecryptfs-auto-service
mkdir recipes-ecryptfs-auto/ecryptfs-auto-service
mkdir recipes-ecryptfs-auto/ecryptfs-auto-service/files

レシピファイルの作成(ecryptfs-auto)

必要なスクリプト類を追加するためのレシピファイルを作成します。
ecryptfs-auto_1.0.bbという名前で以下の内容を保存します。保存先はmy-app/recipes-ecryptfs-auto/ecryptfs-autoです。

DESCRIPTION = "Automatically mount ecryptfs directory at startup using a generated password"
LICENSE = "CLOSED"

PR = "r0"

SRC_URI = "file://mount-ecryptfs.sh \
           file://gen-passwd.c"

S = "${WORKDIR}"

DEPENDS += " openssl"

do_compile() {
    ${CC} ${CFLAGS} ${LDFLAGS} gen-passwd.c -o gen-passwd -lcrypto
}

do_install() {
    install -d ${D}${sbindir}
    install -m 0755 ${WORKDIR}/gen-passwd ${D}${sbindir}


    install -d ${D}${sysconfdir}
    install -m 0755 ${WORKDIR}/mount-ecryptfs.sh ${D}${sysconfdir}

}

FILES:${PN} += "${sbindir}/gen-passwd \
                ${sysconfdir}/mount-ecryptfs.sh"

必要なファイルの追加(ecryptfs-auto)

meta-myapp/recipes-ecryptfs-auto/ecryptfs-auto/files以下に必要なファイルを格納します。以下の2種類のファイルを置きます。

  • mount-ecryptfs.sh
    今回は/data以下にsecureというディレクトリとinfoというディレクトリを準備し、secureが暗号化されたディレクトリ、infoがecryptfsで複合化されたディレクトリとします。
#!/bin/sh

ENCRYPTED_DIR="/data/secure"
MOUNT_POINT="/data/info"

if [ ! -e $ENCRYPTED_DIR ]; then
  mkdir $ENCRYPTED_DIR
fi
if [ ! -e $MOUNT_POINT ]; then
  mkdir $MOUNT_POINT
fi

PASSWORD=$(/usr/sbin/gen-passwd)
SIG2=$(printf "%s" "${PASSWORD}" | ecryptfs-add-passphrase --fnek | awk '/^Inserted/ {print substr($6, 2, length($6)-2)}')

SIG=$( echo $SIG2 | awk '{print $1}' )

# echo $PASSWORD
# echo $SIG2
# echo $SIG

mount -t ecryptfs $ENCRYPTED_DIR $MOUNT_POINT -o key=passphrase:passphrase_passwd=$PASSWORD,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_passthrough=n,no_sig_cache,ecryptfs_enable_filename_crypto=yes,ecryptfs_fnek_sig=$SIG
  • gen-passwd.c
    パスワードを生成するコードです。今回はCPUのシリアルとeth0のMACアドレスから生成してます。
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>


#define SERIAL_FILE "/proc/cpuinfo"
#define MAC_FILE "/sys/class/net/eth0/address"

// CPUのシリアル番号を取得する関数
void get_cpu_serial(char *serial) {
    FILE *fp;
    char line[256];    // CPUシリアル番号の読み込み

    if ((fp = fopen(SERIAL_FILE, "r")) != NULL) {
        while (fgets(line, sizeof(line), fp)) {
            if (strncmp(line, "Serial", 6) == 0) {
                strcpy(serial, strchr(line, ':') + 2);
                serial[strlen(serial) - 1] = '\0'; // 改行を削除
                break;
            }
        }
        fclose(fp);
    } else {
        *serial = '\x0';
    }
}

// LANのMACアドレスを取得する関数
void get_lan_mac(char *mac) {
    FILE *fp;
    char line[256];    // CPUシリアル番号の読み込み

    if ((fp = fopen(MAC_FILE, "r")) != NULL) {
        if (fgets(mac, sizeof(mac), fp) != NULL) {
            mac[strlen(mac) - 1] = '\0'; // 改行を削除
        }
        fclose(fp);
    } else {
        *mac = '\x0';
    }
}

// メイン関数
int main() {
    char cpu_serial[32] = {0};
    char lan_mac[32] = {0};
    char combined[64] = {0};
    unsigned char hash[SHA256_DIGEST_LENGTH];
    
    get_cpu_serial(cpu_serial);
    get_lan_mac(lan_mac);
    
    // シリアル番号とMACアドレスを結合
    sprintf(combined, "%s%s", cpu_serial, lan_mac);
    
    // SHA-256でハッシュ化
    SHA256((unsigned char*)combined, strlen(combined), hash);
    
    // ハッシュを16進数の文字列として出力
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        printf("%02x", hash[i]);
    }
    printf("\n");
    
    return 0;
}

レシピファイルの作成(ecryptfs-auto-service)

systemdで自動起動するための設定を追加するためのレシピファイルを作成します。
ecryptfs-auto-service_1.0.bbという名前で以下の内容を保存します。保存先はmy-app/recipes-ecryptfs-auto-service/ecryptfs-auto-serviceです。
YoctoのマニュアルではSYSTEMD_AUTO_ENABLEを"enable"に設定すると自動起動するように設定してくれるはずですが、どうにもうまく動いていないようなのでdo_install()で独自にsymbolic linkを作成して対応しています。

DESCRIPTION = "Automatically mount ecryptfs directory at startup using a generated password"
LICENSE = "CLOSED"

PR = "r0"

SRC_URI = "file://ecryptfs-mount.service"

S = "${WORKDIR}"

inherit systemd

SYSTEMD_PACKAGES = "${PN}"
SYSTEMD_SERVICE:${PN} = "ecryptfs-mount.service"
SYSTEMD_AUTO_ENABLE = "enable"

do_install() {

    install -d ${D}${systemd_system_unitdir}
    install -d ${D}${sysconfdir}/systemd/system/multi-user.target.wants
    
    install -m 0644 ${WORKDIR}/ecryptfs-mount.service ${D}${systemd_system_unitdir}/ecryptfs-mount.service
    ln -sf ${D}${systemd_system_unitdir}/ecryptfs-mount.service \
       ${D}${sysconfdir}/systemd/system/multi-user.target.wants/ecryptfs-mount.service
}

FILES:${PN} += "${systemd_unitdir}/system/ecryptfs-mount.service"

必要なファイルの追加(ecryptfs-auto-service)

meta-myapp/recipes-ecryptfs-auto/ecryptfs-auto/files以下に必要なファイルを格納します。

  • ecryptfs-mount.service
    systemdの設定ファイルです。
[Unit]
Description=Mount ecryptfs directory at startup
After=network.target

[Service]
Type=oneshot
ExecStart=/etc/mount-ecryptfs.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

bblayer.conf/local.confの修正

ecryptfsを利用できるように設定を変更します。

meta-securityレイヤーの追加

ecriptfsを利用するためにmeta-securityレイヤーを追加します。
まず、gitでmeta-securityレイヤーを取得します。

# poky以下に移動
git clone https://git.yoctoproject.org/git/meta-security
cd meta-security
git checkout -b kirkstone origin/kirkstone
cd ..
cd build
bitbake-layers add-layer ../meta-security/

必要なレシピを追加

local.confに以下を追加します。

DISTRO_FEATURES:append = " security"
IMAGE_INSTALL:append = " ecryptfs-utils"
IMAGE_INSTALL:append = " ecryptfs-auto"
IMAGE_INSTALL:append = " ecryptfs-auto-service"

イメージをビルド

修正が終わったらイメージをビルドして動作確認を行います。

bitbake core-image-minimal

イメージを書き込み、実際に暗号化されていることを確認します。

これで簡単な保護を行えることがわかりました。ラズパイとかでSDカード抜き取られた場合などは有効かと思います。

Discussion