Jetson Nano Dev Boardを使ってSDカード暗号化をテスト(LUKS 調査編)


LUKSの基本形

前回でu-bootまでは署名された状態で改ざんを防止したSecurebootに対応できた。
ルートファイルシステムの暗号化を検討するにあたり、LUKSに必要な要素を確認してみる。

Jetson Nano ではcryptsetupをインストールして、外付けUSBデバイスを暗号化する事例はあるようだ。
Jetson Nanoで持ち運び可能な暗号化ディレクトリの使用

r32.4.2で試してみたところ、カーネルモジュールdm-cryptのコンパイルは不要なようだった。

$ zcat /proc/config.gz  | grep DM_CRYPT
CONFIG_DM_CRYPT=y
$ sudo apt install cryptsetup

上記のみでOKだった。

USBフラッシュをJetson Nanoに接続すると/dev/sdaで認識する。
新規に領域を作り暗号化してみる。

$ sudo fdisk /dev/sda

Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (1-4, default 1):
First sector (2048-61120511, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-61120511, default 61120511):

Created a new partition 1 of type 'Linux' and of size 29.1 GiB.

Command (m for help): w
The partition table has been altered.
Syncing disks.

これで新規に領域を作成できた。

$ sudo fdisk -l /dev/sda
Disk /dev/sda: 29.1 GiB, 31293702144 bytes, 61120512 sectors
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: 0x49783f5b

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        2048 61120511 61118464 29.1G 83 Linux

$ sudo cryptsetup luksFormat /dev/sda1

WARNING!
========
This will overwrite data on /dev/sda1 irrevocably.

Are you sure? (Type uppercase yes): YES<大文字YES回答>
Enter passphrase for /dev/sda1:<パスワード、ここでは"test"と入れる>
Verify passphrase: <パスワード、ここでは"test"と入れる>

これでLUKSパーティションが完成した。
LUKSパーティション内に鍵情報も保管される。

アクセスしてみる。

$ sudo cryptsetup luksOpen /dev/sda1 crypt
Enter passphrase for /dev/sda1:<パスワード、ここでは"test"と入れる>
$ ls /dev/mapper/
control  crypt

cryptマッパーデバイスができている。

$ sudo mkfs.ext4 /dev/mapper/crypt
mke2fs 1.44.1 (24-Mar-2018)
Creating filesystem with 40472 1k blocks and 10120 inodes
Filesystem UUID: e480b75b-b80b-42a6-bddc-36b22f3b846a
Superblock backups stored on blocks:
        8193, 24577

Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

ext4でフォーマットした。

$ sudo mkdir /media/crypt

$ sudo mount /dev/mapper/crypt /media/crypt
$ df -h
Filesystem         Size  Used Avail Use% Mounted on
/dev/mapper/crypt   35M  782K   31M   3% /media/crypt

この時点で/media/cryptで暗号化USBフラッシュにアクセスが可能。

アンマウントとLUKSパーティションの登録解除

$ sudo umount /media/crypt

$ sudo luksClose crypt

このように簡単に暗号化を使うことができる。

今回作成した暗号化USBフラッシュの状態を以下で確認できる。

$ sudo cryptsetup luksDump /dev/sda1
LUKS header information for /dev/sda1

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        256
MK digest:      c2 cd 56 9b 89 22 f7 94 19 2f bb 3e 5f f4 8c 18 cf fa 92 f1
MK salt:        db b0 78 51 9b 16 3a a8 a5 3b 6f 04 30 4f 07 e7
                78 a0 0b e9 08 12 76 5e a7 a2 b1 75 fc b5 04 d0
MK iterations:  128000
UUID:           eac27503-bc3e-4fa2-85b3-48a962ec303e

Key Slot 0: ENABLED
        Iterations:             2048000
        Salt:                   83 1f 38 56 b8 38 0b f1 2d c5 80 f8 56 35 ce bd
                                41 c6 5d be 3d 80 71 55 d0 1a bd ef 2b 74 3c e5
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

これによれば8個あるキースロットの0番に手打ちしたパスワード、"test"が登録されていることわかる。

ルートファイルシステムの暗号化の際の検討事項

今までは、起動した後のLinux内で、ユーザーのパスワード入力も行いながら特定のUSBフラッシュを暗号化したが、ルートファイルシステムの暗号化の場合、自動で安全にルートファイルシステムを復号してマウントし、Linuxに引き渡さなければならない。


1、ユーザーパスワード操作でなく、鍵ファイルで自動復号
2、Linuxの起動プロセスの間へ復号処理を割り込ませる。

上記の2つが必要。

1、ユーザーパスワード操作でなく、鍵ファイルで自動復号
これは、LUKSデバイスをオープンするためのコマンドでパスワード操作ではなく、ファイルを渡す設定を行えばいい。

具体的には上記の例でいうと

$ sudo cryptsetup luksOpen /dev/sda1 crypt

上記を変更して、

$ sudo cryptsetup luksOpen /dev/sda1 crypt --key-file=<鍵ファイル>

とすればいい。
しかし<鍵ファイル>自体を置く場所が難しい。
ルートファイルシステムの暗号化となると、ルートファイルシステム自体には鍵を置けない。
別途USBフラッシュという手もあるだろうが、鍵ファイル自体を盗まれれば意味がない。
これはどうにか隠したい。

もう一つ、パイプで鍵を渡す方法もある。

