暗号とはなにか
CTF とは技術における高度な知識とパズルを解く発想力の両方を問う総合格闘技です!中でも Crypto は暗号という一見フシギなシステムを攻撃することで現代では欠かせなくなった暗号は本当に安全なのかを考えさせてくれる分野です。
ただ Crypto の知識を得る手段は実際に CTF に出て writeup を読んだり、大量の資料を読むことでしかがなかったと思います。そこで Crypto における体系的に解説するこのシリーズを作りました!私自身これが欲しくて助かりました!(?)
このシリーズの一覧は次のようになっています。
今回は Crypto つまり暗号というのは何なのかを解説します。
暗号とは
暗号とはなんでしょうか?
具体的な状況として Web サービスにログインした状態を考えてみましょう。このとき個人情報が大量に含まれている可能性があるので、攻撃者に悪いことをさせたくありません。これを暗号化して通信を行いたいのですが本当に暗号化だけで大丈夫でしょうか?よく考えてみると大体この 3 つが必要になります。
- 機密性 (Confidentiality)
内容に関するあらゆる情報を得られない - 完全性 (Integrity)
改ざんされない - 真正性 (Authenticity)
なりすまされない
これらの「解読、改ざん、なりすまし」を防げれば通信において悪いことが出来ないということが証明されます。これを実現するシステムの総称を暗号技術といいます。
解読されないとは
暗号というのは元来「暗号化/復号は簡単でも解読は難しい」という非対称性があります。
例えば換え字暗号は「文字置換は簡単でもどう置換したのかを調べるのは難しい」という非対称性、 RSA 暗号であれば「掛け算は簡単でも素因数分解は難しい」という非対称性、AES であれば「シャッフルは簡単でも元に戻すのは難しい」という非対称性があります。
その難しさこそが暗号の機密性です。
そしてその難しさは カギ が担っています。カギは暗号化/復号するときに必要なデータで、暗号化プログラムが全世界に公開されている現代暗号ではカギのない暗号だと誰もが復号できてしまいます。カギを部分的に公開するかどうかによって暗号を大きく 2 つに分けられます。1 つは全て秘密にする共通鍵暗号です。
共通鍵暗号
暗号化と復号で 同じ鍵 を使い、暗号化で使う鍵を 秘密 にする方式
ex.) AES, DES, ChaCha20 など
共通鍵暗号は高速に暗号化できる反面、最初に鍵を共有しなければならず、共有しているところを攻撃者に盗聴される危険があって安全に通信できません。そこで公開鍵暗号です。
公開鍵暗号
暗号化と復号で 別の鍵 を使い、暗号化で使う鍵を 公開 する方式
ex.) RSA暗号, 楕円曲線暗号 など
公開鍵暗号は暗号化と復号で別の鍵を用いるので、暗号鍵を公開しても攻撃者は復号することができません。このためある人以外は暗号化できてその人だけ復号できるという状態となります。その為、共通鍵を渡すときや秘密を安全に通信したいときに重宝します。
この 2 つの暗号を使い分けることで高速で安全な通信路を構築することができます。
このようにして機密性のある通信ができます。
なりすまされないとは
信頼できない相手に対してどのように正当性を担保するのかという問題はインターネットが普及した現代では非常によくあります。
皆さんがよく使う パスワード認証 はなりすましを防ぐ手段の 1 つです。
合言葉であるパスワードを知っている人しかログインできないようにすれば、ユーザーの正当性は大体担保できます。ただしこれはユーザーにとって分かりやすいシステムな反面、パスワードが使い回されていたり、簡潔なものに設定されているなどしていると、アカウントが乗っ取られてしまうことがあります。ですのでちゃんとサービス毎にそれぞれ違う複雑なパスワードを覚えて設定する...なんてことは私には無理なのでブラウザが生成した乱数値か FIDO を使うのがいいでしょう。
パスワード認証の他に 電子署名 というのもあります。
これは認証局だけが署名でき、電子証明書が存在するならばそこに書かれている人は認証され、認証局ではない攻撃者は正当な署名を作ることができないようなシステムです。
- ユーザーは信頼された第三者機関である認証局 (CA) に許可を得て、所有者情報や有効期限が書かれた電子証明書を発行してもらいます。
- ユーザーは公開鍵暗号の秘密鍵を用いて署名し、公開鍵と署名をホストに渡します。
- ホストは署名を公開鍵で復号したものを CA で検証してもらってユーザーの正当性を保証します。
逆に攻撃者がその人になりすます為には証明書を後から署名しなければなりませんが、ホストに保持された公開鍵に対応する秘密鍵を持っていないので署名は不可能です。
あとは SSH の公開鍵認証ってしたことありますか?鍵のペアを生成して、公開鍵を authorized_keys
に書いて ssh
コマンド叩いて fingerprint
がなんとかかんとかとか言われたりして接続できるやつです。あれは電子署名の簡易版で、ユーザー自身で証明書を発行/署名して、ホストだけが持つ公開鍵で検証してもらうという認証をしています。
最近この手の話題はよくあって、それらの単語と結びつけてざっと理解してみましょう。
- MFA; Multi-Factor Authentication / 2FA
パスワードに加えて、デバイス認証やEメール、生体認証など、他の認証方法も用いた認証。 - OAuth 2.0 / OpenID Connect / SAML
他サービスへの認可と認証を行う為の規格。「Google でサインインする」や「Twitter と連携する」とかいうあれが認可認証です。 - FIDO / WebAuthn / passkeys
公開鍵認証をブラウザなどで行う為の規格。パスワードなしでログインできるようにする。SoloKey, NitroKey など - マイナンバーカード
電子証明書を搭載した IC チップ付き身分証。身分証に目が行きがちですが電子署名で確実な本人確認が可能なことが良いところ。 - セキュアブート
カーネルやブートマネージャーなどのファームウェアの電子署名を管理することで OS が正当なものか検知する仕組み。Linux をデュアルブートするときとかにお世話になりますね。 - TEE; Trusted Execution Envrionment
厳密にセキュアな領域を広げていくシステム。
このように真正性は保証されます。
改ざんされないとは
まず先に断っておくのですが、本質的に改ざんさせないということは 不可能 です。
暗号化された通信をしていて攻撃者は暗号文の内容がわからなくとも、適当に書き換えて送りつければ、平文も書き換わりますからね。何故かというと、暗号は復号可能性により暗号文と平文は一対一に対応しているので平文が変われば暗号文も変わるし、逆も同様です。
それでは改ざんされることは許すとして、改ざんされたことを検知できれば良いですよね。検知する手法としてはいくつかありますが、最も基本的な方法はハッシュ関数という関数を使う方法です。
ハッシュ関数
一方向にしか計算できない関数、つまりあるデータのハッシュ値から元のデータが取り出せられないような関数です。例えば SHA256, MD5 などがあります。
これを使って以下のようなことをします。
- 暗号化された通信上でファイルとそのハッシュ値を送る
- 送られてきたファイルのハッシュ値と送られてきたハッシュ値が一致するかどうか検査する
こうすることでデータが書き換わると送られてきたハッシュ値とは異なるハッシュ値となり、改ざんを検知できるという訳です。
しかし、これだけだと以前に送った暗号文に入れ替えるリプレイ攻撃に弱いので、共有鍵や疑似乱数 Nonce を取り入れた検知方法が主流です。
- MAC; Message Authentication Code
暗号学的に強い一方向性の関数を用いてメッセージ改ざん検知する関数。HMAC, AES-CMAC など。 - AEAD; Authenticated Encryption with Associated Data
暗号化とメッセージ改ざん検知を同時に行う暗号方式。AES-GCM, ChaCha20-Poly1308 など。
このように完全性が保証されます。
あそんでみよう
実際の CTF ではよくわからない暗号やエンコーディング、古典暗号が出題されることがあるのですが、大抵ググるか CyberChef に投げれば解けてしまいます。
換え字式暗号なら quipquip というのが有用です。
まとめ
暗号というのは何を守るのか、どうして必要なのかをさくっと解説しました。
これを聞いて次は中身がどうなっているのか気になりませんか?そして中身が分かってくると脆弱な点が見えてきて攻撃ができるようになってきます。
Discussion
練習問題で心折れた