科目Bの暗号化問題の解き方|文字をずらす計算を表で追う
Aを3つずらすとD。それは分かるのに、Zのあたりで急に分からなくなる。
科目Bの問題で、文字をずらして暗号にするコードを見て、手が止まったことはありませんか?
文字を数に直して、足して、余りを取って、また文字に戻す。変換が何度も重なるうちに、いま扱っているのが文字なのか数なのか、見失ってしまう人も多いのではないでしょうか。
大丈夫です。暗号化の問題の多くは、文字を番号に置き換えて、決まった数だけずらしているだけです。
私はエンジニアとして10年以上、Webシステムの開発や運用に携わってきました。実務で単純な文字ずらしの暗号を使うことはありませんが、番号を一定の範囲の中でずらして折り返す処理は、IDの変換やログの加工で何度も書いてきました。
ある時、範囲の最後の値だけが変換されずに、おかしな値が混じるという不具合に出会いました。原因は折り返しの計算の書き忘れで、端の値を含む小さなデータを表に書き出して、ようやく気づけました。
この記事では、暗号化の問題を、科目Bの解き方に合わせて5つの段階で紹介します。科目B全体の中で、こうしたアルゴリズムの問題がどんな位置にあるのかを先に確かめたい人は、親記事から読んでおくと流れがつかみやすくなります。
【関連記事】基本情報技術者試験の科目Bとは?擬似言語・アルゴリズム対策を初心者向けに解説
暗号化の問題は何を聞いているのか¶
最初に、暗号化とは何をする処理なのかを短く押さえておきましょう。暗号化とは、元の文を決まった規則で別の文に置き換えて、規則を知らない人には読めなくする処理のことです。
元の文を平文、置き換えたあとの文を暗号文と呼びます。暗号文を平文に戻す処理は、復号と呼ばれます。
科目Bでよく題材になるのが、シーザー暗号と呼ばれる方式です。アルファベットの各文字を、決まった数だけ後ろの文字に置き換えるという、いちばん単純な暗号です。
たとえば3文字ずらすなら、AはDに、BはEに置き換わります。この、ずらす数のことを鍵と呼びます。
暗号化と復号の計算を表で比べる¶
文字のままでは計算ができないので、コードの中では文字を番号に直してから計算します。ここでは、Aを0、Bを1と数えて、Zを25とする番号を使います。
暗号化と復号で、計算がどう違うのかを表に整理しました。鍵を k、文字の番号を n とします。
| 処理 | やること | 計算式 | 鍵3でのWの例 |
|---|---|---|---|
| 暗号化 | 後ろへ k 文字ずらす | (n + k) mod 26 | 22 が 25 になり Z |
| 復号 | 前へ k 文字戻す | (n − k + 26) mod 26 | 25 が 22 に戻り W |
| 折り返し | Zの次をAに戻す | mod 26 が担当 | Yに3を足すと27、余りは1でB |
表を見ると、暗号化と復号は、足すか引くかが違うだけだと分かります。そして、どちらにも mod 26 が付いていることに注目してください。
アルファベットは26文字しかないので、Zを越えたらAに戻る必要があります。この折り返しを1行で引き受けているのが、26で割った余りを取る計算です。
文字列や剰余の問題との違い¶
暗号化の問題は、文字列の問題と剰余の問題を組み合わせたものだと考えると分かりやすくなります。1文字ずつ取り出す部分は文字列の問題と同じで、ずらして折り返す部分は剰余の問題と同じです。
1文字ずつ取り出して新しい文字列を作る処理は、文字列問題の記事で詳しく扱っています。
【関連記事】科目Bの文字列問題の解き方|1文字ずつ取り出す処理を追うコツ
mod という記号の意味そのものに不安がある場合は、先に文法の記事で確かめておくと安心です。
【関連記事】擬似言語の余り(剰余)と割り算がわからない人へ|偶数判定と桁の取り出しを解説
まず目を付ける場所¶
暗号化が何をしているのかつかめたら、次はコードのどこから読むかを決めます。この問題で目を付ける場所は3つです。
ひとつ目は文字と番号をどう対応させているか、ふたつ目は鍵を足しているのか引いているのか、みっつ目は折り返しをどこで処理しているかです。この3か所を確かめれば、コード全体の動きはほとんど決まります。
文字と番号の対応はどう決まっているか¶
最初に確かめたいのが、文字を番号に直す規則です。Aを0とするのか1とするのかで、折り返しの計算が変わるからです。
科目Bでは、文字と番号を変換する関数が、問題文の中で説明されることがよくあります。その説明を読み飛ばさず、Aが何番で、Zが何番なのかを最初にメモしておきましょう。
鍵を足しているか引いているか¶
次に見るのが、番号に鍵を加える行です。足していれば暗号化、引いていれば復号です。
問題によっては、鍵がマイナスの値で渡されることもあります。その場合は、足し算の形でも実際には前へ戻していることになるので、渡された値の符号まで確かめてください。
折り返しはどこで処理しているか¶
最後に見るのが、Zを越えたときの処理です。mod 26 で余りを取る書き方のほかに、if で25を超えたら26を引く書き方もあります。
どちらの書き方でも、結果が0から25の範囲に収まっているかを確かめるのが目的です。この範囲から外れた値が出る選択肢は、それだけで候補から外せます。
例題:鍵の数だけ文字をずらして暗号文を作る¶
ここからは、実際の例題で追い方を確かめます。この記事の例題は説明のために作成したもので、IPA の公開問題そのものではありません。
次のプログラムは、英大文字だけでできた文字列 plain を、鍵 k の数だけ後ろへずらした暗号文を返す関数です。関数 code は英大文字をAが0、Zが25の番号に変換し、関数 letter はその逆に、番号を英大文字に変換するものとします。
○文字列型: encrypt(文字列型: plain, 整数型: k)
文字列型: result ← ""
整数型: i, n
for (i を 1 から plain の文字数 まで 1 ずつ増やす)
n ← code(plain の i 文字目)
n ← (n + k) mod 26
result ← result の末尾に letter(n) を連結した文字列
endfor
return result
encrypt は、平文から1文字ずつ取り出して番号に直し、鍵を足して26で割った余りを取ります。その番号を文字に戻して、result の末尾につなげていきます。
では、encrypt("WAY", 3) の戻り値は何になるでしょうか?
トレース表で1文字ずつのずれを追う¶
頭の中だけで変換を続けると、いまの値が文字なのか番号なのかが分からなくなりがちです。そこで、ループ1回ごとに、i、取り出した文字、変換前の番号、鍵を足した値、余りを取った値、戻した文字をトレース表に書きます。
ポイントは、鍵を足した値と余りを取った値を別の列にすることです。折り返しが起きた行がひと目で分かるようになります。
| i | 取り出した文字 | code の値 | n + k | mod 26 の値 | letter の値 | result |
|---|---|---|---|---|---|---|
| 1 | W | 22 | 25 | 25 | Z | Z |
| 2 | A | 0 | 3 | 3 | D | ZD |
| 3 | Y | 24 | 27 | 1 | B | ZDB |
ループが終わった時点で、result は ZDB です。したがって、戻り値は ZDB になります。
3行目を見てください。Yに3を足すと27になり、26を越えるので余りを取って1、つまりBに折り返しています。
1行目と2行目では、n + k と mod 26 の値が同じです。26より小さい値は、余りを取っても変わらないからです。
トレース表の書き方そのものに慣れていない場合は、こちらの記事で基本から確認できます。
【関連記事】擬似言語のトレース表の書き方|科目Bで変数の値を追う手順を解説
復号の計算でも同じ表を使う¶
暗号化の問題では、復号する側の関数も一緒に出ることがあります。復号では鍵を引くので、番号がマイナスになる場面に注意が必要です。
ZDB を鍵3で復号すると、Zは25から3を引いて22でW、Dは3から3を引いて0でAに戻ります。ところがBは、1から3を引くと −2 になってしまいます。
ここで26を足して24にしてから余りを取れば、Yに正しく戻ります。復号のコードで、鍵を引いたあとに26を足している行があるのはこのためです。
マイナスの数の余りは、言語や定義によって結果の扱いが変わることがあります。26を足して0以上にしてから余りを取る形にしておけば、どの場合でも安全に計算できます。
鍵が文字ごとに変わる形も出る¶
もう少し手ごわい形として、文字ごとに鍵が変わる暗号もあります。鍵を1つの数ではなく、数の並びとして持っておき、何文字目かによって使う鍵を切り替える方式です。
たとえば鍵の並びが {1, 2} なら、1文字目は1つ、2文字目は2つ、3文字目はまた1つずらします。コードの中では、鍵の添字を i mod 2 のような式で決めていることが多いです。
この形でも追い方は変わりません。トレース表に、その文字に使った鍵の列を1つ足せば、同じように1行ずつ確かめられます。
間違いやすい選択肢の見分け方¶
暗号化の問題では、足すか引くか、折り返しをどう扱うかを少しだけずらした選択肢が並びます。どんな誤りが用意されやすいのかを知っておけば、選択肢を見た瞬間に候補を絞れます。
例題の encrypt("WAY", 3) を使って、よくある誤りを表にまとめました。
| 誤りの種類 | 選択肢の例 | 計算結果 | 起きること |
|---|---|---|---|
| 鍵を引いてしまう | (n − k + 26) mod 26 | TXV | 暗号化のはずが前へずれる |
| 割る数を間違える | (n + k) mod 25 | ADC | 25番のZが0番のAとして扱われる |
| 余りを取り忘れる | n + k をそのまま使う | 3文字目が27 | 0から25の範囲を越えて文字に戻せない |
| 先頭に連結する | result の先頭に letter(n) をつなぐ | BDZ | 文字の並び順が逆になる |
1行目は、暗号化と復号を取り違えた選択肢です。結果を見ただけでは正しそうに見えるので、足しているのか引いているのかを式で確かめる必要があります。
2行目の mod 25 は、W、A、Yの例ではAとDとCになり、一見ちゃんと文字になってしまいます。それでも、元のWが22番から25番に進むはずなのに0番になっている時点で、折り返しの位置がずれていると分かります。
端の文字で必ず試す¶
選択肢を絞るときは、例題とは別に、端の文字を含む小さな文字列を用意すると安全です。おすすめは、Aと、Zと、Zの少し手前の文字を1つずつ入れた3文字です。
Aは鍵を引く誤りで前へはみ出し、Zは割る数の誤りで折り返し方がずれます。この3文字で答えが合えば、折り返しに関する誤りはほぼ見分けられます。
暗号化と復号を往復させる¶
もう1つの確かめ方が、暗号化した結果を復号して、元に戻るかどうかを見る方法です。WAY を暗号化して ZDB になり、それを復号して WAY に戻れば、2つの関数はかみ合っています。
戻らない場合は、どちらかの関数の符号か折り返しに誤りがあります。どの文字で戻らなかったかを見れば、誤りのある行まで絞り込めます。
情報セキュリティの考え方ともつながる¶
シーザー暗号は、鍵の候補が25通りしかないため、全部試せばすぐに解読されてしまいます。実際の情報システムでこの方式が使われないのは、そのためです。
それでも、鍵があれば元に戻せる、鍵がなければ読めない、という暗号の基本の考え方は、科目Bの情報セキュリティの問題にもつながっています。暗号を守る側の考え方に興味が出てきたら、こちらの記事も読んでみてください。
【関連記事】基本情報 科目Bの情報セキュリティ対策|擬似言語との勉強時間の配分を解説
Giji Academy のシミュレーターで動かす¶
紙のトレース表で動きをつかんだら、最後は実際に動かして確かめましょう。文字と番号の変換が何度も重なる処理ほど、動かして見る効果は大きくなります。
Giji Academy の擬似言語シミュレーターでは、擬似言語のコードを1行ずつ実行し、変数の値が変わる様子を目で確かめられます。自分で書いたトレース表と見比べながら進めると、どの文字で予想とずれたのかがすぐに分かります。
試すときは、まず正しい encrypt を動かして、n が27から1へ折り返す瞬間を確かめてください。そのあと mod 26 を mod 25 に書き換えて、Wが思わぬ文字に変わる様子を見ると、割る数の意味が体で分かります。
慣れてきたら、復号の関数を自分で書いて、暗号文が平文に戻るかを試してみましょう。26を足す行を消すとどうなるかを見ておくと、復号の選択肢で迷わなくなるはずです。
まずはGiji Academy の擬似言語シミュレーターで講座を選び、文字が番号に変わり、ずれて、また文字に戻る流れを確かめてみてください。
まとめ¶
科目Bの暗号化の問題は、暗号の専門知識を問うものではありません。文字を番号に直してずらし、範囲の端で折り返して文字に戻す、という手順を表に書いて追えば、落ち着いて解けます。
この記事でお伝えした5つの段階を振り返っておきましょう。
| 段階 | やること |
|---|---|
| 1 設問を読む | 文字と番号の対応、鍵の値、暗号化か復号かを問題文から読み取る |
| 2 目を付ける | 番号への変換、鍵を足すか引くか、折り返しの処理の3か所を見る |
| 3 トレースする | 文字、番号、鍵を足した値、余り、戻した文字を1文字ずつ表に書く |
| 4 選択肢を見分ける | 引き算との取り違え、割る数、余りの取り忘れ、連結の向きを端の文字で試す |
| 5 動かす | 正しいコードとずれたコードをシミュレーターで動かし、表と見比べる |
最初は、3文字くらいの短い文字列で十分です。何度か表を書くうちに、mod 26 を見ただけで、どこで折り返しが起きるのかが分かるようになります。
文字はいったん番号に直して考える。端の文字で折り返しを必ず試す。 この2つを習慣にしておけば、暗号化の問題にも自信を持って向き合えます。次に文字をずらすコードに出会ったら、まずはZに近い文字から表に書いてみてください。