warning: Creating default object from empty value in /var/www/drupal-5.23/modules/taxonomy/taxonomy.module on line 1418.

Visual C++ (Win32) で、SHA1 のハッシュ値を取得する方法

以下がサンプルコード。Win32 Crypto API を使うコンソールアプリです。
// HashTest.cpp : Defines the entry point for the console application.
// Copyright (c) 2005, 2006 twinkle.cc All Rights Reserved.
//
//" title="https://perltips.twinkle.cc/
//">https://perltips.twinkle.cc/
//
perltips@gmail.com

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

int _tmain(int argc, _TCHAR* argv[])
{
    #define BUFFER_LEN 253
    #define SHA1LEN  20

    PCHAR    pcMessage;
    DWORD    ccMessage;

    DWORD dwStatus = 0;
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    BYTE pbHash[SHA1LEN];
    BYTE pbRandom[BUFFER_LEN];
    DWORD cbHash = 0;
    CHAR pcDigits[] = "0123456789ABCDEF";
    CHAR pcHash[SHA1LEN * 2 + 1];

    //Get handle to the crypto provider
    if (!CryptAcquireContext(&hProv,
        NULL,
        NULL,
        PROV_RSA_FULL,
        CRYPT_VERIFYCONTEXT))
    {
        dwStatus = GetLastError();
        goto done;
    }

    // Get a random value
    if( CryptGenRandom(
        hProv,
        BUFFER_LEN,
        pbRandom))
    {
        printf("%d bytes of random data have been generated.\n", BUFFER_LEN);
    }
    else
    {
        dwStatus = GetLastError();
        printf("Random bytes were not correctly generated.\n");
        goto done;
    }
   
    if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
    {
        dwStatus = GetLastError();
        goto done;
    }
   
    if (!CryptHashData(hHash, pbRandom, BUFFER_LEN, 0))
    {
        dwStatus = GetLastError();
        printf("CryptHashData failed: %d\n", dwStatus);
        goto done;
    }

    cbHash = SHA1LEN;
    if (CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &cbHash, 0))
    {
        printf("SHA1 hash is: ");
        for (DWORD i = 0; i < cbHash; i++)
        {
            pcHash[i * 2]      = pcDigits[pbHash[i] >> 4];
            pcHash[i * 2 + 1 ] = pcDigits[pbHash[i] & 0xf];
            pcHash[i * 2 + 2 ] = '\0';
        }
        printf("%s\n", pcHash);
    }
    else
    {
        dwStatus = GetLastError();
        printf("CryptGetHashParam failed: %d\n", dwStatus);
    }

    done:

    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);

    WCHAR pwcMessage[BUFFER_LEN];
    MultiByteToWideChar(CP_ACP, 0, pcHash, sizeof(pcHash), pwcMessage, sizeof(pwcMessage));
  
    ccMessage = ( DWORD ) wcslen( pwcMessage );

    if( ( pcMessage = ( PCHAR ) malloc( ccMessage + 1 ) ) )
    {
        WideCharToMultiByte( CP_ACP, 0, pwcMessage, -1, pcMessage, ccMessage + 1, NULL, NULL );
        printf("malloc ok: %s\n", pcMessage);
    }
    else
    {
        printf("Not enough memory");
        dwStatus = ERROR_NOT_ENOUGH_MEMORY;
    }

    return dwStatus;
}
以下がサンプルコード。Win32 Crypto API を使うコンソールアプリです。
// HashTest.cpp : Defines the entry point for the console application.
// Copyright (c) 2005, 2006 twinkle.cc All Rights Reserved.
//
//" title="https://perltips.twinkle.cc/
//">https://perltips.twinkle.cc/
//
perltips@gmail.com

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

