天天看點

嵌入式 ARM 平台使用dm-crypt加密磁盤分區

By Toradex秦海

1). 簡介

出于安全考慮,嵌入式裝置有時需要将某個資料分區甚至整個檔案系統進行加密處理,本文就介紹在嵌入式Linux系統下基于dm-crypt進行加密示例,dm-crypt加密具有速度快,易用性強,适用性廣等特點,dm-crypt內建于linux kernel中,通過前端應用cryptsetup來進行調用。

本文示範所使用的ARM平台來自Toradex基于NXP iMX6Q SoC平台的Apalis iMX6 ARM核心闆。

2). 準備

a). Apalis iMX6Q ARM核心版配合Apalis Evaluation Board載闆,連接配接調試序列槽UART1(載闆X29)到開發主機友善調試。更多關于Apalis iMX6配合Apalis Evaluation Board載闆的說明請參考Datasheet和開發上手指南。

b). 開發Linux PC主機, 用于搭建Ycoto Project/OpenEmbedded 編譯環境,友善編譯針對Apalis iMX6Q的內建所需功能的測試Linux image。

3). 編譯內建dm-crypt的Linux image

a). 首先根據下面文章的描述在Linux開發主機上面配置Ycoto Project/OpenEmbedded編譯環境

https://developer.toradex.cn/knowledge-base/board-support-package/openembedded-(core)

本文配置使用 LinuxImageV2.8 分支。

b). 配置Linux kernel,增加dm-crypt的支援

-----------------------

$ cd oe-core/build

$ make -c menuconfig virtual/kernel

Device Drivers  --->

[*] Multiple devices driver support (RAID and LVM)  --->

<*>   Device mapper support

[*]     Device mapper debugging support

<*>     Crypt target support

-*- Cryptographic API  --->

<*>   User-space interface for hash algorithms

<*>   User-space interface for symmetric key cipher algorithms

<*>   User-space interface for random number generator algorithms

<*>   User-space interface for AEAD cipher algorithms

$ bitbake virtual/kernel -f -c deploy

$ bitbake virtual/kernel -f -c compile

-----------------------

c). 修改配置檔案以增加所需要的安裝包

./ conf/local.conf 檔案

https://github.com/simonqin09/crypt_test/blob/master/local.conf.patch

./ layers/meta-openembedded/meta-oe/recipes-support/lvm2/libdevmapper_2.02.171.bb 檔案

https://github.com/simonqin09/crypt_test/blob/master/libdevmapper.patch

d). 編譯部署image

./ 執行下面指令編譯 Linux image

-----------------------

$ bitbake -k angstrom-lxde-image

-----------------------

./ 編譯成功的image位于 ../deploy/images/apalis-imx6/ 目錄,參考這裡的說明将linux image更新到Apalis iMX6子產品上

4). 測試加密資料分區(非rootfs啟動分區)

a). 進入上一步驟更新好的Apalis iMX6 Linux系統序列槽終端,首先準備用于加密的分區,可以是實際的實體分區(如外部USB盤,SD卡或者sata硬碟等),也可以通過 dd 指令在現有eMMC Linux 分區上面建立一個分區塊,其後續加密操作都是類似的,本文就以後者作為示範。

b). 具體操作流程如下:

-----------------------

# 在 $HOME 目錄下建立用于測試的分區塊,100MB容量

[email protected]:~# cd /home/root/

roo[email protected]:~# dd if=/dev/urandom of=test.luks bs=1M count=100

# 建立加密分區,這裡會要求設定加密密碼,如果需要調試,可以增加 --debug 調試參數

[email protected]:~# cryptsetup luksFormat test.luks

WARNING!

========

This will overwrite data on test.luks irrevocably.

Are you sure? (Type uppercase yes): YES

Enter passphrase:

Verify passphrase:

# 可選操作:如果想要實作自動通過腳本挂載,則需要配置 key 檔案,并添加到加密分區

[email protected]:~# dd if=/dev/urandom of=key bs=1024 count=4

[email protected]:~# cryptsetup luksAddKey test.luks key

Enter any existing passphrase:

# 打開加密分區

// 手動方式,需要手動輸入并驗證密碼

[email protected]:~# cryptsetup luksOpen test.luks testvolume

Enter passphrase for test.luks:

// 通過 key 檔案自動方式

[email protected]:~# cryptsetup luksOpen --key-file key test.luks testvolume

# 格式化加密分區

[email protected]:~# mkfs.ext4 -j /dev/mapper/testvolume

mke2fs 1.43.5 (04-Aug-2017)

Creating filesystem with 100352 1k blocks and 25168 inodes

Filesystem UUID: db13767e-9057-48f2-9908-31a14ec6d02c

