DES暗号を実装する(1) ~サブ鍵生成アルゴリズム編~
共通鍵暗号方式の代表的な暗号方式である「DES暗号」を実装してみたいと思います.
今回の記事では, DESで使用する「サブ鍵」の生成アルゴリズムを実装していきます.
使用言語
Python 3系
DES暗号とは
DES暗号は, 「ブロック暗号」の一種です. 1977年ごろに開発され, 米国政府の標準暗号となりました. 1984年にはANSI(米国規格協会)によって, 民間標準規格となりました.
DES暗号については, 過去の記事で詳しく説明をしていますので, こちらを参照してください.
tomonori4565.hatenablog.com
サブ鍵の生成方法
DESでは秘密鍵(共通鍵)keyを入力として, 16個の「サブ鍵」というものを生成します. ここでサブ鍵の生成方法を見ていきましょう.
まずkeyが入力されたら, PC1という縮小転置を実行します. PC1によって64bitのkeyは56bitに縮小されます. PC1は以下の転置表によって実行されます.
数式で表すと以下のようになります. に対して,
PC1が実行されたら, 左28bit, 右28bitに分割し, それぞれとします. はそれぞれLSという手続きによって, 左に1ビット巡回シフトさせます(シフトし終わったものをそれぞれとします).
そして, を連結させたものをPC2という縮小転置に適用させ, 48bitのサブ鍵を生成します. PC2 は以下の転置表によって実行されます.
これらの動作を16ラウンド続けていきます.
ただ一点注意しておくことがあります. 左に1bit巡回シフトを実行するのは,1,2,9,16ラウンド目のときです. それ以外は左に2bit巡回シフトさせる必要があります.
サブ鍵生成アルゴリズム
入力
key:秘密鍵(64bit)
出力
:サブ鍵(それぞれ48bit)
(1)64bitのkeyを56bitに変換する縮小転置PC1を適用.すなわち,
PC1()
(2) = 1とする.
(3) の間, 以下を繰り返す.
(3-1) ならば左に1bit巡回シフトする. それ以外なら左に2bit巡回シフトする.
(3-2) を連結させ, 縮小転置PC2を適用. すなわち,
PC2()
(3-3) i = i + 1とする.
(4) を出力.
プログラム
各メソッドについてはコメントを参照してください.
import math import random pc1_table = [57,49,41,33,25,17,9, 1,58,50,42,34,26,18, 10,2,59,51,43,35,27, 19,11,3,60,52,44,36, 63,55,47,39,31,23,15, 7,62,54,46,38,30,22, 14,6,61,53,45,37,29, 21,13,5,28,20,12,4] pc2_table = [14,17,11,24,1,5, 3,28,15,6,21,10, 23,19,12,4,26,8, 16,7,27,20,13,2, 41,52,31,37,47,55, 30,40,51,45,33,48, 44,49,39,56,34,53, 46,42,50,36,29,32] bit_list = [0,1] # # odd_parity() # 入力:リストl # 出力:0 or 1 # リストlにおけるハミング重みが奇数個ならば0, 偶数個ならば1 # def odd_parity(l): odd_count = 0 for l_bit in l: if l_bit == 1: odd_count += 1 if (odd_count % 2 == 0): return 1 else: return 0 # # key_generate() # 入力:なし # 出力:秘密鍵64bit # 秘密鍵を生成する. # def key_generate(): key = [] for i in range(8): l = random.choices(bit_list, k=7) key += l key.append(odd_parity(l)) return key # # PC1 # 入力:配列secret_key...64bit # 出力: C0, D0...それぞれ28bit # C0は左28bit, D0は右28bit # def pc1(secret_key): c0 = [] d0 = [] for i in range(56): if i <= 27: c0.append(secret_key[pc1_table[i]-1]) else: d0.append(secret_key[pc1_table[i]-1]) return c0, d0 # # PC2 # 入力:配列c_d_list(C0とD0を連結させたもの)...56bit # 出力: サブ鍵k 48bit # def pc2(c_d_list): k = [] for i in range(48): k.append(c_d_list[pc2_table[i]-1]) return k # # shift # 入力:リストl, 移動ビット数n # 出力:巡回シフト結果 (n=1のとき左に1bit巡回シフト) # def shift(l, n): return l[n:] + l[:n] # # enc_sub_key_generate() # 入力:秘密鍵key # 出力:sub_key_list # def enc_sub_key_generate(key): c = [] d = [] sub_key_list = [] c, d = pc1(key) for i in range(1, 1+16): if (i == 1) or (i == 2) or (i == 9) or (i == 16): c = shift(c, 1) d = shift(d, 1) else: c = shift(c, 2) d = shift(d, 2) sub_key_list.append(pc2(c + d)) for k in sub_key_list: print(k) return sub_key_list # # dec_sub_key_generate(key) # 入力:秘密鍵 # 出力:sub_key_list (encのときと逆順) # def dec_sub_key_generate(key): c = [] d = [] sub_key_list = [] c, d = pc1(key) for i in range(1, 1+16): if i == 1: c = c d = d elif (i == 2) or (i == 9) or (i == 16): c = shift(c, -1) d = shift(d, -1) else: c = shift(c, -2) d = shift(d, -2) sub_key_list.append(pc2(c + d)) for k in sub_key_list: print(k) return sub_key_list if __name__ == '__main__': sub_key_list = enc_sub_key_generate(key)