小学生でもわかる!Python! - 8(暗号)
「暗号作り」は、プログラミングの基本である**「文字を1つずつ調べる(ループ)」と「ルールに合わせて変える(条件分岐)」**を練習するのに最高のテーマです!
「シーザー暗号」
もっとも有名な**「シーザー暗号」**を作ってみましょう。
「シーザー暗号」とは、アルファベットをズラして秘密のメッセージにする方法です。
1. シーザー暗号のルール
例えば、全ての文字を**「3つ右にズラす」**というルールにしてみましょう。
「A」 → B, C, 「D」
「B」 → C, D, 「E」
「C」 → D, E, 「F」
もし「CAFE(カフェ)」という言葉をこのルールで暗号にすると、**「FDIH」**になります。これなら、パッと見ただけでは何のことかわかりませんよね!
2. Pythonで「暗号化マシン」を作ろう!
コンピュータには「文字を数字(番号)として扱う」という得意技があります。それを使ってプログラムを書いてみます。
message = 'HELLO' # 暗号にしたい言葉
secret_text = '' # 暗号文を入れる変数
for s in message :
# 3文字左にずらして暗号文の変数に追加
secret_text+= chr(ord(s) - 3)
# 暗号文を出力
print(secret_text)これを実行すると"EBIIL"と出てきます。
3. このプログラムの「ここ」がポイント!
secret_text+= chr(ord(s) - 3)
このコードで文字をずらします。1つの文字が"s"に入っていくのでこれをコンピュータの仕組みでずらします。
ord() と chr(): コンピュータは文字を「背番号」で覚えています(Aは65番、Bは66番...)。ord は文字を番号に、chr は番号を文字に変える魔法の言葉です。
for char in message: 「伝言ゲーム」みたいに、1文字ずつ順番に処理していくループの力を使っています。
4. 暗号を「解読」するには?
暗号を元に戻す(解読する)のはとっても簡単。**「逆向きにズラす」**だけです!
暗号化: 3つプラスする
解読: 3つマイナスする
プログラムの shift(ズラす数)を -3 にして実行すれば、元のメッセージが浮かび上がってきます。
secret_text = 'EBIIL' # 暗号文を設定
message = '' # 平文を初期化
for s in secret_text:
# 3文字右にずらして平文に追加する
message += chr(ord(s) + 3)
print(message)これを実行すると"HELLO"と出てきます。
「あいうえお暗号」
「あいうえお暗号」に挑戦しましょう! アルファベットと同じように、日本語も「あいうえお……」の順番をずらすことで、立派な暗号になります。
ひらがなの場合は、**「あいうえお表(五十音図)」**をイメージするとわかりやすいですよ。
1. 「あいうえお暗号」のルール
例えば、**「1つ後ろにずらす」**というルールにしてみましょう。
「あ」 → い
「き」 → く
「す」 → せ
このルールで**「すいか」を暗号にすると、「せうき」**になります! (※「ん」の次は「あ」に戻る、というルールにします)
2. Pythonで作ってみよう!
ひらがなをずらすために、まずは「あいうえお」が全部並んだリストを準備します。関数にしてみます。
def aiueo_cipher(message, shift):
# 【1】「文字の順番」を決めた長いリスト(五十音表)
kana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん"
# 【2】暗号になった文字を入れていく「空の箱」
result = ""
# 【3】メッセージを1文字ずつ取り出して調べる(伝言ゲーム)
for char in message:
# 【4】もしその文字が「あいうえお表」の中にあったら
if char in kana:
# 【5】今、その文字が「何番目」に並んでいるか調べる
current_index = kana.find(char)
# 【6】今の番号に、ずらしたい数(shift)を足す
# ※ 「% len(kana)」は、一番最後の「ん」を過ぎたら「あ」に戻る魔法の計算!
new_index = (current_index + shift) % len(kana)
# 【7】新しく決まった番号の文字を、あいうえお表から取ってくる
result += kana[new_index]
else:
# 【8】表にない文字(!やスペース)はそのまま箱に入れる
result += char
# 【9】全部終わったら、暗号になった文字の箱を返す
return result実行します。
aiueo_cipher("あいす", 3)"えおた"と出てきます。
ここが魔法のポイント!
このコードの中で、一番賢い動きをしているのはこの部分です: new_index = (current_index + shift) % len(kana)
1. kana.find(char) ってなに?
「あいうえお...」という長い文字の列から、**「『い』は何番目?」と聞くと、「1番目だよ」**と答えてくれる機能です(プログラミングでは、0番目、1番目、2番目……と数えます)。
2. % len(kana) (あまりの計算)のすごさ
もし「ん」の場所にいて、あと1つずらしたいとき、そのまま足すと「次の番号」を探しに行ってしまいます。でも、次はありません。 そこで、全体の数で「わり算したあまり」を出すことで、最後になっても自動的に「0番目(あ)」に戻してくれるんです。
イメージ
メッセージから**「す」**を取り出す。
表で調べると**「10番目」**だった。
合言葉が「1」なら、1足して**「11番目」**にする。
表の11番目は**「せ」**。
「せ」を箱に入れる。
これを最後の文字まで繰り返す!
3. 暗号を解く
暗号を解くときに使う**「総当たり攻撃(ブルートフォース・アタック)」**の実験をしてみましょう!
もし、誰かが作った暗号の「ズラした数(合言葉)」が分からなくても、コンピュータなら**「1つずつ全部試す」**という力技で、あっという間に答えを見つけることができます。
日本語(ひらがな)の場合は「ずらす回数」が最大で81回(「あ」から「ん」までの数)になります。
1. 「総当たり攻撃」の作戦
ひらがな50音のリスト(暗号化したときと同じものを使うよ)を使って、ズラします。コンピュータに**「1つズラして表示、2つズラして表示……」**と全部やらせて、人間がそれを見て「あ!意味が通じる言葉があった!」と見つける作戦です。
2. 暗号を解くプログラム
さっき作った暗号化の仕組みを使って、全てのパターンを表示させてみます。
def crack_aiueo(secret_message):
# ひらがな50音のリスト(暗号化したときと同じものを使うよ)
kana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん"
print(f"暗号:{secret_message}")
print("-" * 30)
# 1回から81回まで、すべてのずらし方を試す
for shift in range(1, len(kana)):
result = ""
for char in secret_message:
if char in kana:
# 今の場所を見つけて、逆方向にずらす(マイナス)
current_index = kana.find(char)
new_index = (current_index - shift) % len(kana)
result += kana[new_index]
else:
# 記号などはそのまま
result += char
# 結果を表示(20個おきに区切りを入れると見やすいよ)
print(f"{shift:2}回ずらし: {result}")
# 実験!友達から届いた謎の暗号「おやすけ」
crack_aiueo("えおた")コードの中にある % len(kana) という魔法の計算を、もう少し詳しく説明しますね。
もし、今の場所が「あ(0番目)」で、さらに1つ「戻したい(-1)」とき、普通に計算すると -1番目 になってエラーになってしまいます。
そこで、**「全体の数(82個)でわった余り」を計算すると、コンピュータは自動的に時計の針を戻すように、「-1番目」を「81番目(ん)」**として扱ってくれるんです。
3. 実行するとどうなる?
このプログラムを動かすと、画面にズラズラっと25行の文字が出てきます。
1回ずらし: うえそ
2回ずらし: いうせ
3回ずらし: あいす ← これ
4回ずらし: んあし
・・(以下続く)
人間なら一瞬で「3番目の "あいす" が正解だ!」って分かりますよね。
パワーアップ
「あいうえお暗号」の総当たり攻撃プログラムを、**「正解を見つけたら音やメッセージで教えてくれる」**ようにパワーアップさせてみましょう!
今のままだと、81行も表示される中から人間が正解を探すのは大変ですよね。コンピュータに**「意味がわかる言葉が入っていたら教えて!」**という命令を付け足します。
このプログラムには、あらかじめ「よく使う言葉(辞書)」を覚えさせておきます。
def smart_crack_aiueo(secret_message):
kana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん"
# 【追加】知っている言葉のリスト(これが入っていたら正解!)
words_to_find = ["あいす", "ごはん", "すいか", "おかし", "あそぼ"]
print(f"暗号:{secret_message} を解読中...")
for shift in range(1, len(kana)):
result = ""
for char in secret_message:
if char in kana:
current_index = kana.find(char)
new_index = (current_index - shift) % len(kana)
result += kana[new_index]
else:
result += char
# 【追加】もし「知っている言葉」が解読結果に含まれていたら
for word in words_to_find:
if word in result:
print("✨ お宝メッセージを発見しました! ✨")
print(f"【正解】ずらし数 {shift}: {result}")
return # 見つけたらそこで終了!
print("残念!知っている言葉は見つかりませんでした。")
# 実験!「えおた」を解かせてみる
smart_crack_aiueo("えおた")実行すると
暗号:えおた を解読中...
✨ お宝メッセージを発見しました! ✨
【正解】ずらし数 3: あいすポイントは、新しく追加した words_to_find と if word in result です。
words_to_find: コンピュータにとっての「単語テスト」の準備です。
if word in result: 解読した結果の中に、知っている言葉が混ざっていないか一文字ずつチェックしています。
これを使うと、人間がじーっと画面を見なくても、コンピュータが**「これだ!」**と自動で見つけてくれるようになります。
4. 大切なこと
大切なことが2つあります。
単純な暗号はすぐバレる: 「1つずつ全部試す」という力技は、コンピュータにとって超簡単。だからシーザー暗号は今の時代、秘密を守るのには向いていません。
「鍵(かぎ)」の組み合わせが大事: 今のインターネットで使われている本物の暗号は、この「ずらし数」の組み合わせが何兆(ちょう)の何兆倍もあって、世界中のコンピュータを全部集めて何年もかけても「全部試す」ことができないようになっています。
