Raspberry PiでSDカード暗号化をテスト

## ■動機
以前、[Jetson NanoでSDカード暗号化のテスト](qiita.com/kmitsu76/items/de6bcf96b48a3bde95cc)を実施した。
2023年現在のRaspberry Piのセキュリティ対策方法を確認するため検証した。

## ■目指した状態
1. Raspberry PiのSDカードを暗号化し、SDカードをコピーされて内容を見られることを防ぎたい。
2. 暗号化をLUKS+cryptsetupを利用して行うが、手動でLUKS鍵を入力するのではなく、自動で鍵を入力させたい。
3. 鍵入力を自動で行うが、LUKS鍵データをそのままフラッシュに配置しないようにする。
4. 複数台を展開した際に、LUKS鍵データが共通にならないようにしたい。




## ■セキュアエレメントについて
以下は、ChatGPTにまとめてもらった内容となる。

ATECC608の主な特徴：

楕円曲線暗号（ECC）: ATECC608は、楕円曲線Diffie-Hellman（ECDH）や楕円曲線デジタル署名アルゴリズム（ECDSA）など、ECCに基づく暗号化操作を高速に実行できます。

ハードウェアキーストレージ: デバイスには、プライベートキー、証明書、またはその他のセキュアデータのセキュアなストレージとして使用されるセキュアなスロットが複数含まれています。

物理的耐タンパ性: デバイスは、物理的または電気的な侵入に対して耐性があります。

セキュアブートサポート: ATECC608は、システムのセキュアブートプロセスをサポートし、起動時にファームウェアの整合性を確認するのに役立ちます。

ランダム数ジェネレータ: 高品質の真のランダム数ジェネレータ（TRNG）を搭載しています。

I2C/SWIインターフェース: 標準の通信プロトコルを使用してホストマイクロコントローラとの通信が可能です。

小さなフットプリント: 超小型のパッケージングオプションが利用可能で、様々なアプリケーションに組み込むことができます。

消費電力が低い: IoTデバイスやバッテリー駆動のアプリケーションに適しています。

これらの特徴により、ATECC608は、IoTデバイスやその他のアプリケーションでのセキュアなデータ保護、デジタル署名、暗号化通信の確保などに使用されます。


## ■実装

鍵保護のため、ATECC608Bセキュアエレメントを使用して以下のように考えてみた。

1. Raspberry PiのSDカードを暗号化し、SDカードをコピーされて内容を見られることを防ぎたい。
2. 暗号化をLUKS+cryptsetupを利用して行うが、手動でLUKS鍵を入力するのではなく、自動で鍵を入力させたい。

→　自動で鍵を入力させ、マウントまで行うためにinitramfsとcryptsetupを利用する。
また、ATECC608Bにアクセスするための実行ファイルをビルドし、組み込む。
コードは[Github](https://github.com/kmwebnet/cryptsetup-pi4.git)に配置した。
apt updateが走ると、initramfsの作り直しが起こり、設定が飛んでしまうことを防ぎたい。

3. 鍵入力を自動で行うが、LUKS鍵データをそのままフラッシュに配置しないようにする。
4. 複数台を展開した際に、LUKS鍵データが共通にならないようにしたい。

→　この要件は、ATECC608Bへ乱数でAES鍵を作成し保存、その鍵へハッシュを入力し、出力をそのまま鍵として使う方法を考えた。
ハッシュの材料は、Raspberry Piボードが固有で持っているシリアル番号をSHA-256に通して得ることとし、複数台を展開しても鍵が同一となることを避ける。
これにより、特定のRaspberry Piボード、SDカード、ATECC608Bのセットがペアリングされる。

マスターイメージとしてrootfs.imgを作成し、初期鍵を設定するが、実機に展開して1回目の起動時に
* 初期鍵を使ってアクセスし、ATECC608Bを通った鍵を登録
* 初期鍵を削除
上記の動作を行うことで、ATEC608Bを通った鍵のみが登録された状態を作る。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/1d0a58bd-a623-ab8f-fd83-3dfa2c92d767.png)


