Crypto API 學習筆記一

來源:互聯網
上載者:User

微軟公司在NT4.0以上版本中提供了一套完整的Crypto API的函數,支援通行金鑰交換,資料加密解密,數位簽章,給程式員帶來了很大方便,使用者在對軟體進行保護的時候可以直接利用Crypto API來完成這些工作,比如計算註冊碼,檢查程式的完整性等。
  我們在用這些的API進行加密解密的時候,只需要知道如何去應用它們,而不必知道它們的底層實現。如果想知道它們更為詳盡的資料,可以尋找相關的資料。
  對Crypto API只是業餘型的感興趣,想通過寫學習筆記,一是讓自己記的更牢固些,二是想把自己的學的跟大家探討一下。寫的不好,大家多多原諒。我主要通過MSDN來學習,例子也是完全取自MSDN。
  首先,是Crypto API啟動並執行環境。
首先需要Crypt32.lib,將它加到project->setting->link下面,當然你也可以在程式中用#pragma comment (lib, "crypt32.lib")加入。
  在程式開頭,你要加入兩個標頭檔 windows.h 和 Wincrypt.h,和一個#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  在正式應用API進行一系列的加密解密的時候,需要有一些準備工作,下面是介紹一些在正式開始時所需要瞭解和做的工作。
產生密鑰和密鑰容器
  我們知道,在進行加密解密的時候,我們需要一個密鑰進行加密,和一個密鑰進行解密,加密金鑰和解密密鑰可能相同,也可能不同。於是在我們進行加密解密的開始時,我們首先需要有密鑰。下面這個程式,完成了三個任務,並且介紹了一些函數的用法。
任務一:擷取一個指定的密鑰容器,如果這個容器不存在,建立一個。
任務二:如果容器中不存在一個簽名金鑰組,建立一個
任務三:如果容器中不存在一個交換金鑰組,建立一個
  //-------------------------------------------------------------------
下面這段程式使用到了這幾個函數
CryptAcquireContext 
CryptDestroyKey 
CryptGenKey 
CryptGetUserKey 

// Copyright (c) Microsoft Corporation.  All rights reserved.

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Wincrypt.h>

//-------------------------------------------------------------------

