基本加密函数为开发加密应用程序提供了足够灵活的空间。所有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
RC4

MD5
SHA

PROV_RSA_SIG

none

RSA

none

MD5
SHA

PROV_RSA_SCHANNEL

RSA

RSA

RC4
DES
Triple DES

MD5
SHA

PROV_DSS

DSS

none

DSS

MD5
SHA

PROV_DSS_DH

DH

DSS

CYLINK_MEK

MD5
SHA

PROV_DH_SCHANNEL

DH

DSS

DES
Triple DES

MD5
SHA

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的各种参数。

  1. //-----------------------------------------------------------------
  2. //
  3. HCRYPTPROV hCryptProv;
  4. BYTE pbData[1000];
  5. DWORD cbData;
  6. //-------------------------------------------------------------------
  7. //缺省CSP名称
  8. cbData = 1000;
  9. if(CryptGetProvParam(
  10. hCryptProv,
  11. PP_NAME,
  12. pbData,
  13. &cbData,
  14. 0))
  15. {
  16. printf("CryptGetProvParam succeeded.\n");
  17. printf("Provider name: %s\n", pbData);
  18. }
  19. else
  20. {
  21. printf("Error reading CSP name. \n");
  22. exit(1);
  23. }
  24. //--------------------------------------------------------------------
  25. cbData = 1000;
  26. if(CryptGetProvParam(
  27. hCryptProv,
  28. PP_CONTAINER,
  29. pbData,
  30. &cbData,
  31. 0))
  32. {
  33. printf("CryptGetProvParam succeeded. \n");
  34. printf("Key Container name: %s\n", pbData);
  35. }
  36. else
  37. {
  38. printf("Error reading key container name. \n");
  39. exit(1);
  40. }

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指定的哈希对象。当一个哈希对象被销毁后,它对程序来说不可用。

  1. HCRYPTHASH hCryptHash;
  2. if (CryptCreateHash(
  3. hCryptProv,
  4. CALG_MD5,
  5. 0,
  6. 0,
  7. &hCryptHash
  8. ))
  9. 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]需要销毁的密钥句柄

说明:

此函数释放密钥句柄。

  1. HCRYPTKEY hCryptKey;
  2. if (CryptDeriveKey(hCryptProv, m_algid, m_hHash, 0, &hCryptKey))
  3. 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加密过的数据进行解密。

  1. //---------------------------------------------------
  2. HCRYPTPROV hCryptProv;
  3. HCRYPTHASH hCryptHash;
  4. HCRYPTKEY hCryptKey;
  5. CryptAcquireContext(
  6. hCryptProv, NULL,
  7. MS_DEF_PROV,
  8. PROV_RSA_FULL,
  9. CRYPT_VERIFYCONTEXT);
  10. CryptCreateHash(
  11. hCryptProv,
  12. CALG_MD5,
  13. 0,
  14. 0,
  15. &hCryptHash
  16. );
  17. static char szHash[]=”PISAHASHDATA”; //原始字符串
  18. DWORD dwLen=strlen(szHash);
  19. CryptHashData(hCryptHash, (BYTE*)szHash, dwLen, 0);
  20. CryptDeriveKey(hCryptProv, CALG_RC2, hCryptHash, 0, &hCryptKey);
  21. static char szEntry[]=“PISA2002”;
  22. DWORD dwLenIn = strlen(szEntry);
  23. DWORD dwLenOut=dwLenIn;
  24. CryptEncrypt(hCryptKey, 0, TRUE, 0, (BYTE*)szEntry, &dwLenOut, dwLenIn);
  25. CryptDecrypt(hCryptKey, 0, TRUE, 0,(BYTE*)szEntry,&dwLenOut);
  26. CryptDestroyKey(hCryptKey);
  27. CryptDestroyHash(hCryptHash);
  28. 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结构如下:

  1. typedef struct _CRYPT_SIGN_MESSAGE_PARA {
  2. DWORD cbSize;
  3. DWORD dwMsgEncodingType;
  4. PCCERT_CONTEXT pSigningCert;
  5. CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
  6. void *pvHashAuxInfo;
  7. DWORD cMsgCert;
  8. PCCERT_CONTEXT *rgpMsgCert;
  9. DWORD cMsgCrl;
  10. PCCRL_CONTEXT *rgpMsgCrl;
  11. DWORD cAuthAttr;
  12. PCRYPT_ATTRIBUTE rgAuthAttr;
  13. DWORD cUnauthAttr;
  14. PCRYPT_ATTRIBUTE rgUnauthAttr;
  15. DWORD dwFlags;
  16. DWORD dwInnerContentType;
  17. #ifdef CRYPT_SIGN_MESSAGE_PARA_HAS_CMS_FIELDS
  18. CRYPT_ALGORITHM_IDNETIFIER HashEncryptionAlgorithm;
  19. void pvHashEncryptionAuxInfo;
  20. #endif
  21. } 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 的大小。

