ホーム 主筆 その他ソフト その他情報 Syuhitu.org English

Windows関連

スクリーンセーバー作成法

半透明ウインドウの性能

bootfont.bin

キャビネット形式

ウインドウスタイルをいじる

Java製ソフトをServiceに登録する

イベントログにメッセージを出力する

コントロールパネルにアイコンを追加する

スクリプトによる拡張1

スクリプトによる拡張2

ガジェットの作成

大容量メモリ

メモリ搭載量の下限に挑む

スパースファイルにする

表示されるアイコンの種類を調べてみた

メモリマップIOとエラー処理

ファイルを作る順番と速度の関係

Cryptography API: Next Generationを使う

Windows 10のアクセントカラー

iSCSIディスクにバックアップを取る

サーバプロセスを分離して実装する

サーバプロセスを分離して実装する - F#

レジストリに大量に書き込む

Solaris関連

OpenGL

Solaris設定

ディレクトリの読み込み

主筆プラグイン開発

マルチスレッドでの開発

door

音を出す

Blade100の正しい虐め方

パッケージの作成

画像入出力

BMPファイル

ICOファイル

ANIファイル

JPEGファイル

減色アルゴリズム

減色アルゴリズムの並列化

その他アルゴリズムなど

自由軸回転

Base64

文字列操作

CPU利用率の取得

正規表現ライブラリ

メタボールを作る

メタボールを作る2

正規表現とNFA・DFA

C言語の構文解析

液晶ディスプレイを解体してみた

iSCSIの理論と実装

単一フォルダにファイルを沢山作る

USB-HUBのカスケード接続

SafeIntの性能

VHDファイルのフォーマット

USBメモリに書き込み続けてみた

CNG:NULL暗号の利用例

2016年2月28日公開

利用例といったところで、何か役に立つ応用例を示そうとかそういうことではない。自分で実装したアルゴリズムプロバイダをインストールしたところで、それを呼び出して使ってみようというだけのことである。

プログラム例

ロジックは今まで示してきたものの応用にすぎないため、詳細な説明は割愛する。以下に、アルゴリズムプロバイダの登録・実行・削除を行うプログラムを示す。

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <bcrypt.h>
#include <bcrypt_provider.h>
 
/////////////////////////////////////////////////////////////////
// 登録するプロバイダの特性
 
// 同一のアルゴリズムクラスに属する、アルゴリズム名の配列
TCHAR* AlgorithmNames[1] = {
  L"TestCAP-NULL"             // アルゴリズム名
};
 
// アルゴリズムプロバイダにより定義される、
// 単一のアルゴリズムクラスの定義
CRYPT_INTERFACE_REG AlgorithmClass = {
  BCRYPT_CIPHER_INTERFACE,// 対称暗号を指定する
  CRYPT_LOCAL,            // スコープとしてローカルを指定する
  1,                      // このアルゴリズムのクラスに属する
                          // アルゴリズムの個数
  AlgorithmNames          // このアルゴリズムのクラスに属する
                          // アルゴリズムの名前
};
 
// 当該のアルゴリズムプロバイダによりサポートされる
// アルゴリズムクラスの定義
PCRYPT_INTERFACE_REG AllUserModeAlgorithmClasses[1] = {
    &AlgorithmClass
};
 
// DLLの定義
CRYPT_IMAGE_REG UserModeProviderImage = {
  L"TestCAP.dll",             // ファイル名
  1,                          // ファイル数
  AllUserModeAlgorithmClasses // 定義
};
 
// 登録するすべてのDLLの定義
CRYPT_PROVIDER_REG SymmetricCipherProvider = {
  0,                           // エイリアスは使用しない
  NULL,                        // エイリアスは使用しない
  &UserModeProviderImage,      // ユーザモード用のDLL
  NULL                         // カーネルモード用のDLL
                               // (NULLでなければならないらしい)
};
/////////////////////////////////////////////////////////////////
 
// プロバイダを新規に登録する
void Regist()
{
  // レジストリに登録する
  NTSTATUS r = BCryptRegisterProvider(
    L"TestCAP",               // プロバイダ名
    0,                        // 上書きでの登録は行わない
    &SymmetricCipherProvider  // 登録するプロバイダの情報
  );
  if ( r != 0 )
    printf( "BCryptRegisterProvider失敗\n" );
 
  // CNGコンテキストに登録する
  r = BCryptAddContextFunctionProvider(
    CRYPT_LOCAL,             // CRYPT_LOCAL以外はサポートされない
    NULL,                    // デフォルトに任せる
    BCRYPT_CIPHER_INTERFACE, // 対称暗号であることを指定する
    L"TestCAP-NULL",         // アルゴリズム名
    L"TestCAP",              // プロバイダ名
    CRYPT_PRIORITY_BOTTOM    // 追加する位置とはなんだ?
  );
  if ( r != 0 )
    printf( "BCryptAddContextFunctionProvider失敗\n" );
}
 
