使用windows crypto API加密解密

文章一:使用windows crypto API加密解密

本文轉自: http://ticktick.blog.51cto.com/823160/168538

      最近在學習使用windows crypto API 對數據進行加密和解密,有些收穫和經驗,在此分享,希望對學習加密解密的朋友們有所幫助。
      經過這次windows crypto API的學習過程,讓我明白一個道理。其實,使用windows API編程並不難,首先要有信心。MSDN提供了詳細的幫助和指南,許多問題,只要詳細查閱MSND,完全可以不用在網上查找任何資料完成自己所需要的編程任務。
       網上的東西,許多都是來自別人的經驗介紹,很多,但也很雜,爲了搜索到真正有用的資料,往往需要花費很多的時間和精力。

       首先,大家不要覺得加密和解密是一件很深奧的事情,其實說白了,數據加密就是對原始數據進行一種變換而已,比如:你的密碼是123456,我對每一位都加1,即234567,寫到文件中,這就是加密,只要別人不知道你是對每一位都加1得到的234567,別人即使拿到你的密碼文件,他也不知道怎樣把你的密碼從234567解密出來。(當然,這種簡單的加密是可以很容易被破解的)

       數據加密主要分爲兩種,一種爲對稱加密,另一種爲非對稱加密。
       對稱加密主要用於大量數據的加密,加密和解密都使用同一份密鑰,密鑰其實就是一串數據,使用這一串數據對你要加密的數據進行與啊、或啊或者異或什麼的,於是就得到了一串人家看不懂的“密文”。

       非對稱加密最經典的應用場合是客戶端/服務器模式的系統,主要用於需要在網絡中傳送的少量數據進行加密(比如客戶端的用戶名、密碼向服務器傳送)。它使用兩份密鑰,公鑰和私鑰。
       公鑰用於發給客戶端,私鑰留在服務器端。數據經過公鑰加密後只能使用對應的私鑰來解密。
       因此,客戶端先對用戶名密碼信息使用公鑰加密,然後向服務器端發送,即使中途被黑客截獲,由於他沒有私鑰,故無法進行解密,當服務器端收到數據後,就使用自己的私鑰進行解密。這樣就可以實現所有的客戶端都使用公鑰進行加密,然後放心地發送數據到服務器端,因爲只有服務器端才能夠解密。(思考一下:這種場合如果使用對稱密鑰安全嗎?)

       windows crypto API提供了對稱加密和非對稱加密,並且提供了各種加密、解密的算法,要使用相應的算法進行加密解密,只需要對生成密鑰的函數的相關參數改變一下即可。
       爲了學習使用windows crypto API,我沿襲以前的習慣,花費了大量的時間在網上搜索資料(許多資料用處不大),最終還是在MSND的指導下完全掌握了crypto API的用法,不過,MSND還是有其不足之處,它詳細描述了crypto API相關的知識和信息,但沒有從宏觀上對實現用crypto API加密解密到底需要做哪些事情進行做出明確地指導,故在此,我用下面這幅流程圖來告訴大家。
 

         我只從宏觀上描述了整個加密解密需要進行的幾個流程,具體每一步的代碼怎麼寫,可以參考MSDN,或者本文後面鏈接的一份文檔(這份文檔講得非常詳細,也非常好,是我搜集的資料中最好的一份,希望對需要它的人有所幫助)
       當然,在學習和使用windows crypto API的過程中可能會遇到很多的問題,如果有什麼疑問,可以E—Mail給我。


附件下載:
  --CryptoAPI對數據進行加解密



文章二:使用Microsoft CryptoAPI進行加密、解密、簽名及驗證

本文轉自:http://blog.csdn.net/mmpire/article/details/1640670


使用CryptoAPI編寫一個文件保護程序,具有如下功能:
(1)給定明文文件,生成加密文件,同時產生文件的數字簽名文件;
(2)給定密文文件,解密出明文文件,並驗證簽名的正確性。
 
代碼:見所附main.cpp
 