说明:

此函数对指定数据进行哈希,然后对哈希值进行签名,然后对原始消息和签名哈希进行编码。

  1. //--------------------------------------------------------------------
  2. #define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
  3. #define SIGNER_NAME L"Insert_signer_name_here"
  4. #define CERT_STORE_NAME L"MY"
  5. void HandleError(char *s);
  6. void main(void)
  7. {
  8. //系统证书库句柄
  9. HCERTSTORE hStoreHandle;
  10. //--------------------------------------------------------------------
  11. //待签名的消息
  12. BYTE* pbMessage =
  13. (BYTE*)"CryptoAPI is a good way to handle security";
  14. //--------------------------------------------------------------------
  15. DWORD cbMessage = strlen((char*) pbMessage)+1;
  16. //--------------------------------------------------------------------
  17. //证书的上下文
  18. PCCERT_CONTEXT pSignerCert;
  19. CRYPT_SIGN_MESSAGE_PARA SigParams;
  20. DWORD cbSignedMessageBlob;
  21. BYTE *pbSignedMessageBlob;
  22. DWORD cbDecodedMessageBlob;
  23. BYTE *pbDecodedMessageBlob;
  24. CRYPT_VERIFY_MESSAGE_PARA VerifyParams;
  25. //--------------------------------------------------------------------
  26. const BYTE* MessageArray[] = {pbMessage};
  27. DWORD MessageSizeArray[1];
  28. MessageSizeArray[0] = cbMessage;
  29. //--------------------------------------------------------------------
  30. //
  31. printf("Begin processing. \n");
  32. printf(" The message to be signed is\n-> %s.\n",pbMessage);
  33. //--------------------------------------------------------------------
  34. // Open a certificate store.
  35. if ( !( hStoreHandle = CertOpenStore(
  36. CERT_STORE_PROV_SYSTEM,
  37. 0,
  38. NULL,
  39. CERT_SYSTEM_STORE_CURRENT_USER,
  40. CERT_STORE_NAME)))
  41. {
  42. HandleError("The MY store could not be opened.");
  43. }
  44. //--------------------------------------------------------------------
  45. //
  46. //得到证书的上下文,此证书必须能访问签名者的私钥
  47. if(pSignerCert = CertFindCertificateInStore(
  48. hStoreHandle,
  49. MY_TYPE,
  50. 0,
  51. CERT_FIND_SUBJECT_STR,
  52. SIGNER_NAME,
  53. NULL))
  54. {
  55. printf("The signer's certificate was found.\n");
  56. }
  57. else
  58. {
  59. HandleError( "Signer certificate not found.");
  60. }
  61. //--------------------------------------------------------------------
  62. //初始化签名结构
  63. SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
  64. SigParams.dwMsgEncodingType = MY_TYPE;
  65. SigParams.pSigningCert = pSignerCert;
  66. SigParams.HashAlgorithm.pszObjId = szOID_RSA_MD5;
  67. SigParams.HashAlgorithm.Parameters.cbData = NULL;
  68. SigParams.cMsgCert = 1;
  69. SigParams.rgpMsgCert = &pSignerCert;
  70. SigParams.cAuthAttr = 0;
  71. SigParams.dwInnerContentType = 0;
  72. SigParams.cMsgCrl = 0;
  73. SigParams.cUnauthAttr = 0;
  74. SigParams.dwFlags = 0;
  75. SigParams.pvHashAuxInfo = NULL;
  76. SigParams.rgAuthAttr = NULL;
  77. //--------------------------------------------------------------------
  78. //
  79. //首先得到BLOB的大小
  80. if(CryptSignMessage(
  81. &SigParams, // Signature parameters
  82. FALSE, // Not detached
  83. 1, // Number of messages
  84. MessageArray, // Messages to be signed
  85. MessageSizeArray, // Size of messages
  86. NULL, // Buffer for signed message
  87. &cbSignedMessageBlob)) // Size of buffer
  88. {
  89. printf("The size of the BLOB is %d.\n",cbSignedMessageBlob);
  90. }
  91. else
  92. {
  93. HandleError("Getting signed BLOB size failed");
  94. }
  95. //--------------------------------------------------------------------
  96. //分配BLOB的内存.
  97. if(!(pbSignedMessageBlob =
  98. (BYTE*)malloc(cbSignedMessageBlob)))
  99. {
  100. HandleError("Memory allocation error while signing.");
  101. }
  102. //--------------------------------------------------------------------
  103. //
  104. if(CryptSignMessage(
  105. &SigParams, //
  106. FALSE, //
  107. 1, //消息数量
  108. MessageArray, //待签名的消息
  109. MessageSizeArray, //消息大小
  110. pbSignedMessageBlob, //缓冲区
  111. &cbSignedMessageBlob)) //缓冲区大小
  112. {
  113. printf("The message was signed successfully. \n");
  114. }
  115. else
  116. {
  117. HandleError("Error getting signed BLOB");
  118. }
  119. //--------------------------------------------------------------------
  120. //验证签名信息
  121. //--------------------------------------------------------------------
  122. //初始化VerifyParams结构.
  123. VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
  124. VerifyParams.dwMsgAndCertEncodingType = MY_TYPE;
  125. VerifyParams.hCryptProv = 0;
  126. VerifyParams.pfnGetSignerCertificate = NULL;
  127. VerifyParams.pvGetArg = NULL;
  128. //--------------------------------------------------------------------
  129. //
  130. if(CryptVerifyMessageSignature(
  131. &VerifyParams, //.
  132. 0, //
  133. pbSignedMessageBlob, //.
  134. cbSignedMessageBlob, //
  135. NULL, //
  136. &cbDecodedMessageBlob, //.
  137. NULL)) // Pointer to signer certificate.
  138. {
  139. printf("%d bytes need for the buffer.\n",cbDecodedMessageBlob);
  140. }
  141. else
  142. {
  143. printf("Verification message failed. \n");
  144. }
  145. //--------------------------------------------------------------------
  146. //为缓冲区分配内存.
  147. if(!(pbDecodedMessageBlob =
  148. (BYTE*)malloc(cbDecodedMessageBlob)))
  149. {
  150. HandleError("Memory allocation error allocating decode BLOB.");
  151. }
  152. //--------------------------------------------------------------------
  153. //
  154. //得到缓冲区的大小
  155. if(CryptVerifyMessageSignature(
  156. &VerifyParams, // Verify parameters.
  157. 0, // Signer index.
  158. pbSignedMessageBlob, // Pointer to signed BLOB.
  159. cbSignedMessageBlob, // Size of signed BLOB.
  160. pbDecodedMessageBlob, // Buffer for decoded message.
  161. &cbDecodedMessageBlob, // Size of buffer.
  162. NULL)) // Pointer to signer certificate.
  163. {
  164. printf("The verified message is \n-> %s \n",pbDecodedMessageBlob);
  165. }
  166. else
  167. {
  168. printf("Verification message failed. \n");
  169. }
  170. //--------------------------------------------------------------------
  171. //
  172. if(pbSignedMessageBlob)
  173. free(pbSignedMessageBlob);
  174. if(pbDecodedMessageBlob)
  175. free(pbDecodedMessageBlob);
  176. if(pSignerCert)
  177. CertFreeCertificateContext(pSignerCert);
  178. if(CertCloseStore(
  179. hStoreHandle,
  180. CERT_CLOSE_STORE_CHECK_FLAG))
  181. {
  182. printf("The store closed and all certificates are freed. \n");
  183. }
  184. else
  185. {
  186. printf("Store closed after signing -- \n"
  187. "not all certificates, CRLs or CTLs were freed");
  188. }

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强制释放所有和证书库相关的上下文。

说明:

此函数释放证书库句柄。

  1. //-----------------------------------------------------------------
  2. HCERTSTORE hSystemStore;
  3. if(hSystemStore = CertOpenSystemStore(0,"MY"))
  4. {
  5. printf("The MY system store is open. Continue.\n");
  6. CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
  7. }
  8. else
  9. {
  10. printf("The MY system store did not open.\n");
  11. exit(1);
  12. }

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加密、解密

  1. //默认密钥向量
  2. private byte[] Keys = { 0xEF, 0xAB, 0x56, 0x78, 0x90, 0x34, 0xCD, 0x12 };
  3. /// <summary>
  4. /// DES加密字符串
  5. /// </summary>
  6. /// <param name="encryptString">待加密的字符串</param>
  7. /// <param name="encryptKey">加密密钥,要求为8位</param>
  8. /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
  9. public string EncryptDES(string encryptString, string encryptKey)
  10. {
  11. try
  12. {
  13. byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
  14. byte[] rgbIV = Keys;
  15. byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
  16. DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
  17. MemoryStream mStream = new MemoryStream();
  18. CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
  19. cStream.Write(inputByteArray, 0, inputByteArray.Length);
  20. cStream.FlushFinalBlock();
  21. return Convert.ToBase64String(mStream.ToArray());
  22. }
  23. catch
  24. {
  25. return encryptString;
  26. }
  27. }
  28. /// <summary>
  29. /// DES解密字符串
  30. /// </summary>
  31. /// <param name="decryptString">待解密的字符串</param>
  32. /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
  33. /// <returns>解密成功返回解密后的字符串,失败返源串</returns>
  34. public string DecryptDES(string decryptString, string decryptKey)
  35. {
  36. try
  37. {
  38. byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 8));
  39. byte[] rgbIV = Keys;
  40. byte[] inputByteArray = Convert.FromBase64String(decryptString);
  41. DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
  42. MemoryStream mStream = new MemoryStream();
  43. CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
  44. cStream.Write(inputByteArray, 0, inputByteArray.Length);
  45. cStream.FlushFinalBlock();
  46. return Encoding.UTF8.GetString(mStream.ToArray());
  47. }
  48. catch
  49. {
  50. return decryptString;
  51. }
  52. }

