はじめに#
デバイス内でWifiのSSIDやパスワード、クラウド接続トークンなどを保存したいが、平文での保存が適当でない場合が考えられる。その際に如何に解読されにくくするかという実験。
AESによる暗号化#
今回はAES-GCMを選択。いろいろ勉強してみたところ以下のような構成を考えた。
TLS1.2で使用される際は、ハンドシェイク後に相手と共有されるIV(初期化ベクトル)、Key(共通鍵)はどちらも生成してIVはフラッシュ上(保護なし)、KeyはATECC608Aの読み出し禁止スロットに保管。
暗号化された暗号文、その際に出るTagも併せてフラッシュ上(保護なし)に置く。
これを読みだして復号ができるかを試す。
前提条件#
セキュアなIoTデバイス通信をやってみた(MbedTLS移植編-Configure)で行ったATECC608Aの初期化が完了していること。
ソースコードは下記。
https://github.com/kmwebnet/ECC608-Configure
実装#
コードを実際に書いて実装を試していく。
kmwebnet/ECC608-AES-GCM-test
にてコードを公開中。
スロット5番をAES Keyとして書き込みのみ、読み出し不可の設定にする。
これを実現するため、Microchip社のテストコードのコンフィグを確認。
cryptoauthlib/python/tests/test_device.py
今回のATECC608Aでのコンフィグは下記の通りとなる。
Config Zone
バイト13:'AES_Enable': 1に設定
'SlotConfig No5': 0x36C4 → 0x00C4
ビット15-12 :Writeconfig
ビット8-11 :WriteKey
上記を0にし書き込み可とする。
'KeyConfig No5' : 0x001C → 0x0018
ビット2-4 :Keytypeを 0b111(7)から0b110(6)に変更し、AESキーを扱うスロットとして設定する。
上記の設定をcrypto.c冒頭でも確認する。
crypto.c実装解説#
crypto.hにてスロット8の416バイトの内訳を定義した。
76バイトの位置から12バイト:IV
88バイトの位置から16バイト:Tag
104バイトの位置から240バイト:暗号化データ
2つの関数を作成。
ATCA_STATUS encryptwrite(uint8_t *data, size_t length)
デバイス内へdataを書き込む
- atcab_randomで32バイトの乱数を得る。
- スロット5へ乱数を書き込み、AES Keyとする。
- atcab_aes_gcm_init_randでIVの初期化を行い、スロット8へ書き込む
- 暗号化する240バイトを16バイト単位で暗号化し、15回ループを回す。
- atcab_aes_gcm_encrypt_finishでループ終了、Tagを取得
- Tag,データをスロット8へ書き込み終了
ATCA_STATUS decryptread(uint8_t *data, size_t length)
デバイス内からdataを読み込む
- デバイス内からIV,Tagを読み込む
- atcab_aes_gcm_initでIVを設定する。
- 復号する240バイトを16バイト単位で復号し、15回ループを回す。
- atcab_aes_gcm_decrypt_finishでTagの確認を行い、正常なら終了。
上記の2つで、AESキーをデバイスに秘匿した状態、すなわちこのデバイスがないと復号できないデータを作成することができた。