OpenSSLで3DESしてみる
OpenSSLにはDES暗号化する関数が提供されている.これにはいろいろなバリエーションがあるようだが,良くわからないので,とりあえずメジャーそうな3DESを試してみる.
OpenSSLでDES暗号化するには,大まかに以下の手順となる.
- キースケジュールの生成
- DESはキーからサブキーを生成して,このサブキーを使用して暗号化する. で,ライブラリではこのサブキーのセット(16個)をキースケジュールと呼んでいて,これを生成する必要がある.
- 暗号化
- 生成したキースケジュールを使用して実際の暗号化処理を行う. 今回はDESを3重に行う3DESを試してみる. OpenSSLでは3DESの関数は暗号化と復号で共通になっていて,フラグで制御する.
- DES_cblock
- キー,暗号化対象データ,復号データ,暗号文データを格納するデータ型.
des.hでは
typedef unsigned char DES_cblock[8];
とされている. DESでは処理の際にデータを扱う単位が8バイトとなっており,これを保証する意味あいがあるのだと思う. 暗号化対象データが8バイトで割り切れない場合は,ヌルで埋めるなどの処理をしておく必要がある. - DES_key_schedule
- キースケジュールを格納するデータ型. 内容は(DES_cblock+α)が16個あり,これをサブキーとしてラウンドロビンで実際の暗号化/復号処理のキーとして使用する. +αが何なのかはよくわからない.
では,サンプル.
第一引数を暗号化対象データとし,第二〜第四引数を暗号化キーとして3DESで暗号化,復号し,その前後のデータを表示する.
第二〜第四引数が足りない場合は,ランダムでキーを生成する.
サンプルでは,まずキーを引数から受け取り,そこにチェックパリティをセットしている.
// キー情報作成
memset(key, 0, KEY_NUM * sizeof(DES_cblock));
for (i = 2; i < argc; i++)
{
sscanf(argv[i], "%8s", (char *)&key[i - 2]);
}
for (; i < KEY_NUM + 2; i++)
{
DES_random_key(&key[i - 2]);
}
for (i = 0; i < KEY_NUM; i++)
{
DES_set_odd_parity(&key[i]);
}
引数でたりない分のキーをランダム生成するために,OpenSSLにて提供されている関数を使用している.
void DES_random_key(DES_cblock *ret);引数には生成したランダムキーデータを格納する領域のポインタを渡す. キーデータの8バイトにはパリティビットが含まれており,それを計算してセットするのは面倒というか,よくわからないので,OpenSSLにて提供されている関数を使用してパリティをセットする.
void DES_set_odd_parity(DES_cblock *key);引数にはパリティをセットしたいキー情報領域のポインタを渡す. これにより,このサンプルでは引数のキーを使用するのではなく,パリティを考慮していないキーにパリティをセットしてこれを実際のキーとして扱う. 次に準備したキーデータからキースケジュールを生成する.
// キースケジュール作成
DES_key_schedule schedule[KEY_NUM];
for (i = 0; i < KEY_NUM; i++)
{
ret = DES_set_key_checked(&key[i], &schedule[i]);
if (ret != 0)
{
fprintf(stderr, "DES_key_set_checked 失敗 ");
if (ret == -1)
{
fprintf(stderr, "パリティ不正\n");
}
else if (ret == -2)
{
fprintf(stderr, "脆弱なキー\n");
}
else
{
fprintf(stderr, "不明なエラー\n");
}
exit(-1);
}
}
キースケジュールの作成もOpenSSL提供の関数を使用しており,キーに問題がなければうまく生成できる.
int
DES_set_key(const_DES_cblock *key,
DES_key_schedule *schedule);
int
DES_set_key_checked(const_DES_cblock *key,
DES_key_schedule *schedule);
void
DES_set_key_unchecked(const_DES_cblock *key,
DES_key_schedule *schedule);
いずれも第一引数にキー,第二引数に生成したキースケジュールを格納する領域のポインタを渡す.
DES_set_key_checkedは処理に先だってキーのパリティが正当か,キーが脆弱でないかをチェックする.
返り値が-1ならパリティ不正,-2ならキーが脆弱である.
DES_set_key_uncheckedはチェックなしでキースケジュールを生成する.
DES_set_keyはグローバル変数のDES_check_keyが0でなければ,DES_set_key_checkedと等価,0ならばDES_set_key_uncheckedと等価となる.
ただし,man desによるとグローバル変数に依存するこの関数よりも,前者二つを使用する方が推奨されるらしい.
暗号化と復号処理は,準備したキースケジュールで関数を呼び出すだけである.
// 暗号化 DES_ecb3_encrypt(&rawData, &cryptData, &schedule[0], &schedule[1], &schedule[2], DES_ENCRYPT); // 復号 DES_ecb3_encrypt(&cryptData, &decryptData, &schedule[0], &schedule[1], &schedule[2], DES_DECRYPT);OpenSSLでは暗号化,復号処理の関数がいろいろあってよくわからないが,今回は3DESにしてみた.
void
DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
DES_key_schedule *ks1, DES_key_schedule *ks2,
DES_key_schedule *ks3, int enc);
引数の意味は以下の通り.
- 第一引数
- 入力(暗号化の際は平文,復号の際は暗号文)
- 第二引数
- 出力(実際の意味は第一引数と逆)
- 第三〜第四引数
- キースケジュール 一つの暗号化鍵から生成したキースケジュールだと,普通のDESと同じで脆弱なので(3DESの意味がない)注意する.
- 第五引数
- 暗号化,復号の制御フラグである. DES_ENCRYPTが暗号化,DES_DECRYPTが復号.
コンパイルする際には,リンカオプションを設定する(※).
LDFLAGS=-lsslでは実行してみる.
$ ./my3des FIREPROJ 12341234 abcdefgh ABCDEFGH キー情報 KEY [31 32 32 34 31 32 32 34 ] KEY [61 62 62 64 64 67 67 68 ] KEY [40 43 43 45 45 46 46 49 ] 暗号化対象データ [46 49 52 45 50 52 4F 4A ] 暗号文 [FB A3 3C 0B 98 2E 0C 29 ] 復号データ [46 49 52 45 50 52 4F 4A ]
※ OpenSSLがインストールされていないなら,あらかじめインストールしておく.
apt-get install libssl-dev