二.  DES/3DES加密算法源代码

  1. /* Project xxxx
  2. * Package com.xxxx.utils
  3. *
  4. */
  5. package com.xxxxx.utils;
  6. import java.io.FileInputStream;
  7. import java.io.ObjectInputStream;
  8. import java.security.NoSuchAlgorithmException;
  9. import java.security.Security;
  10. import javax.crypto.Cipher;
  11. import javax.crypto.KeyGenerator;
  12. import javax.crypto.NoSuchPaddingException;
  13. import javax.crypto.SecretKey;
  14. public class DES {
  15. private String Algorithm = "DESede"; //"DESede" for Triple DES
  16. private KeyGenerator keygen;
  17. private SecretKey deskey;
  18. private Cipher c;
  19. private byte[] cipherByte;
  20. public DES() {
  21. init();
  22. }
  23. public DES(String filename) {
  24. init(filename);
  25. }
  26. public SecretKey genKey() {
  27. try {
  28. keygen = KeyGenerator.getInstance(Algorithm);
  29. deskey = keygen.generateKey();   //利用JavaBean的持久化将key保存为文件XXX.key
  30. } catch (NoSuchAlgorithmException ex) {
  31. ex.printStackTrace();
  32. } catch (Exception ex) {
  33. ex.printStackTrace();
  34. }
  35. return deskey;
  36. }
  37. /**
  38. *
  39. * @param filename
  40. */
  41. public void init(String filename) {
  42. //  restore key
  43. Security.addProvider(new com.sun.crypto.provider.SunJCE());
  44. try {
  45. FileInputStream fis = new FileInputStream(filename);
  46. fis = new FileInputStream(filename);
  47. ObjectInputStream ois = new ObjectInputStream(fis);
  48. deskey = (SecretKey) ois.readObject();
  49. ois.close();
  50. fis.close();
  51. c = Cipher.getInstance(Algorithm);
  52. } catch (NoSuchAlgorithmException ex) {
  53. ex.printStackTrace();
  54. } catch (NoSuchPaddingException ex) {
  55. ex.printStackTrace();
  56. } catch (Exception ex) {
  57. ex.printStackTrace();
  58. }
  59. }
  60. public void init() {
  61. Security.addProvider(new com.sun.crypto.provider.SunJCE());
  62. try {
  63. keygen = KeyGenerator.getInstance(Algorithm);
  64. deskey = keygen.generateKey();
  65. c = Cipher.getInstance(Algorithm);
  66. } catch (NoSuchAlgorithmException ex) {
  67. ex.printStackTrace();
  68. } catch (NoSuchPaddingException ex) {
  69. ex.printStackTrace();
  70. }
  71. }
  72. public byte[] encryptor(String str) {
  73. try {
  74. c.init(Cipher.ENCRYPT_MODE, deskey);
  75. cipherByte = c.doFinal(str.getBytes());
  76. } catch (java.security.InvalidKeyException ex) {
  77. ex.printStackTrace();
  78. } catch (javax.crypto.BadPaddingException ex) {
  79. ex.printStackTrace();
  80. } catch (javax.crypto.IllegalBlockSizeException ex) {
  81. ex.printStackTrace();
  82. } catch (Exception ex) {
  83. ex.printStackTrace();
  84. }
  85. return cipherByte;
  86. }
  87. public String decryptor(byte[] buff) {
  88. try {
  89. c.init(Cipher.DECRYPT_MODE, deskey);
  90. cipherByte = c.doFinal(buff);
  91. } catch (java.security.InvalidKeyException ex) {
  92. ex.printStackTrace();
  93. } catch (javax.crypto.BadPaddingException ex) {
  94. ex.printStackTrace();
  95. } catch (javax.crypto.IllegalBlockSizeException ex) {
  96. ex.printStackTrace();
  97. } catch (Exception ex) {
  98. ex.printStackTrace();
  99. }
  100. return (new String(cipherByte));
  101. }
  102. }
  103. /*
  104. * Project xxxx
  105. * Package com.xxxx.utils
  106. * Created on 2003-11-24
  107. * Author Derys
  108. *
  109. */
  110. package com.xxxx.utils;
  111. /**
  112. *
  113. *
  114. */
  115. public class XXXDES {
  116. private static XXXDES instance = new XXXDES();
  117. public XXXDES() {
  118. }
  119. /**
  120. *
  121. * @param str
  122. * @return
  123. */
  124. public String encrypt(String str) {
  125. StringBuffer buffer = new StringBuffer();
  126. DES des = new DES("XXX.key");
  127. byte[] en = des.encryptor(str);
  128. for (int i = 0; i < en.length; i++) {
  129. buffer.append((char) en[i]);
  130. }
  131. return buffer.toString();
  132. }
  133. /**
  134. *
  135. * @param str
  136. * @return
  137. */
  138. public String decrypt(String str) {
  139. DES des = new DES("XXX.key");
  140. byte[] en = new byte[str.length()];
  141. for (int i = 0; i < str.length(); i++) {
  142. en[i] = (byte) str.charAt(i);
  143. }
  144. String de = des.decryptor(en);
  145. return de;
  146. }
  147. /**
  148. *
  149. * @param str
  150. * @return
  151. */
  152. public String replaceChar(String str) {
  153. StringBuffer buffer = new StringBuffer();
  154. int index = str.indexOf("'");
  155. if (index == -1) {
  156. return str;
  157. }
  158. while (index > -1) {
  159. buffer.append(str.substring(0, index));
  160. buffer.append("''");
  161. str = str.substring(index + 1);
  162. index = str.indexOf("'");
  163. }
  164. buffer.append(str);
  165. return buffer.toString();
  166. }
  167. /**
  168. *
  169. * @return
  170. */
  171. public static XXXDES getInstance(){
  172. if(instance == null){
  173. instance = new XXXDES();
  174. }
  175. return instance;
  176. }
  177. }