## ■環境：
Raspberry pi 4 4GB　1台(以下Raspberry Pi)
ATECC608B-SSHDA(i2c接続タイプ)(以下ATECC608B)
128GB　MicroSDカード
USB-MicroSDカード変換アダプター
Ubuntu22.04のインストールされたPC(以下Ubuntu PC)

## ■デバイスセットアップ
Raspberry PiとATECC608Bセキュアエレメントは以下のように接続した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/10fc449f-0223-7886-2971-f4857c9d0d25.png)


## ■イメージ作成
Ubuntu PCでRaspberry pi imagerを使い、USB-MicroSDカード変換アダプターを使ってMicroSDカードへ64ビットのOSを書き込む。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/12282092-f571-fb70-72f6-b47e3c946752.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/16ea050d-12ee-7447-96ff-33853be771b8.png)


書き込み後、Raspberry Piで起動させずにそのままUbuntu PCにUSB-MicroSDカード変換アダプターを差し込み直すと、/media/<ユーザー>/bootfs /media/<ユーザー>/rootfsとしてマウントされる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/7a936fa4-b618-00bf-b1b2-fd25176c4255.png)

## ■暗号化されたrootfsを作る
Ubuntu PC上で、以下を実行する。

```
$ dd if=/dev/zero of=rootfs.img bs=1M count=0 seek=4000 
$ sudo losetup -f rootfs.img 
$ losetup -l 
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE                         DIO LOG-SEC
/dev/loop17 #rootfs.imgがマウントされたloop<番号>を記憶しておく
             0      0         0  0 /home/<ユーザー>/rootfs.img 

$ sudo cryptsetup luksFormat /dev/loop17　#rootfs.imgがマウントされたloop<番号>

#鍵登録をする際、初期鍵として"kmwebnet"と打ち込む

$ sudo cryptsetup luksOpen /dev/loop17 luks　#rootfs.imgがマウントされたloop<番号>
$ sudo mkdir /media/luks
$ sudo mkfs.ext4 /dev/mapper/luks
$ sudo mount /dev/mapper/luks /media/luks
$ sudo rsync -axHAWX --numeric-ids --info=progress2 /media/<ユーザー>/rootfs/ /media/luks

#luksの中身のfstabを以下に書き換える。
$ sudo vi /media/<ユーザー>/rootfs/etc/fstab
proc            /proc           proc    defaults          0       0
/dev/mmcblk0p1  /boot           vfat    defaults          0       2
/dev/mapper/luks	/	ext4	defaults,noatime 0 2

#後片付け
$ sudo umount /media/luks
$ sudo cryptsetup luksClose luks
#設定確認
$ sudo cryptsetup luksDump /dev/loop17 #rootfs.imgがマウントされたloop<番号>
LUKS header information
Version:       	2
Epoch:         	3
Metadata area: 	16384 [bytes]
Keyslots area: 	16744448 [bytes]
UUID:          	bd9613a6-d322-414d-91de-9fae5acec5f5
Label:         	(no label)
Subsystem:     	(no subsystem)
Flags:       	(no flags)

Data segments:
  0: crypt
	offset: 16777216 [bytes]
	length: (whole device)
	cipher: aes-xts-plain64
	sector: 512 [bytes]

Keyslots:
  0: luks2
	Key:        512 bits
	Priority:   normal
	Cipher:     aes-xts-plain64
	Cipher key: 512 bits
	PBKDF:      argon2id
	Time cost:  6
	Memory:     1048576
	Threads:    4
	Salt:       c3 df f3 b0 9f f2 93 b9 d5 7a e7 0f 27 7a 14 ce 
	            14 6f ed b8 23 ba 52 60 69 45 82 95 f5 5c 1a 5a 
	AF stripes: 4000
	AF hash:    sha256
	Area offset:32768 [bytes]
	Area length:258048 [bytes]
	Digest ID:  0
Tokens:
Digests:
  0: pbkdf2
	Hash:       sha256
	Iterations: 333516
	Salt:       83 11 81 9f 35 44 3b 36 2f 82 05 a6 0f e2 d0 2a 
	            08 08 bb b5 1a eb 99 49 32 da 5d 62 41 e1 d2 8b 
	Digest:     fb 6f 18 b3 d4 0f 0f d7 d5 35 42 86 ff e1 1c fa 
	            63 be ce 09 5f 1a c3 57 66 38 54 04 8c 28 5c 44 

$ sudo losetup -d /dev/loop17　// rootfs.imgがマウントされたloop<番号>
```