// 登録されているプロバイダを削除する
void Unregist()
{
  // CNGコンテキストから削除する
  NTSTATUS r = BCryptRemoveContextFunctionProvider(
    CRYPT_LOCAL,             // CRYPT_LOCAL以外はサポートされない
    NULL,                    // デフォルトに任せる
    BCRYPT_CIPHER_INTERFACE, // 対称暗号であることを指定する
    L"TestCAP-NULL",         // アルゴリズム名
    L"TestCAP"               // プロバイダ名
  );
  if ( r != 0 )
    printf( "BCryptRemoveContextFunctionProvider失敗\n" );
 
  // レジストリからプロバイダを削除する
  r = BCryptUnregisterProvider( L"TestCAP" );
  if ( r != 0 )
    printf( "BCryptUnregisterProvider失敗\n" );
 
}

// 使ってみる
void Encript()
{
  BCRYPT_ALG_HANDLE hAlgorithm; // アルゴリズムプロバイダ
  BCRYPT_KEY_HANDLE hKey;       // 対称鍵
  unsigned long Result;
  char vPlainText[64] = "abcdefghijklmnopqrstuvwxyz";  // 平文
  char vEncriptText[64];        // 暗号文
 
  // アルゴリズムプロバイダのハンドルを取得する
  NTSTATUS r = BCryptOpenAlgorithmProvider(
    &hAlgorithm,     // アルゴリズムプロバイダのハンドル
    L"TestCAP-NULL", // アルゴリズム名
    L"TestCAP",      // アルゴリズムプロバイダ名
    0
  );
  if ( r != 0 )
    printf( "BCryptOpenAlgorithmProvider失敗\n" );
  else
    printf( "BCryptOpenAlgorithmProvider成功\n" );
 
  // 対称鍵を生成する
  r = BCryptGenerateSymmetricKey(
    hAlgorithm, // アルゴリズムプロバイダのハンドル
    &hKey,      // 鍵のハンドル
    nullptr,    // キーオブジェクトは使用しない
    0,          // キーオブジェクトは使用しない
    (UCHAR*)"", // シークレットは使用しない
    1,          // シークレットは使用しない
    0           // 指定すべきフラグはない
  );
  if ( r != 0 )
    printf( "BCryptGenerateSymmetricKey失敗\n" );
  else
    printf( "BCryptGenerateSymmetricKey成功\n" );
 
  // 暗号化する
  r = BCryptEncrypt(
    hKey,                      // 鍵
    (unsigned char*)vPlainText,// 平文
    sizeof( vPlainText ),      // 平文のサイズ
    nullptr,                   // 認証情報
    nullptr,                   // イニシャルベクタは使用しない
    0,                         // イニシャルベクタは使用しない
    (unsigned char*)vEncriptText, // 暗号文
    sizeof( vEncriptText ),    // 暗号文のバッファ長
    &Result,                   // 出力された暗号文のバイト長
    0                          // フラグ
  );
  if ( r != 0 )
    printf( "BCryptEncrypt失敗\n" );
  else
    printf( "BCryptEncrypt成功 暗号文=%s\n", vEncriptText );
 
  // 復号する
  r = BCryptDecrypt(
    hKey,                         // 鍵
    (unsigned char*)vEncriptText, // 暗号文
    sizeof( vEncriptText ),       // 暗号文のバッファ長
    nullptr,                      // 認証情報
    nullptr,                      // イニシャルベクタは使用しない
    0,                            // イニシャルベクタは使用しない
    (unsigned char*)vPlainText,   // 平文
    sizeof( vPlainText ),         // 平文のサイズ
    &Result,                      // 出力された平文のバイト長
    0                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptDecrypt失敗\n" );
  else
    printf( "BCryptDecrypt 成功 平文=%s\n", vPlainText );
 
  // キーを破棄する
  r = BCryptDestroyKey( hKey );
  if ( r != 0 )
    printf( "BCryptDestroyKey失敗\n" );
  else
    printf( "BCryptDestroyKey成功\n" );
 
  // アルゴリズムプロバイダを破棄する
  r = BCryptCloseAlgorithmProvider( hAlgorithm, 0 );
  if ( r != 0 )
    printf( "BCryptCloseAlgorithmProvider失敗\n" );
  else
    printf( "BCryptCloseAlgorithmProvider成功\n" );
 
}
 
int _tmain(int argc, _TCHAR* argv[])
{
  // 登録
  Regist();
 
  // 使ってみる
  Encript();
 
  // 削除
  Unregist();
 
  return 0;
}
 

当然だが、上記を実行するためにはアルゴリズムプロバイダのDLLを事前にsystem32ないしSysWOW64フォルダに格納しておかなければならない。

実行結果

以下のようになる。

BCryptOpenAlgorithmProvider成功
BCryptGenerateSymmetricKey成功
BCryptEncrypt成功 暗号文=abcdefghijklmnopqrstuvwxyz
BCryptDecrypt 成功 平文=abcdefghijklmnopqrstuvwxyz
BCryptDestroyKey成功
BCryptCloseAlgorithmProvider成功

当たり前といえば当たり前であるが、暗号文として平文そのものが返されており、かつ、復号しても同じ平文が返されていることがわかる。

<< 「Cryptography API: Next Generationを使う」に戻る


連絡先 - サイトマップ - 更新履歴
Copyright (C) 2000 - 2016 nabiki_t All Rights Reserved.