使用:
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基本结构

  1. struct
  2. {
  3. int pad;
  4. long version;
  5. const rsa_method *meth;
  6. engine *engine;
  7. bignum *n;
  8. n=p*q;
  9. bignum *e;        //公开的加密指数,经常为65537(ox10001)
  10. bignum *d;        //私钥
  11. bignum *p;        //大素数p
  12. bignum *q;       //大素数q
  13. bignum *dmp1;     //d mod (p-1)
  14. bignum *dmq1;     //d mod (q-1)
  15. bignum *iqmp;     //(inverse of q) mod p
  16. int references;
  17. int flags;        // ...
  18. }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结构

  1. typedef struct rsa_meth_st
  2. {
  3. const char *name;
  4. int (*rsa_pub_enc)(int flen,const unsigned char *from,            unsigned char *to,rsa *rsa,int padding);
  5. int (*rsa_pub_dec)(int flen,const unsigned char *from,             unsigned char *to,rsa *rsa,int padding);
  6. int (*rsa_priv_enc)(int flen,const unsigned char *from,                unsigned char *to, rsa *rsa,int padding);
  7. int (*rsa_priv_dec)(int flen,const unsigned char *from,                unsigned char *to,rsa *rsa,int padding);
  8. int (*rsa_mod_exp)(bignum *r0,const bignum *i,rsa *rsa);
  9. int (*bn_mod_exp)(bignum *r, const bignum *a, const bignum *p,                const bignum *m, bn_ctx *ctx,bn_mont_ctx *m_ctx);
  10. int (*init)(rsa *rsa);         /* called at new */
  11. int (*finish)(rsa *rsa);       /* called at free */
  12. int flags;             /* rsa_method_flag_* things */         char *app_data;                  /* may be needed! */
  13. int (*rsa_sign)(int type,const unsigned char *m, unsigned int m_length,unsigned char *sigret, unsigned int *siglen, const rsa *rsa);
  14. int (*rsa_verify)(int dtype,const unsigned char *m, unsigned int m_length,unsigned char *sigbuf, unsigned int siglen, const rsa *rsa);
  15. } rsa_method;
  16. const rsa_method *rsa_pkcs1_ssleay(void);
  17. <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);

