OpenSSLでAES暗号処理
概要
OpenSSLが提供しているC言語のAPIを使って共通鍵暗号方式のAES暗号を実行します。OpenSSLのAPIは抽象化されているので,共通鍵暗号処理なら引数を入れ替えるだけでDESなど他のアルゴリズムでも利用できます。
利用するAPI
暗号/復号を実行するためのAPIを使います。
- EVP_CipherInit_ex()
暗号処理を初期化します。 - EVP_CipherUpdate()
暗号処理を実行します。 - EVP_CipherFinal_ex()
暗号処理を終了させます。
基本的にこのAPIを順番にコールしていけばOKです。
平文の長さがブロック長と同じで,パディングをしない場合には EVP_CipherFinal_ex() を呼び出さなくても大丈夫なのですが,その場合,復号時に EVP_CipherFinal_ex()
を呼び出すとエラーになります。
サンプルプログラム
暗号/復号処理の関数
30行目のEVP_CipherInit_ex()関数で第二引数を「EVP_aes_128_cbc()」と指定しています。これを例えば「EVP_des_ede3_cbc()」と指定すると3キーの3DESでの処理になります。DESは古い暗号方式なので,使わないほうが良いですが。
/*
128bit AES CBCモードで暗号化を実行する関数
modeに1を設定すると暗号化,0を設定すると復号を実行する
*/
int Cipher_AES_CBC(unsigned char* inbuf, int inbufLen, unsigned char* outbuf, int* outbufLen, int mode)
{
int enclen = 0;
EVP_CIPHER_CTX* ctx;
unsigned char* ptr = outbuf;
/* 出力バッファ長が入力バッファ長よりも小さい場合は
* 暗号データを書き込めないためエラー
* EVP_MAX_BLOCK_LENGTHはパディング分
*/
if (*outbufLen < (inbufLen + EVP_MAX_BLOCK_LENGTH)) {
// Length不正
printf("Error: Invalid length.\n");
return 0;
}
/*
* 鍵とIVはダミー
* 通常はセキュアな領域から取得するので,関数の外部から与えられても良い
*/
unsigned char key[] = "ABCDEFGHIJKLMNOP";
unsigned char iv[] = "0123456789ABCDEF";
/* 128bit AES CBCモードで初期化する */
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, mode);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* 鍵とIVを設定する */
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, mode);
/* 暗号処理を実行する */
if (!EVP_CipherUpdate(ctx, outbuf, &enclen, inbuf, inbufLen)) {
// Error
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
EVP_CIPHER_CTX_free(ctx);
return 0;
}
/* バッファのポインタを進める */
ptr += enclen;
*outbufLen = enclen;
/* 残りの部分の暗号処理 */
if (!EVP_CipherFinal_ex(ctx, ptr, &enclen)) {
// Error
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
EVP_CIPHER_CTX_free(ctx);
return 0;
}
*outbufLen += enclen;
/* 解放処理 */
EVP_CIPHER_CTX_free(ctx);
return 1;
}
呼び出し側
入力する平文は「My Sample program, Encrypt Test.」です。暗号/復号を同じ関数で実行することができます。
#include "openssl/evp.h"
#include "openssl/aes.h"
#include "openssl/err.h"
#define MODE_ENCRYPTO 1 // 暗号処理
#define MODE_DECRYPTO 0 // 復号処理
int main()
{
unsigned char input[] = "My Sample program, Encrypt Test.";
unsigned char outbuf[256];
int outbufLen = 256;
unsigned char decbuf[256];
int decbufLen = 256;
if (!Cipher_AES_CBC(input, sizeof(input), outbuf, &outbufLen, MODE_ENCRYPTO)) {
printf("Error\n");
return 0;
}
if (!Cipher_AES_CBC(outbuf, outbufLen, decbuf, &decbufLen, MODE_DECRYPTO)) {
printf("Error\n");
return 0;
}
printf("Plain text : [%s]\n", decbuf);
return 1;
}
実行結果
当たり前ですが,inputで設定した文字列が復号後に表示されます。
Plain text : [My Sample program, Encrypt Test.]