热度 19
2019-8-8 17:02
2539 次阅读|
0 个评论
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 mapper support Device mapper debugging support Crypt target support 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 容量 root@apalis-imx6:~# cd /home/root/ root@apalis-imx6:~# dd if=/dev/urandom of=test.luks bs=1M count=100 # 创建加密分区,这里会要求设置加密密码,如果需要调试,可以增加 --debug 调试参数 root@apalis-imx6:~# 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 文件,并添加到加密分区 root@apalis-imx6:~# dd if=/dev/urandom of=key bs=1024 count=4 root@apalis-imx6:~# cryptsetup luksAddKey test.luks key Enter any existing passphrase: # 打开加密分区 // 手动方式,需要手动输入并验证密码 root@apalis-imx6:~# cryptsetup luksOpen test.luks testvolume Enter passphrase for test.luks: // 通过 key 文件自动方式 root@apalis-imx6:~# cryptsetup luksOpen --key-file key test.luks testvolume # 格式化加密分区 root@apalis-imx6:~# 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 # 挂载加密分区 root@apalis-imx6:~# mkdir /mnt/test root@apalis-imx6:~# mount /dev/mapper/testvolume /mnt/test/ # 然后就可以进入 /mnt/test/ 对加密分区进行操作,操作完成后,解除挂载并关闭加密分区 root@apalis-imx6:/# umount /mnt/test root@apalis-imx6:/# 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 文件 ../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 可用的文件 ../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 ... … Freeing unused kernel memory: 1024K hub 1-1.1:1.0: USB hub found hub 1-1.1:1.0: 4 ports detected EXT4-fs (dm-0): couldn't mount as ext3 due to feature incompatibilities EXT4-fs (dm-0): couldn't mount as ext2 due to feature incompatibilities EXT4-fs (dm-0): recovery complete EXT4-fs (dm-0): mounted filesystem with ordered data mode . Opts: (null) systemd : System time before build time, advancing clock. systemd : systemd 234 running in system mode. (+PAM -AUDIT -SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP -LIBCRYPTSETUP -GCRYPT -GN) systemd : 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 来加密磁盘,以便对相关数据进行保护。