CA服务器开开发(三)---UsbKey认证 客户端Activex Com组件

使用Activex主要为了嵌入网页和服务端C#来调用加密。这里只给出关键代码吧

1.私钥解密

STDMETHODIMP CMAddr::DePrivKey(BSTR encode, BSTR* orign)
{

	//HCERTSTORE  hCertStore = NULL;
	BOOL ret=TRUE;
	HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv =NULL;
	BOOL bFreeKeyProv=FALSE;
	DWORD dwKeyType;
	HCRYPTKEY hKey = NULL;
	BYTE* pTempByte=NULL;
	CString outStr;
	CString run;

	run="DecodeJson";
	CString b64Str(encode);
	CString tempStr;
	CStringDecodeBase64(b64Str,tempStr);
	Json::Reader reader;
	Json::Value root;  

	if(NULL==Current_PCTX)
	{
		MessageBox("请选择证书!");
		goto cleanup;
	}

	if (!reader.parse(tempStr.GetBuffer(), root))
	{
		goto cleanup;
	}

	DWORD dwCount=root.size();
	pTempByte=new BYTE[dwCount];
	for(DWORD i=0;i<dwCount;i++)
	{
		pTempByte[i]=root[i].asInt();
	}
	
	run="CryptAcquireCertificatePrivateKey";
	ret=CryptAcquireCertificatePrivateKey(Current_PCTX, 0, 0, &hCryptProv, &dwKeyType, &bFreeKeyProv);
	if(!ret)goto cleanup;

	run="CryptGetUserKey";
	ret=CryptGetUserKey(hCryptProv,AT_KEYEXCHANGE,&hKey);
	if(!ret)goto cleanup;

	run="CryptDecrypt";
	ret=CryptDecrypt(hKey, 0, true, 0,pTempByte, &dwCount);
	if(!ret)goto cleanup;

	for(DWORD i=0;i<dwCount;i++)
	{
		outStr.AppendChar(pTempByte[i]);
	}

cleanup:
	if(NULL!=pTempByte)
	{
		delete[] pTempByte;
		pTempByte=NULL;
	}

	if(NULL!=hKey)
	{
		CryptDestroyKey(hKey);
	}

	if(NULL!=hCryptProv&&bFreeKeyProv)
	{
		CryptReleaseContext(hCryptProv,0);
	}

	if(!ret)
	{
		outStr.Empty();
		outStr.Format("ErrorCode:%0x"+run, GetLastError());
	}
	CComBSTR tempSTR(outStr);
	tempSTR.CopyTo(orign);
	tempSTR.Empty();
	return S_OK;
}

2.公钥加密

