首页 服务器 编程 必备知识 搜索引擎 圩日手册
站内搜索
最近浏览
推荐文章
热文排行

WinCE Security --- X509证书及私钥的导入


作者:ARM-WinCE

来源:http://blog.csdn.net/nanjianhui/article/details/5797772

 

WinCE下如果想导入X509证书及私钥,需要用到微软的CryptoAPI函数集,这是微软提供的专门用来支持PKI相关功能的模块。相信有些人知道在Linux下用的是Openssl,我会在后面介绍基于WinCELinux不同的平台,如何彼此进行证书验证以及加解密。今天这里先介绍一下证书和私钥的导入。

 

 

WinCE支持CryptoAPI函数,但是和Windows环境相比还是有些区别,主要是对一些Hash算法,加解密算法支持的不是很好。在WinCE下调用CryptoAPI函数实现的功能在Windows环境下运行没什么问题,但是反之,就不一定了。

 

下面先介绍一下证书及私钥导入的相关函数:

1. HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv,  DWORD dwFlags, const void* pvPara)

该函数用于打开一个证书库。

lpszStoreProvider: 证书库提供者,可以是一个文件,也可以来自一个注册表中的键值,或者是系统证书库等。

dwMsgAndCertEncodingType: 没有被使用,设置为0

hCryptProv: 密钥提供者,一般设置为NULL表示使用默认的提供者

dwFlags: 打开证书库的标记位,描述如何打开一个证书库

pvPara: 依赖于第一个参数证书提供者,说明具体的证书提供者

该函数如果调用成功,将会返回打开证书库的句柄。

 

2. BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)

该函数用于关闭一个证书库。

hCertStore: 要关闭的证书库的句柄

dwFlags: 标记位,表示如何关闭证书库

该函数调用成功,将返回TRUE

 

3. PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrevCertContext)

该函数用于枚举证书库中的X509证书,该函数可以在循环中反复被调用从而枚举每一个X509证书。

hCertStore: 已打开证书库的句柄

pPrevCertContext: 指向上一个被找到的X509证书,如果该参数为NULL,表示第一次被调用

该函数调用成功,将返回被枚举的X509证书结构信息

 

这里说一下PCCERT_CONTEXT,也就是该函数的返回值,它是一个指针指向CERT_CONTEXT,该结构用于描述X509证书信息,其中包括证书的类型,编码后的证书数据,大小,以及具体X509证书内部的详细信息,比如加密算法,Public key等。

 

 

4. BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)

该函数用于释放一个证书结构。

PCCERT_CONTEXT: 要被释放的X509证书结构的指针

该函数调用成功,返回TRUE

 

 

5. BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, const BYTE* pbCertEncoded, DWORD cbCertEncoded, DWORD dwAddDisposition, PCCERT_CONTEXT* ppCertContext)

该函数用于添加一个X509证书到证书库当中

hCertStore: 已打开证书库的句柄

dwCertEncodingType: 证书的编码类型,这里只能是X509_ASN_ENCODING,表示X509经过ASN.1编码后的证书

pbCertEncoded: 指向要添加的证书数据

cbCertEncoded: 证书的大小

dwAddDisposition: 添加证书标记位,描述添加方法

ppCertContext: 返回经过解码后的证书,一般设置为NULL,如果不为NULL,该结构要通过CertFreeCertificateContext函数释放

该函数调用成功,返回TRUE

 

 

6. BOOLEAN CRYPTFUNC CryptAcquireContext(HCRYPTPROV* phProv, LPCTSTR pszContainer, LPCTSTR pszProvider, DWORD dwProvType, DWORD dwFlags)

该函数用于获得一个可用的密钥容器。

phProv: 返回一个密钥容器提供者的句柄

pszContainer: 密钥容器的名字,如果该参数为NULL,一个默认的秘钥容器名将被使用,如果最后一个参数类型为CYRPT_VERIFYCONTEXT,则该参数必须为NULL

