CTFにおけるCrypto入門とまとめの1つです。
共通鍵暗号と公開鍵暗号
- 共通鍵暗号: 暗号化時と復号時に同じ鍵を使う暗号
- ブロック暗号: 一定長のブロックに分けて暗号化
- ストリーム暗号: 一定数のビットをまとめて1つの単位として暗号化
- 公開鍵暗号: 暗号化時と復号化時に異なる鍵を使う暗号
- ハイブリッド暗号: 公開鍵暗号を用いて鍵共有を行い、共有した鍵により高速な共通鍵暗号を用いて秘匿通信を行う
- 認証付き暗号: AEAD: Authenticated Encryption with Associated Data
- 暗号化と認証(改ざん検知)の両方が備わった暗号のこと
- 暗号 + MACの単純な組み合わせでも概ね実現できるが、不適切な組み合わせなどにより想定した安全性を達成できない場合があるっぽい
- AES-GCMとかChaCha20-Poly1305
- 暗号化と認証(改ざん検知)の両方が備わった暗号のこと
- 鍵配送問題
- 事前共有: 安全な方法で鍵を前もって渡しておく
- 個別に鍵を作ると大量になっちゃうので鍵配布センター(KDC)を用意する
- Deffie-Hallman鍵交換 -> 共通鍵を共有可能
- 公開鍵で解決
- 公開鍵の認証、公開鍵の真生性が証明できない問題が残る
ブロック暗号
https://tex2e.github.io/blog/crypto/symmetric-key-ciphers
- DES: Data Encryption Standard
- もう安全ではない
- Feistel構造: 暗号化と復号で同じ回路を使用できる
- Slide Attack: 複数ラウンドで同じラウンド鍵が使われている時、スライド攻撃によってラウンド鍵を求めることができるかも
- triple-DES
- 鍵を3つ用意して、DESをencrypt->decrypt->encryptと適用して暗号文を作る
- S-DES 鍵長が10ビットしかないので全探索可能 https://github.com/jiegec/ctf-writeups/blob/master/2025-08-22-brunnerctf2025/the-complicated-recipe.md
- AES -> 別記事にて解説
- Blowfish
- Camellia: NTTと三菱電機が共同で開発
- CLEFIA: ソニーが開発した省電力なハードウェアでも動作する軽量暗号で、ISO/IEC 29192の1つ
- MISTY1
- Notary Service
- TEA: 実装が軽量な共通鍵ブロック暗号
Feistel構造
- スキーム
- 設定か実装がちょっと違って、keyがランダムであっても平文が一定であれば、暗号文の指定のビットのxorが一定になってしまうことを発見して利用する https://github.com/Warriii/CTF-Writeups/blob/main/deadsec25/crypto_bpcasino.md
- ImaginaryCTF 2025 Feistel Network https://github.com/ImaginaryCTF/ImaginaryCTF-2025-Challenges/blob/main/Crypto/feistier-network/challenge/solve/writeup.md
- 復号化をよく見ると、巡回鍵Kが「回文」になっているとき、LとRを逆にして暗号化することで復号ができる
攻撃手法
- 選択平文攻撃: 暗号解読者が任意の平文を暗号化できることを前提がある攻撃
- 差分解読法
- 平文の一部を変更すると暗号文がどう変化するかを調べる暗号解読法
- 暗号文の変化の手がかりを調べて解読の手がかりを得ていく
- 線形解読法
- 平文と暗号文のビットをいくつかXORして0になる確率を調べる
- 暗号文が十分にランダムであれば、平文と暗号文のビットをいくつかXORした結果が0になる結果は1/2のはずだが、そこからのずれが大きいビットの箇所を調べて、鍵に関する情報を得る
- 差分解読法
- 弱い鍵
- 暗号強度を下げるような特性を持つ特定の鍵のこと
- DES: 弱い鍵を使うと、暗号化モードと復号化モードが同じように動作する
- 例:0000000000000000ffffffffffffffff
- 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF でもいいみたい
- 単純な平文を使って、定数が求められるかも
00 00 00 ... 00 01を入れると定数が分かった例 https://github.com/Pez1181/CTF/wiki/-BtSCTF-Better_AES
- 暗号化手順が全部線形であれば、逆計算できるかも
Wikipediaに書いてある攻撃
- ショートカット法: ブロック暗号アルゴリズムの弱点を用いて鍵の全数探索以下の計算量で鍵(の一部)を求める手法の総称
- 差分解読法(差分暗号解読) en:Differential cryptanalysis (Biham, 1989): XX以上の確率を有するような差分特性を探す
- 不能差分解読法 en:Impossible differential cryptanalysis
- 切詰差分解読法 Truncated Differential Cryptanalysis
- 高階差分解読法 Higher Order Differential Cryptanalysis
- Square攻撃 en:Square attack
- Integral cryptanalysis https://github.com/elliptic-shiho/crypto_misc/blob/master/AES/4_round_integral_attack.sage
- 飽和攻撃 Saturation Attack
- Square攻撃 en:Square attack
- ブーメラン攻撃 en:Boomerang attack
- 補間攻撃 en:Interpolation attack (Jakobsen, Knudsen, 1997)
- 線形和攻撃 Linear Sum Attack (Aoki, 1999)
- 線形解読法(線形暗号解読) en:Linear cryptanalysis (Matsui, 1993): XX以上の確率を有するような線形特性を探す
- 差分線形攻撃 en:Differential-linear attack
- 切詰線形攻撃 Truncated Linear Attack
- スライド攻撃 en:Slide attack (David Wagner, Alex Biryukov, 1999)
- カイ2乗攻撃
- mod n攻撃 en:Mod n cryptanalysis
- XSL攻撃 en:XSL attack
- 差分解読法(差分暗号解読) en:Differential cryptanalysis (Biham, 1989): XX以上の確率を有するような差分特性を探す
- サイドチャネル攻撃
- 単純電力解析 Simple Power Analysis
- 電力差分攻撃 en:Differential power analysis
- タイミング攻撃 en:Timing attack
- 書いてなかった攻撃
- 関連鍵攻撃
- 丸め差分攻撃
ストリーム暗号
- ストリーム暗号
- RC4: 2012年ごろから攻撃方法が見つかった
- RC6: https://www.cryptrec.go.jp/exreport/cryptrec-ex-0131-2000p1.pdf
- Enocoro: 日立
- KCipher-2: 九州大学とKDDI開発
- ChaCha20: モバイル環境でAESより高速
- ストリーム暗号の基本方針
- ストリーム暗号は対称暗号化
- ストリーム暗号に求められる代表的な安全性
- 共通問題
- とある2つの暗号化について、同じ鍵ストリームを使ってはならない
- 2つの暗号化文をxorすることで、それぞれの平文のxor和が得られ、文字の頻度分析やそのほかの基本的な手法により、暗号化前の情報が得られるかもしれない
- 対策として暗号鍵が同じ場合でもivを鍵に加えて異なる鍵ストリームを生成させることが大事
- とある2つの暗号化について、同じ鍵ストリームを使ってはならない
- カオスベース・ストリーム暗号
- 鍵ストリーム生成段階でカオスマップを用いる
- 一般的に用いられるカオスマップ https://en.wikipedia.org/wiki/List_of_chaotic_maps
ワンタイムパッド One-Time Pad / Vernam / バーナム暗号
- 方式
- 平文と同じ長さの鍵を用意する
- 平文 xor 鍵によって暗号文を作成する
- One-Timeとあるように鍵は1回きりで使用する必要がある
- そうしないと、同一の鍵で作られた暗号文AとBをxorすると、それぞれの平文aとbのxorが得られてしまう
- multi-time pad: ワンタイムパッドが使いまわされた結果、復号されてしまうのをやじったもの
- ワンタイムパッドは平文と同じ長さの鍵が必要なため、実際には使われないが、ワンタイムパッドは全ての暗号文が同じ確率で現れるような安全性を持つ暗号であり、情報理論的安全である。ストリーム暗号では、情報理論的安全であるワンタイムパッドの枠組みを使いながら、共通鍵として共通の疑似乱数系列を使うことで暗号としての安全性を担保しようとしている
- この時使われる疑似乱数系列をキーストリームと呼ぶ
- 攻撃方法
- https://labs.spookies.co.jp/entry/2019/11/12/174348
- 同じ平文に対してランダムな鍵での暗号化結果が与えられるが、鍵は0x00を含むことはできない。
- 0x00で暗号化されると平文がそのまま出てくるが、このパターンはあり得ないということは、何回か試して出てくるパターンを計測したときに、現れない文字が平文の文字であるということが言える
- 頻度解析, Key Reuse: キーストリームが共通で暗号文が複数あるとき、頻度解析をすれば根性でキーストリームが復元できる
- https://labs.spookies.co.jp/entry/2019/11/12/174348
RC4
- アルゴリズム
- 鍵
- ↓ KSA, Key Scheduling Algorithm, 鍵スケジューリングアルゴリズム: 鍵を初期の内部状態に変換する
- 内部状態 256bytesの配列とi,jの2つのindex
- ↓ PRGA, Pseudo-Random Generation Algorithm: 内部状態を更新しながらキーストリームを作成する
- キーストリーム
- ↓ XOR 平文
- 暗号文
- 問題
- AHR9 Equivalent Privacy Wired https://chocorusk.hatenablog.com/entry/2025/01/26/180123
- master_key + ivで鍵を作っていてivを自由に操作可能な場合に、KSAで
key[i mod keylength]となっていることから256文字でループすることを利用し、iv = "a"*(255-len(master_key))とiv = "a"*(255-len(master_key)) + cを比較することで同じキーストリームを作るかを判定し、master_keyを先頭から特定することができる
- master_key + ivで鍵を作っていてivを自由に操作可能な場合に、KSAで
- FMS https://github.com/jvdsn/crypto-attacks/tree/master/attacks/rc4
- AHR9 Equivalent Privacy Wired https://chocorusk.hatenablog.com/entry/2025/01/26/180123
- 資料
ChaCha20
- ChaCha20ではkeyとnonce(=iv)からkeystreamを作成して、それを逐次平文にxorして暗号文を作成している
- ということは、keyとnonceが同じであれば全く同じkeystreamが作成されるので、keyとnonceが同じで、かつ、平文と対応する暗号文の組が手に入っていれば平文 xor 暗号文でkeystreamが手に入り、それを平文にxor和すれば暗号文になるし、暗号文にxor和すれば平文に戻せる
- キーストリームの作成方法 https://gitlab.mma.club.uec.ac.jp/mmabeginners/wanictf-2024/-/tree/main/Crypto/dance?ref_type=heads
- 以下のような情報を元に初期状態を作る 定数:16byte(4 words)->{0x61707865, 0x3320646e, 0x79622d32, 0x6b206574} 鍵:32byte (8 words) ブロックカウント:4byte(1 word) Nonce: 12byte(3 words)
20ラウンド分ラウンド操作を行う(column round -> diagonal roundを10セットやる) ```python def __quarter_round(self, a: F2_32, b: F2_32, c: F2_32, d: F2_32): a += b; d ^= a; d <<= 16 ## <<=は「巡回」左シフト c += d; b ^= c; b <<= 12 a += b; d ^= a; d <<= 8 c += d; b ^= c; b <<= 7 return a, b, c, d
def Qround(self, idx1, idx2, idx3, idx4): self.state[idx1], self.state[idx2], self.state[idx3], self.state[idx4] = \ self.quarter_round(self.state[idx1], self.state[idx2], self.state[idx3], self.state[idx4])
def update_state(self): for _ in range(10): # column round self.Qround(0, 4, 8, 12) self.Qround(1, 5, 9, 13) self.Qround(2, 6, 10, 14) self.Qround(3, 7, 11, 15) # diagonal round self.Qround(0, 5, 10, 15) self.Qround(1, 6, 11, 12) self.Qround(2, 7, 8, 13) self.__Qround(3, 4, 9, 14) ```
- 作成したキーストリームと平文をxorして暗号化
- 弱点
- 同一nonce, 同一キーで暗号化すると同じキーストリームを作る
- ラウンド操作は逆計算が可能であるため、平文と暗号文の組が分かっていれば、そこからキーストリームを作っている状態が分かり、そこから逆計算をして初期状態を計算し、それにより鍵とivが判明する
- ChaCha without Poly is vulnerable to a bit flip attack
- 資料
- ChaCha20-Poly1305 https://tex2e.github.io/blog/crypto/chacha20poly1305
RC4 / ARC4
- RC4: 安全ではないとされていてもう使ってはいけない
- RC4: 以下2つのアルゴリズムから成り立つ https://zenn.dev/mahiro33/articles/6f74d1dc8532b4
- KSA: Key Scheduling Algorithm. 暗号鍵を用いてそれに応じた内部状況を生成する
- PRGA: Pseudo-Random Generation Algorithm. KSAで生成した内部状態をもとに、かき混ぜと1byteの乱数出力を行い、これを使ってXORして暗号文を生成
- 完全に
RC4 = ARC4(Alleged-RC4)である。RC4が商標登録されているため名前が使えないのでARC4と表記されるようになったらしい - 「RC4の鍵テーブルにおける統計的な偏り[8]を利用することで、平文の一部が回復可能であるというものである[9][10]。この攻撃法により、13 × 220通の暗号文を用いれば128ビットのRC4が解読可能であることが示され、2013年のUSENIXセキュリティシンポジウムにおいて「実現可能である」と評された」 from Wikipedia
- https://www2.nict.go.jp/csri/plan/H26-symposium/files/3-1.pdf も非常に良い資料
- ストリーム暗号としての安全性は満たしていないが、見た感じCTFで使えそうなpracticalな攻撃方法は現状無い?
公開鍵暗号
- 公開鍵暗号 PKE: Public Key Encryption: 暗号化時と復号化時に異なる鍵を使う暗号。一方向性関数を利用して構築する
- 一方向性関数: 入力→出力は容易に計算可能だが、出力→入力は困難な関数。各公開鍵暗号方式の安全性の根拠となる。
- 公開鍵暗号の3ステップ
- 公開鍵暗号を用いたデジタル署名: 公開鍵暗号を使って署名を作成し、改ざん検知や否認防止、真正性担保を行う機構
- 公開鍵基盤 PKI, CA, CRL, X.509 電子証明書
- 証明書の基盤となる分野
他、方式
- Okamoto-Uchiyama cryptosystem
- Paillier暗号
- Goldwasser-Micali暗号
PQC / 耐量子暗号 / ポスト量子暗号
- PQC: 量子コンピュータによる暗号解読に対して安全だと考えられる暗号アルゴリズム(主に公開鍵暗号)
- 色んなアプローチがある https://www.cryptrec.go.jp/report/cryptrec-gl-2004-2022.pdf
- 計算量理論によるアプローチもあるみたい
- コルモゴロフ複雑度の計算問題のアルゴリズムおよび暗号学的研究が進められている
- 2022年のNISTの選定
- 鍵共有方式 -> CRYSTALS-KYBER: 格子暗号、加群格子と呼ばれる構造化格子を使う
- ML-KEM https://zenn.dev/ankoma/articles/f165d06efb1468
- 仕様 https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
- ML-KEM.KeyGen
- 乱数d,zを用意する(どちらも32bytes)
- ML-KEM.KeyGen_internal(d,z)を使って、ek,dkを作る
- このとき、K-PKE.KeyGen(d)からek_PKEとdk_PKEを作る
- つまり、dだけでek_PKEが作れる?
- ek_PKEはそのままekとして採用される
- dkはdk_PKE || ek || H(ek) || zで作る
- だめ?
- このとき、K-PKE.KeyGen(d)からek_PKEとdk_PKEを作る
- 秘密鍵に保存されているseed, dk, ekはこれ
- seedはd || zになっている
- seedのdだけ分かればshared keyの復号化は行える
- https://zenn.dev/koba_e964/articles/34bf5e65d5d342#%5Bcrypto%5D-pqc0-(149%2F882)
- 適当にzを埋めて以下のようにして秘密鍵を作れる
SEED=69ad874f2426daf9a60e6c397a178c269ea0266dec72b225a0d65917678a9dc4197c02030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F openssl genpkey -algorithm ML-KEM-768 -pkeyopt hexseed:${SEED} -out priv.pem
- 後は
openssl pkeyutl -decap -inkey priv.pem -in ciphertext.dat -out shared.datのようにして暗号化されたShared Secretを復号化できる
- ML-KEM.Encaps
- ML-KEM.Decaps
- OpenSSL 3.5.0は対応している
- 秘密鍵作成
openssl genpkey -algorithm ML-KEM-768 -out priv-ml-kem-768.pem - 秘密鍵から公開鍵作成
openssl pkey -in priv-ml-kem-768.pem -pubout -out pub-ml-kem-768.pem - 秘密鍵からShared Secretと平文と暗号文を作成
openssl pkeyutl -encap -inkey pub-ml-kem-768.pem -secret shared.dat -out ciphertext.dat - 暗号化されたShared Secretを復号
openssl pkeyutl -decap -inkey priv-ml-kem-768.pem -in ciphertext.dat -out decrypted_shared.dat
- 秘密鍵作成
- 問題
- ML-KEM https://zenn.dev/ankoma/articles/f165d06efb1468
- デジタル署名方式
- 鍵共有方式 -> CRYSTALS-KYBER: 格子暗号、加群格子と呼ばれる構造化格子を使う
- FIPS 203 https://hackmd.io/@Giapppp/mlkem
- 量子鍵配送 QKD: Quantum Key Distribution
- Google Capture The Flag 2019 (Quals) - Quantum Key Distribution で実装だけの問題が出た
- PQCのクソデカ資料 https://publications.tno.nl/publication/34643386/fXcPVHsX/TNO-2024-pqc-en.pdf
- 耐量子計算機暗号と量子情報の数理|共2022a015 https://joint.imi.kyushu-u.ac.jp/post-5123/
多変数多項式暗号 MPKC
- 二次元多変数多項式の求解問題(MQ問題)やEIP問題に基づくと考えられる暗号だが、NIST標準化ではRound 3で全ての方式が脱落した
- https://joint.imi.kyushu-u.ac.jp/wp-content/uploads/2022/08/220804_01furue-.pdf
- https://joint.imi.kyushu-u.ac.jp/wp-content/uploads/2022/08/220804_02ikematsu.pdf
- MQ問題: 有限体上の多変数二次連立方程式の求解問題、NP完全であることが証明されている
- MPKCは,その他の耐量子暗号(格子暗号や同種写像暗号など)と比べても高速な処理性能を有し,さらに署名方式においては署名長が最も短くなることから,IoTで取り扱う機器やICカードのような低資源デバイスでの実装に向いていると考えられています.また最近では,署名方式の一つであるRainbowから仮想通貨を作るという面白い試みも行われています.
- 代表的なスキーム
- Rainbow署名
- HFE: Hidden Field Equations
- Oil and Vinegar
- SFLASH: 破られた