オープンソース暗号化ライブラリLibgcryptによるAES暗号化

4371 ワード

Libgcryptは有名なオープンソース暗号化ソフトウェアGnuPGの下位ライブラリであり、非常に成熟した暗号化アルゴリズムライブラリであり、多くの対称および非対称暗号化アルゴリズムをサポートしている.今自分で勝手に輪を作って暗号化アルゴリズムプログラムを書くのは明らかに安全ではありません.OpenSSLにはHeartbleedの抜け穴がありますが、成熟した暗号化アルゴリズムライブラリを使うと未熟なものよりずっといいです.最近、基本的な機能を見てAESのdemoを書いてみましたが、途中でいろいろなことを学んだので、この手記を書きました.本文は私が書いたgcryptです.demoを例にとると,このdemoの解釈としてもよい.
1.着信キー
暗号化プログラムを書く第一歩は暗号化を開始することであり、第二歩は復号化ですか?君はあまりにも無邪気だ.最初のステップは、実際には転送鍵です.Libgcryptの対称暗号化には鍵Keyと初期化ベクトルInitialization Vectorの2つの重要なパラメータが必要である.後者は一般的に暗号化プログラムによって決定され、前者はユーザによって提供される必要がある.ユーザーが入力した明文を暗号化と復号化の鍵として直接使用すると、本当に安全ではありません.混乱したプロセスを経なければなりません.Libgcryptが提供する鍵を乱すための関数はgcry_ですkdf_derive.
gpg_error_t gcry_kdf_derive ( const void *passphrase, size_t passphraselen, int algo, int subalgo, const void *salt, size_t saltlen, unsigned long iterations, size_t keysize, void *keybuffer )

長い複雑に見えますが、パラメータは4つの部分しかありません.1.送信された鍵の明文と長さ.2.乱用アルゴリズム;3.塩列と塩列の長さ、反復回数などの乱れ用のパラメータ;4.生成された乱された鍵列.この関数を利用すると、良い鍵列が得られます.例を挙げると、私は明文鍵をbufの中に置いて、出力した鍵をbufの中に置いて、PBKDF 2とSHA 512アルゴリズムを選んでハッシュして、塩列はSALTの中に存在して、反復回数はITERです.
gpg_error_t err = gcry_kdf_derive(buf, strlen(buf), GCRY_KDF_PBKDF2, GCRY_MD_SHA512,SALT, sizeof(SALT), ITER, LEN_OF_RETKEY, outbuf);

基本的にすべてのLibgcryptの関数の戻り値はエラーハンドルであり,それを受信してエラーを判定すればよい.
2.暗号化ハンドルの初期化
鍵を取得した後、暗号化されたハンドルを設定する必要があります.暗号化アルゴリズムを選択し、暗号化のためのキャッシュ区間を開く必要があります.比較的簡単なブロックモードを用いて暗号化を行うので,まず,我々が選択した暗号化アルゴリズムが受け入れる鍵の長さとブロックの長さを知る必要がある.Libgcryptでは、暗号化アルゴリズムはマクロで識別され、指定したマクロを渡して、どの暗号化アルゴリズムを使用したいかを伝える必要があります.私のdemoプログラムはAES 256アルゴリズムを使っていますが、共通のためにCIPHER_を使っています.ALGOは私たちが使っている暗号化アルゴリズムの具体的な名前を指します.
まず、基本的なデータを得る必要があります.
size_t key_size = gcry_cipher_get_algo_keylen(CIPHER_ALGO);
size_t block_size = gcry_cipher_get_algo_blklen(CIPHER_ALGO);
size_t block_required=file_size/block_size;
if (file_size % block_size != 0){
    block_required++;
}

file_sizeは、暗号化されるデータファイルの合計サイズです.get_の利用algo_keylen()とget_algo_blklen()の2つの関数は,選択したアルゴリズムの鍵長とブロック長を得ることができ,その後,合計何個のブロックがあるかを計算することができる.これらの情報があれば、ハンドルを作ることができます.
cipher_err=gcry_cipher_open(&cipher_hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);
cipher_err=gcry_cipher_setkey(cipher_hd,key,key_size);
cipher_err=gcry_cipher_setiv(cipher_hd, iv, block_size);

最初の文は暗号化ハンドルを確立します.最初のパラメータcipher_hdは暗号化用のハンドルで、タイプはgcry_cipher_hd_t;2番目のパラメータは暗号化アルゴリズムで、3番目のパラメータと4番目のパラメータは暗号化のモードがブロックモードであることを指定し、詳細はlibgcryptのドキュメントを見ることができます.2番目の文は鍵を設定し、3番目の文は初期化ベクトルを設定します.ここで受信した初期化ベクトルは任意の文字列であり、十分な長さであればblock_を超える.sizeは普通は大丈夫です.もちろん、block_とsizeは同じ長さが一番いいです.最後に、読み込みキャッシュと出力キャッシュ領域を確立すればよい.
char *input_buf = (char*)malloc(file_size);
char *cipher_buffer = malloc(block_size*block_required);
memset(cipher_buffer, 0, block_size*block_required);

3.暗号化
こんなにたくさんの準備をして、やっと暗号化が始まりましたね.finがソースデータストリームでfoutが出力ストリームでファイルであると仮定すると、暗号化されたプログラムをこのように書くことができます.
fread(input_buf,1,file_size,fin);
//         
memcpy(cipher_buffer,input_buf,block_required*block_size);
//           
cipher_err=gcry_cipher_encrypt(cipher_hd,cipher_buffer,
//          
block_required*block_size,NULL,0);
fwrite(cipher_buffer,1,block_required*block_size,fout);
//          
gcry_cipher_close(cipher_hd);
fclose(fin);
fclose(fout);
//          

暗号化用の関数gcry_に注意cipher_encrypt():
gcry_error_t gcry_cipher_encrypt (gcry_cipher_hd_t h, unsigned char *out, size_t outsize, const unsigned char *in, size_t inlen)

受信するパラメータは、出力キャッシュとソースデータに分けられます.ただし、ソースデータのポインタがNULLの場合は、そのまま出力キャッシュのデータをソースデータとして暗号化して戻します.暗号化はこれで終わり、すぐに終了します.準備が頭を占めているが、本当の最も核心的な仕事は実はこれだけだ.
4.復号
対称暗号化が終わったら自然に復号しなければならない.そうしないと意味がない.復号化の初期化作業と暗号化はほぼ一致し,同じ鍵と初期化ベクトルで復号化できる.gcry_を使えばcipher_decrypt()は暗号化用の関数の代わりにすればよい.ここでは簡単に処理しましたが、最後にすべて0であれば、末端を切り取ります.実はこのようにするのは問題があって、1つの魔数の標識をプラスして終わるべきで、でもdemo、怠けましょう.純粋なテキストファイルを暗号化する場合もこの問題はありません.
fread(decry_buf,1,file_size,fin);
cipher_err=gcry_cipher_decrypt(cipher_hd,decry_buf,file_size,NULL,0);
while (decry_buf[file_size-1]==0){
    file_size--;
}
fwrite(decry_buf,1,file_size,fout);
gcry_cipher_close(cipher_hd);
fclose(fin);
fclose(fout);

5.まとめ
AES対称暗号化を利用して最も基本的な安全なデータ交換システムを構築することができる.これまでAES 256アルゴリズムには有効な解読手段がなく,安全といえる.このdemoは粗末で、多くの問題がありますが、demoとしては十分です.車輪を作るのではなく、成熟した倉庫を使うのは、優秀なエンジニアの基本的な素養だろう.最後に皆さんに楽しんで欲しい(*^^)v