## ■initramfs作成

SDカードをRaspberry Piにさして、起動させる。初回セットアップ後、以下を実行

```
$ sudo apt install libssl-dev cryptsetup
$ sudo raspi-config #raspi-configでi2cを有効にする。
$ git clone https://github.com/kmwebnet/cryptsetup-pi4.git
$ cd cryptsetup-pi4/
$ sudo ./intramfssetup.sh
$ sudo shutdown -h now
```

SDカードを取り外し、Ubuntu PCにUSB変換で接続すると勝手にマウントされるのでマウント解除。

```
$ fdisk -l
Disk /dev/sdb: 115.31 GiB, 123815854080 bytes, 241827840 sectors
Disk model: SD/MMC          
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x95789778

Device     Boot  Start       End   Sectors   Size Id Type
/dev/sdb1         8192    532479    524288   256M  c W95 FAT32 (LBA)
/dev/sdb2       532480 241827839 241295360 115.1G 83 Linux

$ sudo dd if=/dev/sdb1 of=/home/<ユーザー>/bootpart.img
524288+0 records in
524288+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 18.9553 s, 14.2 MB/s
```

これでマスターイメージが出来上がった。

## ■展開
別のSDカードを用意しUbuntu PCからクローン。省略してあるがパーティションは設定しておく必要がある。

```
$ sudo dd if=/home/<ユーザー>/bootpart.img of=/dev/sdb1 
524288+0 records in
524288+0 records out
268435456 bytes (268 MB, 256 MiB) copied, 137.626 s, 2.0 MB/s
km@km-vmware:~$ sudo dd if=/home/<ユーザー>/rootfs.img of=/dev/sdb2 bs=4M status=progress
4194304000 bytes (4.2 GB, 3.9 GiB) copied, 176 s, 23.8 MB/s
1000+0 records in
1000+0 records out
4194304000 bytes (4.2 GB, 3.9 GiB) copied, 387.595 s, 10.8 MB/s
```

実機にて起動。初回起動はLUKS鍵の入れ替え作業が入り、時間がかかる。

```
$ df -h
ファイルシス     サイズ  使用  残り 使用% マウント位置
udev               1.6G     0  1.6G    0% /dev
tmpfs              380M  1.3M  379M    1% /run
/dev/mapper/luks   117G  3.4G  109G    3% /
tmpfs              1.9G     0  1.9G    0% /dev/shm
tmpfs              5.0M  4.0K  5.0M    1% /run/lock
/dev/mmcblk0p1     255M   47M  209M   19% /boot
tmpfs              380M   20K  380M    1% /run/user/1000
```

ルートファイルシステムが/dev/mapper/luksとなっており成功。
自動的にパーティションの全体を使う形となっている。

実機で起動した後、以下を実行。

```
$ sudo apt install libssl-dev cryptsetup
$ sudo raspi-config #raspi-configでi2cを有効にする。
$ git clone https://github.com/kmwebnet/cryptsetup-pi4.git
$ cd cryptsetup-pi4/
$ sudo ./intramfssetup.sh
```

これでカーネルアップデートなどの、initramfsの更新時にも追従できる状態になった。

## ■展望

完全な信頼の連鎖（Chain of Trust）を実現するには、ブート開始時からのフラッシュ暗号化＋セキュアブートが必要となるが、Raspberry PiではRaspberry Pi 4からブート領域のフラッシュ暗号化は対応していないものの、セキュアブートに対応しているようだ。

今回のテストから、さらにセキュアブートにつなげられるか試行したい。