一、    程序概況
a)    開發平臺:Visual Studio 2005
b)    開發語言:C/C++
c)    使用密碼庫:CryptoAPI
二、    主要函數
a)    主函數
void main(void)
b)    加密文件
BOOL EncryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword);
c)    解密文件
BOOL DecryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword);
d)    簽名文件
BOOL SignFile (PCHAR szSource, PCHAR szDestination);
e)    驗證簽名
BOOL VerifyFile (PCHAR szSource, PCHAR szDestination);
f)     錯誤處理
void HandleError(char *s);
 
 
 
三、    加密文件
a)    打開源文件
hSource = fopen(szSource,"rb")
b)    取得密鑰容器(CSP)句柄
CryptAcquireContext(&hCryptProv,NULL,NULL,PROV_RSA_FULL,0)
c)    根據用戶輸入的密碼創建一個會話密鑰(即對稱密鑰,用於對原文件加密)
//創建一個Hash對象
CryptCreateHash(hCryptProv,CALG_MD5, 0, 0, &hHash)
//用用戶輸入的密碼產生一個散列
CryptHashData(hHash, (BYTE *)szPassword, strlen(szPassword), 0)
//通過散列生成一個會話密鑰
CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM,hHash, KEYLENGTH, &hKey))
//銷燬Hash對象
CryptDestroyHash(hHash);
注:會話密鑰即對稱密鑰,用於對原文件進行加密;非對稱密鑰由於效率非常低,所以一般不用於對數據直接加密,而是對會話密鑰進行加密,然後把它傳送給對方。對方通過非對稱密鑰解密獲得這個會話密鑰,然後再對數據文件進行解密。可以看出,一個會話密鑰的生存期可以限制在這次通信中,即每次通信都用不同的會話密鑰加密,而非對稱密鑰則必須是長期使用的。在此例中,加解密過程中沒有使用到非對稱RSA密鑰對,而只在數字簽名及驗證使用它。
d)    加密數據文件
CryptEncrypt(
hKey,               //密鑰
0,                    //如果數據同時進行散列和加密,這裏傳入一個散列對象
feof(hSource), //如果是最後一個被加密的塊,輸入TRUE.如果不是輸
//FALSE這裏通過判斷是否到文件尾來決定是否爲最後一塊
0,                    //保留
pbBuffer,          //輸入被加密數據,輸出加密後的數據
&dwCount,       //輸入被加密數據實際長度,輸出加密後數據長度
dwBufferLen)    //pbBuffer的大小
注:查看完整代碼時可以發現這是一個循環加密的過程,pbBuffer循環讀入待加密文件的固定長度的內存塊;當然你也可以將pbBuffer設得很大,一次讀入整個文件,但那樣浪費內存空間,而且影響擴展性(存在緩衝區溢出的可能)。
e)    清理工作,如釋放Buffer空間、密鑰句柄、CSP句柄等。
if(pbBuffer)
free(pbBuffer);
if(hKey)
CryptDestroyKey(hKey);
if(hHash)
CryptDestroyHash(hHash);
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
            …
 
