Python入門トップページ


目次

  1. プログラミング言語
  2. Anaconda - Jupyter Notebook / JupyterLab の環境設定
  3. Python の基礎
  4. リスト,タプル,辞書,集合
  5. 再び Jupyter Notebook の操作
  6. Python の制御構文
  7. 関数
  8. 便利な関数など
  9. リストの内包表記
  10. 多次元リスト
  11. クラス
  12. 演習問題
  13. 雑多な情報

Python の基礎

雑多な情報

排他的論理和で暗号文を作ってみる

排他的論理和はここで説明したとおり,繰り上がりのない足し算です.共通鍵暗号方式によるシンプルな暗号化・復号の処理は,この排他的論理和によって実現可能です.実際上,AES などの暗号化アルゴリズムの中でも排他的論理和が使用されています.

logical-xor
ascii

例として「L」という平文を共通鍵「m」を使って排他的論理和によって暗号化することを考えます.上の ASCII コード表を参照すると,「L」の文字コードは「0100 1100」で「m」の文字コードは「0110 1101」です.次の図ように「0100 1100」と「0110 1101」の排他的論理和を計算すると「0010 0001」になり,このビットの並びは ASCII コード表から「!」であることがわかります.つまり,平文「L」を共通鍵「m」によって暗号化した結果が「!」であることを意味しています.

xor-cipher-encryption

復号の処理も暗号化の処理と全く同じです.暗号文「!」の文字コード「0010 0001」と共通鍵「0110 1101」の排他的論理和を計算すると,次の図のように「0100 1100」,つまり「L」になります.よって「!」を共通解「m」によって復号した結果,平文「L」を得ることができました.

xor-cipher-decryption

目次に戻る

暗号化してみよう

ここでは,Python で排他的論理和による暗号化処理を記述してみよう.まず,平文「L」の文字コードを取得し,10進数,2進数,16進数で表示してみます.この結果,2進数では「0100 1100」であることがわかります.

p = 'L' # 平文
dp = ord(p)      # 平文の10進数
bp = bin(ord(p)) # 平文の2進数
hp = hex(ord(p)) # 平文の16進数
print(dp, bp, hp)
76 0b1001100 0x4c

同じ方法で共通鍵「m」の文字コードを取得すると,2進数では「0110 1101」であることがわかりました.

key = 'm' # 共通鍵
dk = ord(key)     # 共通鍵の10進数
bk = bin(ord(key)) # 共通鍵の2進数
hk = hex(ord(key)) # 共通鍵の16進数
print(dk, bk, hk)
109 0b1101101 0x6d

次に,平文と共通鍵の排他的論理によって暗号文を取得します.このとき,2進数の bpbk ではなく,10進数の dpdk を使って計算していることに注意してください.得られた暗号文「33」が10進数であることにも注意が必要です.

排他的論理和による暗号化(10進数)dc = dp ^ dk
print(dc)
33

10進数の暗号文「33」を2進数や16進数でも表示してみます.この結果,2進数では「0010 0001」であるので,ASCII コード表 を参照して暗号文は「!」であることがわかります.

print(bin(dc), hex(dc))
0b100001 0x21

実際に10進数の暗号文「33」を文字に変換します.確かに「!」となりました.

chr(dc)
'!'

目次に戻る

復号してみよう

復号の処理も暗号化と全く同じです.上で得られた暗号文「!」の文字コードを取得します.

c = '!'   # 暗号文
dc = ord(c)   # 暗号文の10進数
bc = bin(ord(c)) # 暗号文の2進数
hc = hex(ord(c)) # 暗号文の16進数
print(dc, bc, hc)
33 0b100001 0x21

もう一度,共通鍵「m」の文字コードを取得します.

key = 'm' # 共通鍵
dk = ord(key)     # 共通鍵の10進数
bk = bin(ord(key)) # 共通鍵の2進数
hk = hex(ord(key)) # 共通鍵の16進数
print(dk, bk, hk)
109 0b1101101 0x6d

暗号文「!」と共通鍵「m」の排他的論理和を計算することで復号します.得られる結果は10進数の「76」です.

dp = dc ^ dk
print(dp)
76

10進数「76」を文字に変換することで,平文「L」に復号できました.

chr(dp)
'L'

目次に戻る

文字列の暗号化と復号

次は,文字列を暗号化してみましょう.例えば平文「KGU」を共通鍵「m」(0111 0100) を用いて暗号化します.このとき,平文が 3 バイトで,共通鍵が 1 バイトであることから,1 バイトごとに処理をしていくことを考えます.次のコードで「KGU」を暗号化した結果は「?3!」となりました.ただし,暗号化した結果が「!」(0x21) から「~」(0x7E) の範囲以外になると文字として正しく表示できないことに注意してください.次のコードでは暗号文を16進数でも表示しています.

plaintext = 'KGU'  # 平文を設定
key = 0b01110100 # 共通鍵 't'
ciphertext = ''  # 暗号文を初期化
h_ciphertext = '' # 暗号文の16進数表記を初期化
for p in plaintext:
    dp = ord(p)   # 取り出した平文1文字を10進数の文字コードに変換
    dc = dp ^ key  # 平文と鍵の排他的論理和をとる:つまり暗号化する
    ciphertext += chr(dc) # 暗号文に追加する
    h_ciphertext += hex(dc) # 暗号文に16進数で追加する
print(ciphertext)
print(h_ciphertext)
?3!
0x3f0x330x21

上と全く同じコードを使って暗号文「?3!」を復号すると,平文「KGU」を得ることができます.ただし,1行目以外一切変更していないので,変数名やコメントはおかしなことになっています.

plaintext = '?3!'  # 平文を設定
key = 0b01110100 # 共通鍵 't'
ciphertext = ''  # 暗号文を初期化
h_ciphertext = '' # 暗号文の16進数表記を初期化
for p in plaintext:
    dp = ord(p)   # 平文を取り出し,10進数の文字コードに変換
    dc = dp ^ key  # 平文と鍵の排他的論理和をとる:つまり暗号化する
    ciphertext += chr(dc) # 暗号文に文字を追加する
    h_ciphertext += hex(dc) # 暗号文に文字を16進数で追加する
print(ciphertext)
print(h_ciphertext)
KGU
0x4b0x470x55

このページで説明したような排他的論理和による暗号化や復号処理がこれだけで用いられることはありませんが,やはり AES 等の共通鍵暗号方式の中ではこのような手続きが利用されています.

目次に戻る