ヴィジュネル暗号と解析

多表式換字(ヴィジュネル)の暗号化と、それを破る解析パイプラインを実装して理解した(vijunel)。

暗号本体

鍵を文字列にした位置ごとに違うシーザー暗号。平文の各文字を、繰り返す鍵文字の分だけずらす。

  • 暗号化:r = (textNum + keyNum) % 26/復号:r = (textNum - keyNum + 26) % 26
  • 鍵は周期的に使う:key[keyIdx % keyLen]。鍵長 m なら m 個のシーザー暗号が交互にかかる。

なぜ単純な頻度分析で破れないか

1つのシーザー暗号なら文字頻度の山(英語なら E)を探せば一発。だがヴィジュネルは m 個の暗号が混ざる ので、全体の頻度が平坦化して山が消える。鍵長 m を割り出し、暗号文を m 列に分解すれば、各列は ふたたび単一シーザーに戻り、頻度分析が効く――これが攻略の核心。

攻略パイプライン(runAnalysisPipeline

解析には sanitize 済みの最低100文字が要る(短いと頻度が出ない)。

1. 鍵長を当てる(selectKeyLength =方式D)

  • 一致指数 IoC:テキストから2文字引いて一致する確率 Σ f(f-1) / n(n-1)。英語の自然文 ≈ 0.0667、 ランダム ≈ 0.0385
  • 鍵長 k を仮定して k 列に分け、列の平均 IoCを測る。正しい k では各列が英語分布に戻り 0.0667 へ近づく。 中点 0.0526 =(0.0667+0.0385)/2 を有効候補の足切りに使う。
  • 倍数を畳む:IC が最大の peak の約数を小さい順に見て、IC が peak の 92% 以上なら最小周期と判断 (鍵長 4 が 8・12 でも高く出るので、本来の 4 に畳む)。
  • Kasiski 法を併用:繰り返す3文字の出現間隔の公約数を鍵長候補としてスコア化(kl=2..12)。 IoC の候補(IC降順 上位5)と突き合わせて確度を上げる。

2. 列ごとにシフトを当てる(frequencyChiSquared

各列について、観測頻度と英語頻度 ENGLISH_FREQ を 26 通りのシフトでずらし、 χ² = Σ (observed − expected)² / expected が最小のシフトを採用。χ² は内積(相関)より 短い列でのノイズ耐性が高い。expected が 0 のときは 1 で割って 0 除算回避。 各列のシフト → 鍵文字、連結して鍵を復元 → その鍵で復号。

実装の正直な限界(これ自体が知見)

コードのコメントが明言:閾値 92%・中点 0.0526 は経験則で、テキストによっては倍数を畳み損ねる。 「定数を変えても万能にはならない(頻度解析の原理的限界)」。暗号解析はヒューリスティックの束で、 短文・偏った文・繰り返しの少ない文では原理的に外す。閾値いじりで全部は救えない、と割り切る設計。

出典:vijunelvijunel.htmlprocessText / indexOfCoincidence / averageIC / kasiskiExamination / selectKeyLength / frequencyChiSquared / runAnalysisPipeline