概要
暗号化(Encryption)とは、データを特定のアルゴリズムと鍵を使用して変換し、正しい鍵を持つ者のみが元のデータ(平文)に復元できるようにする技術である。通信の盗聴、ストレージへの不正アクセス、データの漏洩を防ぐために使用される。
情報セキュリティの三要素(CIA: Confidentiality / Integrity / Availability)の「機密性(Confidentiality)」を実現する核心技術である。組み込みシステムでは、通信の暗号化(TLS)、ストレージの暗号化(フラッシュ暗号化)、ファームウェアの暗号化など多くの場面で不可欠となっている。
暗号化は鍵の方式によって「共通鍵暗号」と「公開鍵暗号」に大別され、それぞれ異なる特性と用途を持つ。
歴史・背景
暗号の歴史は古代ローマのカエサル暗号まで遡るが、現代の電子暗号技術は次のマイルストーンで発展した。
- DES(1977年): NIST(当時の NBS)が標準化した最初の現代的共通鍵暗号。56bit 鍵のため、現在は安全でない。
- RSA(1978年): 公開鍵暗号の実用的な実装として Rivest・Shamir・Adleman が発表。インターネットセキュリティの基盤となった。
- AES(2001年): NIST が DES の後継として Rijndael アルゴリズムを標準化。現在最も広く使われる共通鍵暗号。
- ECC(楕円曲線暗号): 1985 年に理論提案、2000 年代以降に実用化。RSA より短い鍵で同等のセキュリティを実現し、組み込み向けに普及。
- NIST PQC(2022年): 量子コンピュータへの耐性を持つ「耐量子暗号(Post-Quantum Cryptography)」の標準化が始まり、CRYSTALS-Kyber、CRYSTALS-Dilithium などが選定された。
技術仕様
主要な暗号アルゴリズム一覧
| カテゴリ | アルゴリズム | 鍵長 | 特徴 | 推奨度 |
|---|---|---|---|---|
| 共通鍵(対称) | AES-128 | 128 bit | 高速、ハードウェア支援あり | 推奨 |
| 共通鍵(対称) | AES-256 | 256 bit | より高いセキュリティ | 高セキュリティ向け |
| 共通鍵(対称) | ChaCha20 | 256 bit | ソフトウェア実装に最適 | 推奨 |
| 公開鍵(非対称) | RSA-2048 | 2048 bit | 広く普及 | 互換性重視 |
| 公開鍵(非対称) | ECDH P-256 | 256 bit | 省電力、小コード | 推奨 |
| ハッシュ | SHA-256 | 256 bit 出力 | 整合性確認 | 推奨 |
| ハッシュ | SHA-3 / Keccak | 256〜512 bit | より新しい設計 | 今後主流 |
| 認証付き暗号 | AES-GCM | 128/256 bit | 暗号化+認証を同時 | 推奨 |
| 認証付き暗号 | ChaCha20-Poly1305 | 256 bit | ソフトウェア向け | 推奨 |
AES の動作モード
┌────────────────────────────────────────────────────────┐
│ AES の主要動作モード │
├────────┬───────────────┬────────────────────────────────┤
│ ECB │ 最も単純 │ 危険!同じ平文→同じ暗文 │
│ CBC │ 連鎖ブロック │ IVが必要、並列化不可 │
│ CTR │ カウンタモード│ 並列化可能、IV管理が重要 │
│ GCM │ 認証付き暗号 │ 暗号化+整合性検証を同時実現 │
│ CCM │ 小型向けGCM │ IoT/BLE 向け、メモリ効率が良い │
└────────┴───────────────┴────────────────────────────────┘
動作原理
AES-GCM(認証付き暗号)の仕組み
現代の暗号化では、データの秘匿性(暗号化)と完全性(改ざん検知)を同時に実現する AEAD(Authenticated Encryption with Associated Data)が推奨される。
入力: 平文 P, 鍵 K, Nonce(IV) N, 追加認証データ AAD
↓
[AES-CTR モードで平文を暗号化]
↓
暗号文 C が生成される
↓
[GHASH で認証タグ T を計算]
(C と AAD のハッシュ)
↓
出力: 暗号文 C + 認証タグ T (16 bytes)
復号側: C + T → AES-CTR で復号 → GHASH で T' 計算 → T == T' なら正常
C 言語での AES-GCM 実装例(Mbed TLS 使用)
#include "mbedtls/gcm.h"
#include <string.h>
#define KEY_LEN 16 /* AES-128: 16 bytes */
#define TAG_LEN 16 /* GCM 認証タグ: 16 bytes */
#define IV_LEN 12 /* GCM IV: 12 bytes が推奨 */
int encrypt_data(const uint8_t *key,
const uint8_t *iv,
const uint8_t *plaintext, size_t pt_len,
uint8_t *ciphertext,
uint8_t *tag) {
mbedtls_gcm_context gcm;
int ret;
mbedtls_gcm_init(&gcm);
/* 鍵のセット */
ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES,
key, KEY_LEN * 8);
if (ret != 0) goto exit;
/* 暗号化 */
ret = mbedtls_gcm_crypt_and_tag(
&gcm,
MBEDTLS_GCM_ENCRYPT,
pt_len, /* 平文サイズ */
iv, IV_LEN, /* 初期化ベクタ */
NULL, 0, /* 追加認証データ(なし) */
plaintext, /* 入力平文 */
ciphertext, /* 出力暗号文 */
TAG_LEN, /* タグサイズ */
tag /* 出力認証タグ */
);
exit:
mbedtls_gcm_free(&gcm);
return ret;
}
int decrypt_data(const uint8_t *key,
const uint8_t *iv,
const uint8_t *ciphertext, size_t ct_len,
const uint8_t *tag,
uint8_t *plaintext) {
mbedtls_gcm_context gcm;
int ret;
mbedtls_gcm_init(&gcm);
ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES,
key, KEY_LEN * 8);
if (ret != 0) goto exit;
/* 復号と認証タグ検証を同時実施 */
ret = mbedtls_gcm_auth_decrypt(
&gcm,
ct_len,
iv, IV_LEN,
NULL, 0,
tag, TAG_LEN,
ciphertext,
plaintext
);
/* ret == MBEDTLS_ERR_GCM_AUTH_FAILED なら改ざんあり */
exit:
mbedtls_gcm_free(&gcm);
return ret;
}
ハードウェア AES アクセラレータの活用
多くの組み込み SoC は AES ハードウェアアクセラレータを内蔵している。
/* STM32 CRYP ペリフェラルを使った AES 暗号化 */
#include "stm32h7xx_hal.h"
CRYP_HandleTypeDef hcryp;
CRYP_ConfigTypeDef conf;
void hw_aes_gcm_init(const uint8_t *key) {
conf.DataType = CRYP_DATATYPE_8B;
conf.KeySize = CRYP_KEYSIZE_128B;
conf.pKey = (uint32_t *)key;
conf.Algorithm = CRYP_AES_GCM;
conf.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS;
HAL_CRYP_Init(&hcryp);
}
/* ハードウェアで暗号化(CPU 負荷が大幅に低下) */
HAL_CRYP_Encrypt(&hcryp, (uint32_t *)plaintext, pt_words,
(uint32_t *)ciphertext, HAL_MAX_DELAY);
ESP32 でのフラッシュ暗号化
# ESP-IDF でのフラッシュ暗号化有効化(sdkconfig)
# CONFIG_FLASH_ENCRYPTION_ENABLED=y
# CONFIG_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y # 開発用
# CONFIG_FLASH_ENCRYPTION_MODE_RELEASE=y # 本番用
# CLI での確認
# espsecure.py digest_private_key --keyfile key.pem
# esptool.py --chip esp32 get_security_info
用途・ユースケース
通信の暗号化
TLS/DTLS を使ったクラウドとの通信、BLE の AES-CCM/AES-GCM による無線通信暗号化、LoRaWAN の AES-128 セッション鍵による通信暗号化など。
ストレージの暗号化
フラッシュメモリ上のデータ暗号化(ESP32 フラッシュ暗号化、STM32 TZEN/OTFDEC)、EEPROM に保存する設定値の暗号化、SDカード上のログデータ暗号化。
ファームウェアの暗号化
ファームウェアの知的財産(IP)保護のために、配布するファームウェアイメージを暗号化する。デバイス固有の鍵で復号するため、他のデバイスには移植できない。
鍵交換プロセス
ECDH(楕円曲線ディフィー・ヘルマン)を使って安全に共通鍵を交換し、その後 AES-GCM で通信を暗号化するハイブリッド暗号化が標準的なパターンである。
実装・開発のポイント
組み込み向け暗号ライブラリの選択
| ライブラリ | 特徴 | 適用プラットフォーム |
|---|---|---|
| Mbed TLS | ARM 製、軽量、FOSS | ARM Cortex-M/A |
| wolfSSL / wolfCrypt | 小フットプリント、FIPS 対応 | 各種 MCU |
| tinycrypt | 超軽量、最小機能 | 超小型 MCU |
| OpenSSL | 高機能、サイズ大 | Linux(MPU) |
| libsodium | 使いやすい API、高セキュリティ | Linux(MPU) |
よくある実装ミス
NG: 固定 IV(Nonce)の使用
→ AES-GCM で同じ鍵・同じ IV を使うと鍵が漏洩する
NG: ECB モードの使用
→ 同じ平文ブロックが同じ暗号文になり、パターンが漏洩
NG: 自作暗号アルゴリズム
→ 必ず標準化されたアルゴリズムを使う
NG: 鍵をソースコードにハードコード
→ 解析により簡単に抽出される
OK: 毎回ランダムな IV を生成
OK: AES-GCM / ChaCha20-Poly1305 などの AEAD を使う
OK: 鍵は SE / TPM / OTP に保管
乱数生成の重要性
暗号の強度は乱数の品質に依存する。組み込みでは True Random Number Generator(TRNG)ハードウェアを必ず使用する。
/* STM32 TRNG からの乱数取得 */
uint32_t random_number;
HAL_RNG_GenerateRandomNumber(&hrng, &random_number);
/* AES-GCM IV 生成 */
uint8_t iv[12];
for (int i = 0; i < 3; i++) {
uint32_t r;
HAL_RNG_GenerateRandomNumber(&hrng, &r);
memcpy(iv + i * 4, &r, 4);
}
他技術との比較
| 用途 | 技術 | 説明 |
|---|---|---|
| 秘密性の確保 | 暗号化(本項) | データを第三者に読ませない |
| 真正性・完全性 | ファームウェア署名 | 改ざん・なりすましを検知 |
| 鍵の安全な保管 | セキュアエレメント / TPM | 鍵を物理的に保護 |
| 通信路の保護 | TLS/DTLS | 暗号化+認証を組み合わせたプロトコル |
| 鍵の配布 | 公開鍵暗号 / PKI | 安全な鍵交換の仕組み |
暗号化はセキュリティの「部品」であり、単体では完全な保護を提供しない。鍵管理、認証、アクセス制御などと組み合わせた「セキュリティアーキテクチャ」として設計することが重要である。