[ 詳解 DES暗号化アルゴリズム ] 動作確認は基本的には Linux + gcc で行っていますが des.c に関しては Windows + Borland C++ Compiler でも動作確認済みです。 排他的論理和(ExOR):排他的論理和とはふたつの値が一致したときに 0 、一 致しないときに 1 になる論理演算です。例えば a=1,b=1 とすると a と b の排 他的論理和は 0 になります。何故なら a と b の値が一致しているからです。 逆に a=1,b=0 などのように一致していない場合は 1 になります。 転置:ある規則にしたがってbit列を置き換えること。例えば "ABCD" という 文字列を "3412" という規則にしたがって転置すると "CDAB" となります。 "3412"はそれぞれ3番目の文字、4番目の文字、1番目の文字、二番目の文字と いう言葉に置き換えてもかまわないと思います。 暗号化処理 >> 暗号化処理のおおまかな流れ << 0x01. 64ビットの平文を用意します。 0x02. 初期転置(IP)を行います。 0x03. 32ビットずつに分割します。それぞれL(32), R(32)とする。 0x04. R(32)のデータを保存します。保存した配列を仮にDMY(32)とします。 0x05. R(32)に拡大型転置(E)を行います。48ビットになります。 0x06. 拡大型転置(E)を行ったR(48)と内部鍵との排他的論理和をとります。 0x07. そのデータ(48)に Sボックス処理 を行います。32ビットになります。 0x08. さらに転置(P)を行います。 0x09. そのデータ(32)とL(32)との排他的論理和をとります。 0x0a. そのデータをR(32)にコピーします。 0x0b. 以前R(32)のデータを保存していたDMY(32)をL(32)にコピーします。 0x0c. 0x04 〜 0x0b までを16回繰り返します。 0x0d. L(32)とR(32)を入れ換えます。そしてL(32)とR(32)を合体させます。 0x0e. 最終転置(FP)を行います。 0x0f. 暗号化終了。 では具体例をだして詳細な説明を行っていきます。 >> [ 0x01 ] 64ビットの平文を用意します。 "TestTest" という文字列を用意します。二進数に変換します。 01010100 01100101 01110011 01110100 01010100 01100101 01110011 01110100 char data[] = { 0,1,0,1,0,1,0,0, 0,1,1,0,0,1,0,1, 0,1,1,1,0,0,1,1, 0,1,1,1,0,1,0,0, 0,1,0,1,0,1,0,0, 0,1,1,0,0,1,0,1, 0,1,1,1,0,0,1,1, 0,1,1,1,0,1,0,0, }; >> [ 0x02 ] 初期転置(IP)を行います。 /* 初期転置 */ char IP[] = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, }; data[64]をこの規則に従って転置します。 data(32) = 11111111 11011101 10111011 01100110 00000000 11101110 00000000 01000100 >> [ 0x03 ] 32ビットずつに分割します。それぞれL(32), R(32)とする。 L(32) = 11111111 11011101 10111011 01100110 R(32) = 00000000 11101110 00000000 01000100 >> [ 0x04 ] R(32)のデータを保存します。保存した配列を仮にDMY(32)とします。 R(32) = 00000000 11101110 00000000 01000100 DMY(32) = 00000000 11101110 00000000 01000100 >> [ 0x05 ] R(32)に拡大型転置(E)を行います。48ビットになります。 /* 拡大型転置 */ char e2[] = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1, }; R(48) = 00000000 00010111 01011100 00000000 00000010 00001000 >> [ 0x06 ] 拡大型転置(E)を行ったR(48)と内部鍵との排他的論理和をとります。 R(48) = 00000000 00010111 01011100 00000000 00000010 00001000 内部鍵(KS[0]) = 11011010 01110101 01000111 01010101 01111001 11001001 --------------------------------------------------------------------- 11011010 01100010 00011011 01010101 01111011 11000001 ※内部鍵生成については後述。 >> [ 0x07 ] そのデータ(48)に Sボックス処理 を行います。32ビットになります。 /* S BOX */ char S[8][64] = { { 14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7, 0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8, 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0, 15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13, }, { 15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10, 3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5, 0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15, 13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9, }, { 10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1, 13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7, 1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12, }, { 7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15, 13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9, 10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4, 3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14, }, { 2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9, 14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6, 4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14, 11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3, }, { 12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11, 10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8, 9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6, 4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13, }, { 4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1, 13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6, 1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2, 6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12, }, { 13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7, 1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2, 7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8, 2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11, }, }; Sボックス処理の説明をします。まず上記の処理であたえられた。 11011010 01100010 00011011 01010101 01111011 11000001 というデータを 6ビット ずつ 8つ に分割します。 110110 100110 001000 011011 010101 010111 101111 000001 例えば 最初の110110を例にとると まず 1ビット目と 6ビット目を文字列的に合わせます。 110110 なので最初と最後を文字列的に合わせると 10 となります。 ~ ~ 次に 10 は十進数で 2 です。つまり 2 行目。(ちなみに行列ともに 0 から始まります) >>S[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -+----------------------------------------------------------- 0| { 14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7, 1| 0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8, 2|ココ→ 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0, 3| 15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13, }, 矢印の指してる行を見ます。 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0, 110110 のまんなかの4ビットは 1011 なので 十進数で 11 です。 ~~~~ ココ ↓ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ------------------------------------------------------- 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3, 10, 5, 0, ずばり 7 です。7 は二進数で 0111 ですので これが出力されることになりま す。6ビットが4ビットになっているのでこれでデータは 48ビットから 32ビッ トに縮小されることになります。 もちろん 8つ に分割したのでこれを8回やります。そのための S[8]です。 最終的に 0111 1011 0110 1010 1111 1110 0111 0001 という出力になります。 >> [ 0x08 ] さらに転置(P)を行います。 /* P 転置 */ char P[] = { 16, 7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10, 2, 8,24,14,32,27, 3, 9, 19,13,30, 6,22,11, 4,25, }; 01110011 01111101 11001110 11001110 >> [ 0x09 ] そのデータ(32)とL(32)との排他的論理和をとります。 L(32) = 11111111 11011101 10111011 01100110 01110011 01111101 11001110 11001110 ------------------------------------------- 10001100 10100000 01110101 10101000 >> [ 0x0a ] そのデータをR(32)にコピーします。 R(32) = 10001100 10100000 01110101 10101000 >> [ 0x0b ] 以前R(32)のデータを保存していたDMY(32)をL(32)にコピーします。 DMY(32) = 00000000 11101110 00000000 01000100 L(32) = 00000000 11101110 00000000 01000100 >> [ 0x0c ] 0x04 〜 0x0b までを16回繰り返します。 1 L = 00000000 11101110 00000000 01000100 R = 10001100 10100000 01110101 10101000 2 L = 10001100 10100000 01110101 10101000 R = 11100001 00101000 01001111 10001101 3 L = 11100001 00101000 01001111 10001101 R = 11100101 10110000 10101101 11011000 4 L = 11100101 10110000 10101101 11011000 R = 11000010 01110111 01110011 00000000 5 L = 11000010 01110111 01110011 00000000 R = 01010001 00011110 11111110 01001010 6 L = 01010001 00011110 11111110 01001010 R = 01000101 01110010 01110111 01001001 7 L = 01000101 01110010 01110111 01001001 R = 11100111 10011101 01011011 11111100 8 L = 11100111 10011101 01011011 11111100 R = 00000100 00110101 11001110 01110100 9 L = 00000100 00110101 11001110 01110100 R = 10101001 00011101 10101010 10001101 10 L = 10101001 00011101 10101010 10001101 R = 00010111 11001100 00010010 00010100 11 L = 00010111 11001100 00010010 00010100 R = 01110111 01011110 10100001 01100101 12 L = 01110111 01011110 10100001 01100101 R = 01110101 10000110 10110000 00000100 13 L = 01110101 10000110 10110000 00000100 R = 10110100 10100001 10011011 10011110 14 L = 10110100 10100001 10011011 10011110 R = 00000101 00101100 01101100 00010001 15 L = 00000101 00101100 01101100 00010001 R = 01111110 10111000 00101111 10111111 16 L = 01111110 10111000 00101111 10111111 R = 00000110 00000000 00100101 00101011 >> [ 0x0d ] L(32)とR(32)を入れ換えます。そしてL(32)とR(32)を合体させます。 R = 01111110 10111000 00101111 10111111 L = 00000110 00000000 00100101 00101011 (L,R) = 00000110 00000000 00100101 00101011 01111110 10111000 00101111 10111111 >> [ 0x0e ] 最終転置(FP)を行います。 /* 最終転置 */ char FP[] = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25, }; 00001111 11001011 11001110 10101011 10100010 10101111 10000000 00100010 >> [ 0x0f ] 暗号化終了。 平文 01010100 01100101 01110011 01110100 01010100 01100101 01110011 01110100 暗号文 00001111 11001011 11001110 10101011 10100010 10101111 10000000 00100010 内部鍵生成 0x01. まずは64ビットの鍵(共通鍵)を貰います。 0x02. そのデータを縮約型転置(PC1)にかけます。56ビットになります。 0x03. そして28ビットずつに分割します。それぞれ C(28), D(28) とする。 0x04. C(28), D(28) それぞれに循環シフトを行います。 0x05. C(28)とD(28)を合体させます。再び56ビットです。 0x06. これに縮約型転置(PC2)を行います。 48ビットになります。 0x07. 0x04 〜 0x06 までを16回繰り返します。内部鍵生成完了! 0x06処理後の48ビットのデータが内部鍵として暗号化/復号化に使われます。し かし内部鍵(48ビットのデータ)は16個必要ですので、この4〜6までの処理を16 回繰り返します。 >> [ 0x01 ] まずは64ビットの鍵(共通鍵)を貰います。 たとえば暗号文をやりとりする双方でこのような共通鍵をきめる。 これはやりとりする人以外には誰にも教えられない。 00010011 11001011 01110011 10111110 10100001 11000001 11101101 01011011 >> [ 0x02 ] そのデータを縮約型転置(PC1)にかけます。56ビットになります。 /* 縮約型転置 1 */ char PC1_C[] = { 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 }; char PC1_D[] = { 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 }; プログラムの仕様上、すでに転置の配列を2つに分けているが出力結果に違い はない。 01111010 11100110 01011100 10001000 11110100 10001100 10101101 >> [ 0x03 ] そして28ビットずつに分割します。それぞれ C(28), D(28) とする。 01111010 11100110 01011100 1000 10001111 01001000 11001010 1101 C = 01111010 11100110 01011100 1000 D = 10001111 01001000 11001010 1101 >> [ 0x04 ] C(28), D(28) それぞれに循環シフトを行います。 /* 循環シフト */ char shift[] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 }; 循環シフトとは要するにシフトを循環させるということだ(笑) C(28)を例にとると、 01111010 11100110 01011100 1000 を 1 だけ循環シフトさせるということは、最初の 0 を最後に持っていくという ことだ。 01111010 11100110 01011100 1000 → 11110101 11001100 10111001 0000 | ^ | | +------------------------------+ shift配列に入っている値はどれだけ循環シフトさせるのか?という値だ。 ちょうど16個入っているので16回の内部鍵生成処理の一回分ずつということに なる。最初は 1 なので C(28), D(28)をそれぞれ1回だけ循環シフトさせる。 次も 1 、その次は 2、なので 2 だけ循環シフトさせることになる。 C = 11110101 11001100 10111001 0000 D = 00011110 10010001 10010101 1011 >> [ 0x05 ] C(28)とD(28)を合体させます。再び56ビットです。 C = 11110101 11001100 10111001 0000 D = 00011110 10010001 10010101 1011 (C,D) = 11110101 11001100 10111001 00000001 11101001 00011001 01011011 >> [ 0x06 ] これに縮約型転置(PC2)を行います。 48ビットになります。 /* 縮約型転置 2 */ char PC2_C[] = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, }; char PC2_D[] = { 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32, }; これもプログラムの仕様上、転置の配列を2つに分けているが出力結果に違い はない。 内部鍵(KS[0]) = 11011010 01110101 01000111 01010101 01111001 11001001 >> [ 0x07 ] 0x04 〜 0x06 までを16回繰り返します。内部鍵生成完了! 内部鍵(KS[0]) = 11011010 01110101 01000111 01010101 01111001 11001001 内部鍵(KS[1]) = 00001111 00001110 01110111 01101100 10101110 10000101 内部鍵(KS[2]) = 11101111 01110000 10111000 11111010 01000100 11011011 内部鍵(KS[3]) = 10011110 10000111 11101000 00001111 11010011 00001011 内部鍵(KS[4]) = 11011010 01011010 00011011 10010110 01110101 01100000 内部鍵(KS[5]) = 00101101 10111011 01001100 11101000 10001011 01100100 内部鍵(KS[6]) = 00000010 01111100 11001111 11010000 11101110 10011010 内部鍵(KS[7]) = 01111001 01101101 01110000 01111101 00010110 00011001 内部鍵(KS[8]) = 01010111 11011000 00111100 10101010 10010110 10110100 内部鍵(KS[9]) = 10001110 10100001 11100110 01011001 01001111 10100111 内部鍵(KS[10]) = 10111010 01001110 00101111 00011110 01001000 10011001 内部鍵(KS[11]) = 11101001 00110011 00101000 11000011 01110001 01010101 内部鍵(KS[12]) = 10000000 10011110 11111101 10100011 10100011 10101000 内部鍵(KS[13]) = 11010101 01111010 01010010 11110000 00011111 00000111 内部鍵(KS[14]) = 00100110 11111111 11100000 01011110 00000010 10111110 内部鍵(KS[15]) = 10100110 10110001 00010101 10000000 11100101 11100110 復号化について 復号化は暗号化の逆をたどるのではない。平文と同じデータに復元できればい いのだ。これはどうするのかというと、実はとても簡単。全く同じアルゴリズ ムで内部鍵を逆から渡していけばいいのだ。 >> [ 0x06 ] 拡大型転置(E)を行ったR(48)と内部鍵との排他的論理和をとります。 R(48) = 00000000 00010111 01011100 00000000 00000010 00001000 内部鍵(KS[0]) = 11011010 01110101 01000111 01010101 01111001 11001001 --------------------------------------------------------------------- 11011010 01100010 00011011 01010101 01111011 11000001 この章の排他的論理和で暗号化の場合、内部鍵(KS[0])が最初に利用されてい る。が、復号化の場合はこれを内部鍵(KS[15])から試せばいいだけである。 data配列の中に暗号文をいれて内部鍵を逆から試すだけで平文にもどってしま う。DESはなんとも不思議なアルゴリズムであるのだ。 では最後に私が使用したプログラムを載せる。 des.c ------------------------------------------------------------------------------ #include #include "des.h" #define DEBUG /*--------------------------------------------- data配列の中に暗号文をいれるか平文をいれるか 平文ならコメントアウト!! ---------------------------------------------*/ //#define CRYPT /*--------------------------------------------- data配列の中を暗号化するのか?復号化するのか? 1:暗号化、0:復号化 基本的に CRYPT が define されてるなら 0 コメントアウトなら 1 ---------------------------------------------*/ int crypt = 1; void debug(char *data, unsigned short size, char *str) { #ifdef DEBUG int i; printf("%s =", str); for(i=0; i < size; i++){ if(i % 8 == 0) printf(" "); printf("%d", data[i]); } printf("\n"); #endif } int main(void) { char key[] = { 0,0,0,1,0,0,1,1, 1,1,0,0,1,0,1,1, 0,1,1,1,0,0,1,1, 1,0,1,1,1,1,1,0, 1,0,1,0,0,0,0,1, 1,1,0,0,0,0,0,1, 1,1,1,0,1,1,0,1, 0,1,0,1,1,0,1,1, }; #ifdef CRYPT /* 暗号文 */ char data[] = { 0,0,0,0,1,1,1,1, 1,1,0,0,1,0,1,1, 1,1,0,0,1,1,1,0, 1,0,1,0,1,0,1,1, 1,0,1,0,0,0,1,0, 1,0,1,0,1,1,1,1, 1,0,0,0,0,0,0,0, 0,0,1,0,0,0,1,0, }; #else /* 平文 "TestTest" */ char data[] = { 0,1,0,1,0,1,0,0, 0,1,1,0,0,1,0,1, 0,1,1,1,0,0,1,1, 0,1,1,1,0,1,0,0, 0,1,0,1,0,1,0,0, 0,1,1,0,0,1,0,1, 0,1,1,1,0,0,1,1, 0,1,1,1,0,1,0,0, }; #endif char block[64],dmy_block[64], KS[16][48], preS[48]; char C[28], D[28], L[32], R[32], DMY[32], f[32]; int i, j, k, t; /* if(argc < 3){ fprintf(stderr, "%s [string] [salt]\n", argv[0]); exit(1); } */ /* 内部鍵生成 */ for(i=0; i < 64; i++){ block[i] = key[i]; } /* 縮約型転置 PC1 */ for(i=0; i < 28; i++){ C[i] = block[PC1_C[i]-1]; D[i] = block[PC1_D[i]-1]; } for(i=0; i < 16; i++){ /* 循環シフト */ for(k=0; k < shift[i]; k++){ t = C[0]; for(j=0; j < 28-1; j++) C[j] = C[j+1]; C[27] = t; t = D[0]; for(j=0; j < 28-1; j++) D[j] = D[j+1]; D[27] = t; } /*縮約型転置 PC2 */ for(j=0; j < 24; j++){ KS[i][j] = C[PC2_C[j]-1]; KS[i][j+24] = D[PC2_D[j]-28-1]; } } /* 内部鍵生成完了! */ for(i=0; i < 64; i++) block[i] = data[i]; /* 暗号化開始 */ /* 初期転置 */ for(i=0; i < 32; i++) L[i] = block[IP[i]-1]; for(i=32; i < 64; i++) R[i-32] = block[IP[i]-1]; /* 16段の暗号化オペレーション */ for(i=0; i < 16; i++){ for(j=0; j < 32; j++) DMY[j] = R[j]; /* 内部鍵との排他的論理和 */ for(j=0; j < 48; j++){ if(crypt == 1) preS[j] = R[e2[j]-1] ^ KS[i][j]; else preS[j] = R[e2[j]-1] ^ KS[15-i][j]; } /* S BOX */ for(j=0; j < 8; j++){ t = 6*j; k = S[j][(((preS[t+0]*2)+ (preS[t+5]*1))*16)+ ((preS[t+1]*8)+ (preS[t+2]*4)+ (preS[t+3]*2)+ (preS[t+4]*1))]; t = 4*j; f[t+0] = (k>>3)&01; f[t+1] = (k>>2)&01; f[t+2] = (k>>1)&01; f[t+3] = (k>>0)&01; } /* 転置 P を行ったあとの 排他的論理和 */ for(j=0; j < 32; j++) R[j] = f[P[j]-1] ^ L[j]; for(j=0; j < 32; j++) L[j] = DMY[j]; } for(i=0; i < 32; i++){ t = L[i]; L[i] = R[i]; R[i] = t; } for(i=0; i < 32; i++) dmy_block[i] = L[i]; for(i=32; i < 64; i++) dmy_block[i] = R[i-32]; /* 最終転置 */ for(i=0; i < 64; i++) block[i] = dmy_block[FP[i]-1]; debug(block, 64, "block[64]"); return 0; } ------------------------------------------------------------------------------ includeしている des.h のソースコード des.h ------------------------------------------------------------------------------ /* 縮約型転置 1 */ char PC1_C[] = { 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 }; char PC1_D[] = { 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 }; /* 縮約型転置 2 */ char PC2_C[] = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, }; char PC2_D[] = { 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32, }; /* 循環シフト */ char shift[] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 }; /* P 転置 */ char P[] = { 16, 7,20,21,29,12,28,17, 1,15,23,26, 5,18,31,10, 2, 8,24,14,32,27, 3, 9, 19,13,30, 6,22,11, 4,25, }; /* 拡大型転置 */ char e2[] = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1, }; /* 初期転置 */ char IP[] = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7, }; /* 最終転置 */ char FP[] = { 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25, }; /* S BOX */ char S[8][64] = { { 14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7, 0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8, 4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0, 15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13, }, { 15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10, 3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5, 0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15, 13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9, }, { 10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1, 13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7, 1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12, }, { 7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15, 13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9, 10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4, 3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14, }, { 2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9, 14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6, 4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14, 11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3, }, { 12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11, 10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8, 9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6, 4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13, }, { 4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1, 13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6, 1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2, 6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12, }, { 13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7, 1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2, 7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8, 2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11, }, }; ------------------------------------------------------------------------------ End. written by kenji aiko 2003/10/07 Copyright (C) 2003 kenji aiko All Rights Reserved