void MyHandleError(LPTSTR psz)
{
    _ftprintf(stderr, TEXT("An error occurred in the program. /n"));
    _ftprintf(stderr, TEXT("%s/n"), psz);
    _ftprintf(stderr, TEXT("Error number %x./n"), GetLastError());
    _ftprintf(stderr, TEXT("Program terminating. /n"));
    exit(1);
} // End of MyHandleError.
上面這個函數是一個異常處理函數,當出現錯誤的時候,出現提示,並推出程式。以後的程式中都有這個函數,以後就會將這個函數的實現省去。現在這個函數的實現在後面。
void main(void) 

        HCRYPTPROV hCryptProv;   //定義一個CSP模組的控制代碼。“CSP模組,請查看《加密解密二》222頁,那裡有簡單的說明,這裡就不說了。     
    
        LPCTSTR pszContainerName = TEXT("My Sample Key Container");//用一個TEXT宏定義一個容器的名字,

    
    if(CryptAcquireContext(        //這個函數是擷取有某個容器的CSP模組的指標,成功返回TRUE。
        &hCryptProv,            //指向一個CSP模組控制代碼指標,裡面用指定的容器
        pszContainerName,       //指定容器的名稱
     NULL,                //這個參數這裡用的是預設值,指得是預設得CSP模組,你也可以傳入一個LPCTSTR類型的字串,指定CSP模組
        PROV_RSA_FULL,      //確定密鑰的類型
        0))                    //常設為0,還有些其他的類型,請看MSDN
    {
        _tprintf(
            TEXT("A crypto context with the %s key container ")
            TEXT("has been acquired./n"), 
            pszContainerName);
    }
    else
    { 
        //不成功的處理段
        if(GetLastError() == NTE_BAD_KEYSET)     // NTE_BAD_KEYSET意味著密鑰
//容器不存在,下面就去建立一個
//新的密鑰容器
        {
            if(CryptAcquireContext(
                &hCryptProv, 
                pszContainerName, 
                NULL, 
                PROV_RSA_FULL, 
                CRYPT_NEWKEYSET))           // CRYPT_NEWKEYSET意味著當指定容器不存在的時候,去建立一個容器。
            {
                _tprintf(TEXT("A new key container has been ")
                    TEXT("created./n"));
            }
            else
            {
                MyHandleError(TEXT("Could not create a new key ")
                    TEXT("container./n"));
            }
        }
        else
        {
            MyHandleError(TEXT("CryptAcquireContext failed./n"));
        }
    }

    
    HCRYPTKEY hKey;                            //建立一個密鑰控制代碼
    
    if(CryptGetUserKey(                           // CryptGetUserKey是擷取一個密鑰//控制代碼的函數,成功返回TRUE
        hCryptProv,                               //指定容器的CSP模組控制代碼
        AT_SIGNATURE,                         //指定私密金鑰的類型
        &hKey))                                //原來接收穫取的密鑰控制代碼
    {
        _tprintf(TEXT("A signature key is available./n"));
    }
    else
    {
        _tprintf(TEXT("No signature key is available./n"));
        if(GetLastError() == NTE_NO_KEY)              // NTE_NO_KEY意味著密鑰不存在,下面就產生一個密鑰
        {
           
            _tprintf(TEXT("The signature key does not exist./n"));
            _tprintf(TEXT("Create a signature key pair./n")); 
            if(CryptGenKey(                          // CryptGenKey產生一個密鑰
                hCryptProv,                          //指定CSP模組的控制代碼
                AT_SIGNATURE,                    //對於公開金鑰密碼系統,產生一個私密金鑰和一個公開金鑰,這個參數指定了這個密鑰是公開金鑰,於是產生了一個密碼對。如果不是公開金鑰系統,則指定了密碼演算法,具體看MSDN。
                0,                                 //指定了產生密鑰的類型,這個參數的說明挺多的,想擷取更為詳盡的資料請看MSDN。
                &hKey)) 
            {
                _tprintf(TEXT("Created a signature key pair./n"));
            }
            else
            {
                MyHandleError(TEXT("Error occurred creating a ")
                    TEXT("signature key./n")); 
            }
        }
        else
        {
            MyHandleError(TEXT("An error other than NTE_NO_KEY ")
                TEXT("getting a signature key./n"));
        }
    } // End if.

    _tprintf(TEXT("A signature key pair existed, or one was ")
        TEXT("created./n/n"));

        if(hKey)                              //將密鑰控制代碼銷毀
    {
        if(!(CryptDestroyKey(hKey)))
        {
            MyHandleError(TEXT("Error during CryptDestroyKey."));
        }

        hKey = NULL;
    } 

    下面這部分和上面是類似的,只不過密鑰類型不相同而已。
    if(CryptGetUserKey(
        hCryptProv,
        AT_KEYEXCHANGE,
        &hKey)) 
    {
        _tprintf(TEXT("An exchange key exists./n"));
    }
    else
    {
        _tprintf(TEXT("No exchange key is available./n"));

        // Check to determine whether an exchange key 
        // needs to be created.
        if(GetLastError() == NTE_NO_KEY) 
        { 
            // Create a key exchange key pair.
            _tprintf(TEXT("The exchange key does not exist./n"));
            _tprintf(TEXT("Attempting to create an exchange key ")
                TEXT("pair./n"));
            if(CryptGenKey(
                hCryptProv,
                AT_KEYEXCHANGE,
                0,
                &hKey)) 
            {
                _tprintf(TEXT("Exchange key pair created./n"));
            }
            else
            {
                MyHandleError(TEXT("Error occurred attempting to ")
                    TEXT("create an exchange key./n"));
            }
        }
        else
        {
            MyHandleError(TEXT("An error other than NTE_NO_KEY ")
                TEXT("occurred./n"));
        }
    }

    // Destroy the exchange key.
    if(hKey)
    {
        if(!(CryptDestroyKey(hKey)))
        {
            MyHandleError(TEXT("Error during CryptDestroyKey."));
        }

        hKey = NULL;
    }

    // Release the CSP.
    if(hCryptProv)
    {
        if(!(CryptReleaseContext(hCryptProv, 0)))
        {
            MyHandleError(TEXT("Error during CryptReleaseContext."));
        }
    } 
    
    _tprintf(TEXT("Everything is okay. A signature key "));
    _tprintf(TEXT("pair and an exchange key exist in "));
    _tprintf(TEXT("the %s key container./n"), pszContainerName);  
} // End main.
  下面我們再通過一個程式,用幾種不同的方法,將CryptAcquireContext和其他的API函數聯絡起來,看看它們是如何與一個CSP和容器工作的。這個程式示範了以下內容和幾個函數。
