ホーム 主筆 その他ソフト その他情報 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:乱数を生成する

2016年1月31日公開

簡単なところで、CNGを使って乱数を生成してみる。

必要性

そもそも、なぜ暗号化ライブラリで乱数の生成をサポートする必要があるのか?

俺自身究極的なことは知らない。とりあえず、ヘタレな疑似乱数を使うと、乱数として生成される値が予測できてしまって、暗号鍵とかパスワードとか、そういったものが破られる危険性があるらしい。

とりあえず、下記のURLだけリンクしておく。

https://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c203.html

使用例

短いから、先にコードを全部示す。

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

// CNGのヘッダファイル
#include <Bcrypt.h>

int _tmain( int argc, _TCHAR* argv[])
{
  // CNGのアルゴリズムプロバイダのハンドル
  BCRYPT_ALG_HANDLE hAlgorithm;
  
  // 乱数を取得するバッファ
  unsigned char buf[ 64 ] ;

  // アルゴリズムプロバイダを取得する
  NTSTATUS r = BCryptOpenAlgorithmProvider(
    &hAlgorithm,
    BCRYPT_RNG_ALGORITHM,
    MS_PRIMITIVE_PROVIDER,
    0
  );
  if ( r != 0 )
    printf( "失敗\n" );

  // 乱数を生成する
  r = BCryptGenRandom( hAlgorithm, buf, sizeof( buf ), 0 );
  if ( r != 0 )
    printf( "失敗\n" );

  // アルゴリズムプロバイダを破棄する
  r = BCryptCloseAlgorithmProvider( hAlgorithm, 0 );
  if ( r != 0 )
    printf( "失敗\n" );

  return 0;
}

呼び出しているのは、下記3つの関数である。

  1. BCryptOpenAlgorithmProvider
  2. BCryptGenRandom
  3. BCryptCloseAlgorithmProvider

BCryptOpenAlgorithmProviderは、CNGのアルゴリズムプロバイダと言われるオブジェクトのハンドルを取得する関数である。大体常にこれを一番最初に呼び出す必要がある。

乱数を生成するのであれば、BCryptOpenAlgorithmProviderで取得したハンドルを指定してBCryptGenRandomを呼んでやれば、指定したバッファに、指定したバイト数分の乱数を生成することができる。

でもって、取得したアルゴリズムプロバイダはBCryptCloseAlgorithmProvider関数で破棄してやる。

実行例

ステップ実行してみる。

まずはアルゴリズムプロバイダの取得。

hAlgorithmに何らかの値が取得されているが、これがハンドルとして正しい値なのかどうかといわれても困る。とりあえず、rにエラーが返されていない以上は正しく終了したのだろうと考えておく。

次に、乱数の取得を行う。

bufに乱数っぽい値が格納される。ここでは上記1回分しか結果を示していないが、bufには毎回異なる値が格納されるように見える。

仕事が終わったら、アルゴリズムプロバイダを破棄する。

これはさすがに面白いことは何もない。

別の方法

ところで、実行時のOSがWindows 7以降(つまりVistaを含まない)かつ、「IRQLがPASSIVE_LEVEL」である場合は、アルゴリズムプロバイダのハンドルを指定しない(つまりNULLにする)で乱数を生成することもできるらしい。

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

// CNGのヘッダファイル
#include <Bcrypt.h>

int _tmain( int argc, _TCHAR* argv[])
{
  // 乱数を取得するバッファ
  unsigned char buf[ 64 ] ;

  // 乱数を生成する
  r = BCryptGenRandom(
    NULL,
    buf,
    sizeof( buf ),
    BCRYPT_USE_SYSTEM_PREFERRED_RNG
  );
  if ( r != 0 )
    printf( "失敗\n" );

  return 0;
}

プログラムを短くできるのはいいのだが、しかし、Vistaはサポートしないとか、「IRQLがPASSIVE_LEVEL」云々の下りを考えると、あまり現実的ではない。おとなしく、アルゴリズムプロバイダの取得と破棄を行うべきだと思われる。

それと、IRQLはカーネルモードで動作させている場合にはPASSIVE_LEVELとDISPATCH_LEVELというのがあるらしいのだが、しかし、ユーザモードで動作する普通のプログラムは一体どっちなのか、デバイスドライバの開発には何の興味も関心もない人間にとっては、いまいちよくわからない。

とりあえず、Windows 10でステップ実行してみたら、なんとなく乱数っぽい値が取得できたことを付記しておく。

 

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


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