四、    解密文件
a)    打開加密文件(同上)
b)    取得密鑰容器(CSP)句柄(同上)
c)    根據用戶輸入的密碼創建一個會話密鑰(即對稱密鑰,用於對原文件解密)(同上)
注:這裏要求用戶輸入的密碼與加密時輸入的密碼相同。在實際應用中,這個所謂用戶輸入的“密碼”其實只是一個產生密鑰的種子,一旦產生完會話密鑰,則用戶完全可以忘記當初輸入的“密碼”,接收方可以使用傳過來的密鑰直接對加密文件進行解密,而不用再重複一次“生成密鑰”的過程。
d)    解密數據文件
CryptDecrypt(
hKey,               //密鑰
0,                    //如果數據同時進行散列和加密,這裏傳入一個散列對象
feof(hSource), //如果是最後一個被加密的塊,輸入TRUE.如果不是輸.
//FALSE這裏通過判斷是否到文件尾來決定是否爲最後一塊。
0,                    //保留
pbBuffer,          //輸入被加密數據,輸出加密後的數據
&dwCount))           //輸入被加密數據實際長度,輸出加密後數據長度
e)    清理工作,如釋放Buffer空間、密鑰句柄、CSP句柄等。(同上)
五、    簽名文件
a)    打開源文件(同上)
b)    取得密鑰容器(CSP)句柄(同上)
c)    取得簽名用的密鑰句柄(非對稱RSA密鑰)
CryptGetUserKey(
hCryptProv,               // 我們已經得到的CSP句柄
AT_SIGNATURE,            // 這裏想得到signature key pair
&hKey))                       // 返回密鑰句柄
d)    導出簽名用密鑰對的公鑰,保存在pbKeyBlob中
CryptExportKey(hKey, NULL,PUBLICKEYBLOB, 0, pbKeyBlob,&dwBlobLen)
e)    計算數據文件的Hash值,保存在Hash對象hHash中
//生成一個空的Hash對象
CryptCreateHash(hCryptProv,CALG_MD5,0,0,&hHash)
//計算數據文件的Hash值,保存在Hash對象中
CryptHashData(hHash,pbBuffer,dwCount,0)
f)     對數據文件的Hash值進行簽名,數字簽名保存在pbSignature中
CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pbSignature, &dwSigLen)
g)    清理工作,如釋放Buffer空間、密鑰句柄、CSP句柄等。(同上)
六、    驗證簽名
a)    打開文件(同上)
b)    取得密鑰容器(CSP)句柄(同上)
c)    導入 pbKeyBlob 公鑰
CryptImportKey(hCryptProv, pbKeyBlob, dwBlobLen, 0, 0, &hPubKey)
注:必須是與簽名時所用的私鑰配對的公鑰,在此例中,這個公鑰在生成數字簽名時已經導出到pbKeyBlob中。
d)    計算數據文件的Hash值,保存在Hash對象hHash中。(同上)
e)    驗證數字簽名
CryptVerifySignature(hHash, pbSignature, dwSigLen,hPubKey,NULL, 0)
f)     清理工作,如釋放Buffer空間、密鑰句柄、CSP句柄等。(同上)
七、    實驗結果
// 加密文件
Encrypt a file.
 
 
Enter the name of the file to be encrypted: 1.txt
 
Enter the name of the output file: 2.txt
 
Enter the password:123456
 
The source plaintext file, 1.txt, is open.
 
Destination file 2.txt is open.
A cryptographic provider has been acquired.
A hash object has been created.
The password has been added to the hash.
An encryption key is derived from the password hash.
Memory has been allocated for the buffer.
 
Encryption of the file 1.txt was a success.
 
The encrypted data is in file 2.txt.
 
//解密文件
Decrypt a file.
 
 
Enter the name of the file to be decrypted: 2.txt
 
Enter the name of the output file: 3.txt
 
Enter the password:123456
 
The source plaintext file, 2.txt, is open.
 
Destination file 3.txt is open.
A cryptographic provider has been acquired.
A hash object has been created.
The password has been added to the hash.
An encryption key is derived from the password hash.
Memory has been allocated for the buffer.
 
Decryption of the file 2.txt was a success.
 
The decrypted data is in file 3.txt.
 
//數字簽名
Sign a file.
 
 
Enter the name of the file to be signed: 1.txt
 
Enter the name of the signature file: 11
 
The source plaintext file, 1.txt, is open.
Memory has been allocated for the buffer.
 
Destination file 11 is open.
A cryptographic provider has been acquired.
A signature key is available.
Size of the BLOB for the public key determined.
Memory has been allocated for the BLOB.
Contents have been written to the BLOB.
Hash object created.
The data buffer has been hashed.
Signature length 128 found.
Memory allocated for the signature.
pbSignature is the hash signature.
The hash object has been destroyed.
The signing phase of this program is completed.
 
 
Signature of the file 1.txt was a success.
 
The signature data is in file 11.
 
//驗證簽名
Verify a file and its signature.
 
 
Enter the name of the file to be verified: 1.txt
 
Enter the name of the signature file: 11
 
The source plaintext file, 1.txt, is open.
Memory has been allocated for the buffer.
A cryptographic provider has been acquired.
The key has been imported.
The hash object has been recreated.
The new has been created.
The signature has been verified.
 
Verification of the file 1.txt was a success.
八、    參考資料
1)      Microsoft CryptoAPI加密技術
2)      MSDN


九、  代碼:

          http://blog.csdn.net/mmpire/article/details/1640670


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章