[轉(zhuǎn)]http://www.chinaitpower.com/A200507/2005-07-27/175804.html
一:準(zhǔn)備工作
一般必須包含如下頭
文件
以及定義
#include
#include
#include
#define MY_ENCODING_TYPE? (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
?當(dāng)包含wincrypt.h頭
文件
時(shí),一般都需要定義#define _WIN32_WINNT 0x(具體的值),否則將得到如下錯(cuò)誤:error C2065: undeclared identifier,不同的操作
系統(tǒng)
不同定義如下:
Windows Server 2003 family _WIN32_WINNT>=0x0502
WINVER>=0x0502
Windows XP _WIN32_WINNT>=0x0501
WINVER>=0x0501
Windows 2000 _WIN32_WINNT>=0x0500
WINVER>=0x0500
Windows NT 4.0 _WIN32_WINNT>=0x0400
WINVER>=0x0400
Windows Me _WIN32_WINDOWS=0x0500
WINVER>=0x0500
Windows 98 _WIN32_WINDOWS>=0x0410
WINVER>=0x0410
Windows 95 _WIN32_WINDOWS>=0x0400
WINVER>=0x0400
Internet Explorer 6.0 _WIN32_IE>=0x0600
Internet Explorer 5.6 _WIN32_IE>=0x0560
Internet Explorer 5.01, 5.5 _WIN32_IE>=0x0501
Internet Explorer 5.0, 5.0a, 5.0b _WIN32_IE>=0x0500
Internet Explorer 4.01 _WIN32_IE>=0x0401
Internet Explorer 4.0 _WIN32_IE>=0x0400
Internet Explorer 3.0, 3.01, 3.02 _WIN32_IE>=0x0300
二:了解基本知識(shí)
CryptoAPI的配置信息存儲(chǔ)在注冊(cè)表中,包括如下密鑰:
HKEY_LOCAL_M(jìn)ACHINE\SOFTWARE\Microsoft \ Cryptography \Defaults
HKEY_CURRENT_USER\ Software \ Microsoft\ Cryptography \Providers
---- CryptoAPI使用兩種密鑰:會(huì)話密鑰與公共/私人密鑰對(duì)。會(huì)話密鑰使用相同的加密和解密密鑰,這種算法較快,但必須保證密鑰的安全傳遞。公共/私人密鑰對(duì)使用一個(gè)公共密鑰和一個(gè)私人密鑰,私人密鑰只有專人才能使用,公共密鑰可以廣泛傳播。如果密鑰對(duì)中的一個(gè)用于加密,另一個(gè)一定用于解密。公共/私人密鑰對(duì)算法很慢,一般只用于加密小批數(shù)據(jù),例如用于加密會(huì)話密鑰。CryptoAPI支持兩種基本的編碼方法:流式編碼和塊編碼。流式編碼在明碼文本的每一位上創(chuàng)建編碼位,速度較快,但安全性較低。塊編碼在一個(gè)完整的塊上(一般為64位)上工作,需要使用填充的方法對(duì)要編碼的數(shù)據(jù)進(jìn)行舍入,以組成多個(gè)完整的塊。這種算法速度較慢,但更安全。
三:下面進(jìn)入具體的編程?
一: Creating a Key Container and Generating Keys
? 創(chuàng)建一個(gè)密鑰容器,在進(jìn)行加密,解密
文件
,并且簽名的時(shí)候,必須需要一個(gè)公/私鑰對(duì),下面我們就來創(chuàng)建默認(rèn)的密鑰容器,要注意的是創(chuàng)建密鑰容器并不會(huì)自動(dòng)產(chǎn)生公/私鑰對(duì).
? 下面是我們
程序
的任務(wù):
? 1,假如密鑰容器不存在則創(chuàng)建一個(gè)。
? 2,假如簽名密鑰不存在則在密鑰容器里創(chuàng)建一個(gè)。
? 3,假如交換密鑰不存在則在密鑰容器里創(chuàng)建一個(gè)。
? 4,獲取CSP中的一些參數(shù)
? 下面是具體的步驟:
? 1,連接缺省的CSP
BOOL WINAPI CryptAcquireContext(
? HCRYPTPROV* phProv,?? //out
? LPCTSTR pszContainer, //in
? LPCTSTR pszProvider,? //in
? DWORD dwProvType,???? //in
? DWORD dwFlags???????? //in
);
第一個(gè)參數(shù)是返回的CSP句柄,第二個(gè)是密鑰容器的名字,第三個(gè)是A null-terminated string that specifies the name of the CSP to be used.第四個(gè)是指定提供的類型。例如:CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0));
如果當(dāng)前機(jī)器的未曾設(shè)置過缺省的密鑰容器,因此必須為機(jī)器創(chuàng)建缺省的密鑰容器。
CryptAcquireContext( &hCryptProv, UserName, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)大家有沒有看到,只是最后一個(gè)參數(shù)不同而已,多了一個(gè)CRYPT_NEWKEYSET而已。
? 2,取得CSP的參數(shù)
BOOL WINAPI CryptGetProvParam(
? HCRYPTPROV hProv,
? DWORD dwParam,
? BYTE* pbData,
? DWORD* pdwDataLen,
? DWORD dwFlags
);
第一個(gè)參數(shù)是CSP的句柄,第二個(gè)參數(shù)是需要取得的具體參數(shù)對(duì)象(類型比較多,具體請(qǐng)看MSDN)。
例子:CryptGetProvParam(hCryptProv, PP_CONTAINER, (BYTE *)szUserName, &dwUserNameLen, 0)
? 3,函數(shù)返回所獲取密鑰類型的句柄(0表失敗,非0表成功)
BOOL WINAPI CryptGetUserKey(
? HCRYPTPROV hProv,
? DWORD dwKeySpec,
? HCRYPTKEY* phUserKey
);
? 參數(shù)比較簡(jiǎn)單,只談?wù)劦诙螀?shù),它可以是AT_KEYEXCHANGE(交換密鑰) or AT_SIGNATURE(簽名密鑰),例如:
CryptGetUserKey(hCryptProv,AT_KEYEXCHANGE,&hKey)
? 4,產(chǎn)生一個(gè)隨機(jī)的交換密鑰或者公/私鑰對(duì)
BOOL WINAPI CryptGenKey(
? HCRYPTPROV hProv,
? ALG_ID Algid,
? DWORD dwFlags,
? HCRYPTKEY* phKey
);
ALG_ID 表明產(chǎn)生私鑰所使用的算法。有如下參數(shù):
微軟
提供的基本算法
CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1,CALG_MAC,CALG_HMAC,CALG_SSL3_SHAMD5,CALG_MD2,CALG_MD2
CALG_RSA_SIGN,CALG_RSA_KEYX,CALG_RC2,CALG_RC4,CALG_DES
微軟
提供的增強(qiáng)型算法:
CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1
CALG_MAC,CALG_HMAC ,CALG_SSL3_SHAMD5,CALG_RSA_SIGN,CALG_RSA_KEYX,CALG_RC2,CALG_RC4,CALG_DES,CALG_3DES_112,CALG_3DES
使用DH的CSP有如下兩個(gè)參數(shù),CALG_DH_EPHEM,CALG_DH_SF
使用公開密鑰算法:AT_KEYEXCHANGE,AT_SIGNATURE
dwFlags,,表示密鑰使用的長(zhǎng)度,參數(shù)可以為0,采用默認(rèn)的密鑰長(zhǎng)度?;蛘呤沁M(jìn)行如下幾個(gè)參數(shù)的或:
CRYPT_ARCHIVABLE:表示在句柄在關(guān)閉之前都能夠被導(dǎo)出
CRYPT_CREATE_SALT:表示密鑰按照一個(gè)salt value來隨機(jī)產(chǎn)生。
CRYPT_EXPORTABLE:表示密鑰可以從CSP中導(dǎo)出到BLOB,因?yàn)闀?huì)話密鑰產(chǎn)生是必須可導(dǎo)出的,所以必須設(shè)置
CRYPT_NO_SALT:表示沒有SALT VALUE獲取allocated for a forty-bit symmetric key
CRYPT_PREGEN:表示在DH或者DSS密鑰產(chǎn)生必須有個(gè)初始化。
例如:CryptGenKey(hCryptProv,AT_KEYEXCHANGE,0,&hKey)
? 5,釋放CSP句柄
BOOL WINAPI CryptReleaseContext(
? HCRYPTPROV hProv,
? DWORD dwFlags //保留字,現(xiàn)在必須為0
);
? 6,為CSP增加一個(gè)reference count(用來跟蹤C(jī)OM對(duì)象的整數(shù)值,當(dāng)對(duì)象創(chuàng)建,值為1。每次對(duì)對(duì)象的操作都將增加,而對(duì)對(duì)象的關(guān)閉將減少,當(dāng)值為0是,對(duì)象釋放,所以與對(duì)象相關(guān)操作將無效)
BOOL WINAPI CryptContextAddRef(
? HCRYPTPROV hProv,
? DWORD* pdwReserved,? //保留字,必須為NULL
? DWORD dwFlags??????? //保留字,必須為0
);
? 二:Deriving a Session Key from a Password
? 1,連接CSP
? 2,使用CryptCreateHash產(chǎn)生一個(gè)空的HASH對(duì)象
? 3,對(duì)密碼進(jìn)行HASH處理
? 4,釋放HASH以及密碼對(duì)象
? 5,釋放CSP
? 下面是具體的步驟:
? 1,CryptCreateHash初始化一個(gè)HASH對(duì)象
BOOL WINAPI CryptCreateHash(
? HCRYPTPROV hProv,? //in
? ALG_ID Algid,????? //in
? HCRYPTKEY hKey,??? //in
? DWORD dwFlags,???? //in保留字,必須為0
? HCRYPTHASH* phHash //out
);
第二個(gè)參數(shù)是指定HASH算法,有CALG_HMAC,CALG_MAC,CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1,CALG_SSL3_SHAMD5。第三個(gè)參數(shù)對(duì)于那些keyed hash,例如HMAC,MAC算法。但是nonkeyed算法,必須設(shè)置為0。
? 2,CryptHashData對(duì)數(shù)據(jù)使用HASH
BOOL WINAPI CryptHashData(
? HCRYPTHASH hHash,? //in,HASH對(duì)象句柄
? BYTE* pbData,????? //in,待HASH的數(shù)據(jù)
? DWORD dwDataLen,?? //in,待HASH數(shù)據(jù)的長(zhǎng)度,當(dāng)dwFlags為CRYPT_USERDATA為0時(shí),必須為0
? DWORD dwFlags????? //in,一般為0,或者為CRYPT_USERDATA(用在用戶進(jìn)入
系統(tǒng)
時(shí)需要輸入PIN)
);
? 3,CryptDeriveKey從某一數(shù)據(jù)產(chǎn)生會(huì)話密鑰,他有點(diǎn)類似CryptGenKey,但是他產(chǎn)生的會(huì)話密鑰來自固定數(shù)據(jù),而CryptGenKey是隨機(jī)產(chǎn)生的。并且不能產(chǎn)生公/私鑰對(duì)
BOOL WINAPI CryptDeriveKey(
? HCRYPTPROV hProv,????? //in,CSP句柄
? ALG_ID Algid,????????? //in,指定的算法,類似CryptGenKey
? HCRYPTHASH hBaseData,? //in,HASH對(duì)象的句柄
? DWORD dwFlags,???????? //in,指定產(chǎn)生密鑰的類型
? HCRYPTKEY* phKey?????? //in,out產(chǎn)生的密鑰句柄地址
);
例如:CryptDeriveKey(hCryptProv, CALG_RC2, hHash, CRYPT_EXPORTABLE, &hKey)
? 4,CryptDestroyHash(hHash);
? 5, CryptDestroyKey(hKey);
? 6, 在這里發(fā)現(xiàn)一個(gè)不錯(cuò)的函數(shù),就是那種提示輸入密碼的命令行(屏幕只會(huì)出現(xiàn)***)
? void GetConsoleInput(char* strInput, int intMaxChars)
{
?char ch;
?char minChar = ' ';
?minChar++;
?ch = getch();
?while (ch != '\r')
?{
? if (ch == '\b' && strlen(strInput) > 0)
? {
?? strInput[strlen(strInput)-1]?? = '\0';
?? printf("\b \b");
? }
? else if (ch >= minChar && strlen(strInput) < intMaxChars)
? {
?? strInput[strlen(strInput)+1] = '\0';
?? strInput[strlen(strInput)]?? = ch;
?? putch('*');
? }
? ch = getch();
?}
?putch('\n');
}
? 三:Duplicating,setting and getting Session key
? 1,連接CSP
? 2,使用CryptGenKey產(chǎn)生一個(gè)會(huì)話密鑰
? 3,CryptDuplicateKey復(fù)制會(huì)話密鑰
? 4,CryptSetKeyParam改變密鑰產(chǎn)生的過程
? 5,CryptGenRandom產(chǎn)生隨機(jī)數(shù)
具體過程。
1,CryptDuplicateKe復(fù)制會(huì)話密鑰
BOOL WINAPI CryptDuplicateKey(
? HCRYPTKEY hKey,????? //in 會(huì)話密鑰句柄
? DWORD* pdwReserved,? //in 保留字,必須為NULL
? DWORD dwFlags,?????? //in 保留字,必須為0
? HCRYPTKEY* phKey???? //out 新的會(huì)話密鑰
);
2,CryptSetKeyParam定制會(huì)話密鑰的參數(shù)
BOOL WINAPI CryptSetKeyParam(
? HCRYPTKEY hKey,
? DWORD dwParam,? //in 很多,具體請(qǐng)看MSDN
? BYTE* pbData,
? DWORD dwFlags? //in? 只有在dwParam=KP_ALGID才被使用
);
例如CryptSetKeyParam(hOriginalKey, KP_MODE, (BYTE*)&dwMode, 0)(dwMode = CRYPT_MODE_ECB)
3,CryptGenRandom為空間產(chǎn)生隨機(jī)字節(jié)
BOOL WINAPI CryptGenRandom(
? HCRYPTPROV hProv,
? DWORD dwLen,??? //需要產(chǎn)生的隨機(jī)比特?cái)?shù)
? BYTE* pbBuffer? //需要返回?cái)?shù)據(jù)的空間,這個(gè)pbBuffer可以等于CryptSetKeyParam的pbData
);
例如:CryptGenRandom(hCryptProv, 8, pbData)
4,CryptGetKeyParam獲取密鑰的一些參數(shù)
BOOL WINAPI CryptGetKeyParam(
? HCRYPTKEY hKey,
? DWORD dwParam,???? //in,參數(shù)眾多
? BYTE* pbData,????? //out,獲取BYTE數(shù)據(jù)的指針
? DWORD* pdwDataLen, //out,獲取BYTE數(shù)據(jù)的長(zhǎng)度
? DWORD dwFlags????? //關(guān)鍵字,必須為0
);
例如:CryptGetKeyParam(hKey, KP_IV, pbData, &dwCount, 0)
? 四:Exporting a Session Key
? 1,連接CSP
? 2,CryptGetUserKey獲取公/私鑰對(duì)和交換密鑰,公私鑰用來簽名,而交換密鑰用來導(dǎo)出會(huì)話密鑰
? 3,CryptGenKey產(chǎn)生會(huì)話密鑰
? 4,CryptExportKey創(chuàng)建簡(jiǎn)單包含有會(huì)話密鑰的key BLOB
? 5,釋放處理:
? 具體過程:
1,CryptExportKey函數(shù)導(dǎo)出密鑰
BOOL WINAPI CryptExportKey(
? HCRYPTKEY hKey,???? //需要導(dǎo)出的密鑰句柄
? HCRYPTKEY hExpKey,? //將待導(dǎo)出密鑰用交換密鑰進(jìn)行加密,假如是公開的BLOG當(dāng)然就設(shè)置為0
? DWORD dwBlobType,?? //指定導(dǎo)出的密鑰BLOB類型。六個(gè)參數(shù)見MSDN
? DWORD dwFlags,????? //CRYPT_DESTROYKEY,CRYPT_SSL2_FALLBACK,CRYPT_OAEP
? BYTE* pbData,?????? //導(dǎo)出的數(shù)據(jù)指針,以后就可以將這個(gè)數(shù)據(jù)寫如磁盤或者別的任務(wù)。
? DWORD* pdwDataLen?? //導(dǎo)出的數(shù)據(jù)長(zhǎng)度
);
例如:CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen)
2,CryptImportKey將密鑰從BLOB轉(zhuǎn)換到CSP中
BOOL WINAPI CryptImportKey(
? HCRYPTPROV hProv,? //CSP句柄
? BYTE* pbData,????? //待轉(zhuǎn)換的BLOB數(shù)據(jù)
? DWORD dwDataLen,?? //待轉(zhuǎn)換的數(shù)據(jù)長(zhǎng)度
? HCRYPTKEY hPubKey, //對(duì)BLOB解密的公鑰,譬如上面是用交換密鑰密鑰加密的,就用交換密鑰解密
? DWORD dwFlags,???? //目前還只應(yīng)用在當(dāng)一對(duì)公/私鑰從PRIVATEKEYBLOB中加入CSP中這種情況。
? HCRYPTKEY* phKey?? //out導(dǎo)入的密鑰
);
例如:CryptImportKey(hProv,pbKeyBlob,dwBlobLen,0,0,&hPubKey)
? 五:Encoding and Decoding Messages
? 編碼的處理過程
? 1,將待編碼的數(shù)據(jù)轉(zhuǎn)化為合適的格式,使用
? 2,調(diào)用CryptMsgOpenToEncode,passing the necessary argument;
? 3, 調(diào)用CryptMsgUpdate函數(shù)多次,最后一次調(diào)用時(shí),將final參數(shù)設(shè)置為true
? 4, 調(diào)用CryptMsgGetParam來獲取一個(gè)需要得到的參數(shù)。
? 5, 調(diào)用CryptMsgClose來關(guān)閉消息
? 解碼的處理過程
? 1,檢查申請(qǐng)的放編碼后數(shù)據(jù)的空間,利用函數(shù)CryptMsgCalculateEncodedLength.
? 2,調(diào)用函數(shù)CryptMsgOpenToDecode,passing the necessary argument;
? 3,調(diào)用CryptMsgUpdate一次,這將導(dǎo)致合適的動(dòng)作去處理信息,以來于信息的格式
? 4,一些額外的處理,例如額外的解密或者是驗(yàn)證,調(diào)用CryptMsgControl,
? 5,調(diào)用CryptMsgGetParam來獲取需要得到的參數(shù)
? 6,調(diào)用CryptMsgClose來關(guān)閉消息
? 具體的函數(shù)介紹:
? 1,CryptMsgCalculateEncodedLength計(jì)算所需要的存儲(chǔ)編碼的最大空間值
DWORD WINAPI CryptMsgCalculateEncodedLength(
? DWORD dwMsgEncodingType,//指定編碼類型。一般為X509_ASN_ENCODING|PKCS_7_ASN_ENCODING
? DWORD dwFlags,
? DWORD dwMsgType,
? const void* pvMsgEncodeInfo, //in 指向待編碼的數(shù)據(jù),數(shù)據(jù)類型依賴于dwMsgType
? LPSTR pszInnerContentObjID,
? DWORD cbData???????????????? //in 比特?cái)?shù)的容量
);
第二個(gè)參數(shù):CMSG_BARE_CONTENT_FLAG,CMSG_DETACHED_FLAG,CMSG_CONTENTS_OCTETS_FLAG,CMSG_CMS_ENCAPSULATED_CONTENT_FLAG
第三個(gè)參數(shù):CMSG_DATA,CMSG_SIGNED,CMSG_ENVELOPED,CMSG_SIGNED_AND_ENVELOPED,CMSG_HASHED,CMSG_ENCRYPTED
第五個(gè)參數(shù):szOID_RSA_data,szOID_RSA_signedData,szOID_RSA_envelopedData,szOID_RSA_signEnvData,szOID_RSA,digestedData ,
szOID_RSA_encryptedData,SPC_INDIRECT_DATA_OBJID,NULL
返回值:返回需要的一個(gè)加密信息所需要的長(zhǎng)度
? 2,CryptMsgOpenToEncode打開一個(gè)消息以便進(jìn)行編碼,返回打開消息的句柄
? HCRYPTMSG WINAPI CryptMsgOpenToEncode(
? DWORD dwMsgEncodingType,????? //指定編碼類型。一般為X509_ASN_ENCODING|PKCS_7_ASN_ENCODING
? DWORD dwFlags,???????????????
? DWORD dwMsgType,?????????????
? const void* pvMsgEncodeInfo,
? LPSTR pszInnerContentObjID,??? //和CryptMsgCalculateEncodedLength一樣
? PCMSG_STREAM_INFO pStreamInfo //當(dāng)流沒被使用時(shí),該參數(shù)為NULL
);
第二個(gè)參數(shù):CMSG_BARE_CONTENT_FLAG,CMSG_DETACHED_FLAG,CMSG_CONTENTS_OCTETS_FLAG,CMSG_CMS_ENCAPSULATED_CONTENT_FLAG,
CMSG_CRYPT_RELEASE_CONTEXT_FLAG
第三個(gè)參數(shù):
CMSG_DATA(Not used),CMSG_SIGNED,CMSG_SIGNED_ENCODE_INFO,CMSG_ENVELOPED,CMSG_ENVELOPED_ENCODE_INFO
CMSG_SIGNED_AND_ENVELOPED(Not currently implemented),CMSG_HASHED
? 3,CryptMsgOpenToDecode打開一個(gè)消息以便進(jìn)行解碼,返回打開消息的句柄
? CRYPTMSG WINAPI CryptMsgOpenToDecode(
? DWORD dwMsgEncodingType,???? //指定編碼類型。一般為X509_ASN_ENCODING|PKCS_7_ASN_ENCODING
? DWORD dwFlags,?? //CMSG_DETACHED_FLAG,CMSG_CRYPT_RELEASE_CONTEXT_FLAG
? DWORD dwMsgType, //CMSG_DATA,CMSG_ENVELOPED,CMSG_HASHED,CMSG_SIGNED,CMSG_SIGNED_AND_ENVELOPED
? HCRYPTPROV hCryptProv,??? //指定使用HASHING的句柄,一般設(shè)置為0
? PCERT_INFO pRecipientInfo,//保留字,必須為NULL
? PCMSG_STREAM_INFO pStreamInfo//假如流沒被使用,必須為NULL
);
? 4,CryptMsgUpdate增加內(nèi)容到加密信息中
BOOL WINAPI CryptMsgUpdate(
? HCRYPTMSG hCryptMsg, //待更新的加密信息句柄
? const BYTE* pbData,? //待編碼/解碼的數(shù)據(jù)
? DWORD cbData,??????? // pbData 的數(shù)據(jù)長(zhǎng)度
? BOOL fFinal?????????
);
第四個(gè)參數(shù):當(dāng)CMSG_DETACHED_FLAG沒有設(shè)置,并且信息由CryptMsgOpenToDecode或CryptMsgOpenToEncode打開,那么fFinal被設(shè)置為TRUE,并且CryptMsgUpdate只被調(diào)用一次。當(dāng)CMSG_DETACHED_FLAG被設(shè)置,并且信息由 CryptMsgOpenToEncode打開,那么僅在最后一次調(diào)用CryptMsgUpdate才被設(shè)置為TRUE。當(dāng)CMSG_DETACHED_FLAG被設(shè)置,并且信息由CryptMsgOpenToDecode打開,那么僅在信息頭單獨(dú)被處理時(shí)CryptMsgUpdate才被設(shè)置為TRUE。
? 5,CryptMsgGetParam在數(shù)據(jù)編碼/解碼后獲取參數(shù)
? BOOL WINAPI CryptMsgGetParam(
? HCRYPTMSG hCryptMsg,? //in 信息句柄
? DWORD dwParamType,?? //in 參數(shù)眾多,參見MSDN
? DWORD dwIndex,?????? //in 可適用的返回參數(shù)句柄,假如參數(shù)沒有被獲取,則被忽略或則為0
? void* pvData,??????? //out 獲取的數(shù)據(jù)指針
? DWORD* pcbData????? //in,out數(shù)據(jù)長(zhǎng)度
);
?? 6,CryptMsgClose關(guān)閉信息句柄
BOOL WINAPI CryptMsgClose(
? HCRYPTMSG hCryptMsg
);
具體的例子:
cbEncodedBlob = CryptMsgCalculateEncodedLength(
???????????? MY_ENCODING_TYPE,?????? // Message encoding type
???????????? 0,????????????????????? // Flags
???????????? CMSG_DATA,????????????? // Message type
???????????? NULL,?????????????????? // Pointer to structure
???????????? NULL,?????????????????? // Inner content object ID
???????????? cbContent))???????????? // Size of content
hMsg = CryptMsgOpenToEncode(
????????? MY_ENCODING_TYPE,??????? // Encoding type
????????? 0,?????????????????????? // Flags
????????? CMSG_DATA,?????????????? // Message type
????????? NULL,??????????????????? // Pointer to structure
????????? NULL,??????????????????? // Inner content object ID
????????? NULL))?????????????????? // Stream information (not used)
CryptMsgUpdate(
??????? hMsg,???????? // Handle to the message
??????? pbContent,??? // Pointer to the content
??????? cbContent,??? // Size of the content
??????? TRUE))??????? // Last call
{
CryptMsgGetParam(
?????????????? hMsg,????????????????????? // Handle to the message
?????????????? CMSG_BARE_CONTENT_PARAM,?? // Parameter type
?????????????? 0,???????????????????????? // Index
?????????????? pbEncodedBlob,???????????? // Pointer to the BLOB
?????????????? &cbEncodedBlob))?????????? // Size of the BLOB
CryptMsgClose(hMsg);
hMsg = CryptMsgOpenToDecode(
?????????????? MY_ENCODING_TYPE,????? // Encoding type.
?????????????? 0,???????????????????? // Flags.
?????????????? CMSG_DATA,???????????? // Look for a data message.
?????????????? NULL,????????????????? // Cryptographic provider.
?????????????? NULL,????????????????? // Recipient information.
?????????????? NULL))???????????????? // Stream information.