一.  用CryptAcquireContext擷取一個預設容器的預設CSP的控制代碼。如果預設容器不存在,用CryptAcquireContext建立一個。
二.  用CryptGetProvParam擷取CSP和容器的資訊。
三.  用CryptContextAddRef增加CSP的引用計數器的數值。
四.  用CryptAcquireContext建立一個指定的容器
五.  用CryptAcquireContext刪除一個容器
六.  用一個新建立的容器擷取一個CSP的控制代碼。
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Wincrypt.h>
異常處理函數省略
void main(void)
{
    
    HCRYPTPROV hCryptProv;                            //定義CSP控制代碼

    if(CryptAcquireContext(
        &hCryptProv, 
        NULL,                                           //預設容器
        NULL,                                           //預設CSP
        PROV_RSA_FULL, 
        0)) 
    {
        _tprintf(TEXT("CryptAcquireContext succeeded./n"));
    }
    else
    {
        if (GetLastError() == NTE_BAD_KEYSET)               //同樣,如果當不存在這樣的容器的時候,建立一個
        {
            if(CryptAcquireContext(
                &hCryptProv, 
                NULL, 
                NULL, 
                PROV_RSA_FULL, 
                CRYPT_NEWKEYSET))                     
            {
                _tprintf(TEXT("CryptAcquireContext succeeded./n"));
            }
            else
            {
                MyHandleError(TEXT("Could not create the default ")
                    TEXT("key container./n"));
            }
        }
        else
        {
            MyHandleError(TEXT("A general error running ")
                TEXT("CryptAcquireContext."));
        }
    }

    CHAR pszName[1000];
    DWORD cbName;

    cbName = 1000;
    if(CryptGetProvParam(
        hCryptProv,                                     //CSP模組控制代碼
        PP_NAME,                                     //指定擷取哪些資訊,這裡是指定擷取CSP名字的資訊
        (BYTE*)pszName,                               //緩衝區接受資訊傳回值
        &cbName, 
        0))
    {
        _tprintf(TEXT("CryptGetProvParam succeeded./n"));
        printf("Provider name: %s/n", pszName);
    }
    else
    {
        MyHandleError(TEXT("Error reading CSP name./n"));
    }

    //---------------------------------------------------------------
    // Read the name of the key container.
    cbName = 1000;
    if(CryptGetProvParam(
        hCryptProv, 
        PP_CONTAINER,                                       //擷取容器名字
        (BYTE*)pszName, 
        &cbName, 
        0))
    {
        _tprintf(TEXT("CryptGetProvParam succeeded./n"));
        printf("Key Container name: %s/n", pszName);
    }
    else
    {
        MyHandleError(TEXT("Error reading key container name./n"));
    }
    

    if(CryptContextAddRef(                       // CryptContextAddRef是向一個CSP的引用計數器增加一個值的函數
        hCryptProv, 
        NULL,                                //保留值,必須為NULL
        0))                     //保留值,必須為0
    {
        _tprintf(TEXT("CryptcontextAddRef succeeded./n"));
    }
    else
    {
        MyHandleError(TEXT("Error during CryptContextAddRef!/n"));
    }

    //---------------------------------------------------------------
    //  The reference count on hCryptProv is now greater than one. 
    //  The first call to CryptReleaseContext will not release the 
    //  provider handle. 

    //---------------------------------------------------------------
    //  Release the context once.
    if (CryptReleaseContext(hCryptProv, 0))                // CryptReleaseContext是用來釋放CSP控制代碼的,當這個函數調用一次的時候,CSP裡面的引用計數就減少一,當引用計數減少的0的時候。CSP將不能再被這個程式中的任何函數調用了。
    {
        _tprintf(TEXT("The first call to CryptReleaseContext ")
            TEXT("succeeded./n"));
    }
    else
    {
        MyHandleError(TEXT("Error during ")
            TEXT("CryptReleaseContext #1!/n"));
    }

    if (CryptReleaseContext(hCryptProv, 0))                //再次釋放CSP模組
    {
        _tprintf(TEXT("The second call to CryptReleaseContext ")
            TEXT("succeeded./n"));
    }
    else
    {
        MyHandleError(TEXT("Error during ")
            TEXT("CryptReleaseContext #2!/n"));
    }

   下面是從PROV_RSA_FULL的CSP模組中建立一個自己的容器
    LPCTSTR pszContainerName = TEXT("My Sample Key Container");

    hCryptProv = NULL;
    if(CryptAcquireContext(
        &hCryptProv, 
        pszContainerName,
        NULL, 
        PROV_RSA_FULL, 
        CRYPT_NEWKEYSET)) 
    {
        _tprintf(TEXT("CryptAcquireContext succeeded. /n"));
        _tprintf(TEXT("New key set created. /n")); 

        //-----------------------------------------------------------
        // Release the provider handle and the key container.
        if(hCryptProv)
        {
            if(CryptReleaseContext(hCryptProv, 0)) 
            {
                hCryptProv = NULL;
                _tprintf(TEXT("CryptReleaseContext succeeded. /n"));
            }
            else
            {
                MyHandleError(TEXT("Error during ")
                    TEXT("CryptReleaseContext!/n"));
            }
        }
    }
    else
    {
        if(GetLastError() == NTE_EXISTS)
        {
            _tprintf(TEXT("The named key container could not be ")
                TEXT("created because it already exists./n"));
            
        }
        else
        {
            MyHandleError(TEXT("Error during CryptAcquireContext ")
                TEXT("for a new key container."));
        }
    }

   
    if(CryptAcquireContext(
        &hCryptProv, 
        pszContainerName, 
        NULL, 
        PROV_RSA_FULL,
        0)) 
    {
        _tprintf(TEXT("Acquired the key set just created. /n"));
    }
    else
    {
        MyHandleError(TEXT("Error during CryptAcquireContext!/n"));
    }

    //---------------------------------------------------------------
    // Perform cryptographic operations.

    //---------------------------------------------------------------
       if(CryptReleaseContext(
        hCryptProv, 
        0)) 
    {
        _tprintf(TEXT("CryptReleaseContext succeeded. /n"));
    }
    else
    {
        MyHandleError(TEXT("Error during CryptReleaseContext!/n"));
    }

  
    if(CryptAcquireContext(
        &hCryptProv, 
        pszContainerName, 
        NULL, 
        PROV_RSA_FULL,
        CRYPT_DELETEKEYSET))                    //CRYPT_DELETEKEYSET意味著CryptAcquireContex刪除一個指定的容器
    {
        _tprintf(TEXT("Deleted the key container just created. /n"));
    }
    else
    {
        MyHandleError(TEXT("Error during CryptAcquireContext!/n"));
    }
}

就先寫到這,大家多提寶貴意見。附件中有這兩個程式編譯好的程式,來源程式就是文章中的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.