STDMETHODIMP CMAddr::EnPubKey(BSTR orign, BSTR cert, BSTR* encode)
{
	PCCERT_CONTEXT pCertContext=NULL;
	HCERTSTORE hCertStore = NULL;    
	HCRYPTPROV hCryptProv = NULL;
	HCRYPTKEY hPubKey = NULL;
	BYTE* pBinByte=NULL;
	BYTE* pOrignByte=NULL;

	BOOL ret;
	DWORD binBytes = 0;
	CString outStr;
	CString run;
	CString tempStr;
	Json::Value value;

	//get cert
	std::wstring scert(cert,SysStringLen(cert));

	run="Acquire Context";
	ret=CryptAcquireContext(&hCryptProv,NULL, NULL,PROV_RSA_FULL,0);
	if(!ret)goto cleanup;

	run="Read Cert";
	ret=CryptStringToBinaryW(scert.c_str()  , scert.length() ,CRYPT_STRING_BASE64HEADER , NULL , &binBytes ,NULL,NULL);
	if(!ret)goto cleanup;

	pBinByte=new BYTE[binBytes];
	ZeroMemory(pBinByte,binBytes);
	ret=CryptStringToBinaryW(scert.c_str() , scert.length() ,CRYPT_STRING_BASE64HEADER , pBinByte, &binBytes ,NULL,NULL);
	if(!ret)goto cleanup;

	run="Create Cert";
	pCertContext = CertCreateCertificateContext( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pBinByte , binBytes );

	run="Import PubKey";
	ret=CryptImportPublicKeyInfo(hCryptProv,PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
		&(pCertContext->pCertInfo->SubjectPublicKeyInfo),
		&hPubKey);
	if(!ret)goto cleanup;

	DWORD orignLen=SysStringLen(orign);
	DWORD pDataLen=orignLen;


	run="Run Encrypt";
	ret=CryptEncrypt(hPubKey,NULL,true,0,NULL,&pDataLen,orignLen);
	if(!ret)goto cleanup;

	pOrignByte=new BYTE[pDataLen];
	ZeroMemory(pOrignByte,pDataLen);

	for(DWORD i=0;i<orignLen;i++)
	{
		pOrignByte[i]=(BYTE)orign[i];
	}

	ret=CryptEncrypt(hPubKey,NULL,true,0,pOrignByte,&orignLen,pDataLen);
	if(!ret)goto cleanup;

	for(DWORD i=0;i<pDataLen;i++)
	{
		value[i]=pOrignByte[i];
	}
	tempStr=value.toStyledString().c_str();
	CStringEncodeBase64(tempStr,outStr);

cleanup:
	if(NULL!=pOrignByte)
	{
		delete[] pOrignByte;
		pOrignByte=NULL;
	}

	if(NULL!=pBinByte)
	{
		delete[] pBinByte;
		pBinByte=NULL;
	}

	if(NULL!=pCertContext)
	{
		CertFreeCertificateContext(pCertContext);
	}

	if(NULL!=hPubKey)
	{
		CryptDestroyKey(hPubKey);
	}


	if(NULL!=hCryptProv)
	{
		CryptReleaseContext(hCryptProv,0);
	}

	if(!ret)
	{
		outStr.Empty();
		outStr.Format(run+"ErrorCode:%0x", GetLastError());
	}


	CComBSTR outStrTemp(outStr);
	outStrTemp.CopyTo(encode);
	outStrTemp.Empty();
	return S_OK;
}

为了避免登录的时候重复选择证书,用户选择证书使用静态变量保存,并手动释放

STDMETHODIMP CMAddr::LoadCert(BSTR* certInfo)
{
	//加载会话证书
	
	HCERTSTORE       hCertStore = NULL;
	CString resultStr="";
	CString subject = "";
	CString sno="";
	Json::Value value;
	CHAR szName[1024];

	hCertStore = CertOpenSystemStore(
		0,
		"MY");
	if(NULL == hCertStore)
	{
		CertCloseStore(hCertStore, 0);
		MessageBox("CertOpenSystemStore Error!");
		goto cleanup;
	}
	Current_PCTX = CryptUIDlgSelectCertificateFromStore(
		hCertStore,   
		NULL,NULL,NULL,
		CRYPTUI_SELECT_LOCATION_COLUMN,0,NULL);

	if(!Current_PCTX)
	{
		MessageBox("请选择证书!");
		goto cleanup;
	}
	 ZeroMemory(szName,1024);
	 CertNameToStr(Current_PCTX->dwCertEncodingType,
		 &Current_PCTX->pCertInfo->Subject,
		 CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
		 szName,
		 sizeof(szName));
	 subject.Append(szName);

	 for(DWORD i=0 ;i<Current_PCTX->pCertInfo->SerialNumber.cbData; i++)
	 {
	 	BYTE  byteTemp =Current_PCTX->pCertInfo->SerialNumber.pbData[i];
	 	byteTemp = (byteTemp&0xF0>>4)|(byteTemp&0x0F<<4);
	 	sno.Format("%X"+sno,byteTemp);
	 }
	 
	 value["name"]=Json::Value(sno);
	 value["subject"]=Json::Value(subject);

	 resultStr.Append(value.toStyledString().c_str());
cleanup:
	CComBSTR tempSTR(resultStr);
	tempSTR.CopyTo(certInfo);
	tempSTR.Empty();
	if(NULL!=hCertStore)
	{
		CertCloseStore(hCertStore,NULL);
	}
	return S_OK;
}


STDMETHODIMP CMAddr::FreeCert(void)
{
	//释放会话证书
	if(NULL!=Current_PCTX)
	{
		CertFreeCertificateContext(Current_PCTX);
		Current_PCTX=NULL;
	}
	return S_OK;
}

这样一个完整的CA服务器开发的核心部分已经介绍完了。加密解密方法并没有做中文编码的处理,由于原文中也不含有中文,所以我也没处理。




你可能感兴趣的:(CA服务器开开发(三)---UsbKey认证 客户端Activex Com组件)