int _tmain(int argc, _TCHAR* argv[])
{
    #define BUFFER_LEN 253
    #define SHA1LEN  20

    PCHAR    pcMessage;
    DWORD    ccMessage;

    DWORD dwStatus = 0;
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    BYTE pbHash[SHA1LEN];
    BYTE pbRandom[BUFFER_LEN];
    DWORD cbHash = 0;
    CHAR pcDigits[] = "0123456789ABCDEF";
    CHAR pcHash[SHA1LEN * 2 + 1];

    //Get handle to the crypto provider
    if (!CryptAcquireContext(&hProv,
        NULL,
        NULL,
        PROV_RSA_FULL,
        CRYPT_VERIFYCONTEXT))
    {
        dwStatus = GetLastError();
        goto done;
    }

    // Get a random value
    if( CryptGenRandom(
        hProv,
        BUFFER_LEN,
        pbRandom))
    {
        printf("%d bytes of random data have been generated.\n", BUFFER_LEN);
    }
    else
    {
        dwStatus = GetLastError();
        printf("Random bytes were not correctly generated.\n");
        goto done;
    }
   
    if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
    {
        dwStatus = GetLastError();
        goto done;
    }
   
    if (!CryptHashData(hHash, pbRandom, BUFFER_LEN, 0))
    {
        dwStatus = GetLastError();
        printf("CryptHashData failed: %d\n", dwStatus);
        goto done;
    }

    cbHash = SHA1LEN;
    if (CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &cbHash, 0))
    {
        printf("SHA1 hash is: ");
        for (DWORD i = 0; i < cbHash; i++)
        {
            pcHash[i * 2]      = pcDigits[pbHash[i] >> 4];
            pcHash[i * 2 + 1 ] = pcDigits[pbHash[i] & 0xf];
            pcHash[i * 2 + 2 ] = '\0';
        }
        printf("%s\n", pcHash);
    }
    else
    {
        dwStatus = GetLastError();
        printf("CryptGetHashParam failed: %d\n", dwStatus);
    }

    done:

    CryptDestroyHash(hHash);
    CryptReleaseContext(hProv, 0);

    WCHAR pwcMessage[BUFFER_LEN];
    MultiByteToWideChar(CP_ACP, 0, pcHash, sizeof(pcHash), pwcMessage, sizeof(pwcMessage));
  
    ccMessage = ( DWORD ) wcslen( pwcMessage );

    if( ( pcMessage = ( PCHAR ) malloc( ccMessage + 1 ) ) )
    {
        WideCharToMultiByte( CP_ACP, 0, pwcMessage, -1, pcMessage, ccMessage + 1, NULL, NULL );
        printf("malloc ok: %s\n", pcMessage);
    }
    else
    {
        printf("Not enough memory");
        dwStatus = ERROR_NOT_ENOUGH_MEMORY;
    }

    return dwStatus;
}

秀丸で、日付をファイル名にして自動的に保存するマクロ。

コードのコメントにも書いたのだが、一応説明しておくと、このマクロは、秀丸で書いた文章にファイル名を日付(yyyymmddx.txt)で付けて保存し、ウィンドウを閉じる(ファイル名最後の「x」は、その日で保存した順に、a、b、c、…とついていく)。保存先のディレクトリは、コードの中で指定して欲しい。 このコードは 1996年に作ったものだから、かれこれ 10年くらい使ってるコードです(笑)。
// 秀丸 ファイル名自動作成&保存マクロ
//
// Copyright (c) 1996-2006 twinkle.cc All Rights Reserved.
// 改変、配布は自由
// →でも修正したら連絡いただけると嬉しいです:perltips@gmail.com
//
// ○このマクロについて
//
//    このマクロは、秀丸で書いた文章にファイル名を日付で付けて保存し、終了します。
//    以下の 2点で自動化します。
//
//    1)  書いた文を、指定されたディレクトリに日付をファイル名として保存。
//        ファイル名は yyyyddmmx.txt というフォーマット。
//        yyyymmdd は 2006/12/24 などのフォーマット。
//        x は、その日で保存した順に、a、b、c、…とついていきます。
//        つまりファイル名は 20061224a.txt、20061224b.txt... などの名前に
//        なります(ファイル名を考えなくてすむので便利)。
//    2)  タブを空白に変換します (97行目)。
//
//
// ○ 設定方法
//
//    1)  秀丸エディタの設定メニューから、
//        その他|動作環境|環境|マクロファイル用のフォルダ
//        で、マクロを保存するディレクトリを指定。
//    2)  下の、[保存するディレクトリの指定] のところで、
//        書いたメールを保存するディレクトリを指定。
//        ディレクトリの区切り記号 \ は \\ と2つ重ねる。
//    3)  このマクロを save_txt.mac などの名前で、
//        1) で設定したディレクトリに保存。
//    4)  秀丸のメニューから、マクロ|マクロ登録|ファイル名で
//        3) で指定したファイル名を選択。タイトルを設定。
//    5)  必要なら、秀丸でキーカスタマイズとツールバーを
//        カスタマイズすればボタンひとつでマクロを走らせることが可能。

// [保存するディレクトリの指定]
// ネットワークにある PC に保存するとき
// \\your_computer_name\data\mail\2006 に保存する場合
// (2006 などの年ごとのディレクトリは毎年作ってください)
$savedir = "\\\\your_computer_name\\data\\mail\\" + year + "\\";

// ローカルに保存するとき
// $savedir = "c:\\data\\mail\\logs\\" + year + "\\";


// ここから先はプログラム
#index = 0;                             // 行を表す

// 最初の空白行は無視
gofiletop;                              // ファイルの先頭に移動
while(!linelen2) {
    delete;                             // 改行を削除
}

// 日付をファイル名として保存
gofileend;                              // ファイルの終わりで作業
insert "\n";
insert year;
insert month;
insert day;
insert "a.txt";                         // yyyymmdd.txt という名前を付ける
copyline;                               // 行をコピー
beginclipboardread;                     // クリップボードの選択を開始
$filename = getclipboard;               // ファイル名をクリップボードから取得

// ファイルが存在するかどうか
if (filename != "" ) {

    // filename の初期化
    if (leftstr(filename, 3) == "\\\\\\")
        $filename = rightstr(filename, strlen(filename) - 1);
    else
        $filename = filename;           // 既存のファイル名をつける。

} else {

    while (existfile($savedir + $filename)) {

        $index = midstr($filename,8,1); // 現在の index を取得 (初期値 a)
        $index = char(ascii($index)+1); // index を更新(a,b,c, ...)
        golinetop;                      // 行の先頭に移動
        right 8;                        // index 位置に移動
        insert $index;                  // index を付加
        delete;                         // 更新前の index を消す
        copyline;                       // できたファイル名をコピー
        beginclipboardread;             // クリップボードの選択を開始
        $filename = getclipboard;       // ファイル名をクリップボードから取得
    }
}

$filename = $savedir + $filename;       // ファイル名をフルパスで生成

// ファイル名の後処理
selectline;                             // 1行選択
cut;                                    // カット
backspace;                              // 最初に付けた \n を削除

// 作成した内容をクリップボードにコピー
selectall;                              // 全ての範囲を選択
tospace;                                // タブ→空白変換
copy;                                   // クリップボードへコピー
escape;                                 // 選択を解除

// ファイル名を付けて保存
saveas $filename;

// 秀丸を終了
exit;
コードのコメントにも書いたのだが、一応説明しておくと、このマクロは、秀丸で書いた文章にファイル名を日付(yyyymmddx.txt)で付けて保存し、ウィンドウを閉じる(ファイル名最後の「x」は、その日で保存した順に、a、b、c、…とついていく)。保存先のディレクトリは、コードの中で指定して欲しい。 このコードは 1996年に作ったものだから、かれこれ 10年くらい使ってるコードです(笑)。
// 秀丸 ファイル名自動作成&保存マクロ
//
// Copyright (c) 1996-2006 twinkle.cc All Rights Reserved.
// 改変、配布は自由
// →でも修正したら連絡いただけると嬉しいです:perltips@gmail.com
//
// ○このマクロについて
//
//    このマクロは、秀丸で書いた文章にファイル名を日付で付けて保存し、終了します。
//    以下の 2点で自動化します。
//
//    1)  書いた文を、指定されたディレクトリに日付をファイル名として保存。
//        ファイル名は yyyyddmmx.txt というフォーマット。
//        yyyymmdd は 2006/12/24 などのフォーマット。
//        x は、その日で保存した順に、a、b、c、…とついていきます。
//        つまりファイル名は 20061224a.txt、20061224b.txt... などの名前に
//        なります(ファイル名を考えなくてすむので便利)。
//    2)  タブを空白に変換します (97行目)。
//
//
// ○ 設定方法
//
//    1)  秀丸エディタの設定メニューから、
//        その他|動作環境|環境|マクロファイル用のフォルダ
//        で、マクロを保存するディレクトリを指定。
//    2)  下の、[保存するディレクトリの指定] のところで、
//        書いたメールを保存するディレクトリを指定。
//        ディレクトリの区切り記号 \ は \\ と2つ重ねる。
//    3)  このマクロを save_txt.mac などの名前で、
//        1) で設定したディレクトリに保存。
//    4)  秀丸のメニューから、マクロ|マクロ登録|ファイル名で
//        3) で指定したファイル名を選択。タイトルを設定。
//    5)  必要なら、秀丸でキーカスタマイズとツールバーを
//        カスタマイズすればボタンひとつでマクロを走らせることが可能。

// [保存するディレクトリの指定]
// ネットワークにある PC に保存するとき
// \\your_computer_name\data\mail\2006 に保存する場合
// (2006 などの年ごとのディレクトリは毎年作ってください)
$savedir = "\\\\your_computer_name\\data\\mail\\" + year + "\\";

// ローカルに保存するとき
// $savedir = "c:\\data\\mail\\logs\\" + year + "\\";


// ここから先はプログラム
#index = 0;                             // 行を表す

// 最初の空白行は無視
gofiletop;                              // ファイルの先頭に移動
while(!linelen2) {
    delete;                             // 改行を削除
}

// 日付をファイル名として保存
gofileend;                              // ファイルの終わりで作業
insert "\n";
insert year;
insert month;
insert day;
insert "a.txt";                         // yyyymmdd.txt という名前を付ける
copyline;                               // 行をコピー
beginclipboardread;                     // クリップボードの選択を開始
$filename = getclipboard;               // ファイル名をクリップボードから取得

// ファイルが存在するかどうか
if (filename != "" ) {

    // filename の初期化
    if (leftstr(filename, 3) == "\\\\\\")
        $filename = rightstr(filename, strlen(filename) - 1);
    else
        $filename = filename;           // 既存のファイル名をつける。

} else {

    while (existfile($savedir + $filename)) {

        $index = midstr($filename,8,1); // 現在の index を取得 (初期値 a)
        $index = char(ascii($index)+1); // index を更新(a,b,c, ...)
        golinetop;                      // 行の先頭に移動
        right 8;                        // index 位置に移動
        insert $index;                  // index を付加
        delete;                         // 更新前の index を消す
        copyline;                       // できたファイル名をコピー
        beginclipboardread;             // クリップボードの選択を開始
        $filename = getclipboard;       // ファイル名をクリップボードから取得
    }
}

$filename = $savedir + $filename;       // ファイル名をフルパスで生成

// ファイル名の後処理
selectline;                             // 1行選択
cut;                                    // カット
backspace;                              // 最初に付けた \n を削除

// 作成した内容をクリップボードにコピー
selectall;                              // 全ての範囲を選択
tospace;                                // タブ→空白変換
copy;                                   // クリップボードへコピー
escape;                                 // 選択を解除

// ファイル名を付けて保存
saveas $filename;

// 秀丸を終了
exit;