前のページ <<<

1.14 ブロック暗号化アルゴリズムによる簡単な暗号化

 ブロック暗号アルゴリズム AES(Advanced Encryption Standard)による暗号化の解説です。従来のCryptoAPIを使ったサンプルで説明します。

 Microsoftは、CryptoAPIに替わる次世代暗号化(Cryptography Next Genaration; CNG)APIをサポートしています。CNG APIの解説[http://www.trsustss.co.jp/cng/0000.html]こちらでもAESでのブロック暗号化の解説をしています、ご参照ください。

C#(.NET Framework)での暗号化の手順は、サンプルと共に8.C#による簡単な暗号化で説明しています。

1.14.1 概要

 ここでは、共通鍵によるAESブロック暗号化アルゴリズムを使った暗号化・復号の方法を解説します。ブロック暗号化は、被暗号化データをブロックサイズごとに切り返し暗号化します。なお、ストリーミング暗号化簡単な暗号化[http://www.trustss.co.jp/smnEncrypt010.html]を参照してください。

 AESブロック暗号化アルゴリズムによる暗号化は、以下の関数を使います。

  • CryptAcquireContext
  • CryptCreateHash
  • CryptHashData
  • CryptDeriveKey
  • CryptSetKeyParam
  • CryptEncrypt / CryptDecrypt
大まかな手順は、以下のとおりです。
  • CSPを準備する。
  • ハッシュ計算の準備をする。
  • パスワードからハッシュ値を算出する。
  • 計算されたハッシュ値を鍵(AES暗号鍵)に変換する。
  • 鍵および初期化ベクタを設定する。
  • 目的のデータを暗号化(復号)する。

1.14.2 キーコンテナー を準備する

 ストリーミング暗号化アルゴリズムと同様ですが、CSPAESブロック暗号化が使えるものを選択します。詳しくは、簡単な暗号化[http://www.trustss.co.jp/smnEncrypt010.html]を参照してください。
 ここでは、以下のCSPでAES暗号化アルゴリズムを使って説明します。
   "Microsoft AES Cryptographic Provider"
   Type: PROV_RSA_AES
   Name: MS_ENH_RSA_AES_PROV
#include <WinCrypt.h>

// キーコンテナーの取得
BOOL        bResult;
HCRYPTPROV  hProv;

bResult = CryptAcquireContext(
              &hProv,           // ハンドルが戻ります
              NULL,             // 既定のユーザーのCSPを使います
              MS_ENH_RSA_AES_PROV,  // バンドルされたMicrosoftのCSPを指定
              PROV_RSA_AES,     // タイプを指定
              0);               // キーコンテナーがある場合の指定です
if(!bResult)
{
    if(!CryptAcquireContext(&hProv,NULL,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,
                            CRYPT_NEWKEYSET))
    {
        printf("CryptAcquireContext error\n");
        return;
    }
}

1.14.3 ハッシュ計算のインスタンスを生成する

 暗号化の鍵は、ハッシュ値から生成します。ストリーミング暗号化とまったく同じ手順です。詳細は、簡単な暗号化[http://www.trustss.co.jp/smnEncrypt010.html]を参照してください。
HCRYPTHASH  hHash;

bResult = CryptCreateHash(
                hProv,     // ハッシュ値を計算するCSPのハンドル
                CALG_SHA,  // ハッシュ値の計算アルゴリズム
                0,         // (後述します)
                0,         //  未使用、0(ゼロ)をセット
                &hHash);   //  求めるインスタンスのハンドル
if(!bResult)
{
    printf("CryptCreateHash error\n");
    return;
}
ハッシュ値の計算アルゴリズムは、以下の値が利用できます。
   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クライアント認証
   CALG_SHA_256      256ビットSHAハッシュアルゴリズム
   CALG_SHA_384      384ビットSHAハッシュアルゴリズム
   CALG_SHA_512      512ビットSHAハッシュアルゴリズム
(ただし、CALG_SHA_256、CALG_SHA_384、CALG_SHA_512は
 Windows XP/200/NTでは利用できません。
ここでは、MD5もしくは、SHA-1を選択するべきでしょう。鍵を生成するためのハッシュ計算ですのでアルゴリズムの選択には神経質になる必要はないでしょう。

1.14.4 ハッシュ値を計算する

 ここもストリーミング暗号化とまったく同じ手順です。詳細は、簡単な暗号化[http://www.trustss.co.jp/smnEncrypt010.html]を参照してください。
#define PASSWORD  "password"

if(!CryptHashData(
            hHash,                   // ハッシュ計算インスタンスのハンドル
            (BYTE*)PASSWORD,         // 実際のパスワードを指定
            (DWORD)strlen(PASSWORD), // パスワードのバイト長
            0))
{
    printf("CryptHashData error\n");
    return;
}

1.14.5 AES鍵の生成

 AESの「鍵」を生成します。ここでは、256ビット長の鍵を使って説明します。

以下のようにします。
#define KEYLENGTH_256   256 * 0x10000        // 256-bit長

HCRYPTKEY   hKey;

if(!CryptDeriveKey(
            hProv,          // CSPのハンドル
            CALG_AES_256,   // 暗号化のアルゴリズム
            hHash,          // ハッシュ値のハンドル
            KEYLENGTH_256,  // 暗号化鍵のビット長とフラグ
            &hKey))         // 鍵のハンドル
{
    printf("CryptDeriveKey error\n");
    return;
}
第2引数には、AESブロック暗号のアルゴリズムを指定します。他のブロック暗号化のアルゴリズムは、以下のとおり用意されています。CSPそれぞれで利用できるアルゴリズムが違いますので注意してください。詳細は、1.12 CSPについて[http://www.TrustSS.co.jp/smnEasyEnc1C0.html]を参照してください。
   CALG_DES       DES暗号化アルゴリズム
   CALG_DESX      DESX暗号化アルゴリズム
   CALG_3DES      トリプルDES暗号化アルゴリズム
   CALG_3DES_112  112ビット2キーDES暗号化アルゴリズム
   CALG_AES       AES暗号化アルゴリズム
   CALG_AES_128   128ビットAES暗号化アルゴリズム
   CALG_AES_192   192ビットAES暗号化アルゴリズム
   CALG_AES_256   256ビットAES暗号化アルゴリズム
   CALS_RC2       RC2ブロック暗号化アルゴリズム
   CALG_RC5       RC5ブロック暗号化アルゴリズム
   CALG_SEAL      SEAL暗号化アルゴリズム
   CALG_SKIPJACK  Skipjackブロック暗号化アルゴリズム

1.14.6 パディングモードの指定

 ブロック暗号化の場合は、被暗号化データのサイズをブロックサイズごとに暗号化しますので、被暗号化データのサイズはブロックサイズの整数倍でなければなりません。ブロック暗号化のアプリケーションでは、暗号化の前に被暗号化データに対してこの処理をしますが、自動でデータのサイズを伸張させることができます。さらに、伸張したデータには規格(PKCS#5)に従ったデータでパディング(Padding)されます。ここでは、その処理をするパディングモードを指定します。
// ブロック暗号化のパディングを設定
DWORD      padding_mode=PKCS5_PADDING;

if(!CryptSetKeyParam(
                hKey,                 // 鍵のハンドル
                KP_PADDING,           // パディング
                (BYTE*)&padding_mode, // PKCS#5のパディングモード
                0))
{
    printf("CryptSetKeyParam error\n");
    return;
}
 鍵オブジェクトにパディングの指定をします。MicrosoftのCSPでは、PKCS5_PADDING以外はサポートされていません。

1.14.7 初期化ベクタ

 ブロック暗号では、初期化ベクタを指定できます。初期化ベクタを変えて暗号化すると、同じ鍵を使った場合でも暗号結果を得ます。すなわち、初期化ベクタは、暗号化の鍵を推測しにくくする効果があります。
 なお、初期化ベクタを指定しない場合は、値ゼロが使われます。
// 初期ベクタ
BYTE    iv[]={0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

if(!CryptSetKeyParam(
                hKey,   // 鍵のハンドル
                KP_IV,  // 初期化ベクタ指定
                iv,     // 初期化ベクタ値
                0))
{
    printf("CryptSetKeyParam error\n");
    return 1;
}
初期化ベクタのサイズは、暗号化アルゴリズムごとに決まっています。このサンプルの場合は、16バイトですので、上記のようにしています。なお、ivはブロックの暗号化ごとに変化します。暗号化後に鍵オブジェクトから関数CryptGetKeyParam( )を使って新しいivを取得できます。

1.14.8 暗号モードの指定

 暗号モードは、暗号を解読しにくくするように暗号化されたデータウィさらに変えるために使われます。例えば、暗号化されrデータが類似したパターンを含む場合、結果として生ずるデータのいくつかのパターンは暗号を解読する手がかりとなることがあります。暗号のモードはこの種類の攻撃に役立ちます。
 以下のモードを設定できます。
   ECB (Electronic CodeBook mode) 基本モード
        CBC (Cipher Block Chaining mode) 暗号文ブロック連鎖モード
        CFB (Cipher-FeedBack mode) 暗号文フィードバックモード
        OFB (Output-FeedBack mode) 出力フィードバックモード
        CTS (Cipher Text mode) テキストスティーリングモード
MicrosoftのCSPは、OFBモードをサポートしていませんので、ご注意ください。
この設定をしなかった場合は、CBCモードが利用されます。以下にコードを記します。
// Cipherモードを設定
DWORD   mode = CRYPT_MODE_CBC;
if(!CryptSetKeyParam(
                hKey,           // 鍵のハンドル
                KP_MODE,        // 暗号モード指定
                (BYTE*)&mode,   // 暗号モード
                0))
{
    tprintf("CryptSetKeyParam error\n");
    return;
}

1.14.9 復号用に鍵オブジェクトを複製する

 解説では、同じ鍵を使って簡単に復号するために、鍵オブジェクトを複製しておきます。ブロック暗号化では、ブロック暗号化ごとに初期化ベクタが変化するために、暗号化後の鍵オブジェクトを使って暗号化データを復号できません。そのために、鍵オブジェクトを利用前に複製しておきます。
 実際のアプリケーションでは、鍵オブジェクトを暗号化と同じ手順で生成します。
// 復号用にキーを複製
HCRYPTKEY  hdKey;
if(!CryptDuplicateKey(
                hKey,
                NULL,
                0,
                &hdKey))
{
    printf("CryptDuplicateKey error\n");
    return;
}
関数の第2、3引数は予約された引数ですので、上記のように指定してください。新しい鍵オブジェクトが生成されますので、利用後には関数CryptDestroyKey( )で削除しなければなりません。

1.14.10 暗号化

 暗号化します。ここでは、簡単のために暗号化に十分なバッファサイズを用意して実施しました。しかしながら、実際に利用する場合には、データが大きくて1度の関数呼び出しだけでは不足する場合もあります。その場合は、後述のCryptEncrypt( )関数の大3引数をfalseにして必要なだけ関数をコールします。そして最後の関数コールで第3引数をtrueにすれば暗号化できます。復号の場合も同じです。

以下に、暗号化のコードを記します。
// 暗号化 
#define BUF_LEN  100

BYTE    pbData[BUF_LEN]="This is a palin text.";
DWORD   dwDataLen=(DWORD)(strlen((char*)pbData)+1);

if(!CryptEncrypt(
            hKey,         // 鍵のハンドル
            0,            // 暗号化と同時にハッシュ化する場合に指定
            TRUE,         // 最後のデータを渡すときに真
            0,            // ゼロを指定
            pbData,       // 暗号化されるデータのポインター
            &dwDataLen,   // 暗号化データのバイト長データの格納ポインター
            (DWORD)BUF_LEN))  // データバッファーの大きさ
{
    printf("CryptEncrypt error\n");
    return;
}
第2引数には、暗号化されるデータを暗号化と同時にハッシュ値にする場合に設定します。電子署名のアプリケーションなどで利用されます。今回のようなアプリケーションでは、その必要がありませんので、0(ゼロ)をセットします。
第3引数は、大量のデータを分割して関数に渡す場合に利用します。例えば、2回に分けて渡す場合は、最初のデータを渡すときにFALSEを指定し、2つ目のデータを渡すときにTRUEを指定します。
第4引数は、特殊な暗号化を行う場合に指定します。ここでは、0(ゼロ)を指定します。
第5引数には、暗号化するデータのポインターが入ります。戻りデータの大きさがわからないとき、で解説しますが、NULLが設定されてもエラーになりませんのでご注意ください。
第6引数には、データの長さが入ります。
第7引数には、暗号化データが格納されるバッファーのバイト長を指定します。

暗号化データは、pbDataに格納され、そのバイト長は、dwDataLenに格納されます。

1.14.11 復号

 次は、暗号化したデータを復号します。
 復号の場合も、暗号化と同じ手順で鍵オブジェクトを生成します。ここでは、簡単のために先に複製した鍵オブジェクトを使って復号します。
if(!CryptDecrypt(
            hKey,         // 鍵のハンドル
            0,             // 復号と同時にハッシュ計算をする場合に指定
            TRUE,          // 最後のデータを渡すときに真、他は偽
            0,             // 特殊な服後をする場合にフラグをセットする
            pbData,        // [in]暗号化データ/[out]復号したデータ
            &dwDataLen))   // [in]暗号化データのバイト長
                    /[out]復号したデータのバイト長
{
    printf("CryptDecrypt error\n");
    return;
}
printf("データは、「%s」です。\n", pbData)
第2引数には、ハッシュ計算のインスタンスのハンドルを渡します。復号と同時にハッシュ値が計算されます。このハッシュ値をもとのハッシュ値と比較するような電子署名のアプリケーションで利用します。ここでは、その機能を利用しませんので0(ゼロ)を指定します。
第3引数は、大量のデータを渡す場合に利用します。データを分割して関数に渡す場合、残りのデータがある場合は、FALSEをセットし、残りのデータがなくなった最後のデータを渡すときにTRUEを渡します。
第4引数は、特殊な復号を行う場合にフラグをセットしますが、こんかいのアプリケーションでは使用しませんので、0(ゼロ)をセットします。
第5引数には、データのポインターを渡します。入力では、暗号化したデータが入ります。出力では、復号されたデータが入ります。戻りデータの大きさがわからないとき、で解説しますが、NULLが設定されてもエラーになりませんのでご注意ください。
第5引数には、データのバイト長をセットします。もし、復号されたデータが、暗号化されたデータと違う場合(ブロック暗号化の場合)は、この値が関数によって変更されますので第3引数のTRUEを渡した時に確認が必要です。

1.14.12 リソースの開放

 暗号化や復号の処理が終わりましたら、利用したリソースを開放します。
 鍵オブジェクトやハッシュ計算のインスタンスハンドルは、以下の方法で開放します。
if(!CryptDestroyKey(hdKey)) // 複製された鍵オブジェクト
{
    printf("CryptDestroyKey error\n");
    return;
}
if(!CryptDestroyKey(hKey)) // オリジナルの鍵オブジェクト
{
    printf("CryptDestroyKey error\n");
    return;
}
if(!CryptDestroyHash(hHash))
{
    printf("CryptDestroyHash error\n");
    return;
}
引数に、ハッシュ計算のハンドルを指定します。

続いて CSP のハンドルを開放します。
if(!CryptReleaseContext(hProv, 0))
{
    fprintf(stderr, "CryptReleaseContext error\n");
    return;
}
第1引数に CSP のハンドルを指定します。
第2引数には、0(ゼロ)を指定します。

また、暗号化や復号処理のために確保した領域も開放するのを忘れないようにしてください。

1.14.13 サンプル・コード

 サンプル・コードです。Microsoft Visual Studio 2005 のプロジェクトです。
 サンプルの商業利用および転載を禁止します。

1.14.14 ご質問・ご要望

 ご質問やご要望は、こちらからお送りください。(匿名でも可能です。)ご感想などもお聞かせください。



(記載の会社名および製品名は、各社の登録商標および商標です。)

PDF-Tools
PDFおよびPDF/Aを作成・編集などができるライブラリ
128ビットの暗号化や電子署名に対応
http:
//www.trustss.co.jp/pdf/
株)トラスト・ソフトウェア・システム
PDF文書に電子署名するツール(ライブラリ)PDF Tools
PDFからPDF/A変換も可能
暗号化・電子署名・タイムスタンプ ライブラリ作成します。
お問い合わせください。
1. 簡単な暗号化
1.1 概要
1.2 キーコンテナー を準備する
1.3 ハッシュ計算のインスタンスを生成する
1.4 ハッシュ値を計算する
1.5 鍵の生成
1.6 暗号化
1.7 復号
1.8 リソースの開放
1.9 サンプル・コード
1.10 ご質問・ご要望
 
1.11 簡単な暗号化アプリを作りたい方のために
 
1.12 CSP
1.12.1 概要
1.12.2 CSPを列挙する
1.12.3 CSPの種類
1.12.4 CSPのタイプ
1.12.5 CSPのタイプを列挙する
1.12.6 規定のCSP
 
1.13 鍵の生成について
1.13.1 概要
1.13.2 鍵の生成
1.13.3 基本データからの鍵生成
1.13.4 基本データ
1.13.5 暗号化データが必ず復号されるために
 
1.14 ブロック暗号化アルゴリズムによる暗号化
1.14.1 概要
1.14.2 キーコンテナー を準備
1.14.3 ハッシュ計算のインスタンス
1.14.4 ハッシュ値を計算
1.14.5 鍵の生成
1.14.6 パディングモードの指定
1.14.7 初期化ベクタ
1.14.8 暗号モードの指定
1.14.9 復号用に鍵オブジェクトを複製
1.14.10 暗号化
1.14.11 復号
1.14.12 リソースの開放
1.14.13 サンプル・コード
1.14.14 ご質問・ご要望
会員用ログイン
ID:
パスワード:
ログインすると、一般公開していないページを閲覧できます。