代码示例如下:

    1. using System;
    2. using System.Security.Cryptography;
    3. using System.IO;
    4. using System.Text;
    5. namespace Microsoft.Samples.Security.PublicKey
    6. {
    7. class App
    8. {
    9. // Main entry point
    10. static void Main(string[] args)
    11. {
    12. // Instantiate 3 People for example. See the Person class below
    13. Person alice = new Person("Alice");
    14. Person bob = new Person("Bob");
    15. Person steve = new Person("Steve");
    16. // Messages that will exchanged. See CipherMessage class below
    17. CipherMessage aliceMessage;
    18. CipherMessage bobMessage;
    19. CipherMessage steveMessage;
    20. // Example of encrypting/decrypting your own message
    21. Console.WriteLine("Encrypting/Decrypting Your Own Message");
    22. Console.WriteLine("-----------------------------------------");
    23. // Alice encrypts a message using her own public key
    24. aliceMessage = alice.EncryptMessage("Alice wrote this message");
    25. // then using her private key can decrypt the message
    26. alice.DecryptMessage(aliceMessage);
    27. // Example of Exchanging Keys and Messages
    28. Console.WriteLine();
    29. Console.WriteLine("Exchanging Keys and Messages");
    30. Console.WriteLine("-----------------------------------------");
    31. // Alice Sends a copy of her public key to Bob and Steve
    32. bob.GetPublicKey(alice);
    33. steve.GetPublicKey(alice);
    34. // Bob and Steve both encrypt messages to send to Alice
    35. bobMessage = bob.EncryptMessage("Hi Alice! - Bob.");
    36. steveMessage = steve.EncryptMessage("How are you? - Steve");
    37. // Alice can decrypt and read both messages
    38. alice.DecryptMessage(bobMessage);
    39. alice.DecryptMessage(steveMessage);
    40. Console.WriteLine();
    41. Console.WriteLine("Private Key required to read the messages");
    42. Console.WriteLine("-----------------------------------------");
    43. // Steve cannot read the message that Bob encrypted
    44. steve.DecryptMessage(bobMessage);
    45. // Not even Bob can use the Message he encrypted for Alice.
    46. // The RSA private key is required to decrypt the RS2 key used
    47. // in the decryption.
    48. bob.DecryptMessage(bobMessage);
    49. } // method Main
    50. } // class App
    51. class CipherMessage
    52. {
    53. public byte[] cipherBytes; // RC2 encrypted message text
    54. public byte[] rc2Key; // RSA encrypted rc2 key
    55. public byte[] rc2IV; // RC2 initialization vector
    56. }
    57. class Person
    58. {
    59. private RSACryptoServiceProvider rsa;
    60. private RC2CryptoServiceProvider rc2;
    61. private string name;
    62. // Maximum key size for the RC2 algorithm
    63. const int keySize = 128;
    64. // Person constructor
    65. public Person(string p_Name)
    66. {
    67. rsa = new RSACryptoServiceProvider();
    68. rc2 = new RC2CryptoServiceProvider();
    69. rc2.KeySize = keySize;
    70. name = p_Name;
    71. }
    72. // Used to send the rsa public key parameters
    73. public RSAParameters SendPublicKey()
    74. {
    75. RSAParameters result = new RSAParameters();
    76. try
    77. {
    78. result = rsa.ExportParameters(false);
    79. }
    80. catch (CryptographicException e)
    81. {
    82. Console.WriteLine(e.Message);
    83. }
    84. return result;
    85. }
    86. // Used to import the rsa public key parameters
    87. public void GetPublicKey(Person receiver)
    88. {
    89. try
    90. {
    91. rsa.ImportParameters(receiver.SendPublicKey());
    92. }
    93. catch (CryptographicException e)
    94. {
    95. Console.WriteLine(e.Message);
    96. }
    97. }
    98. public CipherMessage EncryptMessage(string text)
    99. {
    100. // Convert string to a byte array
    101. CipherMessage message = new CipherMessage();
    102. byte[] plainBytes = Encoding.Unicode.GetBytes(text.ToCharArray());
    103. // A new key and iv are generated for every message
    104. rc2.GenerateKey();
    105. rc2.GenerateIV();
    106. // The rc2 initialization doesnt need to be encrypted, but will
    107. // be used in conjunction with the key to decrypt the message.
    108. message.rc2IV = rc2.IV;
    109. try
    110. {
    111. // Encrypt the RC2 key using RSA encryption
    112. message.rc2Key = rsa.Encrypt(rc2.Key, false);
    113. }
    114. catch (CryptographicException e)
    115. {
    116. // The High Encryption Pack is required to run this sample
    117. // because we are using a 128-bit key. See the readme for
    118. // additional information.
    119. Console.WriteLine("Encryption Failed. Ensure that the" +
    120. " High Encryption Pack is installed.");
    121. Console.WriteLine("Error Message: " + e.Message);
    122. Environment.Exit(0);
    123. }
    124. // Encrypt the Text Message using RC2 (Symmetric algorithm)
    125. ICryptoTransform sse = rc2.CreateEncryptor();
    126. MemoryStream ms = new MemoryStream();
    127. CryptoStream cs = new CryptoStream(ms, sse, CryptoStreamMode.Write);
    128. try
    129. {
    130. cs.Write(plainBytes, 0, plainBytes.Length);
    131. cs.FlushFinalBlock();
    132. message.cipherBytes = ms.ToArray();
    133. }
    134. catch (Exception e)
    135. {
    136. Console.WriteLine(e.Message);
    137. }
    138. finally
    139. {
    140. ms.Close();
    141. cs.Close();
    142. }
    143. return message;
    144. } // method EncryptMessage
    145. public void DecryptMessage(CipherMessage message)
    146. {
    147. // Get the RC2 Key and Initialization Vector
    148. rc2.IV = message.rc2IV;
    149. try
    150. {
    151. // Try decrypting the rc2 key
    152. rc2.Key = rsa.Decrypt(message.rc2Key, false);
    153. }
    154. catch (CryptographicException e)
    155. {
    156. Console.WriteLine("Decryption Failed: " + e.Message);
    157. return;
    158. }
    159. ICryptoTransform ssd = rc2.CreateDecryptor();
    160. // Put the encrypted message in a memorystream
    161. MemoryStream ms = new MemoryStream(message.cipherBytes);
    162. // the CryptoStream will read cipher text from the MemoryStream
    163. CryptoStream cs = new CryptoStream(ms, ssd, CryptoStreamMode.Read);
    164. byte[] initialText = new Byte[message.cipherBytes.Length];
    165. try
    166. {
    167. // Decrypt the message and store in byte array
    168. cs.Read(initialText, 0, initialText.Length);
    169. }
    170. catch (Exception e)
    171. {
    172. Console.WriteLine(e.Message);
    173. }
    174. finally
    175. {
    176. ms.Close();
    177. cs.Close();
    178. }
    179. // Display the message received
    180. Console.WriteLine(name + " received the following message:");
    181. Console.WriteLine(" " + Encoding.Unicode.GetString(initialText));
    182. } // method DecryptMessage
    183. } // class Person
    184. } // namespace PublicKey

