因为是.net安全,所以必须在VC7上运行下面面的一些例子(今天害得我在VC6上运行,错误一大堆),上面介绍了CRYPTAPI的一些基础,下面我就不按照MSDN的往下看了,下面的几个专题是Hashing,Signing Data,Creating and Receiving Enveloped Data Messages以及Encrypting and Decrypting.这些专题等需要用到的时候再具体看吧。主要专注于证书的操作。不过cryptui.dll又要求是在windows 2003 Server版本才可以,哎,只好等晚上再去买盘了。
1,解码CERT_INFO结构
给定一个证书,第一步是调用函数CertCreateCertificateContext解码证书BLOB。当这个函数被调用,那么产生一个编码证书的复制品,创建一个CERT_CONETXT类型的结构和一个CERT_INFO类型的结构。一个certificate_context包含一个原始证书 BLOB,一个CERT_CONETXT类型的结构以及一个CERT_INFO类型的结构。下面我们具体看看CERT_CONETXT以及 CERT_INFO的结构(wincrypt.h):
typedef struct _CERT_CONTEXT {
DWORD dwCertEncodingType;
BYTE *pbCertEncoded;
DWORD cbCertEncoded;
PCERT_INFO pCertInfo;
HCERTSTORE hCertStore;
} CERT_CONTEXT, *PCERT_CONTEXT;
typedef const CERT_CONTEXT *PCCERT_CONTEXT;
typedef struct _CERT_INFO {
DWORD dwVersion;
CRYPT_INTEGER_BLOB SerialNumber;
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
CERT_NAME_BLOB Issuer;
FILETIME NotBefore;
FILETIME NotAfter;
CERT_NAME_BLOB Subject;
CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
CRYPT_BIT_BLOB IssuerUniqueId;
CRYPT_BIT_BLOB SubjectUniqueId;
DWORD cExtension;
PCERT_EXTENSION rgExtension;
} CERT_INFO, *PCERT_INFO;
typedef struct _CERT_EXTENSIONS {
DWORD cExtension;
PCERT_EXTENSION rgExtension;
} CERT_EXTENSIONS, *PCERT_EXTENSIONS;
由上面的三个结构可以明显的看出证书的存储过程。(具体参数意思可以由参数名看出来)
2,编码一个CERT_INFO结构
编码过程和解码过程是相反的,下面事例如何增加签发者到CERT_INFO结构中。
1,创建一个包含签发者名字的字符串。
2,创建一个CERT_RDN_ATTR结构的数组,它初始化后能够包含刚刚创建的字符串。
3,创建一个CERT_RDN结构的数组,它包含刚刚初始化的CERT_RDN_ATTR结构的数组
4,创建一个CERT_NAME_INFO结构指向刚刚创建的CERT_RDN结构的数组的指针
5,调用CryptEncodeObject函数来获取输出编码后BLOB的长度。
6,为BLOB分配内存空间
7,再次调用CryptEncodeObject函数,将有关编码信息写入
8,设置CERT_INFO结构中的Issuer.cbData为第5步得到的长度,设置Issuer.pbData为第6步得到的地址,那么现在签发者就存在于CERT_INFO结构中了。
添加一个编码后的扩展信息到CERT_INFO结构中
1,初始化一个扩展信息结构。
2,调用CryptEncodeObject,来获取所需空间大小。
3,分配空间
4,再次调用CryptEncodeObject来获取编码后的信息。
5,创建一个CERT_EXTENSION结构数组
6,初始化CERT_EXTENSION,并且在CERT_EXTENSION中添加刚刚编码后的信息。
7,初始化CERT_INFO结构的rgExtension,并且把他指向CERT_EXTENSION结构数组
1,CertOpenSystemStore打开系统最常用的证书存储区域。假如需要满足复杂的需要,请看CertOpenStore
HCERTSTORE WINAPI CertOpenSystemStore(
HCRYPTPROV hprov, //CSP句柄,NULL为默认句柄,或者由CryptAcquireContext返回
LPTCSTR szSubsystemProtocol //打开的系统存储区的名字。假如名字不为CA,MY,ROOT,SPC则新建一个证书存储区域,可以使用CertEnumSystemStore列出所有的已存在的系统存储区
);
2,CertOpenStore使用一个指定的存储区提供类型来打开一个证书存储区。
HCERTSTORE WINAPI CertOpenStore(
LPCSTR lpszStoreProvider, //指定提供的存储的类型,大量类型,请参见MSDN
DWORD dwMsgAndCertEncodingType, //只有当上一参数为CERT_STORE_PROV_MSG, CERT_STORE_PROV_PKCS7, or CERT_STORE_PROV_FILENAME才使用,否则必须为0
HCRYPTPROV hCryptProv, //密码算法提供方的句柄,推荐使用默认,将参数置为NULL
DWORD dwFlags, //它由高字节和低字节组成,参数众多。
const void* pvPara //void类型,可以指向任意类型数据。
);
例如:if(hSysStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,L"MY")打开系统的MY存储区
3,CertCloseStore关闭打开的证书存储区句柄
BOOL WINAPI CertCloseStore(
HCERTSTORE hCertStore, //证书存储区句柄
DWORD dwFlags
);
第二个参数一般为0,关闭了存储区,但是里面内容并没有释放
假如为CERT_CLOSE_STORE_CHECK_FLAG,检查没有释放空间的证书,CRL和CTL内容。他将返回一个错误报告。一般只用用于程序的诊断工具。
假如为CERT_CLOSE_STORE_FORCE_FLAG,则强制释放相关空间。他只在存储区打开并且存储区以及其相关内容没有被别的程序调用的时候使用才安全的。
4,CertDuplicateStore复制存储区,其reference count 也将增一,返回一个存储区的句柄
HCERTSTORE WINAPI CertDuplicateStore(
HCERTSTORE hCertStore
);
5,CertFindCertificateInStore从证书存储区中寻找符合指定要求的证书内容
PCCERT_CONTEXT WINAPI CertFindCertificateInStore(
HCERTSTORE hCertStore, //打开的证书存储区的句柄
DWORD dwCertEncodingType, //指定编码的类型,一般为X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
DWORD dwFindFlags, //用来修改查找规则,一般都不用并且把它设置为0
DWORD dwFindType, //指定的查找类型,类型中多,例如CERT_FIND_CERT_ID
const void* pvFindPara, //需要查找的内容
PCCERT_CONTEXT pPrevCertContext //返回最近一次返回的CERT_CONTEXT结构。
);
例如:CertFindCertificateInStore(hSystemStore,MY_ENCODING_TYPE,0,CERT_FIND_SUBJECT_STR,L"Cert_subject_1",NULL);
6,CertCreateCertificateContext从一个编码证书创建一个证书内容
PCCERT_CONTEXT WINAPI CertCreateCertificateContext(
DWORD dwCertEncodingType, //指定编码的类型,一般为X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
const BYTE* pbCertEncoded, //包含编码证书内容的指针
DWORD cbCertEncoded //编码证书数据的长度
);
7,CertAddCertificateContextToStore将一个证书内容增加到证书存储区中。
BOOL WINAPI CertAddCertificateContextToStore(
HCERTSTORE hCertStore, //证书存储区的句柄
PCCERT_CONTEXT pCertContext, //CERT_CONTEXT结构指针
DWORD dwAddDisposition, //指定与已存在相同证书的操作,例如CERT_STORE_ADD_ALWAYS
PCCERT_CONTEXT* ppStoreContext //一个证书的复制的指针,可以为NULL,说明不需要返回证书的复制。
);
8,CertAddCertificateLinkToStore增加一个从一个证书存储区中证书内容到另一个证书存储区的连接
BOOL WINAPI CertAddCertificateLinkToStore(
HCERTSTORE hCertStore, //需要被增加的证书存储区的句柄
PCCERT_CONTEXT pCertContext, //CERT_CONTEXT结构指针
DWORD dwAddDisposition, //指定与已存在相同证书的操作,例如CERT_STORE_ADD_ALWAYS
PCCERT_CONTEXT* ppStoreContext //一个连接的复制的指针,可以为NULL,说明不需要返回证书的复制。
);
9, CertEnumCertificatesInStore从证书存储区中获取第一或者下一个证书。使用循环,他可以获取存储区所有的证书序列
PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(
HCERTSTORE hCertStore, //证书存储区的句柄
PCCERT_CONTEXT pPrevCertContext //上一个证书内容的CERT_CONTEXT结构指针,当第一次开始列举时参数必须为NULL
);
10,CryptUIDlgViewContext显示一个证书,CTL或者CRL内容
BOOL WINAPI CryptUIDlgViewContext(
DWORD dwContextType, //表示指向何种类型。参数有CERT_STORE_CERTIFICATE_CONTEXT,CERT_STORE_CRL_CONTEXT,CERT_STORE_CTL_CONTEXT
const void* pvContext, //要显示的证书,CRL或者CTL内容
HWND hwnd, //需要显示的窗口句柄,当为NULL的时候默认为桌面窗口
LPCWSTR pwszTitle, //显示的标题名,当为NULL时默认为内容类型
DWORD dwFlags, //暂时没被使用,并且必须为0
void* pvReserved //保留字,为将来使用。
);
例如:
CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT,pCertContext,NULL,NULL,0,NULL);
11,CertGetNameString获取CERT_CONTEXT结构中的主题或者签发者,并且将他转化为以null结尾的字符串
DWORD WINAPI CertGetNameString(
PCCERT_CONTEXT pCertContext, //包含CERT_CONTEXT证书内容的指针
DWORD dwType, //指定如何找到名字,并且输出的格式,例如CERT_NAME_ATTR_TYPE
DWORD dwFlags, //指定需要处理的类型,CERT_NAME_ISSUER_FLAG请求签发者名字,不设置则代表主题名
void* pvTypePara, //或者是一个包含dwStrType的字节指针,或者是一个指定名字属性的对象标志符指针
LPTSTR pszNameString, //转换后返回的字符串指针
DWORD cchNameString //上一字符串长度,以NULL结尾
);
如:CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,pszNameString,128)
12,CertEnumCertificateContextProperties获取与证书内容相关的第一个或者下一个扩展属性
DWORD WINAPI CertEnumCertificateContextProperties(
PCCERT_CONTEXT pCertContext, //CERT_CONTEXT结构指针
DWORD dwPropId //Property number of the last property enumerated. 参数为0时,获取第一个属性
);
13,CertGetCertificateContextProperty获取每个扩展属性的信息。
BOOL WINAPI CertGetCertificateContextProperty(
PCCERT_CONTEXT pCertContext, //CERT_CONTEXT指针
DWORD dwPropId, //需要获取的属性,参数众多,例如CERT_ACCESS_STATE_PROP_ID
void* pvData, //接收返回的数据指针
DWORD* pcbData //数据长度指针
);
例如:CertGetCertificateContextProperty(pCertContext, dwPropId , NULL, &cbData)
14,CryptUIDlgSelectCertificateFromStore显示一个对话框,允许在其中选择指定的证书。
PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateFromStore(
HCERTSTORE hCertStore, //被查找的证书存储区句柄
HWND hwnd, //要显示的窗口句柄,NULL默认为桌面窗口
LPCWSTR pwszTitle, //对话框标题,NULL默认为“Select Certificate”
LPCWSTR pwszDisplayString, //在选中的对话框中显示的语句,NULL默认为"Select a certificate you wish to use"
DWORD dwDontUseColumn, //排除一些显示的列,例如CRYPTUI_SELECT_ISSUEDTO_COLUMN不显示ISSUEDTO信息
DWORD dwFlags, //暂时设置为0
void* pvReserved //保留字,还未使用。
);
15,CertCompareCertificateName比较两个证书CERT_NAME_BLOB结构是否一致,成功返回true,否则返回false;
BOOL WINAPI CertCompareCertificateName(
DWORD dwCertEncodingType, //指定编码的类型,一般为X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
PCERT_NAME_BLOB pCertName1, //CERT_NAME_BLOB指针
PCERT_NAME_BLOB pCertName2
);
16,BOOL WINAPI CertComparePublicKeyInfo(比较公钥信息。
DWORD dwCertEncodingType,
PCERT_PUBLIC_KEY_INFO pPublicKey1,
PCERT_PUBLIC_KEY_INFO pPublicKey2
);
17,BOOL WINAPI CertCompareCertificate(比较两个证书
DWORD dwCertEncodingType,
PCERT_INFO pCertId1,
PCERT_INFO pCertId2
);
18,BOOL WINAPI CertDeleteCertificateFromStore(从一个证书存储区中删除一个证书。
PCCERT_CONTEXT pCertContext
);
19,BOOL WINAPI CertSerializeCertificateStoreElement(serializes a certificate context's encoded certificate
and its encoded properties
PCCERT_CONTEXT pCertContext, //CERT_CONTEXT指针
DWORD dwFlags, //保留字,为将来使用,设置为0
BYTE* pbElement, //Pointer to a buffer that receives the serialized output, including the
encoded certificate and possibly its properties.
DWORD* pcbElement //上一参数的数据长度。
);
20,CertAddEncodedCertificateToStore从编码证书中创建一个证书内容并且把他加入证书存储区。
BOOL WINAPI CertAddEncodedCertificateToStore(
HCERTSTORE hCertStore, //证书存储区句柄
DWORD dwCertEncodingType, //指定编码的类型,一般为X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
const BYTE* pbCertEncoded, //编码证书指针
DWORD cbCertEncoded, //编码证书长度
DWORD dwAddDisposition, //指定当已存在该证书时的操作。例如CERT_STORE_ADD_ALWAYS
PCCERT_CONTEXT* ppCertContext//证书内容的指针。可以为NULL。
);
例如:CertAddEncodedCertificateToStore(hFileStore,MY_ENCODING_TYPE,pCertContext->pbCertEncoded,pCertContext-
>cbCertEncoded,CERT_STORE_ADD_USE_EXISTING,NULL)
21, CertAddEnhancedKeyUsageIdentifier 增加一个增强密钥用途
BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(
PCCERT_CONTEXT pCertContext,//Cert_context结构。
LPCSTR pszUsageIdentifier //指定需要增加的OID
);
22,CertSetCertificateContextProperty设置指定的证书内容的扩展属性
BOOL WINAPI CertSetCertificateContextProperty(
PCCERT_CONTEXT pCertContext,
DWORD dwPropId,
DWORD dwFlags,
const void* pvData
);
22,CertNameToStr 转换编码后名字到以NULL结尾的字符串中。
DWORD WINAPI CertNameToStr(
DWORD dwCertEncodingType,
PCERT_NAME_BLOB pName,
DWORD dwStrType,
LPTSTR psz,
DWORD csz
);
23,CertStrToName转化一个以NULL结尾的字符串到证书的名字
BOOL WINAPI CertStrToName(
DWORD dwCertEncodingType,
LPCTSTR pszX500,
DWORD dwStrType,
void* pvReserved,
BYTE* pbEncoded,
DWORD* pcbEncoded,
LPCTSTR* ppszError
);