函数pc教程

pc教程  时间:2021-04-03  阅读:()
CryptoAPI培训教程CryptoAPI培训教程项目名称:无开发部门:无项目编号:无密级:无作者:AdyLee版本:1.
2编写日期:2002-3-1审核:无电子邮件:adylee@sina.
com更新记录修改人修改日期修改对象备注(原因、进一步的说明等)AdyLee2002-3-1整篇丰富内容AdyLee2002-3-11整篇丰富内容AdyLee2003-9-29整篇整理CryptoAPI培训教程-2-目录1前言.
32目的.
33新功能.
34CRYPTOAPI.
34.
1基本加密函数34.
1.
1服务提供者函数.
44.
1.
2密钥的产生和交换函数.
44.
1.
3编码/解码函数.
54.
1.
4数据加密/解密函数.
54.
1.
5哈希和数字签名函数.
54.
1.
6函数详解.
64.
2证书和证书库函数244.
2.
1证书库函数.
244.
2.
2维护函数.
244.
2.
3证书函数.
244.
2.
4证书撤销列表函数.
254.
2.
5证书信任列表函数.
264.
2.
6扩展属性函数.
264.
2.
7函数详解.
264.
3证书验证函数274.
3.
1使用CTL的函数.
284.
3.
2证书链验证函数.
284.
4消息函数284.
4.
1低级消息函数.
284.
4.
2简化消息函数.
294.
5辅助函数294.
5.
1数据管理函数.
294.
5.
2数据转换函数.
304.
5.
3增强密钥用法函数.
304.
5.
4密钥标示函数.
314.
5.
5证书库回调函数.
314.
5.
6OID支持函数.
314.
5.
7远程对象恢复函数.
324.
5.
8PFX函数.
325待续.
32CryptoAPI培训教程-3-1前言事隔1年有余,重新整理此文档,感触颇深.
冷眼旁观MS的CryptoAPI飞速发展,如今的CAPI已趋于稳定.
MS还在CryptoAPI的基础上封装了一个CAPICOM(目前版本2.
0),以供其他语言使用.
创建此文档是一年前,当时由于工作需要在Windows上写一个桌面安全的软件,所以接触到了CryptoAPI,顺便自己写了一个教程以备以后使用.
由于当初对CAPI认识有限,文档中难免会有错误和不足,不过以后我会不断的来更新和维护这个文档,以迎合MSCAPI的发展,也希望各位朋友能够一如既往的支持我.
由于工作之余匆忙整理,文档中难免有错误和遗漏,欢迎广大读者批评指正.
作者信箱为adylee@sina.
com.
2目的CryptoAPI(一个应用程序编程接口)目的就是提供开发者在Windows下使用PKI的编程接口.
CryptoAPI提供了很多函数,包括编码、解码、加密、解密、哈希、数字证书、证书管理和证书存储等功能.
对于加密和解密,CryptoAPI同时提供基于会话密钥和公钥/私钥对的方法.
3新功能CryptoAPI2.
0提供了用于密码学的函数.
2.
0版本包括了基本加密函数.
这些函数提供了大部分安全通讯的重要方面——秘密性和完整性.
其它重要的方面是认证——要保证发送者和接收者身份的确定性.
一种方法就是使用数字证书,有一种趋势就是要把证书合并到安全通讯中.
CryptoAPI2.
0中提供了管理和使用证书的函数,另外,2.
0版本中也提供了编码和解码PKCS#7(ASN.
1)消息.
证书管理函数维护和管理了一个证书的可持续库——证书库.
CryptoAPI2.
0在两个级别上加入了消息管理函数——低级消息函数和简化消息函数.
低级消息函数比简化消息函数更加富有弹性,但也需要更多的函数调用.
4CryptoAPI4.
1基本加密函数基本加密函数为开发加密应用程序提供了足够灵活的空间.
所有CSP的通讯都是通过这些函数.
一个CSP是实现所有加密操作的独立模块.
在每一个应用程序中至少需要提供一个CSP来完成所需的加密操作.
CryptoAPI培训教程-4-如果使用多于一个以上的CSP,在加密函数调用中就要指定所需的CSP.
微软基本加密提供者(MicrosoftBaseCryptographicProvider),是缺省绑定到CryptoAPI里的.
如果没有指定其他CSP时,这个CSP就是却省的.
每一个CSP对CryptoAPI提供了一套不同的实现.
一些提供了更加强大的加密算法,而其他一些CSP包含了对硬件的支持,比如智能卡.
另外,一些CSP偶尔和使用者直接通讯,比如数字签名就使用了用户的签名私钥.
基本加密函数包含了以下几种:4.
1.
1服务提供者函数应用程序使用服务提供者函数来连接和断开一个CSP.
下面就是主要的API:CryptAcquireContext获得指定CSP的密钥容器的句柄CryptContextAddRef对HCRYPTPROV句柄增加一个应用计数CryptEnumProviders枚举当前计算机中的CSPCryptEnumProviderTypes枚举CSP的类型CryptGetDefaultProvider对于指定CSP类型的却省CSPCryptGetProvParam得到一个CSP的属性CryptInstallDefaultContext安装先前得到的HCRYPTPROV上下文作为当前却省的上下文CryptReleaseContext释放由CryptAcquireContext得到的句柄CryptSetProvider和CryptSetProviderEx为指定CSP类型指定一个却省的CSPCryptSetProvParam指定一个CSP的属性CryptUninstallDefaultContext删除先前由CryptInstallDefaultContext安装的却省上下文4.
1.
2密钥的产生和交换函数密钥产生函数创建、配置和销毁加密密钥.
他们也用于和其他用户进行交换密钥.
下面就是主要的一些函数:CryptAcquireCertificatePrivateKey对于指定证书上下文得到一个HCRYPTPROV句柄和dwKeySpecCryptDeriveKey从一个密码中派生一个密钥CryptDestoryKey销毁密钥CryptDuplicateKey制作一个密钥和密钥状态的精确复制CryptExportKey把CSP的密钥做成BLOB传送到应用程序的内存空间中CryptGenKey创建一个随机密钥CryptGenRandom产生一个随机数CryptGetKeyParam得到密钥的参数CryptGetUserKey得到一个密钥交换或签名密钥的句柄CryptoAPI培训教程-5-CryptImportKey把一个密钥BLOB传送到CSP中CryptSetKeyParam指定一个密钥的参数4.
1.
3编码/解码函数有一些编码/解码函数,他们可以用来对证书、证书撤销列表、证书请求和证书扩展进行编码和解码.
以下就是这几个函数:CryptDecodeObject对lpszStructType结构进行解码CryptDecodeObjectEx对lpszStructType结构进行解码,此函数支持内存分配选项CryptEncodeObject对lpszStructType结构进行编码CyptEncodeObjectEx对lpszStructType结构进行编码,此函数支持内存分配选项4.
1.
4数据加密/解密函数这些函数支持数据的加密/解密操作.
CryptEncrypt和CryptDecrypt要求在被调用前指定一个密钥.
这个密钥可以由CryptGenKey、CryptDeriveKey或CryptImportKey产生.
创建密钥时要指定加密算法.
CryptSetKeyParam函数可以指定额外的加密参数.
CryptDecrypt使用指定加密密钥来解密一段密文CryptEncrypt使用指定加密密钥来加密一段明文CryptProtectData执行对DATA_BLOB结构的加密CryptUnprotectData执行对DATA_BLOB结构的完整性验证和解密4.
1.
5哈希和数字签名函数这些函数在应用程序中完成计算哈希、创建和校验数字签名.
CryptCreateHash创建一个空哈希对象CryptDestoryHash销毁一个哈希对象CryptDuplicateHash复制一个哈希对象CryptGetHashParam得到一个哈希对象参数CryptHashData对一块数据进行哈希,把它加到指定的哈希对象中CryptHashSessionKey对一个会话密钥进行哈希,把它加到指定的哈希对象中CryptSetHashParam设置一个哈希对象的参数CryptSignHash对一个哈希对象进行签名CryptoAPI培训教程-6-CryptVerifySignature校验一个数字签名4.
1.
6函数详解4.
1.
6.
1获得CSP密钥容器句柄4.
1.
6.
1.
1CryptAcquireContextBOOLWINAPICryptAcquireContext(HCRYPTPROV*phProv,LPCTSTRpszContainer,LPCTSTRpszProvider,DWORDdwProvType,DWORDdwFlags);参数:phProv[out]CSP句柄指针pszContainer[in]密钥容器名称,指向密钥容器的字符串指针.
如果dwFlags为CRYPT_VERIFYCONTEXT,pszContainer必须为NULL.
pszProvider[in]指向CSP名称的字符串指针.
如果为NULL,就使用却省的CSP.
dwProvType[in]CSP类型.
dwFlags[in]标志.
CRYPT_VERIFYCONTEXT此选项指出应用程序不需要使用公钥/私钥对,如程序只执行哈希和对称加密.
只有程序需要创建签名和解密消息时才需要访问私钥.
CRYPT_NEWKEYSET使用指定的密钥容器名称创建一个新的密钥容器.
如果pszContainer为NULL,密钥容器就使用却省的名称创建.
CRYPT_MACHINE_KEYSET由此标志创建的密钥容器只能由创建者本人或有系统管理员身份的人使用.
CRYPT_DELETEKEYSET删除由pszContainer指定的密钥容器.
如果pszContainer为NULL,却省名称的容器就会被删除.
此容器里的所有密钥对也会被删除.
CRYPT_SLIENT应用程序要求CSP不显示任何用户界面.
说明:这个函数是用来取得指定CSP密钥容器句柄,以后的任何加密操作就是针对此CSP句CryptoAPI培训教程-7-柄而言.
函数首先查找由dwProvType和pszProvider指定的CSP,如果找到了CSP,函数就查找由此CSP指定的密钥容器.
由适当的dwFlags标志,这个函数就可以创建和销毁密钥容器,如果不要求访问私钥的话,也可以提供对CSP临时密钥容器的访问.
4.
1.
6.
1.
2CryptReleaseContextBOOLWINAPICryptReleaseContext(HCRYPTPROVhProv,DWORDdwFlags);参数:hProv[in]由CryptAcquireContext获得的CSP句柄.
dwFlags[in]保留.
必须为0.
说明:此函数释放CSP的句柄.
对于每一次调用,CSP的引用计数都减1.
当引用计数为0时,CSP上下文就会被系统释放变成无效句柄,以后针对此CSP句柄的函数不再可用.
此函数并不销毁密钥容器或密钥对.
HCRYPTPROVhCryptProv;if(CryptAcquireContext(hCryptProv,NULL,MS_DEF_PROV,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT))CryptReleaseContext(hCryptProv,NULL);4.
1.
6.
2枚举CSP4.
1.
6.
2.
1CryptEnumProvidersBOOLWINAPICryptEnumProviders(DWORDdwIndex,DWORD*pdwReserved,DWORDdwFlags,DWORD*pdwProvType,LPTSTRpszProvName,DWORD*pcbProvName);参数:CryptoAPI培训教程-8-dwIndex[in]枚举下一个CSP的索引.
pdwReserved[in]保留.
必须为NULL.
dwFlags[in]保留.
必须为NULL.
pdwProvType[out]CSP的类型.
pszProvName[out]指向接收CSP名称的缓冲区字符串指针.
此指针可为NULL,用来得到字符串的大小.
pcbProvName[in/out]指出pszProvName字符串的大小.
说明:此函数得到第一个或下一个可用的CSP.
如果使用循环,就可以得到计算机上所有可用的CSP.
//声明初始化数据DWORDcbName;DWORDdwType;DWORDdwIndex=0;CHAR*pszName;//循环枚举CSP.
dwIndex=0;while(CryptEnumProviders(dwIndex,NULL,0,&dwType,NULL,//如果为NULL,则cbName返回CSP名称所需字节数&cbName//)){////动态分配内存.
if(!
(pszName=(LPTSTR)LocalAlloc(LMEM_ZEROINIT,cbName))){printf("ERROR-LocalAllocfailed!
");CryptoAPI培训教程-9-exit(1);}//获得CSP名称if(CryptEnumProviders(dwIndex++,NULL,0,&dwType,pszName,&cbName)){printf("%4.
0d%s\n",dwType,pszName);}else{printf("ERROR-CryptEnumProviders");exit(1);}LocalFree(pszName);}//循环结束4.
1.
6.
3获得CSP参数4.
1.
6.
3.
1CryptGetProvParamBOOLWINAPICryptGetProvParam(HCRYPTPROVhProv,DWORDdwParam,BYTE*pbData,DWORD*pdwDataLen,DWORDdwFlags);参数:hProv[in]CSP句柄.
dwParam[in]指定查询的参数.
PP_CONTAINER指向密钥名称的字符串PP_ENUMALGS不断的读出CSP支持的所有算法PP_ENUMALGS_EX比PP_ENUMALGS获得更多的算法信息PP_ENUMCONTAINERS不断的读出CSP支持的密钥容器CryptoAPI培训教程-10-PP_IMPTYPE指出CSP怎样实现的PP_NAME指向CSP名称的字符串PP_VERSIONCSP的版本号PP_KEYSIZE_INCAT_SIGNATURE的位数PP_KEYX_KEYSIZE_INCAT_KEYEXCHANGE的位数PP_KEYSET_SEC_DESCR密钥的安全描述符PP_UNIQUE_CONTAINER当前密钥容器的唯一名称PP_PROVTYPECSP类型PP_USE_HARDWARE_RNG指出硬件是否支持随机数发生器PP_KEYSPEC返回CSP密钥的信息pbData[out]指向接收数据的缓冲区指针.
pdwDataLen[in/out]指出pbData数据长度.
dwFlags[in]如果指定PP_ENUMCONTAINERS,就指定CRYPT_MACHINE_KEYSET.
说明:此函数获得CSP的各种参数.
//HCRYPTPROVhCryptProv;BYTEpbData[1000];DWORDcbData;//却省CSP名称cbData=1000;if(CryptGetProvParam(hCryptProv,PP_NAME,pbData,&cbData,0)){printf("CryptGetProvParamsucceeded.
\n");printf("Providername:%s\n",pbData);}else{printf("ErrorreadingCSPname.
\n");exit(1);}CryptoAPI培训教程-11-cbData=1000;if(CryptGetProvParam(hCryptProv,PP_CONTAINER,pbData,&cbData,0)){printf("CryptGetProvParamsucceeded.
\n");printf("KeyContainername:%s\n",pbData);}else{printf("Errorreadingkeycontainername.
\n");exit(1);}4.
1.
6.
4创建哈希4.
1.
6.
4.
1CryptCreateHashBOOLWINAPICryptCreateHash(HCRYPTPROVhProv,ALG_IDAlgid,HCRYPTKEYhKey,DWORDdwFlags,HCRYPTHASH*phHash);参数:hProv[in]CSP句柄Algid[in]哈希算法的标示符.
hKey[in]如果哈希算法是密钥哈希,如HMAC或MAC算法,就用此密钥句柄传递密钥.
对于非密钥算法,此参数为NULL.
dwFlags[in]保留.
必须为0.
phHash[out]哈希对象的句柄.
说明:此函数初始化哈希数据流.
它创建并返回了一个CSP哈希对象的句柄.
此句柄由CryptoAPI培训教程-12-CryptHashData和CryptHashSessionKey来调用.
4.
1.
6.
4.
2CryptHashDataBOOLWINAPICryptHashData(HCRYPTHASHhHash,BYTE*pbData,DWORDdwDataLen,DWORDdwFlags);参数:hHash[in]哈希对象句柄pbData[in]指向要加入到哈希对象的数据指针dwDataLen[in]数据长度dwFlags[in]标志CRYPT_USERDATA所有微软CSP都忽略此参数.
所有其他CSP都不能忽略此参数,如果置此参数,CSP提示用户直接数据数据.
说明:此函数把一段数据加入到指定的哈希对象中去.
4.
1.
6.
4.
3CryptGetHashParamBOOLWINAPICryptGetHashParam(HCRYPTHASHhHash,DWORDdwParam,BYTE*pbData,DWORD*pdwDataLen,DWORDdwFlags);参数:hHash[in]哈希对象的句柄dwParam[in]查询类型.
可以是下列:HP_ALGID哈希算法HP_HASHSIZE哈希值长度HP_HASHVAL哈希值,由hHash指定的哈希值或者消息哈希说明:此函数得到指定哈希对象的数据.
CryptoAPI培训教程-13-4.
1.
6.
4.
4CryptDestroyHashBOOLWINAPICryptDestroyHash(HCRYPTHASHhHash);参数:hHash[in]要销毁的哈希对象句柄说明:此函数销毁由hHash指定的哈希对象.
当一个哈希对象被销毁后,它对程序来说不可用.
…HCRYPTHASHhCryptHash;if(CryptCreateHash(hCryptProv,CALG_MD5,0,0,&hCryptHash))CryptDestroyHash(hCryptHash);…4.
1.
6.
5派生密钥4.
1.
6.
5.
1CryptDeriveKeyBOOLWINAPICryptDeriveKey(HCRYPTPROVhProv,ALG_IDAlgid,HCRYPTHASHhBaseData,DWORDdwFlags,HCRYPTKEY*phKey);参数:hProv[in]CSP句柄Algid[in]要产生密钥的对称加密算法hBaseData[in]哈希对象的句柄dwFlags[in]指定密钥的类型CRYPT_CREATE_SALT典型地,由哈希值产生一个会话密钥,有一些需要补位.
如果用此标志,密钥将会赋予一个盐值CryptoAPI培训教程-14-CRYPT_EXPORTABLE如果置此标志,密钥就可以用CryptExportKey函数导出.
CRYPT_NO_SALT如果置此标志,表示40位的密钥不需要分配盐值.
CRYPT_UPDATE_KEY有些CSP从多个哈希值中派生会话密钥.
如果这种情况,CryptDeriveKey需要多次调用.
phKey[in/out]密钥的句柄说明:此函数从一基本数据值中派生会话密钥.
函数保证当CSP和算法相同时,从相同基本数据值中产生的密钥是唯一的.
4.
1.
6.
5.
2CryptDestroyKeyBOOLWINAPICryptDestroyKey(HCRYPTKEYhKey);参数:hKey[in]需要销毁的密钥句柄说明:此函数释放密钥句柄.
…HCRYPTKEYhCryptKey;if(CryptDeriveKey(hCryptProv,m_algid,m_hHash,0,&hCryptKey))CryptDestroyKey(hCryptKey);…4.
1.
6.
6加密/解密4.
1.
6.
6.
1CryptEncryptBOOLWINAPICryptEncrypt(HCRYPTKEYhKey,HCRYPTHASHhHash,BOOLFinal,DWORDdwFlags,BYTE*pbData,DWORD*pdwDataLen,DWORDdwBufLen);参数:hKey[in]加密密钥的句柄hHashCryptoAPI培训教程-15-[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.
2CryptDecryptBOOLWINAPICryptDecrypt(HCRYPTKEYhKey,HCRYPTHASHhHash,BOOLFinal,DWORDdwFlags,BYTE*pbData,DWORD*pdwDataLen);参数:hKey[in]解密密钥的句柄hHash[in]哈希对象的句柄.
如果需要解密数据并且同时作哈希,hHash传递此参数.
Final[in]指出是否是最后一次解密操作.
dwFlags[in]保留pbData[in/out]需要解密数据的地址pdwDataLen[in/out]指向DWORD值的指针,此值指出解密数据的长度.
在调用此函数前,此值为需要解密数据的长度,调用此函数后,此值为已经解密的数据长度.
说明:此函数对由CryptEncrypt加密过的数据进行解密.
CryptoAPI培训教程-16-HCRYPTPROVhCryptProv;HCRYPTHASHhCryptHash;HCRYPTKEYhCryptKey;CryptAcquireContext(hCryptProv,NULL,MS_DEF_PROV,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT)CryptCreateHash(hCryptProv,CALG_MD5,0,0,&hCryptHash)staticcharszHash[]="PISAHASHDATA";//原始字符串DWORDdwLen=strlen(szHash);CryptHashData(hCryptHash,(BYTE*)szHash,dwLen,0);CryptDeriveKey(hCryptProv,CALG_RC2,hCryptHash,0,&hCryptKey);staticcharszEntry[]="PISA2002";DWORDdwLenIn=strlen(szEntry);DWORDdwLenOut=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.
1CryptSignMessageBOOLWINAPICryptSignMessage(PCRYPT_SIGN_MESSAGE_PARApSignPara,BOOLfDetachedSignature,DWORDcToBeSigned,constBYTE*rgpbToBeSigned[],DWORDrgcbToBeSigned[],CryptoAPI培训教程-17-BYTE*pbSignedBlob,DWORD*pcbSignedBlob);参数:pSignPara[in]指向CRYPT_SIGN_MESSAGE_PARA结构的指针.
CRYPT_SIGN_MESSAGE_PARA结构如下:typedefstruct_CRYPT_SIGN_MESSAGE_PARA{DWORDcbSize;DWORDdwMsgEncodingType;PCCERT_CONTEXTpSigningCert;CRYPT_ALGORITHM_IDENTIFIERHashAlgorithm;void*pvHashAuxInfo;DWORDcMsgCert;PCCERT_CONTEXT*rgpMsgCert;DWORDcMsgCrl;PCCRL_CONTEXT*rgpMsgCrl;DWORDcAuthAttr;PCRYPT_ATTRIBUTErgAuthAttr;DWORDcUnauthAttr;PCRYPT_ATTRIBUTErgUnauthAttr;DWORDdwFlags;DWORDdwInnerContentType;#ifdefCRYPT_SIGN_MESSAGE_PARA_HAS_CMS_FIELDSCRYPT_ALGORITHM_IDNETIFIERHashEncryptionAlgorithm;voidpvHashEncryptionAuxInfo;#endif}CRYPT_SIGN_MESSAGE_PARA,*PCRYPT_SIGN_MESSAGE_PARA;cbSize此结构的大小.
dwMsgEncodingType使用的编码类型.
一般为X509_ASN_ENCODING|PKCS_7_ASN_ENCODINGpSigningCert指向要签名的CERT_CONTEXT指针.
HashAlgorithmCRYPT_ALGORITHM_IDENTIFIER指出了对要进行签名的数据进行哈希的哈希算法pvHashAuxInfo必须为NULLcMsgCertrgpMsgCert数组中CERT_CONTEXT结构的元素数量.
如果此值为0,则签名消息中不包含任何证书.
rgpMsgCert指向CERT_CONTEXT的数组指针.
如果包含pSigningCert,它的指针必须放到rgpMsgCert数组中.
CryptoAPI培训教程-18-cMsgCrlrgpMsgCrl数组指向CRL_CONTEXT结构的元素数量.
如果为0,签名消息中不包含任何CRL_CONTEXT结构.
rgpMsgCrl指向CRL_CONTEXT结构的数组指针.
cAuthAttr必须为0rgAuthAttr指向CRYPT_ATTRIBUTE数组的指针.
每一次都包含了认证信息.
cUnauthAttrrgUnauthAttr数组大小.
rgUnauthAttr指向CRYPT_ATTRIBUTE结构的数组指针.
dwFlags通常为0.
dwInnerContentType通常为0.
HashEncryptionAlgorithmCRYPT_ALGORITHM_IDENTIFIER结构.
通常为0pvHashEncryptionAuxInfo必须为0.
fDetachedSignature[in]如果为TRUE,就是已解邦定的签名,否则为FALSE.
如果此参数为TRUE,pbSignedBlob中只有签名哈希.
否则rgpbToBeSigned和签名哈希都要被编码.
cToBeSigned[in]指出rgpbToBeSigned数据元素的个数.
除非fDetachedSigned为TRUE,此参数就是1.
rgpbToBeSigned[in]指向要签名数据的数组指针.
pbSignedBlob[out]指向一个接收签名哈希的数据地址.
如果此参数为NULL,就是需要来接收数据的内存大小.
pcbSignedBlob[in/out]指向DWORD的地址,此数据指出pbSignedBlob的大小.
说明:此函数对指定数据进行哈希,然后对哈希值进行签名,然后对原始消息和签名哈希进行编码.
…#defineMY_TYPE(PKCS_7_ASN_ENCODING|X509_ASN_ENCODING)#defineSIGNER_NAMEL"Insert_signer_name_here"#defineCERT_STORE_NAMEL"MY"voidHandleError(char*s);CryptoAPI培训教程-19-voidmain(void){//系统证书库句柄HCERTSTOREhStoreHandle;//待签名的消息BYTE*pbMessage=(BYTE*)"CryptoAPIisagoodwaytohandlesecurity";DWORDcbMessage=strlen((char*)pbMessage)+1;//证书的上下文PCCERT_CONTEXTpSignerCert;CRYPT_SIGN_MESSAGE_PARASigParams;DWORDcbSignedMessageBlob;BYTE*pbSignedMessageBlob;DWORDcbDecodedMessageBlob;BYTE*pbDecodedMessageBlob;CRYPT_VERIFY_MESSAGE_PARAVerifyParams;constBYTE*MessageArray[]={pbMessage};DWORDMessageSizeArray[1];MessageSizeArray[0]=cbMessage;//printf("Beginprocessing.
\n");printf("Themessagetobesignedis\n->%s.
\n",pbMessage);CryptoAPI培训教程-20-//Openacertificatestore.
if(!
(hStoreHandle=CertOpenStore(CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,CERT_STORE_NAME))){HandleError("TheMYstorecouldnotbeopened.
");}////得到证书的上下文,此证书必须能访问签名者的私钥if(pSignerCert=CertFindCertificateInStore(hStoreHandle,MY_TYPE,0,CERT_FIND_SUBJECT_STR,SIGNER_NAME,NULL)){printf("Thesigner'scertificatewasfound.
\n");}else{HandleError("Signercertificatenotfound.
");}//初始化签名结构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;CryptoAPI培训教程-21-SigParams.
dwFlags=0;SigParams.
pvHashAuxInfo=NULL;SigParams.
rgAuthAttr=NULL;////首先得到BLOB的大小if(CryptSignMessage(&SigParams,//SignatureparametersFALSE,//Notdetached1,//NumberofmessagesMessageArray,//MessagestobesignedMessageSizeArray,//SizeofmessagesNULL,//Bufferforsignedmessage&cbSignedMessageBlob))//Sizeofbuffer{printf("ThesizeoftheBLOBis%d.
\n",cbSignedMessageBlob);}else{HandleError("GettingsignedBLOBsizefailed");}//分配BLOB的内存.
if(!
(pbSignedMessageBlob=(BYTE*)malloc(cbSignedMessageBlob))){HandleError("Memoryallocationerrorwhilesigning.
");}//if(CryptSignMessage(&SigParams,//FALSE,//1,//消息数量MessageArray,//待签名的消息MessageSizeArray,//消息大小pbSignedMessageBlob,//缓冲区&cbSignedMessageBlob))//缓冲区大小{CryptoAPI培训教程-22-printf("Themessagewassignedsuccessfully.
\n");}else{HandleError("ErrorgettingsignedBLOB");}//验证签名信息//初始化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))//Pointertosignercertificate.
{printf("%dbytesneedforthebuffer.
\n",cbDecodedMessageBlob);}else{printf("Verificationmessagefailed.
\n");}//为缓冲区分配内存.
if(!
(pbDecodedMessageBlob=(BYTE*)malloc(cbDecodedMessageBlob))){HandleError("MemoryallocationerrorallocatingdecodeBLOB.
");}CryptoAPI培训教程-23-////得到缓冲区的大小if(CryptVerifyMessageSignature(&VerifyParams,//Verifyparameters.
0,//Signerindex.
pbSignedMessageBlob,//PointertosignedBLOB.
cbSignedMessageBlob,//SizeofsignedBLOB.
pbDecodedMessageBlob,//Bufferfordecodedmessage.
&cbDecodedMessageBlob,//Sizeofbuffer.
NULL))//Pointertosignercertificate.
{printf("Theverifiedmessageis\n->%s\n",pbDecodedMessageBlob);}else{printf("Verificationmessagefailed.
\n");}//if(pbSignedMessageBlob)free(pbSignedMessageBlob);if(pbDecodedMessageBlob)free(pbDecodedMessageBlob);if(pSignerCert)CertFreeCertificateContext(pSignerCert);if(CertCloseStore(hStoreHandle,CERT_CLOSE_STORE_CHECK_FLAG)){printf("Thestoreclosedandallcertificatesarefreed.
\n");}else{printf("Storeclosedaftersigning--\n""notallcertificates,CRLsorCTLswerefreed");}…CryptoAPI培训教程-24-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在库中增加一系列证书或CRLCertCreateContext从编码字节中创建指定上下文CertEnumSubjectInSortedCTL在CTL库中枚举信任主题CertFindSubjectInCTL在CTL中寻找指定主题CertFindSubjectInSortedCTL在分类CTL中寻找指定主题4.
2.
3证书函数CryptoAPI培训教程-25-下列函数是针对于证书的.
大多数函数都是处理CRL和CTL的.
CertAddCertificateContextToStore在证书库里增加一个证书上下文CertAddCertificateLinkToStore在证书库里增加一个对不同库里的证书上下文的链接CertAddEncodedCertificateToStore把编码证书转换成证书上下文并且把它加到证书库里CertCreateCertificateContext从编码证书中创建一个证书上下文.
但这个上下文并不放到证书库里CertCreateSelfSignCertificate创建一个自签名证书CertDeleteCertificateFromStore从证书库里删除一个证书CertDuplicateCertificate通过增加引用计数来复制证书上下文CertEnumCertificateInStore在证书库里枚举证书上下文CertFindCertificateInStore在证书库里寻找证书上下文CertFreeCertificateContext释放一个证书上下文CertGetIssuerCertificateFromStore在证书库里得到指定主题证书的发行者CertGetSubjectCertificateFromStore获得主题证书的上下文CertGetValidUsages返回所有证书的用法CertSerializeCertificateStoreElement串行化编码证书的证书上下文CertVerifySubjectCertificateContext使用发行者来验证主题证书CryptUIDlgViewContext显示证书、CRL或CTLCryptUIDlgSelectCertificateFromStore从指定库中显示对话框,可以从中选择证书4.
2.
4证书撤销列表函数CertAddCRLContextToStore在证书库里增加一个CRL上下文CertAddCRLLinkToStore在不同的库里增加一个CRL上下文链接CertAddEncodedCRLToStore把编码CRL转化成CRL上下文然后把它加入到证书库中CertCreateCRLContext从编码CRL中创建CRL句柄,但不把它加到库中CertDeleteCRLFromStore从证书库里删除一个CRLCertDuplicateCRLContext通过增加引用计数来复制CRL上下文CertEnumCRLsInStore枚举库里的CRL句柄CertFindCertificateInCRL从指定证书里寻找CRL列表CertFindCRLInStore在库里寻找CRL上下文CertFreeCRLContext释放CRL上下文CertGetCRLFromStore从库里得到CRL上下文句柄CertSerializeCRLStoreElement串行化CRL上下文的编码CRL和它的属性CryptoAPI培训教程-26-4.
2.
5证书信任列表函数CertAddCTLContextToStore把一个CTL上下文加入到证书库里CertAddCTLLinkToStore给不同库里的CRL上下文添加链接CertAddEncodedCTLToStore把编码CTL转化成CTL上下文并且把它加到证书库里CertCreateCTLContext从编码CTL中创建CTL上下文CertDeleteCTLFromStore从证书库里删除CTLCertDuplicateCTLContext通过增加引用计数来复制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.
1CertOpenSystemStoreHCERTSTOREWINAPICertOpenSystemStore(HCRYPTPROVhProv,LPCTSTRszSubsystemProtocol,);CryptoAPI培训教程-27-参数:hProv[in]CSP句柄.
如果为NULL,就为却省CSP.
如果不为NULL,它必须是由CryptAcquireContext得到的CSP句柄.
szSubsystemProtocol[in]系统证书库的名称.
可以为"CA"、"MY"、"ROOT"、"SPC".
说明:此函数用来打开通用的系统证书库.
4.
2.
7.
1.
2CertCloseStoreBOOLWINAPICertCloseStore(HCERTSTOREhCertStore,DWORDdwFlags);参数:hCertStore[in]证书库句柄.
dwFlags[in]典型地,此参数为0.
却省就是关闭证书库,对于为上下文分配的内存并不释放.
如果想要检查并且释放所有为证书、CRL和CTL上下文的分配的内存,就要置下列标志.
CERT_CLOSE_STORE_CHECK_FLAG检查没有释放的证书、CRL和CTL上下文.
CERT_CLOSE_STORE_FORCE_FLAG强制释放所有和证书库相关的上下文.
说明:此函数释放证书库句柄.
…HCERTSTOREhSystemStore;if(hSystemStore=CertOpenSystemStore(0,"MY")){printf("TheMYsystemstoreisopen.
Continue.
\n");CertCloseStore(hSystemStore,CERT_CLOSE_STORE_CHECK_FLAG);}else{printf("TheMYsystemstoredidnotopen.
\n");exit(1);}…4.
3证书验证函数证书验证是通过CTL和证书列表进行的.
CryptoAPI培训教程-28-4.
3.
1使用CTL的函数CertVerifyCTLUsage验证CTL用法CryptMsgEncodeAndSignCTL编码和验证CTLCryptMsgGetAndVerifySigner从一个消息中获得和验证CTLCryptMsgSignCTL对包含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通过增加引用计数来复制加密消息句柄CryptoAPI培训教程-29-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比较两个整数BLOBCertComparePublicKeyInfo通过比较两个证书公钥来决定他们是否相同CertFindAttribute通过OID来查找属性CertFindExtension通过OID来查找扩展CertFindRDNAttr通过OID来查找RDN属性CertGetIntendedKeyUsage从证书中取得相关密钥用法CertGetPublicKeyLength从公钥BLOB中取得公钥/私钥长度CertIsRDNAttrsInCertificateName通过指定RDN数组属性比较证书名称属性来决定证书是否已包含了所有属性CertVerifyCRLRevocation验证主题证书是否在CRL中CryptoAPI培训教程-30-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算法标示符转换成OIDCertGetNameString得到证书的主题或颁发者名称并且把它转换成字符串CertNameToStr把证书名称BLOB转换成字符串CertOIDToAlgId把OID转换成CSP算法表示符CertRDNValueToStr把名称值转换成字符串CertStrToName把字符串转换成编码证书名称CryptBinaryToString把二进制序列转换成字符串CryptFormatObject格式化编码数据,返回Unicode字符串CryptStringToBinary把格式化的字符串转换成二进制序列4.
5.
3增强密钥用法函数CertAddEnhancedKeyUsageIdentifier在证书EKU属性中增加一个用法标示符CertGetEnhancedKeyUsage获得证书的EKU扩展或属性信息CertRemoveEnhancedKeyUsageIdentifier从证书EKU扩展属性中删除用法标示符OIDCryptoAPI培训教程-31-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查找第一个或下一个匹配的CRLCertStoreProvFreeFindCRL释放前一个找到的CRL上下文CertStoreProvGetCRLProperty得到指定CRL属性CertStoreProvFindCTL查找第一个或下一个匹配的CTLCertStoreProvFreeFindCTL释放前一个找到的CTL上下文CertStoreProvGetCTLProperty得到指定CTL属性4.
5.
6OID支持函数CryptEnumOIDFuction枚举由编码类型、函数名和OID指定注册的OID函数CryptEnumOIDInfo枚举注册的OID信息CryptoAPI培训教程-32-CryptEnumOIDInfo使用指定的密钥和组查找OID信息CryptFreeOIDFuctionAddress释放OID函数地址句柄CryptGetDefaultOIDDllList对于指定的函数结合和类型获得却省注册的DLL入口CryptGetDefaultOIDFuctionAddress获得已安装的第一次或下一个却省函数或者加载包含却省函数的DLLCryptGetOIDFuctionAddress搜索匹配指定编码类型和OID函数列表,如果没有找到,就查找注册表.
CryptGetOIDFuctionValue获得指定编码类型、函数名称和OID的值CryptInitOIDFuctionSet初始化OID函数集合的句柄CryptInstallOIDFuctionAddress安装可调用的OID函数地址集合CryptRegisterDefaultOIDFuction注册包含却省函数的DLLCryptRegisterOIDFuction注册包含指定函数的DLLCryptRegisterOIDInfo注册由CRYPT_OID_INFO指定的OID信息CryptSetOIDFuctionValue设置编码类型、函数名称等的值CryptUnregisterDefaultOIDFunction卸载包含却省函数的DLLCryptUnregisterOIDFuction卸载包含函数的DLLCryptUnregisterOIDInfo卸载指定OID的信息4.
5.
7远程对象恢复函数CryptGetObjectUrl从证书、CTL或CRL中取得远程对象的URLCryptRetrieveObjectByUrl由URL指定位置恢复PKI对象4.
5.
8PFX函数PFXExportCertStore从证书库中导出证书或证书和私钥PFXExportCertStoreEx从证书库中导出证书或证书和私钥PFXImportCertStore从PFXBLOB导入到指定证书库PFXIsPFXBlob把外层BLOB像pfx包那样解码PFXVerifyPassword把外层BLOB像pfx包那样解码,并且用指定口令解密5待续由于当时写此文档的时候CAPI的版本为1.
0,现在已经发展到2.
0,CAPI增加了不少函数.
所以我会再以后工作之余抽空把2.
0新加的函数在文档中补充进去,也可能添加CAPICOM的内容.
谢谢!

美国Cera 2核4G 20元/45天 香港CN2 E5 20M物理机服务器 150元 日本CN2 E5 20M物理机服务器 150元 提速啦

提速啦 成立于2012年,作为互联网老兵我们一直为用户提供 稳定 高速 高质量的产品。成立至今一直深受用户的喜爱 荣获 “2021年赣州安全大赛第三名” “2020创新企业入围奖” 等殊荣。目前我司在美国拥有4.6万G总内存云服务器资源,香港拥有2.2万G总内存云服务器资源,阿里云香港机房拥有8000G总内存云服务器资源,国内多地区拥有1.6万G总内存云服务器资源,绝非1 2台宿主机的小商家可比。...

NameCheap 2021年新年首次活动 域名 域名邮局 SSL证书等

NameCheap商家如今发布促销活动也是有不小套路的,比如会在提前一周+的时间告诉你他们未来的活,比如这次2021年的首次活动就有在一周之前看到,但是这不等到他们中午一点左右的时候才有正式开始,而且我确实是有需要注册域名,等着看看是否有真的折扣,但是实际上.COM域名力度也就一般需要51元左右,其他地方也就55元左右。当然,这次新年的首次活动不管如何肯定是比平时便宜一点点的。有新注册域名、企业域...

ZJI-全场八折优惠,香港服务器 600元起,还有日本/美国/韩国服务器

月付/年付优惠码:zji  下物理服务器/VDS/虚拟主机空间订单八折终身优惠(长期有效)一、ZJI官网点击直达ZJI官方网站二、特惠香港日本服务器香港大埔:http://hkdb.speedtest.zji.net/香港葵湾:http://hkkw.speedtest.zji.net/日本大阪:http://jpsk.speedtest.zji.net/日本大阪一型 ...

pc教程为你推荐
地图应用什么地图导航最好用最准确porntimesexy time 本兮 MP3地址百度指数词为什么百度指数里有写词没有指数,还要购买www.niuniu.com哪里有免费牛牛游戏可以玩啊性间道女人性高潮的时候是怎样的状态新广告法被投诉违反了新广告法该怎么办www.8090.com重庆婚纱摄影www.xk8090.com这家好吗?苦木丹槐叶丹有什么功效大虫手绘大虫罗德曼的纹身有哪些(我想在肩膀文一个一样的)?福隆平福伦嘉的床质量怎么样?一般多少钱?
已备案域名 域名系统 vps优惠码cnyvps 187邮箱 x3220 谷歌香港 68.168.16.150 警告本网站 新天域互联 789电视网 如何用qq邮箱发邮件 paypal注册教程 江苏双线服务器 环聊 个人免费邮箱 网页加速 群英网络 广州主机托管 广州服务器托管 google搜索打不开 更多