0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

鍵語による換字式暗号をPythonで

Posted at

公開鍵暗号は「公開錠」と言えばわかりやすいんじゃないという話を見て、暗号の鍵って公開鍵暗号のためにこしらえられた単語ではないけどと思ったんですが、
もしかして皆さん、鍵語(キーワード)を使って換字表を生成するタイプの暗号を経由せずに、公開鍵暗号に挑戦しているのかなと思ったので書きました。

換字式暗号とは

換字式暗号とは文字を規則的に入れ替える暗号です。

問題としては

  • 平文の言語的特徴が保存される(文字の出現頻度など)
  • 平文と暗号のサイズが一致する
    などがあります。

対策として

  • 無意味な字を混ぜる
  • 頻度の高い字は複数の変換先を用意する
  • 複数字からなる文字列を変換単位にする
  • 他の暗号と組み合わせる

などがあります。
しかし、その代わりに次のような利点を失うことになる場合があります

  • 組み立てが簡単である
  • 誤字・脱字があっても、暗号全文が読めなくなることはない

Python によるサンプルコード

鍵語によって換字表を生成する暗号です。英文の小文字アルファベットのみを暗号化・復号化する簡単な暗号です。
換字表は鍵語から重複を排除して、その後ろに残ったアルファベットを並べて作っています。

import unittest


def get_unique_alphabet(alphabets: str) -> str:
    """指定したアルファベット内のユニークな小文字のアルファベットを返す"""
    unique_alphabets = [char.lower() for char in alphabets if char.isalpha()]
    return "".join(sorted(set(unique_alphabets), key=unique_alphabets.index))


def create_alphabet_mapping(unique_alphabet: str) -> dict:
    """ユニークなアルファベットのマッピングを作成する"""
    symbols = "abcdefghijklmnopqrstuvwxyz"
    alphabet_mapping = dict(zip(unique_alphabet, symbols[: len(unique_alphabet)]))
    return alphabet_mapping


def cipher(plain_text: str, keyword: str) -> str:
    """換字式暗号化関数"""
    symbols = "abcdefghijklmnopqrstuvwxyz"
    unique_alphabet = get_unique_alphabet(keyword)
    substitute_table = unique_alphabet + "".join(
        char for char in symbols if char not in unique_alphabet
    )
    alpha_map = create_alphabet_mapping(substitute_table)
    cipher_text = "".join(
        alpha_map.get(char.lower(), char) for char in plain_text if char.isalpha()
    )
    return cipher_text


def decipher(cipher_text: str, keyword: str) -> str:
    """換字式復号化関数"""
    symbols = "abcdefghijklmnopqrstuvwxyz"
    unique_alphabet = get_unique_alphabet(keyword)
    substitute_table = unique_alphabet + "".join(
        char for char in symbols if char not in unique_alphabet
    )
    alpha_map = create_alphabet_mapping(substitute_table)
    reversed_dict = dict(zip(alpha_map.values(), alpha_map.keys()))
    deciphered_text = "".join(
        reversed_dict.get(char, char) for char in cipher_text.lower() if char.isalpha()
    )
    return deciphered_text


# テストケースクラス
class Test_fbrkhs_key_qiita(unittest.TestCase):
    """換字式暗号のテスト"""

    def test_cipher_decipher(self):
        """暗号化と復号化のテスト"""
        keyword = "Hello, World"
        plain_text = "It is said that Drakon himself, when asked why he had fixed the punishment of death for most offences, answered that he considered these lesser crimes to deserve it, and he had no greater punishment for more important ones."
        cipher_text = cipher(plain_text, keyword)
        decipher_text = decipher(cipher_text, keyword)
        expected_result = "".join(char for char in plain_text.lower() if char.isalpha())
        # 復号化したテキストと元のテキストを比較
        self.assertEqual(expected_result, decipher_text)


# プログラムを実行してテストを実行
if __name__ == "__main__":
    unittest.main()

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?