基本加密函數爲開發加密應用程序提供了足夠靈活的空間。所有CSP的通訊都是通過這些函數。一個CSP是實現所有加密操作的獨立模塊。在每一個應用程序中至少需要提供一個CSP來完成所需的加密操作。如果使用多於一個以上的CSP,在加密函數調用中就要指定所需的CSP。微軟基本加密提供者(Microsoft Base Cryptographic Provider),是缺省綁定到CryptoAPI 裏的。如果沒有指定其他CSP時,這個CSP 就是卻省的。每一個CSP對CryptoAPI 提供了一套不同的實現。一些提供了更加強大的加密算法,而其他一些CSP包含了對硬件的支持,比如智能卡。另外,一些CSP 偶爾和使用者直接通訊,比如數字簽名就使用了用戶的簽名私鑰。
基本加密函數包含了以下幾種:
1.1服務提供者函數
應用程序使用服務提供者函數來連接和斷開一個CSP。下面就是主要的API:
CryptAcquireContext獲得指定CSP的密鑰容器的句柄
CryptContextAddRef對HCRYPTPROV句柄增加一個應用計數
CryptEnumProviders枚舉當前計算機中的CSP
CryptEnumProviderTypes枚舉CSP的類型
CryptGetDefaultProvider對於指定CSP類型的卻省CSP
CryptGetProvParam得到一個CSP的屬性
CryptInstallDefaultContext安裝先前得到的HCRYPTPROV上下文作爲當前卻省的上下文
CryptReleaseContext釋放由CryptAcquireContext得到的句柄
CryptSetProvider和CryptSetProviderEx爲指定CSP類型指定一個卻省的CSP
CryptSetProvParam指定一個CSP的屬性
CryptUninstallDefaultContext刪除先前由CryptInstallDefaultContext安裝的卻省上下文
1.2密鑰的產生和交換函數
密鑰產生函數創建、配置和銷燬加密密鑰。他們也用於和其他用戶進行交換密鑰。下面就是主要的一些函數:
CryptAcquireCertificatePrivateKey對於指定證書上下文得到一個HCRYPTPROV句柄和dwKeySpec
CryptDeriveKey從一個密碼中派生一個密鑰
CryptDestoryKey銷燬密鑰
CryptDuplicateKey製作一個密鑰和密鑰狀態的精確複製
CryptExportKey把CSP的密鑰做成BLOB 傳送到應用程序的內存空間中
CryptGenKey創建一個隨機密鑰
CryptGenRandom產生一個隨機數
CryptGetKeyParam得到密鑰的參數
CryptGetUserKey得到一個密鑰交換或簽名密鑰的句柄
CryptImportKey把一個密鑰BLOB傳送到CSP 中
CryptSetKeyParam指定一個密鑰的參數
1.3編碼/解碼函數
有一些編碼/解碼函數,他們可以用來對證書、證書撤銷列表、證書請求和證書擴展進行編碼和解碼。
以下就是這幾個函數:
CryptDecodeObject對lpszStructType結構進行解碼
CryptDecodeObjectEx對lpszStructType結構進行解碼,此函數支持內存分配選項
CryptEncodeObject對lpszStructType結構進行編碼
CyptEncodeObjectEx對lpszStructType結構進行編碼,此函數支持內存分配選項
1.4數據加密/解密函數
這些函數支持數據的加密/解密操作。
CryptEncrypt 和CryptDecrypt 要求在被調用前指定一個密鑰。
注:這個密鑰可以由CryptGenKey、CryptDeriveKey 或CryptImportKey 產生。創建密鑰時要指定加密算法。
CryptSetKeyParam函數可以指定額外的加密參數。
CryptDecrypt使用指定加密密鑰來解密一段密文
CryptEncrypt使用指定加密密鑰來加密一段明文
CryptProtectData執行對DATA_BLOB結構的加密
CryptUnprotectData執行對DATA_BLOB結構的完整性驗證和解密
1.5哈希和數字簽名函數
這些函數在應用程序中完成計算哈希、創建和校驗數字簽名。
CryptCreateHash創建一個空哈希對象
CryptDestoryHash銷燬一個哈希對象
CryptDuplicateHash複製一個哈希對象
CryptGetHashParam得到一個哈希對象參數
CryptHashData對一塊數據進行哈希,把它加到指定的哈希對象中
CryptHashSessionKey對一個會話密鑰進行哈希,把它加到指定的哈希對象中
CryptSetHashParam設置一個哈希對象的參數
CryptSignHash對一個哈希對象進行簽名
CryptVerifySignature校驗一個數字簽名
1.6函數詳解
1.6.1獲得CSP密鑰容器句柄
1.6.1.1 CryptAcquireContext
BOOL WINAPI CryptAcquireContext(
HCRYPTPROV *phProv,
LPCTSTR pszContainer,
LPCTSTR pszProvider,
DWORD dwProvType,
DWORD dwFlags
);
參數:
phProv[out] CSP句柄指針
pszContainer[in]密鑰容器名稱, 指向密鑰容器的字符串指針。如果dwFlags爲CRYPT_VERIFYCONTEXT,pszContainer必須爲NULL。
pszProvider[in]指向CSP名稱的字符串指針。如果爲NULL,就使用卻省的CSP。
dwProvType[in]CSP類型。下表是就中常見的CSP類型
CSP類型 | 交換算法 | 簽名算法 | 對稱加密算法 | Hash算法 |
PROV_RSA_FULL | RSA | RSA | RC2 | MD5 |
PROV_RSA_SIG | none | RSA | none | MD5 |
PROV_RSA_SCHANNEL | RSA | RSA | RC4 | MD5 |
PROV_DSS | DSS | none | DSS | MD5 |
PROV_DSS_DH | DH | DSS | CYLINK_MEK | MD5 |
PROV_DH_SCHANNEL | DH | DSS | DES | MD5 |
PROV_FORTEZZA | KEA | DSS | Skipjack | SHA |
PROV_MS_EXCHANGE | RSA | RSA | CAST | MD5 |
PROV_SSL | RSA | RSA | Varies | Varies |
dwFlags[in]標誌:
CRYPT_VERIFYCONTEXT | 指出應用程序不需要使用公鑰/私鑰對,如程序只執行哈希和對稱加密。只有程序需要創建簽名和解密消息時才需要訪問私鑰。 |
CRYPT_NEWKEYSET | 使用指定的密鑰容器名稱創建一個新的密鑰容器。如果pszContainer爲NULL,密鑰容器就使用卻省的名稱創建。 |
CRYPT_MACHINE_KEYSET | 由此標誌創建的密鑰容器只能由創建者本人或有系統管理員身份的人使用。 |
CRYPT_DELETEKEYSET | 刪除由pszContainer指定的密鑰容器。如果pszContainer 爲NULL,缺省名稱的容器就會被刪除。此容器裏的所有密鑰對也會被刪除。 |
CRYPT_SLIENT | 應用程序要求CSP不顯示任何用戶界面。 |
說明:
這個函數是用來取得指定CSP密鑰容器句柄,以後的任何加密操作就是針對此CSP 句柄而言。函數首先查找由dwProvType和pszProvider 指定的CSP,如果找到了CSP,函數就查找由此CSP指定的密鑰容器。由適當的dwFlags 標誌,這個函數就可以創建和銷燬密鑰容器,如果不要求訪問私鑰的話,也可以提供對CSP臨時密鑰容器的訪問。
1.6.1.2 CryptReleaseContext
BOOL WINAPI CryptReleaseContext(
HCRYPTPROV hProv,
DWORD dwFlags
);
參數:
hProv[in]由CryptAcquireContext獲得的CSP 句柄。
dwFlags[in]保留。必須爲0。
說明:
此函數釋放CSP的句柄。對於每一次調用,CSP 的引用計數都減1。當引用計數爲0時,CSP上下文就會被系統釋放變成無效句柄,以後針對此CSP 句柄的函數不再可用。
此函數並不銷燬密鑰容器或密鑰對。
//--------------------------------------------------------------------
HCRYPTPROV hCryptProv;
if (CryptAcquireContext(
hCryptProv, NULL,
MS_DEF_PROV,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
CryptReleaseContext(hCryptProv, NULL);
1.6.2枚舉CSP
4.1.6.2.1 CryptEnumProviders
BOOL WINAPI CryptEnumProviders(
DWORD dwIndex,
DWORD *pdwReserved,
DWORD dwFlags,
DWORD *pdwProvType,
LPTSTR pszProvName,
DWORD *pcbProvName
);
參數:
dwIndex[in]枚舉下一個CSP的索引。
pdwReserved[in]保留。必須爲NULL。
dwFlags[in]保留。必須爲NULL。
pdwProvType[out]CSP的類型。
pszProvName[out]指向接收CSP名稱的緩衝區字符串指針。此指針可爲NULL,用來得到字符串的大小。
pcbProvName[in/out]指出pszProvName字符串的大小。
說明:
此函數得到第一個或下一個可用的CSP。如果使用循環,就可以得到計算機上所有可用的CSP。
1.6.3獲得CSP參數
4.1.6.3.1 CryptGetProvParam
BOOL WINAPI CryptGetProvParam(
HCRYPTPROV hProv,
DWORD dwParam,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwFlags
);
參數:
hProv[in]CSP句柄。
dwParam[in]指定查詢的參數。
參數名 | 作用 |
PP_CONTAINER | 指向密鑰名稱的字符串 |
PP_ENUMALGS | 不斷的讀出CSP支持的所有算法 |
PP_ENUMALGS_EX | 比PP_ENUMALGS獲得更多的算法信息 |
PP_ENUMCONTAINERS | 不斷的讀出CSP支持的密鑰容器 |
PP_IMPTYPE | 指出CSP怎樣實現的 |
PP_NAME | 指向CSP名稱的字符串 |
PP_VERSION | CSP的版本號 |
PP_KEYSIZE_INC | AT_SIGNATURE的位數 |
PP_KEYX_KEYSIZE_INC | AT_KEYEXCHANGE的位數 |
PP_KEYSET_SEC_DESCR | 密鑰的安全描述符 |
PP_UNIQUE_CONTAINER | 當前密鑰容器的唯一名稱 |
PP_PROVTYPE | CSP類型 |
PP_USE_HARDWARE_RNG | 指出硬件是否支持隨機數發生器 |
PP_KEYSPEC | 返回CSP密鑰的信息 |
pbData[out]指向接收數據的緩衝區指針。
pdwDataLen[in/out]指出pbData數據長度。
dwFlags[in]如果指定PP_ENUMCONTAINERS,就指定CRYPT_MACHINE_KEYSET。
說明:
此函數獲得CSP的各種參數。
- //-----------------------------------------------------------------
- //
- HCRYPTPROV hCryptProv;
- BYTE pbData[1000];
- DWORD cbData;
- //-------------------------------------------------------------------
- //缺省CSP名稱
- cbData = 1000;
- if(CryptGetProvParam(
- hCryptProv,
- PP_NAME,
- pbData,
- &cbData,
- 0))
- {
- printf("CryptGetProvParam succeeded.\n");
- printf("Provider name: %s\n", pbData);
- }
- else
- {
- printf("Error reading CSP name. \n");
- exit(1);
- }
- //--------------------------------------------------------------------
- cbData = 1000;
- if(CryptGetProvParam(
- hCryptProv,
- PP_CONTAINER,
- pbData,
- &cbData,
- 0))
- {
- printf("CryptGetProvParam succeeded. \n");
- printf("Key Container name: %s\n", pbData);
- }
- else
- {
- printf("Error reading key container name. \n");
- exit(1);
- }
4.1.6.4創建哈希
4.1.6.4.1 CryptCreateHash
BOOL WINAPI CryptCreateHash(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTKEY hKey,
DWORD dwFlags,
HCRYPTHASH *phHash
);
參數:
hProv[in]CSP句柄
Algid[in]哈希算法的標示符。
hKey[in]如果哈希算法是密鑰哈希,如HMAC或MAC 算法,就用此密鑰句柄傳遞密鑰。對於非密鑰算法,此參數爲NULL。
dwFlags[in]保留。必須爲0。
phHash[out]哈希對象的句柄。
說明:
此函數初始化哈希數據流。它創建並返回了一個CSP哈希對象的句柄。此句柄由CryptHashData和CryptHashSessionKey來調用。
4.1.6.4.2 CryptHashData
BOOL WINAPI CryptHashData(
HCRYPTHASH hHash,
BYTE *pbData,
DWORD dwDataLen,
DWORD dwFlags
);
參數:
hHash[in]哈希對象句柄
pbData[in]指向要加入到哈希對象的數據指針
dwDataLen[in]數據長度
dwFlags[in]標誌
CRYPT_USERDATA所有微軟CSP都忽略此參數。所有其他CSP 都不能忽略此參數,如果置此參數,CSP提示用戶直接數據數據。
說明:
此函數把一段數據加入到指定的哈希對象中去。
4.1.6.4.3 CryptGetHashParam
BOOL WINAPI CryptGetHashParam(
HCRYPTHASH hHash,
DWORD dwParam,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwFlags
);
參數:
hHash[in]哈希對象的句柄
dwParam[in]查詢類型。可以是下列:
參數名稱 | 作用 |
HP_ALGID | 哈希算法 |
HP_HASHSIZE | 哈希值長度 |
HP_HASHVAL | 哈希值,由hHash指定的哈希值或者消息哈希 |
說明:
此函數得到指定哈希對象的數據。
4.1.6.4.4 CryptDestroyHash
BOOL WINAPI CryptDestroyHash(
HCRYPTHASH hHash
);
參數:
hHash[in]要銷燬的哈希對象句柄
說明:
此函數銷燬由hHash指定的哈希對象。當一個哈希對象被銷燬後,它對程序來說不可用。
- …
- HCRYPTHASH hCryptHash;
- if (CryptCreateHash(
- hCryptProv,
- CALG_MD5,
- 0,
- 0,
- &hCryptHash
- ))
- CryptDestroyHash(hCryptHash);
- …
4.1.6.5派生密鑰
4.1.6.5.1 CryptDeriveKey
BOOL WINAPI CryptDeriveKey(
HCRYPTPROV hProv,
ALG_ID Algid,
HCRYPTHASH hBaseData,
DWORD dwFlags,
HCRYPTKEY *phKey
);
參數:
hProv[in]CSP句柄
Algid[in]要產生密鑰的對稱加密算法
hBaseData[in]哈希對象的句柄
dwFlags[in]指定密鑰的類型
參數 | 作用 |
CRYPT_CREATE_SALT | 由哈希值產生一個會話密鑰,有一些需要補位。如果用此標誌,密鑰將會賦予一個鹽值 |
CRYPT_EXPORTABLE | 如果置此標誌,密鑰就可以用CryptExportKey函數導出。 |
CRYPT_NO_SALT | 如果置此標誌,表示40位的密鑰不需要分配鹽值。 |
CRYPT_UPDATE_KEY | 有些CSP從多個哈希值中派生會話密鑰。如果這種情況,CryptDeriveKey需要多次調用。 |
phKey[in/out]密鑰的句柄
說明:
此函數從一基本數據值中派生會話密鑰。函數保證當CSP和算法相同時,從相同基本數據值中產生的密鑰是唯一的。
4.1.6.5.2 CryptDestroyKey
BOOL WINAPI CryptDestroyKey(
HCRYPTKEY hKey
);
參數:
hKey[in]需要銷燬的密鑰句柄
說明:
此函數釋放密鑰句柄。
- …
- HCRYPTKEY hCryptKey;
- if (CryptDeriveKey(hCryptProv, m_algid, m_hHash, 0, &hCryptKey))
- CryptDestroyKey(hCryptKey);
- …
4.1.6.6加密/解密
4.1.6.6.1 CryptEncrypt
BOOL WINAPI CryptEncrypt(
HCRYPTKEY hKey,
HCRYPTHASH hHash,
BOOL Final,
DWORD dwFlags,
BYTE *pbData,
DWORD *pdwDataLen,
DWORD dwBufLen
);
參數:
hKey[in]加密密鑰的句柄
hHash[in]哈希對象的句柄。如果數據需要同時被哈希並且加密,hHash就指出了哈希對象。
Final[in]指出是否是最後一次加密操作。如果Final爲TRUE,就爲最後一次,否則爲FALSE。
dwFlags[in]保留
pbData[in/out]指向被加密的數據地址。
pdwDataLen[in/out]指向一個DWORD值的地址。在調用此函數前,這個值就是需要加密的數據長度。在調用此函數後,這個值就是已經加密的數據長度。如果此值爲NULL,函數就返回需要數據的長度。
dwBufferLen[in]指出pbData的數據長度。
說明:
此函數用於加密數據。加密數據所需要的算法由hKey的密鑰指定。
4.1.6.6.2 CryptDecrypt
BOOL WINAPI CryptDecrypt(
HCRYPTKEY hKey,
HCRYPTHASH hHash,
BOOL Final,
DWORD dwFlags,
BYTE *pbData,
DWORD *pdwDataLen
);
參數:
hKey[in]解密密鑰的句柄
hHash[in]哈希對象的句柄。如果需要解密數據並且同時作哈希,hHash傳遞此參數。
Final[in]指出是否是最後一次解密操作。
dwFlags[in]保留
pbData[in/out]需要解密數據的地址
pdwDataLen[in/out]指向DWORD值的指針,此值指出解密數據的長度。在調用此函數前,此值爲需要解密數據的長度,調用此函數後,此值爲已經解密的數據長度。
說明:
此函數對由CryptEncrypt加密過的數據進行解密。
- //---------------------------------------------------
- HCRYPTPROV hCryptProv;
- HCRYPTHASH hCryptHash;
- HCRYPTKEY hCryptKey;
- CryptAcquireContext(
- hCryptProv, NULL,
- MS_DEF_PROV,
- PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT);
- CryptCreateHash(
- hCryptProv,
- CALG_MD5,
- 0,
- 0,
- &hCryptHash
- );
- static char szHash[]=”PISAHASHDATA”; //原始字符串
- DWORD dwLen=strlen(szHash);
- CryptHashData(hCryptHash, (BYTE*)szHash, dwLen, 0);
- CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0, &hCryptKey);
- static char szEntry[]=“PISA2002”;
- DWORD dwLenIn = strlen(szEntry);
- DWORD dwLenOut=dwLenIn;
- CryptEncrypt(hCryptKey, 0, TRUE, 0, (BYTE*)szEntry, &dwLenOut, dwLenIn);
- CryptDecrypt(hCryptKey, 0, TRUE, 0,(BYTE*)szEntry,&dwLenOut);
- CryptDestroyKey(hCryptKey);
- CryptDestroyHash(hCryptHash);
- CryptReleaseContext(hCryptProv, NULL);
4.1.6.7簽名/驗證
4.1.6.7.1 CryptSignMessage
BOOL WINAPI CryptSignMessage(
PCRYPT_SIGN_MESSAGE_PARA pSignPara,
BOOL fDetachedSignature,
DWORD cToBeSigned,
const BYTE *rgpbToBeSigned[ ],
DWORD rgcbToBeSigned[ ],
BYTE *pbSignedBlob,
DWORD *pcbSignedBlob
);
參數:
pSignPara[in]指向CRYPT_SIGN_MESSAGE_PARA結構的指針。
CRYPT_SIGN_MESSAGE_PARA結構如下:
- typedef struct _CRYPT_SIGN_MESSAGE_PARA {
- DWORD cbSize;
- DWORD dwMsgEncodingType;
- PCCERT_CONTEXT pSigningCert;
- CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
- void *pvHashAuxInfo;
- DWORD cMsgCert;
- PCCERT_CONTEXT *rgpMsgCert;
- DWORD cMsgCrl;
- PCCRL_CONTEXT *rgpMsgCrl;
- DWORD cAuthAttr;
- PCRYPT_ATTRIBUTE rgAuthAttr;
- DWORD cUnauthAttr;
- PCRYPT_ATTRIBUTE rgUnauthAttr;
- DWORD dwFlags;
- DWORD dwInnerContentType;
- #ifdef CRYPT_SIGN_MESSAGE_PARA_HAS_CMS_FIELDS
- CRYPT_ALGORITHM_IDNETIFIER HashEncryptionAlgorithm;
- void pvHashEncryptionAuxInfo;
- #endif
- } CRYPT_SIGN_MESSAGE_PARA, *PCRYPT_SIGN_MESSAGE_PARA;
cbSize此結構的大小。
dwMsgEncodingType使用的編碼類型。一般爲X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
pSigningCert指向要簽名的CERT_CONTEXT指針。
HashAlgorithm CRYPT_ALGORITHM_IDENTIFIER指出了對要進行簽名的數據進行哈希的哈希算法
pvHashAuxInfo必須爲NULL
cMsgCert rgpMsgCert數組中CERT_CONTEXT結構的元素數量。如果此值爲0,則簽名消息中不包含任何證書。
rgpMsgCert指向CERT_CONTEXT的數組指針。如果包含pSigningCert,它的指針必須放到rgpMsgCert數組中。
cMsgCrl rgpMsgCrl數組指向CRL_CONTEXT結構的元素數量。如果爲0,簽名消息中不包含任何CRL_CONTEXT結構。
rgpMsgCrl 指向CRL_CONTEXT結構的數組指針。
cAuthAttr必須爲0
rgAuthAttr指向CRYPT_ATTRIBUTE數組的指針。每一次都包含了認證信息。
cUnauthAttrrg UnauthAttr數組大小。
rgUnauthAttr指向CRYPT_ATTRIBUTE結構的數組指針。
dwFlags通常爲0。
dwInnerContentType通常爲0。
HashEncryptionAlgorithm CRYPT_ALGORITHM_IDENTIFIER結構。通常爲0
pvHashEncryptionAuxInfo必須爲0。
fDetachedSignature[in]如果爲TRUE,就是已解邦定的簽名,否則爲FALSE。如果此參數爲TRUE,
pbSignedBlob中只有簽名哈希。否則rgpbToBeSigned和簽名哈希都要被編碼。
cToBeSigned[in]指出rgpbToBeSigned數據元素的個數。除非fDetachedSigned 爲TRUE,此參數就是1。
rgpbToBeSigned[in]指向要簽名數據的數組指針。
pbSignedBlob[out]指向一個接收簽名哈希的數據地址。如果此參數爲NULL,就是需要來接收數據的內存大小。
pcbSignedBlob[in/out]指向DWORD的地址,此數據指出pbSignedBlob 的大小。
說明:
此函數對指定數據進行哈希,然後對哈希值進行簽名,然後對原始消息和簽名哈希進行編碼。
- //--------------------------------------------------------------------
- …
- #define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
- #define SIGNER_NAME L"Insert_signer_name_here"
- #define CERT_STORE_NAME L"MY"
- void HandleError(char *s);
- void main(void)
- {
- //系統證書庫句柄
- HCERTSTORE hStoreHandle;
- //--------------------------------------------------------------------
- //待簽名的消息
- BYTE* pbMessage =
- (BYTE*)"CryptoAPI is a good way to handle security";
- //--------------------------------------------------------------------
- DWORD cbMessage = strlen((char*) pbMessage)+1;
- //--------------------------------------------------------------------
- //證書的上下文
- PCCERT_CONTEXT pSignerCert;
- CRYPT_SIGN_MESSAGE_PARA SigParams;
- DWORD cbSignedMessageBlob;
- BYTE *pbSignedMessageBlob;
- DWORD cbDecodedMessageBlob;
- BYTE *pbDecodedMessageBlob;
- CRYPT_VERIFY_MESSAGE_PARA VerifyParams;
- //--------------------------------------------------------------------
- const BYTE* MessageArray[] = {pbMessage};
- DWORD MessageSizeArray[1];
- MessageSizeArray[0] = cbMessage;
- //--------------------------------------------------------------------
- //
- printf("Begin processing. \n");
- printf(" The message to be signed is\n-> %s.\n",pbMessage);
- //--------------------------------------------------------------------
- // Open a certificate store.
- if ( !( hStoreHandle = CertOpenStore(
- CERT_STORE_PROV_SYSTEM,
- 0,
- NULL,
- CERT_SYSTEM_STORE_CURRENT_USER,
- CERT_STORE_NAME)))
- {
- HandleError("The MY store could not be opened.");
- }
- //--------------------------------------------------------------------
- //
- //得到證書的上下文,此證書必須能訪問簽名者的私鑰
- if(pSignerCert = CertFindCertificateInStore(
- hStoreHandle,
- MY_TYPE,
- 0,
- CERT_FIND_SUBJECT_STR,
- SIGNER_NAME,
- NULL))
- {
- printf("The signer's certificate was found.\n");
- }
- else
- {
- HandleError( "Signer certificate not found.");
- }
- //--------------------------------------------------------------------
- //初始化簽名結構
- SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
- SigParams.dwMsgEncodingType = MY_TYPE;
- SigParams.pSigningCert = pSignerCert;
- SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;
- SigParams.HashAlgorithm.Parameters.cbData = NULL;
- SigParams.cMsgCert = 1;
- SigParams.rgpMsgCert = &pSignerCert;
- SigParams.cAuthAttr = 0;
- SigParams.dwInnerContentType = 0;
- SigParams.cMsgCrl = 0;
- SigParams.cUnauthAttr = 0;
- SigParams.dwFlags = 0;
- SigParams.pvHashAuxInfo = NULL;
- SigParams.rgAuthAttr = NULL;
- //--------------------------------------------------------------------
- //
- //首先得到BLOB的大小
- if(CryptSignMessage(
- &SigParams, // Signature parameters
- FALSE, // Not detached
- 1, // Number of messages
- MessageArray, // Messages to be signed
- MessageSizeArray, // Size of messages
- NULL, // Buffer for signed message
- &cbSignedMessageBlob)) // Size of buffer
- {
- printf("The size of the BLOB is %d.\n",cbSignedMessageBlob);
- }
- else
- {
- HandleError("Getting signed BLOB size failed");
- }
- //--------------------------------------------------------------------
- //分配BLOB的內存.
- if(!(pbSignedMessageBlob =
- (BYTE*)malloc(cbSignedMessageBlob)))
- {
- HandleError("Memory allocation error while signing.");
- }
- //--------------------------------------------------------------------
- //
- if(CryptSignMessage(
- &SigParams, //
- FALSE, //
- 1, //消息數量
- MessageArray, //待簽名的消息
- MessageSizeArray, //消息大小
- pbSignedMessageBlob, //緩衝區
- &cbSignedMessageBlob)) //緩衝區大小
- {
- printf("The message was signed successfully. \n");
- }
- else
- {
- HandleError("Error getting signed BLOB");
- }
- //--------------------------------------------------------------------
- //驗證簽名信息
- //--------------------------------------------------------------------
- //初始化VerifyParams結構.
- VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
- VerifyParams.dwMsgAndCertEncodingType = MY_TYPE;
- VerifyParams.hCryptProv = 0;
- VerifyParams.pfnGetSignerCertificate = NULL;
- VerifyParams.pvGetArg = NULL;
- //--------------------------------------------------------------------
- //
- if(CryptVerifyMessageSignature(
- &VerifyParams, //.
- 0, //
- pbSignedMessageBlob, //.
- cbSignedMessageBlob, //
- NULL, //
- &cbDecodedMessageBlob, //.
- NULL)) // Pointer to signer certificate.
- {
- printf("%d bytes need for the buffer.\n",cbDecodedMessageBlob);
- }
- else
- {
- printf("Verification message failed. \n");
- }
- //--------------------------------------------------------------------
- //爲緩衝區分配內存.
- if(!(pbDecodedMessageBlob =
- (BYTE*)malloc(cbDecodedMessageBlob)))
- {
- HandleError("Memory allocation error allocating decode BLOB.");
- }
- //--------------------------------------------------------------------
- //
- //得到緩衝區的大小
- if(CryptVerifyMessageSignature(
- &VerifyParams, // Verify parameters.
- 0, // Signer index.
- pbSignedMessageBlob, // Pointer to signed BLOB.
- cbSignedMessageBlob, // Size of signed BLOB.
- pbDecodedMessageBlob, // Buffer for decoded message.
- &cbDecodedMessageBlob, // Size of buffer.
- NULL)) // Pointer to signer certificate.
- {
- printf("The verified message is \n-> %s \n",pbDecodedMessageBlob);
- }
- else
- {
- printf("Verification message failed. \n");
- }
- //--------------------------------------------------------------------
- //
- if(pbSignedMessageBlob)
- free(pbSignedMessageBlob);
- if(pbDecodedMessageBlob)
- free(pbDecodedMessageBlob);
- if(pSignerCert)
- CertFreeCertificateContext(pSignerCert);
- if(CertCloseStore(
- hStoreHandle,
- CERT_CLOSE_STORE_CHECK_FLAG))
- {
- printf("The store closed and all certificates are freed. \n");
- }
- else
- {
- printf("Store closed after signing -- \n"
- "not all certificates, CRLs or CTLs were freed");
- }
- …
4.2證書和證書庫函數
這組函數管理、使用和取得證書、證書撤銷列表和證書信任列表。這些函數可以分成一下幾組:
4.2.1證書庫函數
一個用戶站點可以收集許多證書。這些證書是爲這個站點的用戶所使用的,證書描述了這個用戶的具體身份。對於每個人,可能有一個以上的證書。證書庫和其相關的函數提供了
對庫獲得、枚舉、驗證和使用證書庫裏的信息。
以下就是這些函數:
CertAddStoreToCollection在證書庫中增加一個證書
CertCloseStore關閉一個證書庫句柄
CertControlStore如果證書緩衝區和證書本身內容不相符時,允許給應用程序發一個通知
CertDuplicateStore通過增加引用計數來複制證書庫句柄
CertEnumPhysicalStore對於指定系統庫枚舉物理庫
CertEnumSystemStore枚舉所有可用的系統庫
CertEnumSystemStoreLocation枚舉可用系統庫的所有位置
CertGetStoreProperty得到一個庫的屬性
CertOpenStore使用指定庫類型來打開證書庫
CertOpenSystemStore打開一個系統證書庫
CertRegisterPhysicalStore在一個註冊系統庫裏增加一個物理庫
CertRegisterSystemStore註冊一個系統庫
CertRemoveStoreFromCollection從一個庫集合裏刪除證書庫
CertSaveStore保存證書庫
CertSetStoreProperty設置證書屬性
CertUnregisterPhysicalStore從系統庫中刪除一個物理庫
CertUnregisterSystemStore反註冊一個指定系統庫
4.2.2維護函數
CryptoAPI提供了證書和證書庫函數如下:
CertAddSerializeElementToStore在庫中增加一系列證書或CRL
CertCreateContext從編碼字節中創建指定上下文
CertEnumSubjectInSortedCTL在CTL庫中枚舉信任主題
CertFindSubjectInCTL在CTL中尋找指定主題
CertFindSubjectInSortedCTL在分類CTL中尋找指定主題
4.2.3證書函數
下列函數是針對於證書的。大多數函數都是處理CRL和CTL 的。
CertAddCertificateContextToStore在證書庫裏增加一個證書上下文
CertAddCertificateLinkToStore在證書庫裏增加一個對不同庫裏的證書上下文的鏈接
CertAddEncodedCertificateToStore把編碼證書轉換成證書上下文並且把它加到證書庫裏
CertCreateCertificateContext從編碼證書中創建一個證書上下文。但這個上下文並不放到證書庫裏
CertCreateSelfSignCertificate創建一個自簽名證書
CertDeleteCertificateFromStore從證書庫裏刪除一個證書
CertDuplicateCertificate通過增加引用計數來複制證書上下文
CertEnumCertificateInStore在證書庫裏枚舉證書上下文
CertFindCertificateInStore在證書庫裏尋找證書上下文
CertFreeCertificateContext釋放一個證書上下文
CertGetIssuerCertificateFromStore在證書庫裏得到指定主題證書的發行者
CertGetSubjectCertificateFromStore獲得主題證書的上下文
CertGetValidUsages返回所有證書的用法
CertSerializeCertificateStoreElement串行化編碼證書的證書上下文
CertVerifySubjectCertificateContext使用發行者來驗證主題證書
CryptUIDlgViewContext顯示證書、CRL或CTL
CryptUIDlgSelectCertificateFromStore從指定庫中顯示對話框,可以從中選擇證書
4.2.4證書撤銷列表函數
CertAddCRLContextToStore在證書庫裏增加一個CRL上下文
CertAddCRLLinkToStore在不同的庫裏增加一個CRL上下文鏈接
CertAddEncodedCRLToStore把編碼CRL轉化成CRL 上下文然後把它加入到證書庫中
CertCreateCRLContext從編碼CRL中創建CRL 句柄,但不把它加到庫中
CertDeleteCRLFromStore從證書庫裏刪除一個CRL
CertDuplicateCRLContext通過增加引用計數來複制CRL上下文
CertEnumCRLsInStore枚舉庫裏的CRL句柄
CertFindCertificateInCRL從指定證書裏尋找CRL列表
CertFindCRLInStore在庫裏尋找CRL上下文
CertFreeCRLContext釋放CRL上下文
CertGetCRLFromStore從庫裏得到CRL上下文句柄
CertSerializeCRLStoreElement串行化CRL上下文的編碼CRL 和它的屬性
4.2.5證書信任列表函數
CertAddCTLContextToStore把一個CTL上下文加入到證書庫裏
CertAddCTLLinkToStore給不同庫裏的CRL上下文添加鏈接
CertAddEncodedCTLToStore把編碼CTL轉化成CTL 上下文並且把它加到證書庫裏
CertCreateCTLContext從編碼CTL中創建CTL 上下文
CertDeleteCTLFromStore從證書庫裏刪除CTL
CertDuplicateCTLContext通過增加引用計數來複制CTL上下文
CertEnumCTLsInStore在證書庫裏枚舉CTL上下文
CertFindCTLInStore在證書庫裏查找CTL上下文
CertFreeCTLContext釋放CTL上下文
CertSerializeCTLStoreElement串行化CTL上下文的編碼CTL 和屬性
4.2.6擴展屬性函數
CertEnumCertificateContextProperties枚舉指定證書上下文的屬性
CertEnumCRLContextProperties枚舉指定CRL上下文的屬性
CertEnumCTLContextProperties枚舉指定CTL上下文的屬性
CertGetCertificateContextProperty得到證書屬性
CertGetCRLContextProperty得到CRL屬性
CertGetCTLContextProperty得到CTL屬性
CertSetCertificateContextProperty設置證書屬性
CertSetCRLContextProperty設置CRL屬性
CertSetCTLContextProperty設置CTL屬性
4.2.7函數詳解
4.2.7.1打開/關閉系統證書庫
4.2.7.1.1 CertOpenSystemStore
HCERTSTORE WINAPI CertOpenSystemStore(
HCRYPTPROV hProv,
LPCTSTR szSubsystemProtocol,
);
參數:
hProv[in] CSP句柄。如果爲NULL,就爲卻省CSP。如果不爲NULL,它必須是由CryptAcquireContext得到的CSP句柄。
szSubsystemProtocol[in]系統證書庫的名稱。可以爲”CA”、”MY”、”ROOT”、”SPC”。
說明:
此函數用來打開通用的系統證書庫。
4.2.7.1.2 CertCloseStore
BOOL WINAPI CertCloseStore(
HCERTSTORE hCertStore,
DWORD dwFlags
);
參數:
hCertStore[in]證書庫句柄。
dwFlags[in]典型地,此參數爲0。卻省就是關閉證書庫,對於爲上下文分配的內存並不釋放。如果想要檢查並且釋放所有爲證書、CRL和CTL 上下文的分配的內存,就要置下列標誌。
CERT_CLOSE_STORE_CHECK_FLAG檢查沒有釋放的證書、CRL和CTL 上下文。
CERT_CLOSE_STORE_FORCE_FLAG強制釋放所有和證書庫相關的上下文。
說明:
此函數釋放證書庫句柄。
- //-----------------------------------------------------------------
- …
- HCERTSTORE hSystemStore;
- if(hSystemStore = CertOpenSystemStore(0,"MY"))
- {
- printf("The MY system store is open. Continue.\n");
- CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
- }
- else
- {
- printf("The MY system store did not open.\n");
- exit(1);
- }
- …
4.3證書驗證函數
證書驗證是通過CTL和證書列表進行的。
4.3.1使用CTL的函數
CertVerifyCTLUsage驗證CTL用法
CryptMsgEncodeAndSignCTL編碼和驗證CTL
CryptMsgGetAndVerifySigner從一個消息中獲得和驗證CTL
CryptMsgSignCTL對包含CTL的消息進行簽名
4.3.2證書鏈驗證函數
CertCreateCertificateChainEngine爲應用程序創建一個新的非卻省的鏈引擎
CertCreateCTLEntryFromCertificateContextProperties創建一個CTL入口
CertDuplicateCertificateChain通過增加引用計數來複制證書鏈
CertFindChainInStore在證書庫裏查找證書鏈
CertFreeCertificateChain釋放證書鏈
CertFreeCertificateChainEngine釋放證書鏈引擎
CertGetCertificateChain從最後一個證書建立一個上下文鏈表
CertSetCertificateContextPropertiesFromCTLEntry通過CTL入口屬性來設置證書上下文的屬性
CertIsValidCRLForCertificate通過檢查CRL來確定CRL 是否包括指定被撤銷的證書
CertVerifyCertificateChainPolicy通過檢查證書鏈來確定它的完整性
4.4消息函數
CryptoAPI消息函數包括兩組:低級消息函數和簡化消息函數。
- 低級消息函數直接和PKCS#7消息工作。這些函數對傳輸的PKCS#7 數據進行編碼,對接收到的PKCS#7數據進行解碼,並且對接收到的消息進行解密和驗證。
- 簡化消息函數是比較高級的函數,是對幾個低級消息函數和證書函數的封裝,用來執行指定任務。這些函數在完成一個任務時,減少了函數調用的數量,因此簡化了CryptoAPI的使用。
4.4.1低級消息函數
CryptMsgCalculateEncodedLength計算加密消息的長度
CryptMsgClose關閉加密消息的句柄
CryptMsgControl執行指定的控制函數
CryptMsgCountersign標記消息中已存在的簽名
CryptMsgCountersignEncoded標記已存在的簽名
CryptMsgDuplicate通過增加引用計數來複制加密消息句柄
CryptMsgGetParam對加密消息進行編碼或者解碼後得到的參數
CryptMsgOpenToDecode打開加密消息進行解碼
CryptMsgOpenToEncode打開加密消息進行編碼
CryptMsgUpdate更新加密消息的內容
CryptMsgVerifyCountersignatureEncoded驗證SignerInfo結構中標記時間
CryptMsgVerifyCountersignatureEncodedEx驗證SignerInfo結構中標記時間,簽名者可以是CERT_PUBLIC_KEY_INFO結構
4.4.2簡化消息函數
CryptDecodeMessage對加密消息進行解碼
CryptDecryptAndVerifyMessageSignature對指定消息進行解密並且驗證簽名者
CryptDecryptMessage解密指定消息
CryptEncryptMessage加密指定消息
CryptGetMessageCertificates返回包含消息的證書和CRL的證書庫
CryptGetMessageSignatureCount返回簽名消息的簽名者數量
CryptHashMessage創建消息的哈希
CryptSignAndEncryptMessage對消息進行簽名並且加密
CryptSignMessage對消息進行簽名
CryptVerifyDetachedMessageHash驗證包含已解邦定哈希的哈希消息
CryptVerifyDetachedMessageSignature驗證包含已解邦定簽名的簽名消息
CryptVerifyMessageHash驗證一個哈希消息
CryptVerifyMessageSignature驗證一個簽名消息
4.5輔助函數
4.5.1數據管理函數
CertCompareCertificate比較兩個證書是否相同
CertCompareCertificateName通過比較兩個證書名稱來決定他們是否相同
CertCompareIntegerBlob比較兩個整數BLOB
CertComparePublicKeyInfo通過比較兩個證書公鑰來決定他們是否相同
CertFindAttribute通過OID來查找屬性
CertFindExtension通過OID來查找擴展
CertFindRDNAttr通過OID來查找RDN 屬性
CertGetIntendedKeyUsage從證書中取得相關密鑰用法
CertGetPublicKeyLength從公鑰BLOB中取得公鑰/私鑰長度
CertIsRDNAttrsInCertificateName通過指定RDN數組屬性比較證書名稱屬性來決定證書是否已包含了所有屬性
CertVerifyCRLRevocation驗證主題證書是否在CRL中
CertVerifyCRLTimeValidity驗證CRL的有效時間
CertVerifyRevocation驗證主題證書是否在CRL中
CertVerifyTimeValidity驗證CRL的有效時間
CertVerifyValidityNesting驗證主題時間的有效性是否在發行者有效時間內
CryptExportPublicKeyInfo導出公鑰信息
CryptExportPublicKeyInfoEx導出公鑰信息(用戶可以指定算法)
CryptFindCertificateKeyProvInfo枚舉CSP和它的密鑰容器來查找對應於公鑰的相應私鑰
CryptFindLocalizedName查找指定名字的局部化名稱
CryptHashCertificate哈希證書內容
CryptHashPublicKeyInfo計算公鑰信息的哈希
CryptHashToBeSigned計算簽名內容的信息哈希值
CryptImportPublicKeyInfo把公鑰信息導入CSP並且返回它的句柄
CryptImportPublicKeyInfoEx把公鑰信息導入CSP並且返回它的句柄
CryptMemAlloc分配內存
CryptMemFree釋放內存
CryptMemRealloc重新分配內存
CryptQueryObject得到BLOB或文件的內容信息
CryptSignAndEncodeCertificate對信息進行簽名並且編碼
CryptSignCertificate對證書進行簽名
CryptVerifyCertificateSignature使用公鑰信息對主題證書或CRL的簽名進行驗證
CryptVerifyCertificateSignatureEx使用公鑰信息對主題證書或CRL的簽名進行驗證
4.5.2數據轉換函數
CertAlgIdToOID把CSP算法標示符轉換成OID
CertGetNameString得到證書的主題或頒發者名稱並且把它轉換成字符串
CertNameToStr把證書名稱BLOB轉換成字符串
CertOIDToAlgId把OID轉換成CSP 算法表示符
CertRDNValueToStr把名稱值轉換成字符串
CertStrToName把字符串轉換成編碼證書名稱
CryptBinaryToString把二進制序列轉換成字符串
CryptFormatObject格式化編碼數據,返回Unicode字符串
CryptStringToBinary把格式化的字符串轉換成二進制序列
4.5.3增強密鑰用法函數
CertAddEnhancedKeyUsageIdentifier在證書EKU屬性中增加一個用法標示符
CertGetEnhancedKeyUsage獲得證書的EKU擴展或屬性信息
CertRemoveEnhancedKeyUsageIdentifier從證書EKU擴展屬性中刪除用法標示符OID
CertSetEnhancedKeyUsage設置證書的EKU屬性
4.5.4密鑰標示函數
CryptCreateKeyIdentifierFromCSP創建CSP公鑰的密鑰標示符
CryptEnumKeyIdentifierProperties枚舉標示符和其屬性
CryptGetKeyIdentifierProperty從指定密鑰標示符中獲得指定屬性
CryptSetKeyIdentifierProperty設置指定密鑰標示符的屬性
4.5.5證書庫回調函數
CertDllOpenStoreProv定義庫提供者打開函數
CertStoreProvCloseCallback決定當證書庫引用計數爲0時將發生的動作
CertStoreProvDeleteCertCallback決定當從證書庫中刪除一個證書之前的動作
CertStoreProvDeleteCRLCallback決定當從證書庫中刪除一個CRL之前的動作
CertStoreProvReadCertCallback保留
CertStoreProvReadCRLCallback保留
CertStoreProvSetCertPropertyCallback決定在CertSetCertificateContextProperty和
CertGetCertificateContext調用之前的動作
CertStoreProvSetCRLPropertyCallback決定在CertSetCRLContextProperty和
CertGetCRLContextProperty調用之前的動作
CertStoreProvWriteCertCallback決定在證書庫中加入一個證書前的動作
CertStoreProvWriteCRLCallback決定在證書庫中加入一個CRL前的動作
CertStoreProvReadCTL讀CSP的CTL 上下文
CertStoreProvWriteCTL決定CTL是否可被加入到證書庫中
CertStoreProvDeleteCTL決定CTL是否可被刪除
CertStoreProvSetCTLProperty決定是否可以設置CTL的屬性
CertStoreProvControl當緩衝庫和存儲庫不同時,通知應用程序
CertStoreProvFindCert在證書庫中查找下一個證書
CertStoreProvFreeFindCert釋放前一個找到的證書上下文
CertStoreProvGetCertProperty得到指定的證書屬性
CertStoreProvFindCRL查找第一個或下一個匹配的CRL
CertStoreProvFreeFindCRL釋放前一個找到的CRL上下文
CertStoreProvGetCRLProperty得到指定CRL屬性
CertStoreProvFindCTL查找第一個或下一個匹配的CTL
CertStoreProvFreeFindCTL釋放前一個找到的CTL上下文
CertStoreProvGetCTLProperty得到指定CTL屬性
4.5.6 OID支持函數
CryptEnumOIDFuction枚舉由編碼類型、函數名和OID指定註冊的OID函數
CryptEnumOIDInfo枚舉註冊的OID信息
CryptEnumOIDInfo使用指定的密鑰和組查找OID信息
CryptFreeOIDFuctionAddress釋放OID函數地址句柄
CryptGetDefaultOIDDllList對於指定的函數結合和類型獲得卻省註冊的DLL入口
CryptGetDefaultOIDFuctionAddress獲得已安裝的第一次或下一個卻省函數或者加載包含卻省函數的DLL
CryptGetOIDFuctionAddress搜索匹配指定編碼類型和OID函數列表,如果沒有找到,就查找註冊表。
CryptGetOIDFuctionValue獲得指定編碼類型、函數名稱和OID的值
CryptInitOIDFuctionSet初始化OID函數集合的句柄
CryptInstallOIDFuctionAddress安裝可調用的OID函數地址集合
CryptRegisterDefaultOIDFuction註冊包含卻省函數的DLL
CryptRegisterOIDFuction註冊包含指定函數的DLL
CryptRegisterOIDInfo註冊由CRYPT_OID_INFO指定的OID 信息
CryptSetOIDFuctionValue設置編碼類型、函數名稱等的值
CryptUnregisterDefaultOIDFunction卸載包含卻省函數的DLL
CryptUnregisterOIDFuction卸載包含函數的DLL
CryptUnregisterOIDInfo卸載指定OID的信息
4.5.7遠程對象恢複函數
CryptGetObjectUrl從證書、CTL或CRL 中取得遠程對象的URL
CryptRetrieveObjectByUrl由URL指定位置恢復PKI 對象
4.5.8 PFX函數
PFXExportCertStore從證書庫中導出證書或證書和私鑰
PFXExportCertStoreEx從證書庫中導出證書或證書和私鑰
PFXImportCertStore從PFX BLOB導入到指定證書庫
PFXIsPFXBlob把外層BLOB像pfx 包那樣解碼
PFXVerifyPassword把外層BLOB像pfx 包那樣解碼,並且用指定口令解密
一些加密解密標準函數示例——DES,RSA
一. DES加密、解密
- //默認密鑰向量
- private byte[] Keys = { 0xEF, 0xAB, 0x56, 0x78, 0x90, 0x34, 0xCD, 0x12 };
- /// <summary>
- /// DES加密字符串
- /// </summary>
- /// <param name="encryptString">待加密的字符串</param>
- /// <param name="encryptKey">加密密鑰,要求爲8位</param>
- /// <returns>加密成功返回加密後的字符串,失敗返回源串</returns>
- public string EncryptDES(string encryptString, string encryptKey)
- {
- try
- {
- byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
- byte[] rgbIV = Keys;
- byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
- DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
- MemoryStream mStream = new MemoryStream();
- CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
- cStream.Write(inputByteArray, 0, inputByteArray.Length);
- cStream.FlushFinalBlock();
- return Convert.ToBase64String(mStream.ToArray());
- }
- catch
- {
- return encryptString;
- }
- }
- /// <summary>
- /// DES解密字符串
- /// </summary>
- /// <param name="decryptString">待解密的字符串</param>
- /// <param name="decryptKey">解密密鑰,要求爲8位,和加密密鑰相同</param>
- /// <returns>解密成功返回解密後的字符串,失敗返源串</returns>
- public string DecryptDES(string decryptString, string decryptKey)
- {
- try
- {
- byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 8));
- byte[] rgbIV = Keys;
- byte[] inputByteArray = Convert.FromBase64String(decryptString);
- DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
- MemoryStream mStream = new MemoryStream();
- CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
- cStream.Write(inputByteArray, 0, inputByteArray.Length);
- cStream.FlushFinalBlock();
- return Encoding.UTF8.GetString(mStream.ToArray());
- }
- catch
- {
- return decryptString;
- }
- }
二. DES/3DES加密算法源代碼
- /* Project xxxx
- * Package com.xxxx.utils
- *
- */
- package com.xxxxx.utils;
- import java.io.FileInputStream;
- import java.io.ObjectInputStream;
- import java.security.NoSuchAlgorithmException;
- import java.security.Security;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.NoSuchPaddingException;
- import javax.crypto.SecretKey;
- public class DES {
- private String Algorithm = "DESede"; //"DESede" for Triple DES
- private KeyGenerator keygen;
- private SecretKey deskey;
- private Cipher c;
- private byte[] cipherByte;
- public DES() {
- init();
- }
- public DES(String filename) {
- init(filename);
- }
- public SecretKey genKey() {
- try {
- keygen = KeyGenerator.getInstance(Algorithm);
- deskey = keygen.generateKey(); //利用JavaBean的持久化將key保存爲文件XXX.key
- } catch (NoSuchAlgorithmException ex) {
- ex.printStackTrace();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return deskey;
- }
- /**
- *
- * @param filename
- */
- public void init(String filename) {
- // restore key
- Security.addProvider(new com.sun.crypto.provider.SunJCE());
- try {
- FileInputStream fis = new FileInputStream(filename);
- fis = new FileInputStream(filename);
- ObjectInputStream ois = new ObjectInputStream(fis);
- deskey = (SecretKey) ois.readObject();
- ois.close();
- fis.close();
- c = Cipher.getInstance(Algorithm);
- } catch (NoSuchAlgorithmException ex) {
- ex.printStackTrace();
- } catch (NoSuchPaddingException ex) {
- ex.printStackTrace();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- public void init() {
- Security.addProvider(new com.sun.crypto.provider.SunJCE());
- try {
- keygen = KeyGenerator.getInstance(Algorithm);
- deskey = keygen.generateKey();
- c = Cipher.getInstance(Algorithm);
- } catch (NoSuchAlgorithmException ex) {
- ex.printStackTrace();
- } catch (NoSuchPaddingException ex) {
- ex.printStackTrace();
- }
- }
- public byte[] encryptor(String str) {
- try {
- c.init(Cipher.ENCRYPT_MODE, deskey);
- cipherByte = c.doFinal(str.getBytes());
- } catch (java.security.InvalidKeyException ex) {
- ex.printStackTrace();
- } catch (javax.crypto.BadPaddingException ex) {
- ex.printStackTrace();
- } catch (javax.crypto.IllegalBlockSizeException ex) {
- ex.printStackTrace();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return cipherByte;
- }
- public String decryptor(byte[] buff) {
- try {
- c.init(Cipher.DECRYPT_MODE, deskey);
- cipherByte = c.doFinal(buff);
- } catch (java.security.InvalidKeyException ex) {
- ex.printStackTrace();
- } catch (javax.crypto.BadPaddingException ex) {
- ex.printStackTrace();
- } catch (javax.crypto.IllegalBlockSizeException ex) {
- ex.printStackTrace();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return (new String(cipherByte));
- }
- }
- /*
- * Project xxxx
- * Package com.xxxx.utils
- * Created on 2003-11-24
- * Author Derys
- *
- */
- package com.xxxx.utils;
- /**
- *
- *
- */
- public class XXXDES {
- private static XXXDES instance = new XXXDES();
- public XXXDES() {
- }
- /**
- *
- * @param str
- * @return
- */
- public String encrypt(String str) {
- StringBuffer buffer = new StringBuffer();
- DES des = new DES("XXX.key");
- byte[] en = des.encryptor(str);
- for (int i = 0; i < en.length; i++) {
- buffer.append((char) en[i]);
- }
- return buffer.toString();
- }
- /**
- *
- * @param str
- * @return
- */
- public String decrypt(String str) {
- DES des = new DES("XXX.key");
- byte[] en = new byte[str.length()];
- for (int i = 0; i < str.length(); i++) {
- en[i] = (byte) str.charAt(i);
- }
- String de = des.decryptor(en);
- return de;
- }
- /**
- *
- * @param str
- * @return
- */
- public String replaceChar(String str) {
- StringBuffer buffer = new StringBuffer();
- int index = str.indexOf("'");
- if (index == -1) {
- return str;
- }
- while (index > -1) {
- buffer.append(str.substring(0, index));
- buffer.append("''");
- str = str.substring(index + 1);
- index = str.indexOf("'");
- }
- buffer.append(str);
- return buffer.toString();
- }
- /**
- *
- * @return
- */
- public static XXXDES getInstance(){
- if(instance == null){
- instance = new XXXDES();
- }
- return instance;
- }
- }
使用:
encryptedTextXXXDES.getInstance().encrypt("your plain text");
plainText=XXXDES.getInstance().decrypt("your encrypted text");
三.RSA加密、解密
RSA加密算法是一種非對稱加密算法。在公鑰加密標準和電子商業中RSA被廣泛使用。RSA是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。當時他們三人都在麻省理工學院工作。RSA就是他們三人姓氏開頭字母拼在一起組成的。
RSA算法的可靠性基於分解極大的整數是很困難的。假如有人找到一種很快的分解因子的算法的話,那麼用RSA加密的信息的可靠性就肯定會極度下降。但找到這樣的算法的可能性是非常小的。今天只有短的RSA鑰匙纔可能被強力方式解破。到2008年爲止,世界上還沒有任何可靠的攻擊RSA算法的方式。只要其鑰匙的長度足夠長,用RSA加密的信息實際上是不能被解破的。
1. rsa基本結構
- struct
- {
- int pad;
- long version;
- const rsa_method *meth;
- engine *engine;
- bignum *n;
- n=p*q;
- bignum *e; //公開的加密指數,經常爲65537(ox10001)
- bignum *d; //私鑰
- bignum *p; //大素數p
- bignum *q; //大素數q
- bignum *dmp1; //d mod (p-1)
- bignum *dmq1; //d mod (q-1)
- bignum *iqmp; //(inverse of q) mod p
- int references;
- int flags; // ...
- }rsa;
2.初始化函數
rsa * rsa_new(void);初始化一個rsa結構
void rsa_free(rsa *rsa);釋放一個rsa結構
3.rsa私鑰產生函數
rsa *rsa_generate_key(int num, unsigned long e,void (*callback)(int,int,void *), void *cb_arg);產生一個模爲num位的密鑰對,e爲公開的加密指數,一般爲65537(ox10001),假如後兩個參數不爲null,將有些調用。在產生密鑰對之前,一般需要指定隨機數種子
4.判斷位數函數
int rsa_size(const rsa *rsa);返回rsa模的位數,他用來判斷需要給加密值分配空間的大小
int rsa_check_key(rsa *rsa);他測試p,q是否爲素數,n=p*q,d*e = 1 mod (p-1*q-1), dmp1, dmq1, iqmp是否均設置正確了。
5.rsa的rsa_method函數
瞭解rsa的運算那就必須瞭解rsa_method,下面我們先看看rsa_method結構
- typedef struct rsa_meth_st
- {
- const char *name;
- int (*rsa_pub_enc)(int flen,const unsigned char *from, unsigned char *to,rsa *rsa,int padding);
- int (*rsa_pub_dec)(int flen,const unsigned char *from, unsigned char *to,rsa *rsa,int padding);
- int (*rsa_priv_enc)(int flen,const unsigned char *from, unsigned char *to, rsa *rsa,int padding);
- int (*rsa_priv_dec)(int flen,const unsigned char *from, unsigned char *to,rsa *rsa,int padding);
- int (*rsa_mod_exp)(bignum *r0,const bignum *i,rsa *rsa);
- int (*bn_mod_exp)(bignum *r, const bignum *a, const bignum *p, const bignum *m, bn_ctx *ctx,bn_mont_ctx *m_ctx);
- int (*init)(rsa *rsa); /* called at new */
- int (*finish)(rsa *rsa); /* called at free */
- int flags; /* rsa_method_flag_* things */ char *app_data; /* may be needed! */
- int (*rsa_sign)(int type,const unsigned char *m, unsigned int m_length,unsigned char *sigret, unsigned int *siglen, const rsa *rsa);
- int (*rsa_verify)(int dtype,const unsigned char *m, unsigned int m_length,unsigned char *sigbuf, unsigned int siglen, const rsa *rsa);
- } rsa_method;
- const rsa_method *rsa_pkcs1_ssleay(void);
- <span style="font-family:Microsoft YaHei;font-size:16px;color:black;">const rsa_method *rsa_null_method(void);</span>
主要有上面兩個函數。第二個函數是定義了rsa_null纔會調用,其實要調用這個函數以後幾乎什麼都不能幹,只是輸出錯誤信息。第一個是常用的method,下面我們看看它的定義
const rsa_method *rsa_pkcs1_ssleay(void)
{
return(&rsa_pkcs1_eay_meth);
}
static rsa_method rsa_pkcs1_eay_meth={ "eric young's pkcs#1 rsa", rsa_eay_public_encrypt, rsa_eay_public_decrypt, /* signature verification */ rsa_eay_private_encrypt, /* signing */ rsa_eay_private_decrypt, rsa_eay_mod_exp, bn_mod_exp_mont, rsa_eay_init, rsa_eay_finish, 0, /* flags */ null, 0, /* rsa_sign */ 0 /* rsa_verify */ };
由此可以看出,一般rsa->meth-> rsa_pub_enc對應於rsa_eay_public_encrypt,剛開始看openssl的時候最難得就是這個指向函數的指針,根本不知道rsa->meth-> rsa_pub_enc對應於哪裏。在openssl裏面這種指針很多,到以後也能夠看到。下面是設置meth的一些函數應該都很容易理解
void rsa_set_default_method(const rsa_method *meth);
const rsa_method *rsa_get_default_method(void);
int rsa_set_method(rsa *rsa, const rsa_method *meth);
const rsa_method *rsa_get_method(const rsa *rsa);
int rsa_flags(const rsa *rsa);
rsa *rsa_new_method(engine *engine);
6.加解密函數
int rsa_public_encrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa, int padding);
int rsa_private_decrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa, int padding);
int rsa_private_encrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa,int padding);
int rsa_public_decrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa,int padding);
假如rsa_set_method(rsa, rsa_pkcs1_ssleay())的話,那rsa_public_encrypt對應於rsa_eay_public_encrypt,這樣我們就可以調試公鑰加密的過程了。flen爲要加密信息的長度,from爲需要加密的信息,to爲加密後的信息,一般to至少要申請bn_num_bytes(rsa->n)大的空間。padding是採取的加解密方案。pkcs#1中主要提供了兩種加密方案,rsaex-oaep和psaes-pkcs1-v1_5(反正就是兩種加密過程了,有點複雜,它主要是先對先對需要加密的數據進行了編碼,比如rsaes-oaep採用eme-oaep編碼,再進行加密或解密)。編碼的函數:
case rsa_pkcs1_padding: i=rsa_padding_add_pkcs1_type_2(buf,num,from,flen);
#ifndef openssl_no_sha case rsa_pkcs1_oaep_padding: i=rsa_padding_add_pkcs1_oaep(buf,num,from,flen,null,0);
#endif case rsa_sslv23_padding: i=rsa_padding_add_sslv23(buf,num,from,flen);
case rsa_no_padding: i=rsa_padding_add_none(buf,num,from,flen);等上面編好碼後,就調用bn_mod_exp_mont來進行模冪了。最後得出值,這也就是具體的加密和解密過程。在這裏還可以發現,加密時輸入的rsa有兩種方式,一是p,q,...爲null,只有rsa->d,和rsa->n不爲空,這樣就直接用rsa->d和rsa->n進行模冪計算,假如p,q.....都不爲空的話,他會調用中國剩餘定理來進行加密。
7.簽名函數
int rsa_sign(int type, unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, rsa *rsa);
int rsa_verify(int type, unsigned char *m, unsigned int m_len, unsigned char *sigbuf, unsigned int siglen, rsa *rsa);其實簽名其實和用私鑰加密差不多是一回事,所以簽名函數最終調用的就是私鑰加密的函數,在openssl中這個簽名函數很少單獨拿出來用的,都是爲了給evp_signfinal來調用的。所以假如是利用rsa進行簽名的話,rsa_private_encrypt,bn_mod_exp_mont是最基本的,所有的都需要調用他,區別無非就在於在需要簽名的信息上做了一下處理(一般將需要簽名的信息求取摘要值得到m)
8.寫入文件函數
int rsa_print(bio *bp, rsa *x, int offset);
int rsa_print_fp(file *fp, rsa *x, int offset);offset是爲了調整輸出格式的,隨意一個數都可以(例如2,12,16。。)
9.其他
int rsa_blinding_on(rsa *rsa, bn_ctx *ctx);
void rsa_blinding_off(rsa *rsa);爲了防止時間攻擊,openssl還在簽名的時候產生一個隨機因子,附加在私鑰上。
int rsa_sign_asn1_octet_string(int dummy, unsigned char *m,unsigned int m_len, unsigned char *sigret, unsigned int *siglen,rsa *rsa);
int rsa_verify_asn1_octet_string(int dummy, unsigned char *m,unsigned int m_len, unsigned char *sigbuf, unsigned int siglen,rsa *rsa);
代碼示例如下:
- using System;
- using System.Security.Cryptography;
- using System.IO;
- using System.Text;
- namespace Microsoft.Samples.Security.PublicKey
- {
- class App
- {
- // Main entry point
- static void Main(string[] args)
- {
- // Instantiate 3 People for example. See the Person class below
- Person alice = new Person("Alice");
- Person bob = new Person("Bob");
- Person steve = new Person("Steve");
- // Messages that will exchanged. See CipherMessage class below
- CipherMessage aliceMessage;
- CipherMessage bobMessage;
- CipherMessage steveMessage;
- // Example of encrypting/decrypting your own message
- Console.WriteLine("Encrypting/Decrypting Your Own Message");
- Console.WriteLine("-----------------------------------------");
- // Alice encrypts a message using her own public key
- aliceMessage = alice.EncryptMessage("Alice wrote this message");
- // then using her private key can decrypt the message
- alice.DecryptMessage(aliceMessage);
- // Example of Exchanging Keys and Messages
- Console.WriteLine();
- Console.WriteLine("Exchanging Keys and Messages");
- Console.WriteLine("-----------------------------------------");
- // Alice Sends a copy of her public key to Bob and Steve
- bob.GetPublicKey(alice);
- steve.GetPublicKey(alice);
- // Bob and Steve both encrypt messages to send to Alice
- bobMessage = bob.EncryptMessage("Hi Alice! - Bob.");
- steveMessage = steve.EncryptMessage("How are you? - Steve");
- // Alice can decrypt and read both messages
- alice.DecryptMessage(bobMessage);
- alice.DecryptMessage(steveMessage);
- Console.WriteLine();
- Console.WriteLine("Private Key required to read the messages");
- Console.WriteLine("-----------------------------------------");
- // Steve cannot read the message that Bob encrypted
- steve.DecryptMessage(bobMessage);
- // Not even Bob can use the Message he encrypted for Alice.
- // The RSA private key is required to decrypt the RS2 key used
- // in the decryption.
- bob.DecryptMessage(bobMessage);
- } // method Main
- } // class App
- class CipherMessage
- {
- public byte[] cipherBytes; // RC2 encrypted message text
- public byte[] rc2Key; // RSA encrypted rc2 key
- public byte[] rc2IV; // RC2 initialization vector
- }
- class Person
- {
- private RSACryptoServiceProvider rsa;
- private RC2CryptoServiceProvider rc2;
- private string name;
- // Maximum key size for the RC2 algorithm
- const int keySize = 128;
- // Person constructor
- public Person(string p_Name)
- {
- rsa = new RSACryptoServiceProvider();
- rc2 = new RC2CryptoServiceProvider();
- rc2.KeySize = keySize;
- name = p_Name;
- }
- // Used to send the rsa public key parameters
- public RSAParameters SendPublicKey()
- {
- RSAParameters result = new RSAParameters();
- try
- {
- result = rsa.ExportParameters(false);
- }
- catch (CryptographicException e)
- {
- Console.WriteLine(e.Message);
- }
- return result;
- }
- // Used to import the rsa public key parameters
- public void GetPublicKey(Person receiver)
- {
- try
- {
- rsa.ImportParameters(receiver.SendPublicKey());
- }
- catch (CryptographicException e)
- {
- Console.WriteLine(e.Message);
- }
- }
- public CipherMessage EncryptMessage(string text)
- {
- // Convert string to a byte array
- CipherMessage message = new CipherMessage();
- byte[] plainBytes = Encoding.Unicode.GetBytes(text.ToCharArray());
- // A new key and iv are generated for every message
- rc2.GenerateKey();
- rc2.GenerateIV();
- // The rc2 initialization doesnt need to be encrypted, but will
- // be used in conjunction with the key to decrypt the message.
- message.rc2IV = rc2.IV;
- try
- {
- // Encrypt the RC2 key using RSA encryption
- message.rc2Key = rsa.Encrypt(rc2.Key, false);
- }
- catch (CryptographicException e)
- {
- // The High Encryption Pack is required to run this sample
- // because we are using a 128-bit key. See the readme for
- // additional information.
- Console.WriteLine("Encryption Failed. Ensure that the" +
- " High Encryption Pack is installed.");
- Console.WriteLine("Error Message: " + e.Message);
- Environment.Exit(0);
- }
- // Encrypt the Text Message using RC2 (Symmetric algorithm)
- ICryptoTransform sse = rc2.CreateEncryptor();
- MemoryStream ms = new MemoryStream();
- CryptoStream cs = new CryptoStream(ms, sse, CryptoStreamMode.Write);
- try
- {
- cs.Write(plainBytes, 0, plainBytes.Length);
- cs.FlushFinalBlock();
- message.cipherBytes = ms.ToArray();
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- }
- finally
- {
- ms.Close();
- cs.Close();
- }
- return message;
- } // method EncryptMessage
- public void DecryptMessage(CipherMessage message)
- {
- // Get the RC2 Key and Initialization Vector
- rc2.IV = message.rc2IV;
- try
- {
- // Try decrypting the rc2 key
- rc2.Key = rsa.Decrypt(message.rc2Key, false);
- }
- catch (CryptographicException e)
- {
- Console.WriteLine("Decryption Failed: " + e.Message);
- return;
- }
- ICryptoTransform ssd = rc2.CreateDecryptor();
- // Put the encrypted message in a memorystream
- MemoryStream ms = new MemoryStream(message.cipherBytes);
- // the CryptoStream will read cipher text from the MemoryStream
- CryptoStream cs = new CryptoStream(ms, ssd, CryptoStreamMode.Read);
- byte[] initialText = new Byte[message.cipherBytes.Length];
- try
- {
- // Decrypt the message and store in byte array
- cs.Read(initialText, 0, initialText.Length);
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- }
- finally
- {
- ms.Close();
- cs.Close();
- }
- // Display the message received
- Console.WriteLine(name + " received the following message:");
- Console.WriteLine(" " + Encoding.Unicode.GetString(initialText));
- } // method DecryptMessage
- } // class Person
- } // namespace PublicKey