MicroSoft CryptoAPI data/file encrypt/decrypt
linux 用第三方庫 Crypto++, 還未實戰。
CryptoAPI使用兩種密鑰:會話密鑰與公共/私人密鑰對。會話密鑰使用相同的加密和解密密鑰,這種算法較快,但必須保證密鑰的安全傳遞。公共/私人密鑰對使用一個公共密鑰和一個私人密鑰,私人密鑰只有專人才能使用,公共密鑰可以廣泛傳播。如果密鑰對中的一個用于加密,另一個一定用于解密。公共/私人密鑰對算法很慢,一般只用于加密小批數據,例如用于加密會話密鑰。
#include <tchar.h> #include <stdio.h> #include <windows.h> #include <wincrypt.h>
//#include <conio.h>
//#pragma comment (lib, "advapi32")
#define KEYLENGTH 0x00800000
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
常用步驟:
一. 獲取容器handle
CryptAcquireContext(
&hCryptProv, //返回的CSP句柄,密鑰容器
NULL, //密鑰容器的名字
MS_ENHANCED_PROV, //這個參數這里用的是缺省值,指得是缺省得CSP模塊,你也可以傳入一個LPCTSTR類型的字符串,指定CSP模塊
PROV_RSA_FULL, //這里為使用的加密策略 0
);
返回true, 則正常; false, 則異常
二. 創建密鑰
1. 根據固定password, 主要用于對稱加密
//初始化一個HASH對象,產生一個空的HASH對象
CryptCreateHash(
hCryptProv, //密鑰容器句柄
CALG_MD5, //指定的hash算法
0,
0,
&hHash //hash句柄
);
//對數據使用hash后, 保存在hHash中
CryptHashData(
hHash,
(BYTE *)pszPassword, //LPTSTR pszPassword
lstrlen(pszPassword),
0
);
//利用hash對象生成密鑰
CryptDeriveKey( //從某一數據產生會話密鑰。有點類似CryptGenKey,但是產生的會話密鑰來自固定數據,而CryptGenKey是隨機產生的。并且不能產生公 / 私鑰對
hCryptProv, //密鑰容器句柄
ENCRYPT_ALGORITHM, //in,指定的算法,類似CryptGenKey
hHash, //in,HASH對象的句柄
KEYLENGTH, //in,指定產生密鑰的類型
&hKey); //in, out, 產生的密鑰句柄地址
2. 隨機產生, 每次產生都不一樣,解密時,要根據獲取的blob解密, 主要用于非對稱加密
//產生一個隨機的交換密鑰或者公/私鑰對
CryptGenKey(
hCryptProv, //密鑰容器句柄
ENCRYPT_ALGORITHM, //表明產生私鑰所使用的算法或者公鑰生成的算法
KEYLENGTH | CRYPT_EXPORTABLE, //表示密鑰使用的長度,參數可以為0,采用默認的密鑰長度
&hKey //獲取密鑰句柄
);
//獲取交換密鑰
CryptGetUserKey(
hCryptProv, //密鑰容器句柄
AT_KEYEXCHANGE, //AT_KEYEXCHANGE(交換密鑰) or AT_SIGNATURE(簽名密鑰)
&hXchgKey //獲取交換密鑰
);
//以下3步是用交換密鑰將密鑰加密后,存儲到Blob
a. 導出密鑰只是先獲取導出key Blob的長度
CryptExportKey(
hKey, //需要導出的密鑰句柄
hXchgKey, //將待導出密鑰用交換密鑰進行加密,假如是公開的BLOG當然就設置為0
SIMPLEBLOB, // 指定導出的密鑰BLOB類型,BLOB也就是一種存儲結構。六個參數見MSDN
0,
NULL, //導出的數據指針,以后就可以將這個數據寫如磁盤或者別的任務
&dwKeyBlobLen //導出的數據長度
);
b. 為Blob分配內存
pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen);
c. 用交換密鑰加密后,存儲到Blob
CryptExportKey( hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwKeyBlobLen);
//釋放交換密鑰 if(hXchgKey)
CryptDestroyKey(hXchgKey);
//創建導出的Keyblob目標文件
hexportkeyDestinationFile = CreateFile(pszexportkeyDestination, FILE_WRITE_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
//將keyblob長度保存到文件中
WriteFile( hexportkeyDestinationFile, &dwKeyBlobLen, sizeof(DWORD), &dwCount, NULL)
//將keyblob內容寫入
WriteFile( hexportkeyDestinationFile, pbKeyBlob, dwKeyBlobLen, &dwCount, NULL);
free(pbKeyBlob);
3. 根據key產生固定的blob產生, 用于對稱加密
#define ENCRYPT_ALGORITHM CALG_DES
#define ENCRYPT_BLOCK_SIZE 8
#define KEYSIZE 8
typedef struct _stKeyBlob
{
BLOBHEADER hdr;
DWORD cbKeySize;
BYTE rgbKeyData[KEYSIZE];
_stKeyBlob()
{
hdr.bType = PLAINTEXTKEYBLOB;
hdr.bVersion = CUR_BLOB_VERSION;
hdr.reserved = 0;
hdr.aiKeyAlg = ENCRYPT_ALGORITHM;
cbKeySize = KEYSIZE;
memset(rgbKeyData, 0, KEYSIZE);
}
} stKeyBlobType; //結構參考MSDN - CryptImportKey
XML_EnDecryption::XML_EnDecryption(BYTE pbKey[], DWORD dwKeyLen)
{
init(); m_pstKeyBlob = new stKeyBlobType();
memcpy(m_pstKeyBlob->rgbKeyData, pbKey, dwKeyLen > KEYSIZE ? KEYSIZE : dwKeyLen);
if (!CryptImportKey(m_hProv, (BYTE*)m_pstKeyBlob, sizeof(stKeyBlobType), 0, 0, &m_hKey))
{
}
}
三. 解密
經過一和二,the session key(會話密鑰)就創建好了,如果不是隨機產生出來的,the session key(會話密鑰)就被寫到文件中或保存起來以便解密時用
由password或key產生的hKey, 可由CrytImportKey導入
CryptImportKey(m_hProv, (BYTE*)m_pstKeyBlob, sizeof(stKeyBlobType), 0, 0, &m_hKey)); //獲取key句柄
四. 代碼
1. 根據key產生固定的blob
#ifndef _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894FJ3F23OFJ230FJFJWEFJWWEFWE
#define _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894FJ3F23OFJ230FJFJWEFJWWEFWE
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
//#include <conio.h>
//#pragma comment (lib, "advapi32")
//#define KEYLENGTH 0x00800000 #define ENCRYPT_ALGORITHM CALG_DES #define ENCRYPT_BLOCK_SIZE 8
#define KEYSIZE 8
typedef struct _stKeyBlob
{
BLOBHEADER hdr;
DWORD cbKeySize;
BYTE rgbKeyData[KEYSIZE];
_stKeyBlob()
{
hdr.bType = PLAINTEXTKEYBLOB;
hdr.bVersion = CUR_BLOB_VERSION;
hdr.reserved = 0;
hdr.aiKeyAlg = ENCRYPT_ALGORITHM;
cbKeySize = KEYSIZE;
memset(rgbKeyData, 0, KEYSIZE);
}
} stKeyBlobType; //結構參考MSDN - CryptImportKey
class XML_EnDecryption
{
public:
XML_EnDecryption(BYTE pbKey[] = NULL, DWORD dwKeyLen = 0);
virtual ~XML_EnDecryption();
void GetLastCryptError(LPTSTR psz, int nErrorNumber);
BOOL DES(__in const BYTE* pbData, __in DWORD cbDataLen, __out BYTE* pbBuf, __inout DWORD* pcbBufLen, __in BOOL bIsDecrypt = FALSE, __in BOOL isLast = TRUE);
void GetBufferLen(__in const BYTE* pbData, __in DWORD cbDataLen, DWORD* pBufferLen);
BOOL XmlEncDec(LPTSTR pszSourceFile, LPTSTR pszDestinationFile, BOOL isDecrypt = FALSE);
private:
bool init();
bool InitialCSP();
bool IsCSPValided();
bool ReleaseCSP();
private:
HCRYPTPROV m_hProv;
bool m_bAcquireContextOK;
HCRYPTKEY m_hKey;
DWORD m_dwLastError;
stKeyBlobType* m_pstKeyBlob;
};
#endif //_PUBLIC_H_EFOFWEJOSDJFJ3933F3F894FJ3F23OFJ230FJFJWEFJWWEFWE
2. 根據password, hash后得到hKey
#ifndef _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894PEPROGEPROGPOEPWEOVWOEVOWEV
#define _XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894PEPROGEPROGPOEPWEOVWOEVOWEV
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
//#include <conio.h>
//#pragma comment (lib, "advapi32")
#define KEYLENGTH 0x00800000
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 8
class XML_EnDecryption
{
public:
XML_EnDecryption(LPTSTR m_pszPassword);
virtual ~XML_EnDecryption();
void GetBufferLen(__in const BYTE* pbData, __in DWORD cbDataLen, DWORD* pBufferLen);
BOOL DES(__in const BYTE* pbData, __in DWORD cbDataLen, __out BYTE* pbBuf, __inout DWORD* pcbBufLen, __in BOOL bIsDecrypt = FALSE, __in BOOL isLast = TRUE);
BOOL XmlDes(LPTSTR pszSourceFile, LPTSTR pszDestinationFile, BOOL isDecrypt = FALSE);
void GetLastCryptError(LPTSTR psz, int nErrorNumber); private: // int getKey(); bool HashPassword();
private:
bool init();
bool ReleaseCSP();
bool InitialCSP();
bool IsCSPValided();
private:
HCRYPTPROV m_hProv;
bool m_bAcquireContextOK;
HCRYPTHASH m_hHash;
HCRYPTKEY m_hKey;
DWORD m_dwLastError;
LPTSTR m_pszPassword;
};
#endif //_XMLENCDEC_H_EFOFWEJOSDJFJ3933F3F894PEPROGEPROGPOEPWEOVWOEVOWEV
3. 隨機產生hKey, 每次都不一樣
來自微軟的例子。
https://docs.microsoft.com/zh-cn/windows/desktop/SecCrypto/example-c-program-encrypting-a-file
https://docs.microsoft.com/zh-cn/windows/desktop/SecCrypto/example-c-program-decrypting-a-file
浙公網安備 33010602011771號