排他的論理和はここで説明したとおり,繰り上がりのない足し算です.共通鍵暗号方式によるシンプルな暗号化・復号の処理は,この排他的論理和によって実現可能です.実際上,AES などの暗号化アルゴリズムの中でも排他的論理和が使用されています.
例として「L」という平文を共通鍵「m」を使って排他的論理和によって暗号化することを考えます.上の ASCII コード表を参照すると,「L」の文字コードは「0100 1100」で「m」の文字コードは「0110 1101」です.次の図ように「0100 1100」と「0110 1101」の排他的論理和を計算すると「0010 0001」になり,このビットの並びは ASCII コード表から「!」であることがわかります.つまり,平文「L」を共通鍵「m」によって暗号化した結果が「!」であることを意味しています.
復号の処理も暗号化の処理と全く同じです.暗号文「!」の文字コード「0010 0001」と共通鍵「0110 1101」の排他的論理和を計算すると,次の図のように「0100 1100」,つまり「L」になります.よって「!」を共通解「m」によって復号した結果,平文「L」を得ることができました.
ここでは,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進数の bp
,bk
ではなく,10進数の dp
と dk
を使って計算していることに注意してください.得られた暗号文「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'
次は,文字列を暗号化してみましょう.例えば平文「KPC」を共通鍵「t」(0111 0100) を用いて暗号化します.このとき,平文が 3 バイトで,共通鍵が 1 バイトであることから,1 バイトごとに処理をしていくことを考えます.次のコードで「KPC」を暗号化した結果は「?$7」となりました.ただし,暗号化した結果が「!」(0x21) から「~」(0x7E) の範囲以外になると文字として正しく表示できないことに注意してください.次のコードでは暗号文を16進数でも表示しています.
plaintext = 'KPC' # 平文を設定
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)
?$7 0x3f0x240x37
上と全く同じコードを使って暗号文「?$7」を復号すると,平文「KPC」を得ることができます.ただし,1行目以外一切変更していないので,変数名やコメントはおかしなことになっています.
plaintext = '?$7' # 平文を設定
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)
KPC 0x4b0x500x43
このページで説明したような排他的論理和による暗号化や復号処理がこれだけで用いられることはありませんが,やはり AES 等の共通鍵暗号方式の中ではこのような手続きが利用されています.