$ sudo sh -c ”echo <鍵ファイル> | cryptsetup luksOpen /dev/sda1 crypt --key-file=-”

上記の"--key-file=-"はstdinから読み取るというオプションになる。
これであれば、ファイルを置く必要、また一時的にファイルを生成する必要がなく、stdoutでデータが吐けるプログラムを作ればそれを入力させることもできる。

この方法を使い、安全な鍵データを出力するプログラムを作成してみる。

ATECC608Aの鍵を保存してあるスロットへアクセスし、IO保護キーで通信経路を暗号化しながら読み出してstdoutに出力するプログラムを作成した。
github/ECC608-keyout2

ビルドする際は、Jetson Nano上で

$ sudo apt install build-essential
$ git clone --recursive https://github.com/kmwebnet/ECC608-keyout2
$ cd ECC608-keyout2
$ make

とすると、keyoutというバイナリができる。
このプログラムの実行には別途ATECC608Aの初期化、指定スロットへの鍵の書き込みをやっておく必要があるため、後述する。
現時点では、stdoutに任意の出力があればいいということで下記のシェルスクリプトで代用してみる。

どこにでもあるチュートリアルのようなコードでいいだろう。

$ vi keyout.sh
#! /bin/bash
echo "Hello"

$ chmod +x keyout.sh

$ ./keyout.sh
Hello

これを使って、先ほどのUSBフラッシュを使いテストしてみる。
すでにキースロット0に"test"というパスワードを登録した。

人のパスワード入力をなくす設定を試してみる。

まず、keyout.shから生成される鍵を追加して登録したい。

$ echo -en "\x74\x65\x73\x74" > preset.key
$ sudo sh -c "./keyout.sh | cryptsetup luksAddKey /dev/sda1 --key-file=preset.key /dev/stdin"

手打ちで入力したパスワードは、改行コードなしのバイナリ扱いで登録されている。
よって、ただ単にecho "test" >とやって鍵ファイルを作ると、

$ echo "test" > preset.key
$ xxd preset.key
00000000: 7465 7374 0a                             test.

こんな風に末尾に”0a”がついて認証に失敗する。
これで数時間はまった。

実行した結果を確認する。

$ sudo cryptsetup luksDump /dev/sda1
LUKS header information for /dev/sda1

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        256
MK digest:      c2 cd 56 9b 89 22 f7 94 19 2f bb 3e 5f f4 8c 18 cf fa 92 f1
MK salt:        db b0 78 51 9b 16 3a a8 a5 3b 6f 04 30 4f 07 e7
                78 a0 0b e9 08 12 76 5e a7 a2 b1 75 fc b5 04 d0
MK iterations:  128000
UUID:           eac27503-bc3e-4fa2-85b3-48a962ec303e

Key Slot 0: ENABLED
        Iterations:             2048000
        Salt:                   83 1f 38 56 b8 38 0b f1 2d c5 80 f8 56 35 ce bd
                                41 c6 5d be 3d 80 71 55 d0 1a bd ef 2b 74 3c e5
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: ENABLED
        Iterations:             2001098
        Salt:                   de 39 9b 4b 6b 65 4e fb 62 78 e1 e0 de c1 2e 6c
                                4c ab 9b 3b 0c 88 6f ee 7b 8f a8 68 dd b2 0b 48
        Key material offset:    264
        AF stripes:             4000
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

キースロット0の鍵で認証し、キースロット1をstdinから追加できた。

後、"test"というわかりやすいパスワードを消したい。
キースロット1の鍵で認証して、キースロット0の"test"鍵を消す。

$ sudo sh -c "./keyout.sh | cryptsetup luksKillSlot /dev/sda1 0 --key-file=-"

$ sudo cryptsetup luksDump /dev/sda1
LUKS header information for /dev/sda1

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha256
Payload offset: 4096
MK bits:        256
MK digest:      c2 cd 56 9b 89 22 f7 94 19 2f bb 3e 5f f4 8c 18 cf fa 92 f1
MK salt:        db b0 78 51 9b 16 3a a8 a5 3b 6f 04 30 4f 07 e7
                78 a0 0b e9 08 12 76 5e a7 a2 b1 75 fc b5 04 d0
MK iterations:  128000
UUID:           eac27503-bc3e-4fa2-85b3-48a962ec303e

Key Slot 0: DISABLED
Key Slot 1: ENABLED
        Iterations:             2001098
        Salt:                   de 39 9b 4b 6b 65 4e fb 62 78 e1 e0 de c1 2e 6c
                                4c ab 9b 3b 0c 88 6f ee 7b 8f a8 68 dd b2 0b 48
        Key material offset:    264
        AF stripes:             4000
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

キースロット0の鍵を消すことができた。

これらの操作ができれば、鍵ファイルを置かないでluksOpenができるようになる。

2、Linuxの起動プロセスの間へ復号処理を割り込ませる。

上記で作成した安全に鍵を出力するプログラムをLinuxの起動プロセスに割り込ませる必要がある。
これはinitramfsの調査が必要になる。
次回Jetson Nano Dev Boardを使ってSDカード暗号化をテスト(initramfs 調査編)でこれを行っていきたい。

Jetson Nano Dev Boardを使ってSDカード暗号化をテスト 記事インデックス

概要編
Jetson Nano secureboot編
LUKS 調査編 <いまここ
initramfs 調査編
起動シーケンス作成編