Superblock backups stored on blocks:

        8193, 24577, 40961, 57345, 73729

Allocating group tables: done                           

Writing inode tables: done                           

Creating journal (4096 blocks): done

Writing superblocks and filesystem accounting information: done

# 挂載加密分區

[email protected]:~# mkdir /mnt/test

[email protected]:~# mount /dev/mapper/testvolume /mnt/test/

# 然後就可以進入 /mnt/test/ 對加密分區進行操作,操作完成後,解除挂載并關閉加密分區

[email protected]:/# umount /mnt/test

[email protected]:/# cryptsetup luksClose testvolume

-----------------------

5). 測試加密 Rootfs 啟動分區

a). 由于Uboot下無法完成對加密啟動分區的解密,是以我們需要準備一個最小啟動initramfs鏡像,uboot加載initramfs啟動後再解密并挂載rootfs啟動分區,最後切換到這個啟動分區來完成整個啟動過程

b). 首先還是通過之前配置好的Ycoto環境編譯所需的initramfs鏡像

-----------------------

# 配置busybox,增加 --install 和 mdev 支援

./ 添加 fragment.cfg 檔案到 layers/openembedded-core/meta/recipes-core/busybox/busybox/ 目錄,内容如下:

https://github.com/simonqin09/crypt_test/blob/master/fragment.cfg

./ 如下修改 layers/openembedded-core/meta/recipes-core/busybox/busybox_1.24.1.bb 檔案

https://github.com/simonqin09/crypt_test/blob/master/busybox.patch

./ 如下修改 layers/meta-openembedded/meta-initramfs/recipes-bsp/images/initramfs-debug-image.bb 檔案

https://github.com/simonqin09/crypt_test/blob/master/initramfs-debug-image.patch

# 編譯 initramfs image

$ cd build

$ bitbake -k initramfs-debug-image

-----------------------

c). 添加 key 檔案到initramfs image中

-----------------------

# 從生成目錄将 initramfs image檔案複制到PC的工作目錄

$ mkdir work-dir

$ cd work-dir

$ cp deploy/images/apalis-imx6/Angstrom-initramfs-debug-image-glibc-ipk-v2017.12-apalis-imx6.rootfs.cpio.gz .

# 解壓cpio.gz檔案,并生成随機内容的key檔案,為後面加密rootfs啟動分區使用

$ mkdir temp

$ cd temp

$ gunzip -c ../Angstrom-initramfs-debug-image-glibc-ipk-v2017.12-apalis-imx6.rootfs.cpio.gz | cpio -i

$ dd if=/dev/urandom of=key bs=1024 count=4

# 重新壓縮為 cpio.gz 檔案

$ find . | cpio -H newc -o | gzip -9 > ../initramfs.cpio.gz

# 将生成的 cpio.gz 檔案轉換為 uboot 可用的initramfs image

$ cd ..

$ mkimage -A arm -O linux -T ramdisk -n "Initial Ram Disk" -d initramfs.cpio.gz initramfs.img

-----------------------

d). 将生成的 initramfs.img 檔案複制到FAT32分區的SD卡上面,連接配接到Apalis iMX6底闆X18 8bit SD插槽。啟動Apalis iMX6子產品,進入 uboot 指令行,将 initramfs image檔案複制到 iMX6 boot 分區并修改啟動參數

-----------------------

# 複制 initramfs image到boot分區

Apalis iMX6 # mmc rescan

Apalis iMX6 # load mmc 1:1 ${ramdisk_addr_r} initramfs.img

Apalis iMX6 # fatwrite mmc 0:1 ${ramdisk_addr_r} initramfs.img ${filesize}

# 修改啟動環境變量

Apalis iMX6 # setenv boot_initfs ‘run load_initramfs_files && bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}’

Apalis iMX6 # setenv load_initramfs_files ‘load mmc 0:1 ${fdt_addr_r} ${fdt_file}; load mmc 0:1 ${ramdisk_addr_r} initramfs.img; load mmc 0:1 ${kernel_addr_r} ${boot_file}’

Apalis iMX6 # setenv bootcmd ‘run boot_initfs; echo; echo initramfs_failed; run emmcboot ; echo ; echo emmcboot failed ; run nfsboot ; echo ; echo nfsboot failed ; usb start ;setenv stdout serial,vga ; setenv stdin serial,usbkbd’

Apalis iMX6 # saveenv

-----------------------

e). 重新啟動後,系統會加載到initramfs環境下,然後進行對rootfs 分區進行加密操作

-----------------------

# 加密并挂載 rootfs 分區 /dev/mmcblk0p2

/ # cryptsetup luksFormat /dev/mmcblk0p2

/ # cryptsetup --debug luksAddKey /dev/mmcblk0p2 key