CSP应用开发-CryptAPI函数库介绍的更多相关文章

  1. loadrunner 脚本开发-web_custom_request函数详细介绍

    脚本开发-web_custom_request函数详细介绍 by:授客 QQ:1033553122 c语言版本: int web_custom_request(const char *RequestN ...

  2. linux100讲——80 系统函数库介绍

    1.系统自建了函数库,可以在脚本中引用 /etc/init.d/functions 2.自建函数库 使用 source 函数脚本文件 “导入”函数 3. vim /etc/init.d/functio ...

  3. javaweb学习总结(三十)——EL函数库

    一.EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

  4. javaWeb学习总结(10)- EL函数库(2)

    一.EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

  5. jsp el函数库

    EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,所以SUN公司针对一些常见的处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

  6. day12(jsp指令&内置对象&动作标签、JavaBean、EL表达式&函数库)

    day12 JSP指令 JSP指令概述 JSP指令的格式:<%@指令名 attr1="" attr2="" %>,一般都会把JSP指令放到JSP文件 ...

  7. EL函数库

    一.EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

  8. javaweb基础(30)_EL函数库

    一.EL函数库介绍 由于在JSP页面中显示数据时,经常需要对显示的字符串进行处理,SUN公司针对于一些常见处理定义了一套EL函数库供开发者使用. 这些EL函数在JSTL开发包中进行描述,因此在JSP页 ...

  9. stm32开发之标准库的介绍

    1 STM32标准外设库概述 STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序.数据结构和宏组成,包括了微控制器所有外设的性能特征.该函数库还包括每一个外设的驱动描 ...

随机推荐

  1. [2019BUAA软工助教]第0次个人作业

    [2019BUAA软工助教]第0次个人作业 一.前言 我认为人生就是一次次地从<存在>到<光明>. 二.软件工程师的成长 博客索引 同学们在上这门课的时候基本都是大三,觉得在大 ...

  2. HDU 3518 Boring counting

    题目:Boring counting 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518 题意:给一个字符串,问有多少子串出现过两次以上,重叠不能算两次 ...

  3. safari打开的页面数字识别变为蓝色

    今天网页碰到一个很怪异的问题:app打开的一个网页样式是好的,但通过safari打开后数字的颜色变为蓝色,并且还变得可点击了! 原来safari总会把长串数字识别为电话号码,文字变成蓝色,点击还会弹出 ...

  4. CodeSmith如何生成实体类 ,完善版

    <%-- Name: Database Table Properties Author: Paul Welter Description: Create a list of properties ...

  5. union的特性,去重与不去重

    转载:https://blog.csdn.net/kingmax54212008/article/details/33762921 union的特性,去重与不去重 集合操作有 并,交,差 3种运算. ...

  6. python 条件分支与循环

    一.if判断: 语法一: if 条件: # 条件成立时执行的子代码块 代码1 代码2 代码3 示例: sex='female' age=18 is_beautiful=True if sex == ' ...

  7. 机器学习---文本特征提取之词袋模型(Machine Learning Text Feature Extraction Bag of Words)

    假设有一段文本:"I have a cat, his name is Huzihu. Huzihu is really cute and friendly. We are good frie ...

  8. Scrapy-redis 组件

    scrapy-redis 简介 scrapy-redis是scrapy框架基于redis数据库的组件,用于scrapy项目的分布式开发和部署. 特征 分布式爬取 可以启动多个spider工程,相互之间 ...

  9. C++ bitset 常用函数及运算符

    C++ bitset--高端压位卡常题必备STL 以下内容翻译自cplusplus.com,极大地锻炼了我的英语能力. bitset存储二进制数位. bitset就像一个bool类型的数组一样,但是有 ...

  10. 金融量化分析【day110】:NumPy-切片和索引

    一.索引和切片 1.数组和标量之间的运算 2.同样大小的数组之间的运算 3.数组索引 4.数组切片 1.一维数组 2.多维数组 二.布尔索引 1.问题 给一个数组,选出数组中所有大于5的数 1.答案 ...