Skip to content

Instantly share code, notes, and snippets.

@NaoY-2501
Last active January 23, 2021 08:03
Show Gist options
  • Select an option

  • Save NaoY-2501/4534e6864a9e168e6928504ddc2c5287 to your computer and use it in GitHub Desktop.

Select an option

Save NaoY-2501/4534e6864a9e168e6928504ddc2c5287 to your computer and use it in GitHub Desktop.
『Pythonでいかにして暗号を破るか』1章 練習問題 回答
# 『Pythonでいかにして暗号を破るか』1章 練習問題
from typing import Any
PLAIN_ALPHABET = [chr(i) for i in range(65, 91)]
NUM_TO_ALPHABET = {idx: char for idx, char in enumerate(PLAIN_ALPHABET)}
ALPHABET_TO_NUM = {char: idx for idx, char in enumerate(PLAIN_ALPHABET)}
def encode_caeser(key: int, plain: str) -> str:
plain_nums = []
not_encodes = []
for idx, s in enumerate(plain):
s = s.upper()
if s in PLAIN_ALPHABET:
plain_nums.append(ALPHABET_TO_NUM[s])
else:
# アルファベット以外の文字(記号など)は平文でのインデックスと文字を保持しておく
not_encodes.append((idx, s))
encoded_nums = []
for num in plain_nums:
if num + key < 26:
encoded_nums.append(num + key)
else:
# 番号と鍵の和が26以上の場合、(番号+鍵)-26 する
encoded_nums.append((num + key) - 26)
encoded_sentence = [NUM_TO_ALPHABET[num] for num in encoded_nums]
for not_encoded in not_encodes:
# アルファベット以外の文字(記号など)を平文と同じインデックスに戻す
idx, s = not_encoded
encoded_sentence.insert(idx, s)
return ''.join(encoded_sentence)
def decode_caesar(key: int, cipher: str) -> str:
cipher_nums = []
not_decodes = []
for idx, s in enumerate(cipher):
s = s.upper()
if s in PLAIN_ALPHABET:
cipher_nums.append(ALPHABET_TO_NUM[s])
else:
# アルファベット以外の文字(記号など)は平文でのインデックスと文字を保持しておく
not_decodes.append((idx, s))
decoded_nums = []
for num in cipher_nums:
if num - key >= 0:
decoded_nums.append(num - key)
else:
# 番号と鍵の差がゼロ未満の場合、 (番号-鍵)+26 する
decoded_nums.append((num - key) + 26)
decoded_sentence = [NUM_TO_ALPHABET[num] for num in decoded_nums]
for not_decode in not_decodes:
# アルファベット以外の文字(記号など)を平文と同じインデックスに戻す
idx, s = not_decode
decoded_sentence.insert(idx, s)
return ''.join(decoded_sentence)
def guess_key(plain: str, cipher: str) -> Any:
plain_nums = []
for s in plain:
plain_nums.append(ALPHABET_TO_NUM[s.upper()])
cipher_nums = []
for s in cipher:
cipher_nums.append(ALPHABET_TO_NUM[s.upper()])
# 平文のアルファベットの番号と暗号文のアルファベットの番号の差分を求める(鍵の推測)
diffs = [p-c for p, c in zip(plain_nums, cipher_nums)]
keys = []
for diff, plain, cipher in zip(diffs, plain_nums, cipher_nums):
if diff < 0:
# 差分がゼロ未満の場合、(平文のアルファベットの番号+26) - 暗号文のアルファベットの番号 にする
keys.append((plain + 26) - cipher)
else:
keys.append(diff)
# 推測した鍵の配列がすべて同じ値であるか確認する
keys_validate = [keys[i] == keys[i+1] for i in range(0, len(keys)-1)]
if all(keys_validate):
return keys[0]
return None
# 1-1
plain = 'AMBIDEXTROUS: Able to pick with equal skill a right-hand pocket or a left.'
key = 4
cipher = encode_caeser(key, plain)
print(f'{"-"*5} 1-1 {"-"*5}')
print(plain)
print(cipher)
# 1-2
plain = 'GUILLOTINE: A machine which makes a Frenchman shrug his shoulders with good reasons.'
key = 17
cipher = encode_caeser(key, plain)
print(f'{"-"*5} 1-2 {"-"*5}')
print(plain)
print(cipher)
# 1-3
plain = 'IMPIETY: Your irreverence toward to my deity.'
key = 21
cipher = encode_caeser(key, plain)
print(f'{"-"*5} 1-3 {"-"*5}')
print(plain)
print(cipher)
# 2-1
cipher = 'ZXAI: P RDHIJBT HDBTIXBTH LDGC QN HRDIRWBTC XC PBTGXRP PCS PBTGXRPCH XC HRDIAPCS.'
key = 15
plain = decode_caesar(key, cipher)
print(f'{"-"*5} 2-1 {"-"*5}')
print(cipher)
print(plain)
# 2-2
cipher = 'MQTSWXSV: E VMZEP EWTMVERX XS TYFPMG LSRSVW.'
key = 4
plain = decode_caesar(key, cipher)
print(f'{"-"*5} 2-2 {"-"*5}')
print(cipher)
print(plain)
# 3-1
plain = 'This is silly example'
key = 0
cipher = encode_caeser(key, plain)
print(f'{"-"*5} 3-1 {"-"*5}')
print(plain)
print(cipher)
# 4-1
plain = 'ROSEBUD'
cipher = 'LIMYVOX'
key = guess_key(plain, cipher)
print(f'{"-"*5} 4-1 {"-"*5}')
print(f'Plain: {plain} Cipher: {cipher}')
print(f'key: {key}')
print(decode_caesar(key, plain))
print(encode_caeser(key, cipher))
# 4-2
plain = 'YAMAMOTO'
cipher = 'PRDRDFKF'
key = guess_key(plain, cipher)
print(f'{"-"*5} 4-2 {"-"*5}')
print(f'Plain: {plain} Cipher: {cipher}')
print(f'key: {key}')
print(decode_caesar(key, plain))
print(encode_caeser(key, cipher))
# 4-3
plain = 'ASTRONOMY'
cipher = 'HZAYVUVTF'
key = guess_key(plain, cipher)
print(f'{"-"*5} 4-3 {"-"*5}')
print(f'Plain: {plain} Cipher: {cipher}')
print(f'key: {key}')
print(decode_caesar(key, plain))
print(encode_caeser(key, cipher))
# 5-1
cipher = 'UMMSVMAA: Cvkwuuwv xibqmvkm qv xtivvqvo i zmdmvom bpib qa ewzbp epqtm.'
key = 8
plain = decode_caesar(key, cipher)
print(f'{"-"*5} 5-1 (correct) {"-"*5}')
print(cipher)
print(plain)
key = 9
plain = decode_caesar(key, cipher)
print(f'{"-"*5} 5-1 (incorrect) {"-"*5}')
print(cipher)
print(plain)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment