Bagikan melalui


Membuat Hash dengan CNG

Hash adalah operasi satu arah yang dilakukan pada blok data untuk membuat nilai hash unik yang mewakili konten data. Tidak peduli kapan hash dilakukan, algoritma hash yang sama yang dilakukan pada data yang sama akan selalu menghasilkan nilai hash yang sama. Jika salah satu data berubah, nilai hash akan berubah dengan tepat.

Hash tidak berguna untuk mengenkripsi data karena tidak dimaksudkan untuk digunakan untuk memproduksi ulang data asli dari nilai hash. Hash paling berguna untuk memverifikasi integritas data saat digunakan dengan algoritma penandatanganan asimetris. Misalnya, jika Anda hash pesan teks, menandatangani hash, dan menyertakan nilai hash yang ditandatangani dengan pesan asli, penerima dapat memverifikasi hash yang ditandatangani, membuat nilai hash untuk pesan yang diterima, lalu membandingkan nilai hash ini dengan nilai hash yang ditandatangani yang disertakan dengan pesan asli. Jika kedua nilai hash identik, penerima dapat cukup yakin bahwa pesan asli belum dimodifikasi.

Ukuran nilai hash diperbaiki untuk algoritma hash tertentu. Apa artinya ini adalah bahwa tidak peduli seberapa besar atau kecil blok data, nilai hash akan selalu berukuran sama. Sebagai contoh, algoritma hash SHA256 memiliki ukuran nilai hash 256 bit.

Membuat Objek Hashing

Untuk membuat hash menggunakan CNG, lakukan langkah-langkah berikut:

  1. Buka penyedia algoritma yang mendukung algoritma yang diinginkan. Algoritma hash yang khas termasuk MD2, MD4, MD5, SHA-1, dan SHA256. Panggil fungsi BCryptOpenAlgorithmProvider dan tentukan pengidentifikasi algoritma yang sesuai dalam parameter pszAlgId . Fungsi mengembalikan handel ke penyedia.

  2. Lakukan langkah-langkah berikut untuk membuat objek hashing:

    1. Dapatkan ukuran objek dengan memanggil fungsi BCryptGetProperty untuk mengambil properti BCRYPT_OBJECT_LENGTH .
    2. Alokasikan memori untuk menahan objek hash.
    3. Buat objek dengan memanggil fungsi BCryptCreateHash .
  3. Hash data. Ini melibatkan pemanggilan fungsi BCryptHashData satu atau beberapa kali. Setiap panggilan menambahkan data yang ditentukan ke hash.

  4. Lakukan langkah-langkah berikut untuk mendapatkan nilai hash:

    1. Ambil ukuran nilai dengan memanggil fungsi BCryptGetProperty untuk mendapatkan properti BCRYPT_HASH_LENGTH .
    2. Alokasikan memori untuk menahan nilai.
    3. Ambil nilai hash dengan memanggil fungsi BCryptFinishHash . Setelah fungsi ini dipanggil, objek hash tidak lagi valid.
  5. Untuk menyelesaikan prosedur ini, Anda harus melakukan langkah-langkah pembersihan berikut:

    1. Tutup objek hash dengan meneruskan handel hash ke fungsi BCryptDestroyHash .

    2. Bebaskan memori yang Anda alokasikan untuk objek hash.

    3. Jika Anda tidak akan membuat objek hash lagi, tutup penyedia algoritma dengan meneruskan handel penyedia ke fungsi BCryptCloseAlgorithmProvider .

      Jika Anda akan membuat lebih banyak objek hash, kami sarankan Anda menggunakan kembali penyedia algoritma daripada membuat dan menghancurkan jenis penyedia algoritma yang sama berkali-kali.

    4. Setelah Anda selesai menggunakan memori nilai hash, bebaskan.

Contoh berikut menunjukkan cara membuat nilai hash dengan menggunakan CNG.

// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) Microsoft. All rights reserved.
/*++

Abstract:

    Sample program for SHA 256 hashing using CNG

--*/


#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>



#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)

#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)


static const BYTE rgbMsg[] = 
{
    0x61, 0x62, 0x63
};


void __cdecl wmain(
                   int                      argc, 
                   __in_ecount(argc) LPWSTR *wargv)
{

    BCRYPT_ALG_HANDLE       hAlg            = NULL;
    BCRYPT_HASH_HANDLE      hHash           = NULL;
    NTSTATUS                status          = STATUS_UNSUCCESSFUL;
    DWORD                   cbData          = 0,
                            cbHash          = 0,
                            cbHashObject    = 0;
    PBYTE                   pbHashObject    = NULL;
    PBYTE                   pbHash          = NULL;

    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(wargv);

    //open an algorithm handle
    if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
                                                &hAlg,
                                                BCRYPT_SHA256_ALGORITHM,
                                                NULL,
                                                0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
        goto Cleanup;
    }

    //calculate the size of the buffer to hold the hash object
    if(!NT_SUCCESS(status = BCryptGetProperty(
                                        hAlg, 
                                        BCRYPT_OBJECT_LENGTH, 
                                        (PBYTE)&cbHashObject, 
                                        sizeof(DWORD), 
                                        &cbData, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
        goto Cleanup;
    }

    //allocate the hash object on the heap
    pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
    if(NULL == pbHashObject)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

   //calculate the length of the hash
    if(!NT_SUCCESS(status = BCryptGetProperty(
                                        hAlg, 
                                        BCRYPT_HASH_LENGTH, 
                                        (PBYTE)&cbHash, 
                                        sizeof(DWORD), 
                                        &cbData, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
        goto Cleanup;
    }

    //allocate the hash buffer on the heap
    pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
    if(NULL == pbHash)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    //create a hash
    if(!NT_SUCCESS(status = BCryptCreateHash(
                                        hAlg, 
                                        &hHash, 
                                        pbHashObject, 
                                        cbHashObject, 
                                        NULL, 
                                        0, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptCreateHash\n", status);
        goto Cleanup;
    }
    

    //hash some data
    if(!NT_SUCCESS(status = BCryptHashData(
                                        hHash,
                                        (PBYTE)rgbMsg,
                                        sizeof(rgbMsg),
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptHashData\n", status);
        goto Cleanup;
    }
    
    //close the hash
    if(!NT_SUCCESS(status = BCryptFinishHash(
                                        hHash, 
                                        pbHash, 
                                        cbHash, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptFinishHash\n", status);
        goto Cleanup;
    }

    wprintf(L"Success!\n");

Cleanup:

    if(hAlg)
    {
        BCryptCloseAlgorithmProvider(hAlg,0);
    }

    if (hHash)    
    {
        BCryptDestroyHash(hHash);
    }

    if(pbHashObject)
    {
        HeapFree(GetProcessHeap(), 0, pbHashObject);
    }

    if(pbHash)
    {
        HeapFree(GetProcessHeap(), 0, pbHash);
    }

}

Membuat Objek Hashing yang Dapat Digunakan Kembali

Dimulai dengan Windows 8 dan Windows Server 2012, Anda dapat membuat objek hashing yang dapat digunakan kembali untuk skenario yang mengharuskan Anda menghitung beberapa hash atau HMAC berturut-turut dengan cepat. Lakukan ini dengan menentukan BCRYPT_HASH_REUSABLE_FLAG saat memanggil fungsi BCryptOpenAlgorithmProvider . Semua penyedia algoritma hash Microsoft mendukung bendera ini. Objek hashing yang dibuat dengan menggunakan bendera ini dapat digunakan kembali segera setelah memanggil BCryptFinishHash seolah-olah telah dibuat baru dengan memanggil BCryptCreateHash. Lakukan langkah-langkah berikut untuk membuat objek hashing yang dapat digunakan kembali:

  1. Buka penyedia algoritma yang mendukung algoritma hash yang diinginkan. Panggil fungsi BCryptOpenAlgorithmProvider dan tentukan pengidentifikasi algoritma yang sesuai dalam parameter pszAlgId dan BCRYPT_HASH_REUSABLE_FLAG dalam parameter dwFlags . Fungsi mengembalikan handel ke penyedia.

  2. Lakukan langkah-langkah berikut untuk membuat objek hashing:

    1. Dapatkan ukuran objek dengan memanggil fungsi BCryptGetProperty untuk mengambil properti BCRYPT_OBJECT_LENGTH .
    2. Alokasikan memori untuk menahan objek hash.
    3. Buat objek dengan memanggil fungsi BCryptCreateHash . Tentukan BCRYPT_HASH_REUSABLE_FLAG dalam parameter dwFlags .
  3. Hash data dengan memanggil fungsi BCryptHashData .

  4. Lakukan langkah-langkah berikut untuk mendapatkan nilai hash:

    1. Dapatkan ukuran nilai hash dengan memanggil fungsi BCryptGetProperty untuk mendapatkan properti BCRYPT_HASH_LENGTH .
    2. Alokasikan memori untuk menahan nilai.
    3. Dapatkan nilai hash dengan memanggil BCryptFinishHash.
  5. Untuk menggunakan kembali objek hashing dengan data baru, buka langkah 3.

  6. Untuk menyelesaikan prosedur ini, Anda harus melakukan langkah-langkah pembersihan berikut:

    1. Tutup objek hash dengan meneruskan handel hash ke fungsi BCryptDestroyHash .
    2. Bebaskan memori yang Anda alokasikan untuk objek hash.
    3. Jika Anda tidak akan membuat objek hash lagi, tutup penyedia algoritma dengan meneruskan handel penyedia ke fungsi BCryptCloseAlgorithmProvider .
    4. Setelah Anda selesai menggunakan memori nilai hash, bebaskan.

Menduplikasi Objek Hash

Dalam beberapa keadaan, mungkin berguna untuk hash beberapa jumlah data umum dan kemudian membuat dua objek hash terpisah dari data umum. Anda tidak perlu membuat dua objek hash terpisah dan hash data umum dua kali untuk mencapainya. Anda dapat membuat objek hash tunggal dan menambahkan semua data umum ke objek hash. Kemudian, Anda dapat menggunakan fungsi BCryptDuplicateHash untuk membuat duplikat objek hash asli. Objek hash duplikat berisi semua informasi status yang sama dan data yang di-hash sebagai aslinya, tetapi ini adalah objek hash yang sepenuhnya independen. Anda sekarang dapat menambahkan data unik ke setiap objek hash dan mendapatkan nilai hash seperti yang ditunjukkan dalam contoh. Teknik ini berguna saat hashing sejumlah besar data umum. Anda hanya perlu menambahkan data umum ke hash asli satu kali, dan kemudian Anda dapat menduplikasi objek hash untuk mendapatkan objek hash yang unik.