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

2016年2月6日公開

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

プログラム例

#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <assert.h>
#include <Windows.h>
#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 *pSecretData;

  // 平文のデータ
  char Hirabun1[64] = "abcdefghijklmnopqrstuvwxyz";
 
  // 暗号文
  char Angoubun[512];
 
  // 生成された暗号文の長さ
  unsigned long AngoubunSize;
 
  // 復号した平文
  char Hirabun2[512];
 
  // 作業用
  unsigned long Result = 0;
 
  // 暗号利用モード
  TCHAR ChainModeBuf[64];
 
  // アルゴリズムプロバイダのハンドルを取得する
  NTSTATUS r = BCryptOpenAlgorithmProvider(
    &hAlgorithm, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0
  );
  if ( r != 0 )
    printf( "BCryptOpenAlgorithmProvider失敗\n" );
  else
    printf( "BCryptOpenAlgorithmProvider成功\n" );

  // 暗号利用モードを変える
  _tcscpy_s( ChainModeBuf, BCRYPT_CHAIN_MODE_ECB );
  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_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 ) );
  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" );
 
  // 事前に暗号文のバイト数を取得する
  r = BCryptEncrypt(
    hKey,                                         // 鍵
    (unsigned char*)Hirabun1, sizeof( Hirabun1 ), // 平文
    nullptr,                                      // パディングの情報
    nullptr, 0,                                   // イニシャルベクタは使用しない
    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,                                      // パディングの情報
    nullptr, 0,                                   // イニシャルベクタは使用しない
    (unsigned char*)Angoubun, sizeof( Angoubun ), // 暗号文
    &Result,                                      // 出力された暗号文のバイト長
    0                                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptEncrypt失敗\n" );
  else {
    printf( "BCryptEncrypt成功 バイト数=%d, 暗号文=", Result );
    for ( int j = 0; j < Result; j++ )
      printf( "%02X", (unsigned char)Angoubun[j] );
    printf( "\n" );
  }
  AngoubunSize = Result;
 
  printf( "--- 復号 ---------------------------------------------\n" );

  // 事前に平文のサイズを取得しておく
  r = BCryptDecrypt(
    hKey,                                         // 鍵
    (unsigned char*)Angoubun, AngoubunSize,       // 暗号文
    nullptr,                                      // パディングの情報
    nullptr, 0,                                   // イニシャルベクタは使用しない
    nullptr, 0,                                   // 平文
    &Result,                                      // 平文のバイト数
    0                                             // フラグ
  );
  if ( r != 0 )
    printf( "BCryptDecrypt失敗\n" );
  else
    printf( "BCryptDecrypt成功 予測されるバイト数=%d\n", Result );
 
  // 一応確認しておく
  assert( sizeof( Hirabun2 ) > Result );
 
  // 復号する
  r = BCryptDecrypt(
    hKey,                                         // 鍵
    (unsigned char*)Angoubun, AngoubunSize,       // 暗号文
    nullptr,                                      // パディングの情報
    nullptr, 0,                                   // イニシャルベクタは使用しない
    (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( pSecretData );
 
  return 0;
}

実行結果

BCryptOpenAlgorithmProvider成功
BCryptSetProperty成功
BCryptGetProperty成功 キーオブジェクトのバイト長=618
BCryptGetProperty成功 キーのバイト長=32
BCryptGenerateSymmetricKey成功
--- 暗号化 -------------------------------------------
BCryptEncrypt成功 予測されるバイト数=64
BCryptEncrypt成功 バイト数=64, 暗号文=6E4BE73670B7CA35E1
78E70AC81A6202B85C38C3D04FE41DE0DBFFF3ED0890B798C6
9832C1BF3B3A526400BE0ACA9A5098C69832C1BF3B3A526400B
E0ACA9A50
--- 復号 ---------------------------------------------
BCryptDecrypt成功 予測されるバイト数=64
BCryptDecrypt成功 バイト数=64, 平文=abcdefghijklmnopqrstuvwxyz
BCryptDestroyKey成功
BCryptCloseAlgorithmProvider成功

アルゴリズムによらず、ECBはECBであるため同じ問題がある。

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

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


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