/* mycipher.c * EVP 関数による暗号化・復号のサンプル */ #define DEBUG 1 /* cipher_alg = "camellia-128-cbc" */ #include "apr_general.h" #include "apr_buckets.h" #include #include "mybb.h" #include "mycipher.h" #define NOT_USE_FLUSH_FUNC NULL /* * mycipher.c の初期化 * */ void init_mycipher() { OpenSSL_add_all_ciphers(); } /* * ストリームを暗号化・復号する関数 * 返り値: * 暗号化したバイト数 * 失敗時は0 * メモ: * ・ENCDEC_BUFF_SIZE は鍵長の倍数になるように設定すること。 * ・終了時には、入力ストリームは空になり、出力ストリームには暗号化データが末尾に追加されることに注意。 */ int kencdec_from_bb_to_bb( char *cipher_alg /* IN:暗号アルゴリズム。OpenSSL の指定に基づく。暗号名+"-"+鍵長+"-"+暗号モード */ , unsigned char *keyData /* IN:暗号鍵のオクテット列 */ , int keyLen /* IN:暗号鍵の長さ(オクテット長) */ , unsigned char *ivData /* IN:初期化ベクトルのオクテット列 */ , int ivLen /* IN:初期化ベクトルの長さ(オクテット長) */ , int num_in /* IN:暗号対象データのサイズ */ , apr_bucket_brigade *bbIn /* IN:入力ストリーム */ , apr_bucket_brigade *bbOut/* OUT:出力ストリーム */ , int type /* IN:処理タイプ。1:暗号化、0:復号 */ ) { int result = 1; int remain = num_in; const EVP_CIPHER *evp_cipher = NULL; EVP_CIPHER_CTX ctx; unsigned char inBuf[ENCDEC_BUFF_SIZE]; unsigned char outBuf[ENCDEC_BUFF_SIZE]; apr_size_t inLen = 0; int outLen=0; int encLen = 0; apr_bucket_brigade *tmpbb = NULL; if (NULL == cipher_alg || NULL == bbIn || NULL == bbOut) { #ifdef DEBUG fprintf (stderr, "ERROR: kencdec_from_bb_to_bb: argument null. cipher_alg=[%d], bbIn=[%d], bbOut=[%d]\n", cipher_alg, bbIn, bbOut); #endif return 0; } /* 暗号アルゴリズムを取得 */ if (NULL == (evp_cipher = EVP_get_cipherbyname(cipher_alg))) { #ifdef DEBUG fprintf(stderr, "ERROR: kencdec_from_bb_to_bb: EVP_get_cipherbyname [%s]\n", cipher_alg); #endif return 0; } /* 暗号用コンテキストの初期化 */ EVP_CIPHER_CTX_init(&ctx); /* 暗号用コンテキストに鍵と初期化ベクトルを設定 */ if (!EVP_CipherInit(&ctx, evp_cipher, keyData, ivData, type/*ENCRYPT:1,DECRYPT:0*/)) { #ifdef DEBUG fprintf(stderr, "ERROR: kencdec_from_bb_to_bb: EVP_CipherInit\n"); #endif result = 0; goto _FINALLY_; } /* 暗号用コンテキストにパディングを設定 */ EVP_CIPHER_CTX_set_padding(&ctx, 1); /* 一時ストリームを用意 */ tmpbb = apr_brigade_create(bbIn->p, bbIn->bucket_alloc); /* 入力ストリームから ENCDEC_BUFF_SIZE バイトを切り出して一時ストリームに */ remain = num_in; while (remain > 0) { apr_size_t len = 0; apr_size_t read_size = (remain>ENCDEC_BUFF_SIZE)?ENCDEC_BUFF_SIZE:remain; len = move_bytes_from_bb (bbIn, read_size, tmpbb); outLen = 0; if (len <= 0) { break; } remain -= len; /* 一時ストリームからデータを取得 */ if (APR_SUCCESS == apr_brigade_flatten(tmpbb, inBuf, &len)) { /* データを暗号化 */ if (EVP_CipherUpdate(&ctx, outBuf, &outLen, inBuf, len)) { /* 暗号化データを出力ストリームに */ apr_brigade_write(bbOut, NOT_USE_FLUSH_FUNC, NULL, outBuf, outLen); } else { #ifdef DEBUG fprintf(stderr, "ERROR: kencdec_from_bb_to_bb: EVP_CipherUpdate\n"); #endif result = 0; goto _FINALLY_; } } encLen += outLen; /* 一時ストリームを空に */ apr_brigade_cleanup(tmpbb); } /* 最終ブロックを出力ストリームに */ outLen = 0; if (EVP_CipherFinal(&ctx, outBuf, &outLen)) { apr_brigade_write(bbOut, NOT_USE_FLUSH_FUNC, NULL, outBuf, outLen); encLen += outLen; } else { #ifdef DEBUG fprintf(stderr, "ERROR: kencdec_from_bb_to_bb: EVP_CipherFinal\n"); #endif result = 0; } _FINALLY_: /* 一時ストリームを解放 */ if(tmpbb) { apr_brigade_destroy(tmpbb); } /* 暗号用コンテクストを解放 */ EVP_CIPHER_CTX_cleanup(&ctx); if (result) return encLen; return 0; }