1.簡単な暗号化
1.1 概要
暗号の方式には、共通鍵による暗号方式(対称鍵暗号方式ともいう)と公開鍵による暗号方式(非対称鍵暗号方式ともいう)があります。ここでは、共通鍵による暗号化の方法を解説します。
共通鍵による暗号化では、暗号化するときに利用する鍵と、それを復号するときに利用する鍵に同じものを使います。ちなみに、公開鍵方式では、2つの違った鍵が使われます。
共通鍵による暗号化は、以下の関数を使います。
共通鍵による暗号化では、暗号化するときに利用する鍵と、それを復号するときに利用する鍵に同じものを使います。ちなみに、公開鍵方式では、2つの違った鍵が使われます。
共通鍵による暗号化は、以下の関数を使います。
- CryptAcquireContext
- CryptCreateHash
- CryptHashData
- CryptDeriveKey
- CryptEncrypt / CryptDecrypt
- CSPを準備する。(詳細は、後述)
- ハッシュ計算の準備をする。
- パスワードからハッシュ値を算出する。
- 計算されたハッシュ値を鍵(暗号鍵)に変換する。
- 目的のデータを暗号化(または、復号)する。
1.2 キーコンテナー を準備する
CryptoAPIで暗号化・復号の処理をするには、CSP(CryptoGraphy Service Provider)という仕組みを利用します。
CSPは、暗号と復号およびハッシュ値の計算を行うソフトウェア・エンジンです。既定では、いくつかのCSPがインストール されていますので処理に合ったのCSPを選択します。CSPは、1つだけの機能ではなく、いくつかの機能(タイプといいます)を持ち合わせています。そのため、CSPの選択とともにどの機能を使うかといった指定(タイプの指定)も必要になります。
なお、CSPは、サードベンダーによって追加されることがあります。その場合は、 追加されたCSPの仕様にあわせて利用しなければなりません。
CSPの選択方法や、機能については、1.12 CSPについて を参照してください。
暗号化の場合は、CSP内部に持っている暗号化の鍵(キー)を使って処理が行われます。鍵(の種)は、外部から与えることもできます。このCSP内部の鍵が格納される場所をキーコンテナーといいます。
暗号化のエンジンは、ブラックボックス的に考えなければなりません。CSPという暗号化エンジンに鍵の種と暗号化されるデータを渡して、結果だけを受け取る。これがCSPを介した暗号化の処理です。
キーコンテナーを介して。どのCSPのどの機能を利用するかを指定します。
以下にコードを記します。
CSPは、暗号と復号およびハッシュ値の計算を行うソフトウェア・エンジンです。既定では、いくつかのCSPがインストール されていますので処理に合ったのCSPを選択します。CSPは、1つだけの機能ではなく、いくつかの機能(タイプといいます)を持ち合わせています。そのため、CSPの選択とともにどの機能を使うかといった指定(タイプの指定)も必要になります。
なお、CSPは、サードベンダーによって追加されることがあります。その場合は、 追加されたCSPの仕様にあわせて利用しなければなりません。
CSPの選択方法や、機能については、1.12 CSPについて を参照してください。
暗号化の場合は、CSP内部に持っている暗号化の鍵(キー)を使って処理が行われます。鍵(の種)は、外部から与えることもできます。このCSP内部の鍵が格納される場所をキーコンテナーといいます。
暗号化のエンジンは、ブラックボックス的に考えなければなりません。CSPという暗号化エンジンに鍵の種と暗号化されるデータを渡して、結果だけを受け取る。これがCSPを介した暗号化の処理です。
キーコンテナーを介して。どのCSPのどの機能を利用するかを指定します。
以下にコードを記します。
#include <WinCrypt.h> // キーコンテナーの取得 BOOL bResult; HCRYPTPROV hProv; bResult = CryptAcquireContext( &hProv, // ハンドルが戻ります NULL, // 既定のユーザーのCSPを使います MS_ENHANCED_PROV, // バンドルされたMicrosoftのCSPを指定 PROV_RSA_FULL, // タイプを指定 0); // キーコンテナーがある場合の指定です if(!bResult) { if(!CryptAcquireContext(&hProv,NULL,MS_ENHANCED_PROV,PROV_RSA_FULL,0)) { fprintf(stderr, "CryptAcquireContext error\n"); return; } }
キーコンテナーがない場合は、新規に作成しなければなりません。はじめのCryptAcquireContext( )呼び出しでエラーとなった場合に新規に作成します。
エラーコード(NTE_BAD_KEYSET)を確認して正しく判断すべきですが、このままで十分に利用できます。正しい判断方法は、ヘルプ等で確認してください。
注意)
ここで紹介したキーコンテナーは、そのコンピューターのユーザーであれば誰でも利用できます。しかし、後に説明します方法で生成する鍵はセッション鍵といいワンタイム(一度だけ利用される)の鍵であり、このキーコンテナーに保存されません。その意味でセキュリティーの問題はありません。
注意)
ここで紹介したキーコンテナーは、そのコンピューターのユーザーであれば誰でも利用できます。しかし、後に説明します方法で生成する鍵はセッション鍵といいワンタイム(一度だけ利用される)の鍵であり、このキーコンテナーに保存されません。その意味でセキュリティーの問題はありません。
1.3 ハッシュ計算のインスタンスを生成する
CSPが内部に鍵を生成する場合は、ハッシュ値が使用されます。暗号化では、パスワードを利用する場合がよくあります。本ページでは、パスワードからハッシュ値を計算し、その結果を鍵の種として利用するようにします。
与えられたデータから計算されるハッシュ値は、常に同じ値になります。しかし、ハッシュ値からもとのデータを計算できません。これを利用して、復号の際にもパスワードからハッシュ値を計算し、その値を鍵の種として利用します。
暗号化の鍵は、必ず同じものが生成されなければなりません。たとえば、暗号化データを生成したコンピュータと、それを復号するコンピュータが違う場合は、それぞれで同じ鍵が生成されなければ、正しく復号できません。
以下で説明する方法は、同じ暗号化アルゴリズム、同じ鍵長などによって、暗号化と復号の環境が違っても復号できます。
まず、ハッシュ値を計算するインスタンスを生成します。ハッシュ値の計算は、CSPが処理しますので、そのハンドルを渡さなければなりません。
与えられたデータから計算されるハッシュ値は、常に同じ値になります。しかし、ハッシュ値からもとのデータを計算できません。これを利用して、復号の際にもパスワードからハッシュ値を計算し、その値を鍵の種として利用します。
暗号化の鍵は、必ず同じものが生成されなければなりません。たとえば、暗号化データを生成したコンピュータと、それを復号するコンピュータが違う場合は、それぞれで同じ鍵が生成されなければ、正しく復号できません。
以下で説明する方法は、同じ暗号化アルゴリズム、同じ鍵長などによって、暗号化と復号の環境が違っても復号できます。
まず、ハッシュ値を計算するインスタンスを生成します。ハッシュ値の計算は、CSPが処理しますので、そのハンドルを渡さなければなりません。
HCRYPTHASH hHash; bResult = CryptCreateHash( hProv, // ハッシュ値を計算するCSPのハンドル CALG_SHA, // ハッシュ値の計算アルゴリズム 0, // (後述します) 0, // 未使用、0(ゼロ)をセット &hHash); // 求めるインスタンスのハンドル if(!bResult) { fprintf(stderr, "CryptCreateHash error\n"); return; }
ハッシュ値の計算アルゴリズムは、以下の値が利用できます。
鍵つき(認証)ハッシュアルゴリズムは、ここでの暗号では使用しません。
第3引数には、鍵付きのハッシュを生成する際にキーのハンドルをセットしますが、ここでは使用しませんので、0(ゼロ)をセットします。
第4引数は、将来に予約された引数です。ここにも、0(ゼロ)をセットします。
第5引数にハッシュ計算のハンドルが戻されます。
CALG_HMAC 鍵つきハッシュアルゴリズム CALG_MAC メッセージ認証鍵つきハッシュアルゴリズム CALG_MD2 MD2ハッシュアルゴリズム CALG_MD4 MD4ハッシュアルゴリズム CALG_MD5 MD5ハッシュアルゴリズム CALG_SHA SHA-1ハッシュアルゴリズム CALG_SHA1 SHA-1ハッシュアルゴリズム(CALG_SHAと同じ) CALG_SSL3_SHAMD5 SSLクライアント認証ここでは、MD5もしくは、SHA-1を選択するべきでしょう。
鍵つき(認証)ハッシュアルゴリズムは、ここでの暗号では使用しません。
第3引数には、鍵付きのハッシュを生成する際にキーのハンドルをセットしますが、ここでは使用しませんので、0(ゼロ)をセットします。
第4引数は、将来に予約された引数です。ここにも、0(ゼロ)をセットします。
第5引数にハッシュ計算のハンドルが戻されます。
1.4 ハッシュ値を計算する
パスワードからハッシュ値を計算し、鍵の種を生成します。次のステップでこの値を使って暗号用の鍵を生成します。
ハッシュ値の計算は、以下のように行います。
ハッシュ値の計算は、以下のように行います。
#define PASSWORD "password" if(!CryptHashData( hHash, // ハッシュ計算インスタンスのハンドル (BYTE*)PASSWORD, // 実際のパスワードを指定 (DWORD)strlen(PASSWORD), // パスワードのバイト長 0)) // 後述します { fprintf(stderr, "CryptHashData error\n"); return 3; }
第2と第3引数には、実際のパスワードとそのバイト長を指定してください。
第4引数には、必要があればCRYPT_USERDATAフラグをセットできます。しかしながら、規定のCSPは、このフラグを無視します。このフラグがセットされると、CSPは(アプリケーションの介在なしに)直接ユーザーから値を入力するように求めます。
ちなみに、計算されたハッシュ値を取り出すには、CryptGetHashParam( )を使います。
第4引数には、必要があればCRYPT_USERDATAフラグをセットできます。しかしながら、規定のCSPは、このフラグを無視します。このフラグがセットされると、CSPは(アプリケーションの介在なしに)直接ユーザーから値を入力するように求めます。
ちなみに、計算されたハッシュ値を取り出すには、CryptGetHashParam( )を使います。