暗号化
Encryption ・ あんごうか
鍵を持つ者にしか戻せない形にデータを変える技術。方式と鍵の扱いを誤ると中身が漏れる。
✦ 30秒で試す — 航海白黒の絵を暗号化して、画像として開くと何が見える?暗号化した結果を画像として見ると?予想してみる概要
暗号化とは、そのままでは誰にでも読めるデータ(平文)を、鍵を持つ者だけが元に戻せる形(暗号文)へ変換する技術です。鍵を使って暗号文を平文に戻す操作を「復号」と呼びます。変換のルール(アルゴリズム)は公開されていて、秘密なのは鍵だけです。暗号文を手に入れても、正しい鍵がなければ元のデータを読むことは事実上できません。
私たちは意識しないまま、毎日大量の暗号化の上で暮らしています。ブラウザで HTTPS のサイトを開くとき、スマートフォンでメッセージを送るとき、Wi-Fi につなぐとき、通信はすべて暗号化されています。スマートフォンやノートPCのストレージも多くは端末ごと暗号化されていて、盗まれても中身は読めません。サーバ側でも、ディスクやバックアップを暗号化しておくのが今では標準です。
ただし「暗号化している」だけでは安全とは言えません。同じ AES でも、使い方(暗号利用モード)を誤ると暗号文から絵の輪郭が透けますし、使い捨てにすべき値を使い回すと、鍵が漏れていないのに中身が読めてしまいます。暗号化を考えるときは「誰から何を守るのか」と「その方式は正しく使われているか」の2つを問うことになります。
なぜ生まれたか
「読まれたくない情報を、読まれない形で送りたい」という欲求はコンピュータよりはるかに古く、文字をずらすだけのシーザー暗号は紀元前から、機械式のエニグマは第二次世界大戦で使われました。長いあいだ暗号は軍事と外交の技術でしたが、コンピュータ同士がネットワークでつながると事情が変わります。流れるデータは経路上の機器を通るたびに覗かれうるので、クレジットカード番号やパスワードを平文で流せば途中の誰かに読まれてしまいます。「経路を信用しなくても中身は守られる」仕組みがなければ、商取引も個人情報もネットワークに載せられませんでした。
そこで米国は1977年に民間でも使える標準暗号 DES を定めました。しかし DES の鍵は56ビットしかなく、計算機が速くなると総当たりで破れるようになり(1998年には専用機が数日で鍵を割り出しました)、公募を経て2001年に後継の AES が標準になります。並行して、1976年に発表された公開鍵暗号の考え方が「事前に鍵を共有していない相手とどう鍵を取り決めるか」という難問を解き、暗号化は軍事技術から社会の基盤へと変わりました。
一方で、アルゴリズムが強くても使い方で破られる事件が続きました。無線LANの初期の暗号 WEP は、24ビットしかない IV(初期化ベクトル)がすぐに一巡して使い回されることなどが原因で、2001年には実用的に破られます。暗号化しただけで改ざん検知を後付けした方式では、復号エラーの返し方の違いから平文を1バイトずつ割り出す「パディングオラクル攻撃」(2002年)が見つかり、その後も TLS への同種の攻撃が繰り返されました。こうした反省から、暗号化と改ざん検知を1つの手順で行う「認証付き暗号(AEAD)」が主流になり、2018年の TLS 1.3 では AEAD 以外の方式が廃止されています。
詳細
共通鍵暗号と鍵配送の問題
暗号化の基本形は、暗号化と復号に同じ鍵を使う共通鍵暗号(対称鍵暗号)です。代表が AES で、処理が非常に速く、多くの CPU に専用命令もあるので、大量のデータを暗号化する場面では事実上これ一択です。
弱点は「その鍵をどうやって相手に渡すのか」(鍵配送問題)です。鍵をネットワークで送れば、鍵ごと盗聴されるかもしれません。これを解いたのが公開鍵暗号で、TLS では公開鍵暗号の仕組みで共通鍵を取り決め、実データは速い共通鍵暗号で守る、という組み合わせ(ハイブリッド方式)を使います。
ブロック暗号と暗号利用モード
AES は「ブロック暗号」です。一度に扱えるのは128ビット(16バイト)の固まり1つだけで、鍵を決めると、16バイトの入力を16バイトの出力へ1対1に置き換える巨大な置換表のように振る舞います。実際のデータはもっと長いので、データをブロックに区切り、それぞれをどうつないで暗号化するかを決める必要があります。この決め方が「暗号利用モード」です。
いちばん素朴な ECB(Electronic Codebook)は、各ブロックを独立に暗号化します。すると、同じ内容のブロックは必ず同じ暗号文になります。画像を ECB で暗号化すると、背景のような同じ色の並びは同じ模様の繰り返しになり、絵の輪郭がそのまま透けて見えます。「ECB のペンギン」として知られる有名な例です。これを避けるため、前のブロックの暗号文を次のブロックに混ぜる CBC が長く使われ、いまは CTR(カウンタ)モードを土台にした方式が主流です。CTR は、使い捨ての値 nonce と通し番号を AES で暗号化して「鍵ストリーム」と呼ぶ乱数列を作り、それを平文に XOR(ビットごとの排他的論理和)で重ねます。場所ごとに違う鍵ストリームが重なるので、同じ平文ブロックでも暗号文は毎回違います。
nonce を使い回すと何が起きるか
CTR の安全性は「同じ鍵で同じ nonce を二度使わない」ことに全面的に依存しています。もし2通のメッセージを同じ鍵・同じ nonce で暗号化すると、両方に同じ鍵ストリームが重なります。XOR は同じものを2回重ねると消える性質があるので、盗聴者が2通の暗号文どうしを XOR すると鍵ストリームが打ち消し合い、「平文A XOR 平文B」が手に入ります。片方の中身が推測できれば、もう片方はそのまま読めます。鍵は一度も漏れていないのに、です。
下の部品で確かめてください。左の平文をなぞって描き足すと、ECB では描いた線が暗号文にも透けて見えます。GCM に切り替えると暗号文はノイズになりますが、攻撃者として別の暗号文B を重ね、nonce を使い回した場合と比べると、何が起きるかがはっきり分かります。
左の平文Aを指(マウス)でなぞって、線を描き足してみてください。右の暗号文A がその場で計算し直されます。
nonce は秘密である必要はなく、暗号文と一緒に平文のまま送ってかまいません。必要なのは「一意であること」だけです。実装ではカウンタで数え上げるか、十分に長い乱数を使います。AES-GCM の nonce は96ビットで、乱数で選ぶ場合は偶然の重複を避けるため、1つの鍵で暗号化する回数に上限(NIST の指針ではおよそ2の32乗回)があります。それを超える前に鍵を切り替えます。
機密性と完全性は別物 — 認証付き暗号(AEAD)
見落とされがちなのが、「暗号化すれば改ざんも防げる」わけではないことです。暗号化が守るのは機密性(中身を読まれないこと)で、完全性(中身を書き換えられないこと)ではありません。CTR 方式の暗号文の1ビットを反転させると、復号した平文の同じ位置の1ビットがそのまま反転します。攻撃者は中身を読めなくても、「送金額が入っている位置」さえ分かれば、狙って書き換えられるのです。
そこで、暗号化と同時に改ざん検知用の「認証タグ」を計算するのが認証付き暗号(AEAD: Authenticated Encryption with Associated Data)です。代表は AES-GCM と ChaCha20-Poly1305 で、受信側はタグを検証し、1ビットでも合わなければ平文を1バイトも返さずに拒否します。ヘッダのように暗号化はしないが改ざんは検知したいデータ(追加データ、AAD)も、タグの計算に含められます。TLS 1.3 はこの AEAD しか認めていません。
通信の暗号化と保存の暗号化
実務で暗号化を設計するとき、まず区別すべきは「通信中のデータ(in transit)」と「保存されたデータ(at rest)」です。前者はネットワーク経路上の盗聴・改ざんから守るもので、HTTP に TLS を重ねた HTTPS や、拠点間をつなぐ VPN が代表です。後者はディスクやバックアップが盗まれたり、クラウドのストレージに不正アクセスされたりしたときの備えで、データベースの透過的暗号化(TDE)やディスク全体の暗号化がこれにあたります。
2つは守っている脅威が違うため、片方だけでは足りません。通信を暗号化していてもサーバのディスクが平文なら物理的な盗難には無力ですし、ディスクを暗号化していても通信が平文なら経路で漏れます。一方で、ディスクの暗号化は「動いているサーバに正規の権限で入った者」からは何も守らない点にも注意が必要です。OS が起動した時点で透過的に復号されるので、アプリケーションの脆弱性を突かれればデータは平文で読まれます。守りたい相手がそこまで及ぶなら、アプリケーション側で項目ごとに暗号化します。
ハッシュ化との違い
暗号化と混同されやすいのがハッシュ化です。暗号化は鍵があれば元に戻せる(可逆)のに対し、ハッシュ化は元に戻せない(不可逆)一方向の変換です。パスワードを暗号化して保存すると、鍵が漏れた瞬間に全員のパスワードが平文に戻ってしまいます。だからパスワードはハッシュ化して保存します。「戻す必要があるデータは暗号化、照合できれば十分なデータはハッシュ化」と覚えると整理しやすいでしょう。
実務での落とし穴
暗号化の失敗の多くは、アルゴリズムの弱さではなく使い方と運用の穴から生まれます。第一に鍵管理です。鍵をソースコードにハードコードしたり、暗号化したデータと同じ場所に鍵を置いたりすれば、暗号化の意味がなくなります。鍵はシークレット管理の仕組みや KMS(鍵管理サービス)に預け、アプリケーションは権限を通じて使います。KMS はデータを暗号化する鍵(DEK)をさらに別の鍵(KEK)で暗号化して保管する「エンベロープ暗号化」を採り、鍵の交換(ローテーション)もデータを暗号化し直さずに行えるようにしています。
第二に、モードと nonce の誤用です。ECB を選んでしまう、nonce を固定値にする、乱数生成器の初期化に失敗して同じ値が出続ける、といったバグは暗号文を見ただけでは気づけません。AEAD を使うことに加えて、ライブラリが提供する高水準の API(nonce の生成まで引き受けるもの)を選ぶのが安全です。第三に「自作暗号」です。暗号の安全性は世界中の研究者の攻撃に耐えて初めて信頼されるもので、独自方式も、既存方式の組み合わせを自分で考えることも避け、実績のあるライブラリに任せます。最後に、古い方式の残存です。DES や RC4、CBC と後付けの MAC の組み合わせなどが古いシステムに残っていることは珍しくありません。暗号は時間とともに危殆化する(安全性が下がる)前提で、定期的に棚卸しします。
試問
同じ鍵で送られた2通の暗号文を、盗聴者の目で見る画面です。平文A は星の絵(なぞって描き足せる)、暗号文B は別の絵を暗号化したものです。モードは ECB(区切りごとに独立に変換)と GCM(使い捨ての値 nonce から作った乱数列を重ねる)から、nonce は「通信ごとに新しく」と「使い回す」から選べます。暗号文B はつかんで暗号文A の上に重ねられ、重ねると2枚の XOR(ビットごとの排他的論理和)が見えます。
左の平文Aを指(マウス)でなぞって、線を描き足してみてください。右の暗号文A がその場で計算し直されます。