pszProvider: 密钥容器提供者的名字,为NULL,表示使用一个默认的秘钥容器提供者

dwProvType: 要获得的提供者的类型

dwFlags: 密钥容器标记位,描述如何使用密钥容器

该函数调用成功,返回TRUE

 

 

7. BOOL WINAPI CryptImportKey( HCRYPTPROV hProv, BYTE* pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY* phKey)

该函数用于导入密钥到密钥容器中。

hProv: 密钥容器的句柄

pbData: 密钥数据,必须是密钥BLOB格式

dwDataLen: 密钥数据长度

hPubKey: 一个公钥的句柄,如果导入的密钥是经过签名或者加密的,需要该公钥进行验证或者解密。如果导入的密钥没有加密,该参数为0

dwFlags: 导入标记位,一般为CRYPT_EXPORTABLE

phKey: 返回导入密钥的句柄

该函数调用成功,返回TRUE

 

 

8. CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)

该函数用于导出公钥信息。

hCryptProv: 密钥容器的句柄

dwKeySpec: 密钥的类型,可以是AT_KEYEXCHANGE或者AT_SIGNATURE

dwCertEncodingType: 编码类型,应该是X509_ASN_ENCODING

pInfo: 指向导出的公钥信息

pcbInfo: 作为输入指向Buffer的大小,作为输出表示到处公钥信息的长度

 

 

9. PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore, DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType, const void* pvFindPara, PCCERT_CONTEXT pPrevCertContext)

该函数用于在证书库中查找一个X509证书。

hCertStore: 已打开的证书库的句柄

dwCertEncodingType: 证书的类型,只能是X509_ASN_ENCODING

dwFindFlags: 没被使用,设置为0

dwFindType: 指定查找方法,设置为NULL表示返回下一个证书,也可以设置根据发行者信息,证书的IDpublic key以及签名等信息来查找

pvFindPara: 指向查找的信息

pPrevCertContext: 指向最后一次调用该函数返回的证书信息,一般设置为NULL

该函数调用成功,将返回找到的证书的信息结构。如果没有找到证书,将返回NULL

 

 

10. BOOL CRYPTFUNC CryptDestroyKey(HCRYPTKEY hKey)

该函数用于释放一个被导入的密钥的句柄。

hKey: 曾经被导入到密钥容器中的密钥句柄

函数调用成功,返回TRUE

 

 

11. BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)

该函数用于释放一个以获得的密钥容器。

hProv: 密钥容器的句柄

dwFlags: 没被使用,设置为0

该函数调用成功,返回TRUE

 

 

看完上面的介绍,但是感觉不知如何入手。我第一次使用CryptoAPI就是这种感觉,看完MSDN以后,还是不知道怎么用。幸好WinCE的控制面板中提供了证书和私钥导入的工具,同时也提供了源代码,源代码在” D:/WINCE600/PUBLIC/WCESHELLFE/OAK/CTLPNL/CPLMAIN”下面的certcpl.cpp文件中。我在看过源代码后,将部分移植到我的应用中用于证书和私钥的导入,下面结合代码介绍一下函数的使用。

 

//初始化函数,打开证书库

DWORD Cert_Init(void)