/ # cryptsetup luksOpen --key-file key /dev/mmcblk0p2 rootfs

/ # mke2fs -t ext4 /dev/mapper/rootfs

/ # mkdir -p /mnt/rootfs

/ # mount /dev/mapper/rootfs /mnt/rootfs

# 将rootfs 檔案複制到加密啟動分區

./ 首先将前面章節3生成的Linux image檔案 Apalis-iMX6_LXDE-Image-Tezi_2.8b6-2019xxxx.tar 解壓,并提取 rootfs壓縮包到FAT32 SD卡

$ tar xvf Apalis-iMX6_LXDE-Image-Tezi_2.8b6-2019xxxx.tar

$ cd Apalis-iMX6_LXDE-Image-Tezi_2.8b6

$ cp Apalis-iMX6_LXDE-Image.rootfs.tar.xz /media/sd (SD卡挂載目錄)

./ 然後将SD卡連接配接到 Apalis iMX6進行挂載

mkdir /mnt/sd

/ # mount -t vfat /dev/mmcblk1p1 /mnt/sd

./ 最後将SD卡裡面的rootfs檔案系統壓縮包解壓到剛才建立并挂載的加密啟動分區中

/ # cd /mnt/rootfs

/ # tar Jxf /mnt/sd/Apalis-iMX6_LXDE-Image.rootfs.tar.xz

# 解除安裝并關閉加密啟動分區

/ # umount /mnt/rootfs

/ # cryptsetup luksClose rootfs

-----------------------

f). 為了實作在 initramfs 環境下實作自動解密rootfs啟動分區并切換到啟動分區加載啟動,需要修改 initramfs image的 init腳本檔案

-----------------------

# 重新解壓上面操作 c 添加 key檔案後生成的 initramfs cpio.gz檔案

$ mkdir temp

$ cd temp

$ gunzip -c ../ initramfs.cpio.gz | cpio -i

# 替換 init 檔案為如下内容

https://github.com/simonqin09/crypt_test/blob/master/init.mod

# 重新壓縮并轉換為 uboot 可用的檔案

$ find . | cpio -H newc -o | gzip -9 > ../initramfs-new.cpio.gz

$ cd ..

$ mkimage -A arm -O linux -T ramdisk -n "Initial Ram Disk" -d initramfs-new.cpio.gz initramfs.img

-----------------------

g). 和上述操作 d 同樣方法将新的 initramfs.img 檔案複制到Apalis iMX6 boot分區後重新啟動,系統會正常啟動到最初的檔案系統了,然後就可以繼續進行其他操作了。

-----------------------

U-Boot 2016.11-2.8.6+g83a53c1 (Jul 29 2019 - 04:51:51 +0000)

CPU:   Freescale i.MX6Q rev1.5 at 792 MHz

Reset cause: POR

I2C:   ready

DRAM:  2 GiB

Hit any key to stop autoboot:  0

reading imx6q-apalis-eval.dtb

54620 bytes read in 18 ms (2.9 MiB/s)

reading initramfs-key.img

4455676 bytes read in 147 ms (28.9 MiB/s)

reading zImage

5483824 bytes read in 163 ms (32.1 MiB/s)

## Loading init Ramdisk from Legacy Image at 12200000 ...

   Image Name:   Initial Ram Disk

   Image Type:   ARM Linux RAMDisk Image (gzip compressed)

   Data Size:    4455612 Bytes = 4.2 MiB

Starting kernel ...

[    3.918790] Freeing unused kernel memory: 1024K

[    4.023894] hub 1-1.1:1.0: USB hub found

[    4.028022] hub 1-1.1:1.0: 4 ports detected

[    8.736558] EXT4-fs (dm-0): couldn't mount as ext3 due to feature incompatibilities

[    8.744787] EXT4-fs (dm-0): couldn't mount as ext2 due to feature incompatibilities

[    8.895730] EXT4-fs (dm-0): recovery complete

[    8.900834] EXT4-fs (dm-0): mounted filesystem with ordered data mode. Opts: (null)

[    9.345988] systemd[1]: System time before build time, advancing clock.

[    9.415901] systemd[1]: systemd 234 running in system mode. (+PAM -AUDIT -SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP -LIBCRYPTSETUP -GCRYPT -GN)

[    9.437154] systemd[1]: Detected architecture arm.

The Angstrom Distribution apalis-imx6 ttymxc0

Angstrom v2017.12 - Kernel

Apalis-iMX6_LXDE-Image 2.8b6 20190801

apalis-imx6 login:

-----------------------

6). 總結

本文示例了基于ARM嵌入式平台在嵌入式Linux系統下通過 dm-crypt 來加密磁盤,以便對相關資料進行保護。

下一篇: ES6接口