ホーム 主筆 その他ソフト その他情報 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:RC2 CBCモードのプログラム例

2016年2月6日公開

Cryptography API: Next Generationを使い、RC2 CBCモードで暗号/復号を行うプログラム例を示す。

プログラム例

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <assert.h>
#include <Windows.h>
 
// CNGのヘッダファイル
#include <Bcrypt.h>

int _tmain(int argc, _TCHAR* argv[])
{
  // アルゴリズムプロバイダのハンドル
  BCRYPT_ALG_HANDLE hAlgorithm;
 
  // 対称鍵のハンドル
  BCRYPT_KEY_HANDLE hKey;
 
  // キーオブジェクト
  unsigned char *pKeyObject;
 
  // キーオブジェクトのバイト長
  unsigned long KeyObjectLength;
 
  // 暗号鍵のバイト長(シークレットのバイト長に等しい)
  BCRYPT_KEY_LENGTHS_STRUCT KeyLength;
 
  // イニシャルベクタ
  unsigned char *pIV;
 
  // イニシャルベクタのバイト長(ブロック長と等しい)
  unsigned long IVLength;
 
  // 対称鍵生成元となるシークレット
  unsigned char *pSecretData;
 
  // 平文のデータ
  char Hirabun1[64] = "abcdefghijklmnopqrstuvwxyz";
 
  // 暗号文
  char Angoubun[512];

  // 暗号文のサイズ
  unsigned long AngoubunSize = 0;
 
  // 復号した平文
  char Hirabun2[512];
 
  // 作業用
  unsigned long Result = 0;
 
  // 暗号利用モード
  TCHAR ChainModeBuf[64];
 
  // アルゴリズムプロバイダのハンドルを取得する
  NTSTATUS r = BCryptOpenAlgorithmProvider(
    &hAlgorithm, BCRYPT_RC2_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0
  );
  if ( r != 0 )
    printf( "BCryptOpenAlgorithmProvider失敗\n" );
  else
    printf( "BCryptOpenAlgorithmProvider成功\n" );
 
  // 暗号利用モードを変える
  _tcscpy_s( ChainModeBuf, BCRYPT_CHAIN_MODE_CBC );
  r = BCryptSetProperty(
    hAlgorithm, BCRYPT_CHAINING_MODE, (unsigned char*)ChainModeBuf, sizeof( ChainModeBuf ), 0
  );
  if ( r != 0 )
    printf( "BCryptSetProperty失敗\n" );
  else
    printf( "BCryptSetProperty成功\n", ChainModeBuf );
 
  // キーオブジェクトのサイズを取得する
  r = BCryptGetProperty(
    hAlgorithm, BCRYPT_OBJECT_LENGTH, (unsigned char*)( &KeyObjectLength ), sizeof( KeyObjectLength ), &Result, 0
  );
  if ( r != 0 )
    printf( "BCryptGetProperty失敗\n" );
  else
    printf( "BCryptGetProperty成功 キーオブジェクトのバイト長=%d\n", KeyObjectLength );
 
  // イニシャルベクタのサイズを取得する
  r = BCryptGetProperty(
    hAlgorithm, BCRYPT_BLOCK_LENGTH, (unsigned char*)( &IVLength ), sizeof( IVLength ), &Result, 0
  );
  if ( r != 0 )
    printf( "BCryptGetProperty失敗\n" );
  else
    printf( "BCryptGetProperty成功 イニシャルベクタのバイト長=%d\n", IVLength );
 
  // キーのサイズを取得する
  r = BCryptGetProperty(
    hAlgorithm, BCRYPT_KEY_LENGTHS, (unsigned char*)( &KeyLength ), sizeof( KeyLength ), &Result, 0
  );
  if ( r != 0 )
    printf( "BCryptGetProperty失敗\n" );
  else {
    KeyLength.dwMaxLength /= 8;
    printf( "BCryptGetProperty成功 キーのバイト長=%d\n", KeyLength.dwMaxLength );
  }
 
  // 必要なメモリ領域を確保する
  pKeyObject = (unsigned char*)( malloc( KeyObjectLength ) );
  pIV = (unsigned char*)( malloc( IVLength ) );
  pSecretData = (unsigned char*)( malloc( KeyLength.dwMaxLength ) );
 
  // 対称鍵生成元となるシークレットを生成する
  for ( unsigned long i = 0; i < KeyLength.dwMaxLength; i++ )
    pSecretData[i] = rand();    // 本当は、乱数はrandを使ってはいけない
 
  // 対称鍵を生成する
  r = BCryptGenerateSymmetricKey(
    hAlgorithm, &hKey, pKeyObject, KeyObjectLength, pSecretData, KeyLength.dwMaxLength, 0
  );
  if ( r != 0 )
    printf( "BCryptGenerateSymmetricKey失敗\n" );
  else
    printf( "BCryptGenerateSymmetricKey成功\n" );
 
  printf( "--- 暗号化 -------------------------------------------\n" );
 
  // イニシャルベクタを生成する
  for ( unsigned long i = 0; i < IVLength; i++ )
    pIV[i] = (unsigned char)i;    // 本当は乱数にする
 
  // 事前に暗号文のバイト数を取得する
  r = BCryptEncrypt(
    hKey,                                         // 鍵
    (unsigned char*)Hirabun1, sizeof( Hirabun1 ), // 平文
    nullptr,                                      // 認証情報
    pIV, IVLength,                                // イニシャルベクタ
    nullptr, 0,                                   // 暗号文
    &Result,                                      // 出力された暗号文のバイト長
    0                                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptEncrypt失敗\n" );
  else
    printf( "BCryptEncrypt成功 予測されるバイト数=%d\n", Result );
 
  // 一応確認しておく
  assert( sizeof( Angoubun ) > Result );
 
  // 暗号化する
  r = BCryptEncrypt(
    hKey,                                         // 鍵
    (unsigned char*)Hirabun1, sizeof( Hirabun1 ), // 平文
    nullptr,                                      // 認証情報
    pIV, IVLength,                                // イニシャルベクタ
    (unsigned char*)Angoubun, sizeof( Angoubun ), // 暗号文
    &Result,                                      // 出力された暗号文のバイト長
    0                                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptEncrypt失敗\n" );
  else {
    printf( "BCryptEncrypt成功 バイト数=%d, 暗号文=", Result );
    for ( unsigned int j = 0; j < Result; j++ )
      printf( "%02X", (unsigned char)Angoubun[j] );
    printf( "\n" );
  }
  AngoubunSize = Result;
 
  printf( "--- 復号 ---------------------------------------------\n" );
 
  // まず、暗号化時に使用したイニシャルベクタが必要になるため、
  // 復号に備えてイニシャルベクタを元に戻す
  for ( unsigned long i = 0; i < IVLength; i++ )
    pIV[i] = (unsigned char)i;    // 本当は乱数にする
 
  // 平文のサイズを取得する
  r = BCryptDecrypt(
    hKey,                                         // 鍵
    (unsigned char*)Angoubun, AngoubunSize        // 暗号文のバッファ
    nullptr,                                      // 認証情報
    pIV, IVLength,                                // イニシャルベクタ
    nullptr, 0,                                   // 平文
    &Result,                                      // 出力された平文のバイト長
    0                                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptDecrypt失敗\n" );
  else
    printf( "BCryptDecrypt成功 予測される平文のバイト数=%d\n", Result );
 
  // 復号する
  r = BCryptDecrypt(
    hKey,                                         // 鍵
    (unsigned char*)Angoubun, AngoubunSize,       // 暗号文のバッファ
    nullptr,                                      // 認証情報
    pIV, IVLength,                                // イニシャルベクタ
    (unsigned char*)Hirabun2, sizeof( Hirabun2 ), // 平文
    &Result,                                      // 出力された平文のバイト長
    0                                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptDecrypt失敗\n" );
  else
    printf( "BCryptDecrypt成功 バイト数=%d, 平文=%s\n", Result, Hirabun2 );
 
  // キーを破棄する
  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" );
 
  // メモリ領域を解放する
  free( pKeyObject );
  free( pIV );
  free( pSecretData );
 
  return 0;
}

実行結果

BCryptOpenAlgorithmProvider成功
BCryptSetProperty成功
BCryptGetProperty成功 キーオブジェクトのバイト長=374
BCryptGetProperty成功 イニシャルベクタのバイト長=8
BCryptGetProperty成功 キーのバイト長=16
BCryptGenerateSymmetricKey成功
--- 暗号化 -------------------------------------------
BCryptEncrypt成功 予測されるバイト数=64
BCryptEncrypt成功 バイト数=64, 暗号文=50A10E3DC1FBE8C7
70FF25861D8D460042CC6BA39166F0F5BABEB783465138236
F425F7055347D3C1FE4C25E2C84C3734D07795A2524CFFC47
C364CA5A26FA2F
--- 復号 ---------------------------------------------
BCryptDecrypt成功 予測される平文のバイト数=64
BCryptDecrypt成功 バイト数=64, 平文=abcdefghijklmnopqrstuvwxyz
BCryptDestroyKey成功
BCryptCloseAlgorithmProvider成功

<< 「CNG:共通鍵暗号アルゴリズムの比較」に戻る

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


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