{

      DWORD fRet = FALSE;

      HANDLE hCaStore;

      PCCERT_CONTEXT pCaCert;

      WCHAR szName[512];

 

      //加载Crypt32.dll

      g_hCrypt32 = LoadLibraryW(L"crypt32.dll");

      g_CaPubKeySize = 0;

      if (g_hCrypt32)

      {

            pCertOpenStore = (PFNCERTOPENSTORE)GetProcAddressW(g_hCrypt32, L"CertOpenStore");

            pCertAddEncodedCertificateToStore = (PFNCERTADDENCODEDCERTIFICATETOSTORE)GetProcAddressW(g_hCrypt32, L"CertAddEncodedCertificateToStore");

            pCertCloseStore = (PFNCERTCLOSESTORE)GetProcAddressW(g_hCrypt32, L"CertCloseStore");

            pCryptExportPublicKeyInfo = (PFNCRYPTEXPORTPUBLICKEYINFO)GetProcAddressW(g_hCrypt32, L"CryptExportPublicKeyInfo");

            pCertFindCertificateInStore = (PFNCERTFINDCERTIFICATEINSTORE)GetProcAddressW(g_hCrypt32, L"CertFindCertificateInStore");

            pCertSetCertificateContextProperty = (PFNCERTSETCERTIFICATECONTEXTPROPERTY)GetProcAddressW(g_hCrypt32, L"CertSetCertificateContextProperty");

            pCertFreeCertificateContext = (PFNCERTFREECERTIFICATECONTEXT)GetProcAddressW(g_hCrypt32, L"CertFreeCertificateContext");

    &nfsp; 'nbsp;     pCryptAcquireC%rtificatePrivateKey = (PFNCRYPTACQUIRECERTIFICATOPRIVATEKEY)GetProcAddressW(g_hCrpt32, L&uuot;CsyptAcquireCertificatePrivateKey&quo;);

span style="box-sizing: border-bo};padding:`0px">&hbsp;   &nBsp; &nbs; &nrsp;   pCryptDecodaObjectEx = (PFNCRYPTDEFODEOBJECTEXaGetProcAddressW(b_hCrypt32, L&Quo;CryptDecodeObje#tEx");

 &nbwp; &ncsp;  &n"sr;     pCryptImportPublicKeyInfoEh = "PFNCRYPTIMPORTPUGLICKEYINFOEX+GetProcAd`ressW(g_hCrypt32, "CryptImportPublicKeyInfoEx&quoT;);

e-sPac. normaP&bac{gr辒-con黕: rgb(h5, 25u255)"緤鮬an st8/e="box耰zing:淊order-废x;padd+g: 0py偈ont-si: &: EP圙iw*g1磫e{wm4齕 黤J^L"l~eV甈`_魪2孶囂礼vQK稈p&鯱?Rx羠298啛R M敡`EPe端T^偎L昚_s^kvk-圯醖仺C6真緟対"EQ钰/旣揗wBt僂埏勳.G]籀銟d#-孙e薵剡+賄X獶┩該伝~w葋+^7X鰇焲(背漯搈'>?$漚!橲 "-Z唓䴖[佥湆鞆骀墶6隕F]蝎W 哖&$g闯 z䜩U>-嵄传長廂澤噱z棂滙焙b癛汲韼(残砰胁gu癝坰/辪嗵圜蓕O{8k0X汿S)覯课w%叿v鹬u阣惉JP轖刜|迩邻峬NJEt釰翚@媺=e洢鯑)盵WяK逳篎賁+y娍8r*D,鈡[歌9k* 敚趃杈(w史e*(幷板崵桨䴘#`岖柦岋B][*犣猗@簞 钧閱蜊$-鍉Co&闶c悡閺囵燻!G3b豆'闦K%\攣8欍杩U艱)鰢Uc决咐柅>孉.:弇凋u热g鐤1 諎椫3p`軟莆`Z^梦!粤见踻轭1鸛9稔9{#f娕犗圓?70xS)!i諁2梘鼱cw鵫僮 T饼鱋犙嬻K軞靬饛 0勾峙竗 1B,鞶, ]瞃s,棶D>!"z秙傅蓹帮帅_瓢s士栽Z7渼/a75蟵郡籋e蒱!嬟漴dO炢蔲襒7须@吷5菜 X m1#颡仰}漜俥遑t萇◆缾@ y橪穏异殤{T贷瓈酜鷱醊徥僱DP蒞T霾碞喂f(禌D蝐蟞菍}泘%瘐佐 q燪U'}E哔5b腀曛嵍i l貹噓8=$a*A4ψDc抴FQH鲄庪EM哶?繥M懈<蝚\O愖穭礜凥箑玗%琲鴘氿q僬靶;甝 嶊欖%aFAIc01W譀96蔙I耍:āN*!蚭袜危(弖亏 鵑摛&|$u鋓C剶x]tz< -@讦梟"R枝p6彖*m划甋7/|歪D&嬏靼吋/筼z\4"蚉槦(k `^臵閏悄Y嗋魭W震验$Pc!Dz媾郴崚崉氍p卥謢埩J_侯P(煚l氛墬jL㎜ 硧验4A#k<儀4壡C銨sP蒅蓍G 阡.諮e@E祼o枋;|RkK2&Oj觽煲3復u|X蛷+P,` l!:%婂媦g3堙d隞K9徔跲册 朻H铏H#'鸥0>6⺄=Zu&裳G緫u詿A荠糩u苺O'陦A銏嘛" X紥`QQ踻殇+畽厵$;B瘦:E倘炼巈鸛[倒?瘹;粁瞛X骢蕔剿n访"(^Iu逞妣-礒蚇f}囶ㄒ\橬an?俧瓵mDw6蔔vo@稏雿阖@_-5GG/~f萖=,k-,y[銾(/蹗擘0Q.\M钣橣敲'擎罇Lq+ 帅V呃 b 藇躵牤聞覴F8弨*涰2吙3.ポ埨苨>蘈 <4>柒矝趷/橆U綵N搌<8'7p暈pUq漥3瀵1w榆:{4U#V蛊6vM p$%S4X沎夥沈i55圑B椺A%8悇!丶懽掮遣銢瑳悥k0$眝e`)+t $$孄5攉7,:l随?憋邇杻+塪穳k祣 Btw滜N#77,戜wC3衺[GN 洡↑/b}ueg%- H5e捉|N裡嶇嶃(邤} z罍K駃TK<乾壽様 箰}孽雖L2が2Ng辞蜐Y葇SU帼q浏簉暌捹1欳镜廯蜧<琣~肿X|PZlo,:/藗$J偫f踌\/魂鶘x齘Xj形夞$-I a;韜嘭微DPx=: 栔8幄 秉8U嶙 轺恌猍4酴p蒸j 挏充珯-幄xA[WS(6貇ナ>厂痶\yj1鵯醘L:V-j?茶哖銬爢x\斃tH譴XP跽画潉A软腺H姻m']k鱎S榈氄Y$7.f 夑b坆*怀竞絺^zP> ys巑顅,vw&袩. 矌s&泌蚺x貹<,-嗺C潒*筈碼N漈e(髨^}O籓?M砝O "密[ 朁X莡簃eDE馅(G$@@*磁凶鍅柈w 螞A韭P昲墩Rz鲄犴xq*ΒJS 匆鹋9宸'枦d_汓}伵弔挰$襆M荳嵱5篬獷q曥4闸艘a额楚秕蓻J贌U瓶TVB啩j诮霯K*姮bV{勷$ 垝嵉U`齴6=7}h饤骓唒仂7寐2i赤[Z#fye 2唱6鵡5魀伋8f墌药g2:呿痂△*埵嬛4鄳席-絣YC玮Z斕?腰/銟將HZヰ7 J啍蔭|,恠垡1羓0蟕&仦j榝楲粗lM镞 咳<[崲宓n觌Gc塤1oyDk搝M鸙(7祻嫤K=1B適_7)J傼~焬8桒[vǒ~癢漥'i$t#竓s \/?藚桡A磴僢阬邛椣!橓<+y濻h 竊靺E鷱O 禞塢-<5凥s挄|輝壿啹1T,qC+kP穯酤枖2]鸆o坉=穴T嵇y}曽a鏑z蟇檢嚻瀻疶鹦kL!簲e欙駸=狦齜瘘 獻CX抾轸*墈桂民椾莙魥=桹洧WZ薱掅u狔(昆N-均e3A璐"#sKqD氳欲0茀F0'Q諳罏潤廉 吳ga鸟绉1/繹8 讥s)暥58Sj慦I}/飼烂犧{黆峅7v蛪Q(4L療颦鉻E槦o鵦7磡ogLcL桙睡秜jk筮x進禇5,遏C斦怶' 祚泤w,3ik憵T w-:焇/灻#t<)噍@呫] 耞A*E=eHIx忯@>5殝揫FD嬖X ; J6逦燭尩捦勱踄}箑V& 澛裩)鼒豦v_ぶ淗黽p.5儖)扚毛` 剫鍻~[hL5騗钸'絬穈飣~)m版NM Ih潿禲_?鉸糀伂!G+o崂 #_橫糊咸寈楑湞)圁噖6嬨餇jR+&{^鹭|業/e麯mDx)>菅骫Wp嘄 [ 浥+tw@YW2*B+椤p祝パ<)0il飭jU0t濴N峬U"JuBMK阨)<雾芢锄鳸SE敟韯z伅又L陕 錀钔佀┞韎<彡;r訆婴X某k蓈|捓m曑┤;s~.黕坡缶e檄屨鑊Li墩繕b祉n韌q 拹vV険眬^]]湝}擪j釀朴俚|巺JPI╖W86 b7萺&T煗夭支迊)瓉胤騟矵鵹+aoσ7=!-Ue"A垥I懫E%惔)sVt骧iu7Mw4x[.碲谺_莖闘 淿蕲:珞向%嵍4铭籫 m0B谕勮pz+眜\廦侬鱃v抓AB:啒6盜@, 縋j籔 :魎z┼呯諛屾l瓗z\t书厜柔€(矕苡dR~廓蔰^f[刋: 4懟S﨎+k3h蜉pk播U k贂Jmo怘i拝B篈儢駧*澺(.0旊=鸳噏玻(:^萈6}"|WZ{J軋バ滰k)6tV趺X>熭|%y2y半〤牗,稍c?筳舚&鶬R戣 `+鹱<踺T睥,E仪>歷糼="pz摼増=冈狾)讞驂cOI鑛;.-Jt膢糞谌綔蜖菼網g厵埪SN嵽1坧蘦 X塍]?f足Jm蜹<憥鋽9瘒wf琶扦)傭}阸P 嗨犩0>胹.床騉祧櫣粘賬b遍I跳6A4筢嶖憆9v7 $9 2滂-祁轔滀.IfgtO芨C懧2oA庂? *阓 r惈A4W*S堍<蛵*R^Ш@扊頬閺9}?#鑎/谡bG&Y0 rN艙单辖F0)珘u矞馬?羨1/鯣HI中裓(酩恮熗&7p郈'齏I:掚瀬醰晒趗{3?揿沲P.鱿贑&KTVBr…匆媟7鬃嶏0`;鸒b3墠 ;z)侾狨-龅镁#3p(麙+躽jビk鬨Q,D]~邷V=┇稢j儖J痹幬瞢鉛 裓帤雚'<{ヱ镞患囕+继 7棣,Z彃T崔r按 h互⿴弤椹Lm縻os幍X浮屑k痶1z[kNg*梠')Eb嚽6貒掊毥鱧7欪 H瘱枸X 荵LR*/畐牡󴚺m#浺VrA諪蘋鶂{蹒&糏0r曹夾s[+寉VU5瞋lh]闻9稬)バ5铂孙-鹄據襉z妩鎹扃敎okk#hЯ&%0銍齍M锸8p6眕&tT嚨鼒點6颅焧珀(濪: 牑鱁績篍d⑿痧瓈w偎s 坏n甁惂磺愬I掙KW$忏С0*濲 >杗*碯I搱D攔] KOe`y]|靡DwSIF籕+>扏琦r鸰=谑睙r欑蠨_圊)嬋 祭9餡"]>1{験㈣Y{s卵D霎槰a躉(I('鼪布 R, 昸//导入X509证书,lpszFileName为证书的路径

DWORD Cert_ImportCert(LPTSTR lpszFileName)

{

      DWORD dwSize, dwRealSize;

      PBYTE pbFile = NULL;

      HANDLE hFile = INVALID_HANDLE_VALUE;

      BOOL fRet = FALSE;

 

 

      // 打开证书文件

      hFile = CreateFile(lpszFileName, GENERIC_READ, 0, NULL,      OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);

      if (hFile)

      {     // 获得证书文件大小

            dwSize = GetFileSize(hFile, NULL);

            if (dwSize != 0xFFFFFFFF)

            {     // 分配内存

                  pbFile = (PBYTE)LocalAlloc(LPTR, dwSize);

                  if (pbFile)

                  {     // 读入证书

                        if (ReadFile(hFile, pbFile, dwSize, &dwRealSize, NULL) == TRUE)

                        {    

                              // 添加一个DER格式的X509证书到证书库

                              fRet = pCertAddEncodedCertificateToStore(hStore, X509_ASN_ENCODING,

                                          pbFile, dwRealSize, CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES,0);

                              if (fRet == TRUE)

                              {

                                    printf("Import Certificate OK./r/n");

                              }

                              else if (fRet = CRYPT_E_EXISTS)

                              {

                                    printf("Certificate exists./r/n");

                                    fRet = TRUE;

                              }

                              else

                              {

                                    printf("Import Certificate Error./r/n");

                              }

                        }

                  }

            }

      }

 

      if (hFile)

      {

            CloseHandle(hFile);

      }

      if (pbFile)

      {

            LocalFree(pbFile);     

      }

 

      return fRet;

}

 

// 获得私钥中的密码,该函数会被Cert_ImportPrvtKey函数调用

static BOOL GetPasswordKey(

            IN HCRYPTPROV hProv,

            IN ALG_ID Algid,

            IN PBYTE pbPswd,

            IN DWORD dwPswdLen,

            IN BYTE *pbSalt,

            IN DWORD cbSalt,

            OUT HCRYPTKEY *phEncryptKey

            )

{

      BOOL fResult;

      BYTE *pbPassword;

      DWORD cbPassword;

      HCRYPTHASH hHash = 0;

      HCRYPTKEY hEncryptKey = 0;

     

 

      pbPassword = pbPswd;

      cbPassword = dwPswdLen;

      if (cbPassword)

      {

            if (!CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash))

                  goto ErrorReturn;

            if (cbSalt) {

                  if (!CryptHashData(hHash, pbSalt, cbSalt, 0))

                        goto ErrorReturn;

            }

            if (!CryptHashData(hHash, pbPassword, cbPassword, 0))

                  goto ErrorReturn;

            if (!CryptDeriveKey(hProv, Algid, hHash, 0, &hEncryptKey))

                  goto ErrorReturn;

      }

 

      fResult = TRUE;

      goto CommonReturn;

 

ErrorReturn:

      fResult = FALSE;

      if (hEncryptKey)

      {

            CryptDestroyKey(hEncryptKey);

            hEncryptKey = 0;

      }

CommonReturn:

      if (hHash)

            CryptDestroyHash(hHash);

      *phEncryptKey = hEncryptKey;

 

      return fResult;

}

 

//导入PVK格式的私钥并在证书库中查找和它匹配的证书,lpFileName为私钥文件路径,pbPassword为私钥密码,dwPswdLen为密码长度

DWORD Cert_ImportPrvtKey(LPTSTR lpFileName, BYTE* pbPassword, DWORD dwPswdLen)

{

      BOOL fRet = TRUE;

      DWORD dwSize, dwRealSize, cbPvk, cbData;

      PBYTE pbFile = NULL;

      HANDLE hFile = INVALID_HANDLE_VALUE;

      HCRYPTPROV hCryptProv = NULL;

      PCERT_PUBLIC_KEY_INFO pcertpubkeyinfo = NULL;

      BYTE *pbEncryptData = NULL;

      BYTE *pbPvk = NULL;

      CRYPT_KEY_PROV_INFO keyProvInfo;

      HCRYPTKEY hKey = 0;

      PCCERT_CONTEXT pCert = NULL;

      HCRYPTHASH hHash = 0;

      HCRYPTKEY hDecryptKey = 0;

     

 

      // 打开私钥文件

      hFile = CreateFile(lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);

      if (hFile)

      {    

            dwSize = GetFileSize(hFile, NULL);

            if (dwSize != 0xFFFFFFFF)

            {    

                  pbFile = (PBYTE)LocalAlloc(LPTR, dwSize);

                  if (pbFile)

                  {    

                        if (ReadFile(hFile, pbFile, dwSize, &dwRealSize, NULL) == TRUE)

                        {

                              memcpy(szKeyContainer,TEXT("CERT"), sizeof(TEXT("CERT")));

                              // 检查密钥容器是否存在

                              if (CryptAcquireContext(&hCryptProv, szKeyContainer, NULL, CSP_ALGORITHM, 0) == FALSE)

                                  //不存在,创建新的密钥容器

                                   if (CryptAcquireContext(&hCryptProv, szKeyContainer, NULL, CSP_ALGORITHM, CRYPT_NEWKEYSET) == FALSE)

                                    {

                                          goto PvkErr;

                                    }

                              }

                              // Check the Provider

                              if (!hCryptProv)

                              {

                                    goto PvkErr;

                              }

#if 1

                              // 验证PVK私钥文件

                              if (dwSize < sizeof(FILE_HDR))

                              {

                                    goto PvkErr;

                              }

                              memcpy(&Hdr, pbFile, sizeof(FILE_HDR));   // ensure alignment

                              if (Hdr.dwMagic != PVK_MAGIC)

                              {

                                    goto PvkErr;

                              }

                              // Treat as a "normal" private key file

                              cbPvk = Hdr.cbPvk;

                              if (Hdr.dwVersion != PVK_FILE_VERSION_0 ||

                                          Hdr.cbEncryptData > MAX_PVK_FILE_LEN ||

                                          cbPvk == 0 || cbPvk > MAX_PVK_FILE_LEN)

                              {

                                    goto PvkErr;

                              }

                              if (dwSize - sizeof(FILE_HDR) < Hdr.cbEncryptData + cbPvk)

                              {

                                    goto PvkErr;

                              }

                              if (Hdr.cbEncryptData)

                                    pbEncryptData = pbFile + sizeof(FILE_HDR);

                              pbPvk = pbFile+sizeof(FILE_HDR) + Hdr.cbEncryptData;

#endif

 

                              while (TRUE)

                              {

                                    // Get symmetric key to decrypt the private key

                                    // Check the algorithm used to encrypt the key.

                                    // Unfortunately we cannot get the keysize used for encryption

                                    // so we just guess that its the same as the default used by the CSP (128 bits, unless we picked the base RSA provider)

                                    switch (Hdr.dwEncryptType)

                                    {

                                          case PVK_NO_ENCRYPT:

                                                break;

                                          case PVK_RC4_PASSWORD_ENCRYPT:

                                                if (!GetPasswordKey(hCryptProv, CALG_RC4,     //ENTER_PASSWORD,

                                                                  pbPassword, dwPswdLen,             //Password

                                                                  pbEncryptData, Hdr.cbEncryptData,

                                                                  &hDecryptKey))

                                                fRet = FALSE;

                                                break;

                                          case PVK_RC2_CBC_PASSWORD_ENCRYPT:

                                                if (!GetPasswordKey(hCryptProv, CALG_RC2,     //ENTER_PASSWORD,

                                                                  pbPassword, dwPswdLen,             //pwszKeyName, FALSE,

                                                                  pbEncryptData, Hdr.cbEncryptData,

                                                                  &hDecryptKey))

                                                fRet = FALSE;

                                                break;

                                          default:

                                                fRet = FALSE;

                                    }

                                    if (fRet == FALSE)

                                    {

                                          goto PvkErr;

                                    }

                                    // Decrypt and import the private key

                                    // CRYPT_EXPORTABLE needed for SCHANNEL to work!!

                                    if (CryptImportKey(hCryptProv, pbPvk, cbPvk, hDecryptKey, CRYPT_EXPORTABLE, &hKey) == FALSE)

                                    {

                                          goto PvkErr;

                                    }

                                    else

                                    {

                                          break;

                                    }

                              }

 

                              if (!pCryptExportPublicKeyInfo(hCryptProv, Hdr.dwKeySpec, CRYPT_ASN_ENCODING, NULL , &cbData)                        

                              || !(pcertpubkeyinfo = (PCERT_PUBLIC_KEY_INFO)LocalAlloc(0, cbData))

                                          || !pCryptExportPublicKeyInfo(hCryptProv, Hdr.dwKeySpec, CRYPT_ASN_ENCODING, pcertpubkeyinfo , &cbData))

                              {

                                    goto PvkErr;

                              }

 

                              // 查找和私钥相匹配的证书

                              pCert = pCertFindCertificateInStore(hStore, CRYPT_ASN_ENCODING, 0, CERT_FIND_PUBLIC_KEY, pcertpubkeyinfo, NULL);

                              if (pCert == NULL)

                              {

                                    goto PvkErr;

                              }

 

                              // Set the key provider info property to associate the private key

                              // with the cert

                              keyProvInfo.pwszContainerName = szKeyContainer;

                              keyProvInfo.pwszProvName = MS_ENHANCED_PROV_W;

                              keyProvInfo.dwProvType = CSP_ALGORITHM;

                              keyProvInfo.dwFlags = 0;

                              keyProvInfo.cProvParam = 0;

                              keyProvInfo.rgProvParam = NULL;

                              keyProvInfo.dwKeySpec = Hdr.dwKeySpec;

                              fRet = pCertSetCertificateContextProperty(

                                          pCert,CERT_KEY_PROV_INFO_PROP_ID,

                                          0, &keyProvInfo);

 

                              if (fRet == TRUE)

                              {     // repeat till the user cancels or we successfully import the key

                                    printf("Add Private Key OK!/r/n");

 

                                    if (pCert)

                                          pCertFreeCertificateContext(pCert);

                                    if (pcertpubkeyinfo)

                                          LocalFree(pcertpubkeyinfo);

                                    if (hDecryptKey)

                                          CryptDestroyKey(hDecryptKey);

                                    if (hKey)

                                          CryptDestroyKey(hKey);

                                    if (hCryptProv)

                                          CryptReleaseContext(hCryptProv, 0);

                                    LocalFree(pbFile);     

                                    CloseHandle(hFile);

 

 

                                    return TRUE;

                              }

                        }

                  }

            }

      }

 

 

PvkErr:

      fRet = GetLastError();

      printf("Add Private Key Error. Error code: 0x%x./r/n", fRet);

      if (pCert)

            pCertFreeCertificateContext(pCert);

      if (pcertpubkeyinfo)

            LocalFree(pcertpubkeyinfo);

      if (hDecryptKey)

            CryptDestroyKey(hDecryptKey);

      if (hKey)

            CryptDestroyKey(hKey);

      if (hCryptProv)

            CryptReleaseContext(hCryptProv, 0);

      if (pbFile)

            LocalFree(pbFile);     

      CloseHandle(hFile);

 

      return fRet;

}


[ly70041]
添加时间:2017-12-20
版权所有(C)2005-2015