GOST暗号プロバイダーを作成します

図1

Windows用のCSPを作成する秘密は、Yu.S。Zyryanovの記事で明らかにされています



GOSTロシアの暗号化アルゴリズムは、 OpenSSL Gostに実装されています



インターネット上で、誰かが上記のツールを使用してWindows用のGOST暗号プロバイダーインターフェイスを作成したという確認を見つけることができなかったことに驚いています。



たとえば、次のような情報セキュリティの豊富な経験を持つ大企業のみがこのタスクを実行できると考えるかもしれません。 少なくとも部分的に反論するために、この声明はこの記事のタスクになります。



まず、図に示すように、標準のWindowsツールを使用してGOST証明書の整合性を検証できるようにします。 簡単にするため、EDSの作成については考慮せず、キー生成のトピックについては触れません。 デジタル署名とハッシュ関数を除き、プロバイダーのすべての場所で、Microsoftの例で既に返されているTRUEなどの形式のスタブが使用されます。 著者は、暗号プロバイダーの作成に関するトピックに関する一連の記事を書く予定であり、将来これらの欠点はすべて解消されます。



最初の段階では、それほど多くを行う必要はありません。つまり、最初にYu.S. Zyryanovの記事に記載されている手順を実行し、 RFC-4357からOIDリストを取得し、GOST暗号化アルゴリズムの実装に関するOpenSSLライブラリをコンパイルし、最後に、 ルート証明書だけでなく、実際のCAルート証明書も取得しました。



それでは始めましょう。



ソースをダウンロード



最初に、緑色の[今すぐダウンロード]ボタンをクリックして、 Microsoft暗号化サービスプロバイダー開発キットをダウンロードする必要があります。



間接的なリンクをおaびしますが、CSPDKがサイトwww.microsoft.comで見つかりませんでした。 サイトから削除されたようで、上記のリンクには2001年以降の古いバージョンが含まれていますが、これでも私たちには非常に適しています。 ダウンロードして解凍した後、ソースでcsp.cファイルを見つけ、xyzcsp.defおよびxyzcsp.rcでそれぞれ変更するためにxyzcsp.cに名前を変更します(csp.defおよびcsp.rc)。



次に、 OpenSSLライブラリをダウンロードします 。 執筆時点では、バージョンは1.0.0eです。



暗号プロバイダーxyzcsp.dllの登録



暗号化プロバイダーをレジストリに登録します。 これを行うには、コマンド「regedit xyzcsp.reg」を使用して次のファイルを(管理者権限で)実行します



ファイルxyzcsp.reg:

Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider\XYZ Provider] "Image Path"="xyzcsp.dll" "Type"=dword:0000007B [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider Types\Type 123] "Name"="XYZ Provider" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptDllFindOIDInfo] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptDllFindOIDInfo\1.2.643.2.2.19!1] "Name"="GOST R 34.10-2001" "Algid"=dword:00002036 "ExtraInfo"=hex:00,00,00,00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptDllFindOIDInfo\1.2.643.2.2.3!2] "Name"="GOST R 34.11/34.10-2001" "Algid"=dword:00008037 "ExtraInfo"=hex:36,20,00,00,00,00,00,00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 1\CryptDllConvertPublicKeyInfo] [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 1\CryptDllConvertPublicKeyInfo\1.2.643.2.2.19] "Dll"="xyzcsp.dll" "FuncName"="xyz_ConvertPublicKeyInfo" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 1\CryptDllConvertPublicKeyInfo\1.2.643.2.2.98] "Dll"="xyzcsp.dll" "FuncName"="xyz_ConvertPublicKeyInfo"
      
      







OpenSSLライブラリ



ソースからのOpenSSLのアセンブリは舞台裏に残します。難しいことではないことに注意してください。perlとMS Visual Studioをインストールする必要があります。コンパイルするには、Install.W32ファイルの指示に従う必要があります。その後、ディレクトリCに移動します: \ tmp32dllはオブジェクトファイルのセットであり、簡単にするためにプロジェクトで使用した1つのopenssl.libファイルに集めました。



ファイルflist.txt:

 bf_buff.obj aes_core.obj aes_wrap.obj ameth_lib.obj asn1_gen.obj asn1_lib.obj asn1_par.obj asn_mime.obj asn_moid.obj asn_pack.obj a_bitstr.obj a_bool.obj a_bytes.obj a_d2i_fp.obj a_digest.obj a_dup.obj a_enum.obj a_gentm.obj a_i2d_fp.obj a_int.obj a_mbstr.obj a_object.obj a_octet.obj a_print.obj a_set.obj a_sign.obj a_strex.obj a_strnid.obj a_time.obj a_type.obj a_utctm.obj a_utf8.obj a_verify.obj bio_asn1.obj bio_b64.obj bio_cb.obj bio_enc.obj bio_err.obj bio_lib.obj bio_md.obj bio_ndef.obj bio_ok.obj bio_pk7.obj bio_ssl.obj bn_add.obj bn_asm.obj bn_blind.obj bn_const.obj bn_ctx.obj bn_depr.obj bn_div.obj bn_err.obj bn_exp.obj bn_exp2.obj bn_gcd.obj bn_gf2m.obj bn_kron.obj bn_lib.obj bn_mod.obj bn_mont.obj bn_mpi.obj bn_mul.obj bn_nist.obj bn_prime.obj bn_print.obj bn_rand.obj bn_recp.obj bn_shift.obj bn_sqr.obj bn_sqrt.obj bn_word.obj bss_dgram.obj bss_fd.obj bss_file.obj bss_log.obj bss_mem.obj bss_null.obj bss_sock.obj buffer.obj buf_err.obj by_dir.obj by_file.obj b_dump.obj b_print.obj b_sock.obj ca.obj camellia.obj cbc128.obj cbc_cksm.obj cbc_enc.obj cfb128.obj cfb64ede.obj cfb64enc.obj cfb_enc.obj ciphers.obj cmll_cbc.obj cmll_cfb.obj cmll_ctr.obj cmll_ecb.obj cmll_misc.obj cmll_ofb.obj cms.obj cms_asn1.obj cms_att.obj cms_cd.obj cms_dd.obj cms_enc.obj cms_env.obj cms_err.obj cms_ess.obj cms_io.obj cms_lib.obj cms_sd.obj cms_smime.obj comp_err.obj comp_lib.obj conf_api.obj conf_def.obj conf_err.obj conf_lib.obj conf_mall.obj conf_mod.obj conf_sap.obj cpt_err.obj crl.obj crl2p7.obj cryptlib.obj ctr128.obj cts128.obj cversion.obj c_all.obj c_allc.obj c_alld.obj c_cfb64.obj c_ecb.obj c_enc.obj c_ofb64.obj c_rle.obj c_skey.obj c_zlib.obj d1_both.obj d1_clnt.obj d1_enc.obj d1_lib.obj d1_meth.obj d1_pkt.obj d1_srvr.obj d2i_pr.obj d2i_pu.obj des_enc.obj des_old.obj des_old2.obj dgst.obj dh.obj dhparam.obj dh_ameth.obj dh_asn1.obj dh_check.obj dh_depr.obj dh_err.obj dh_gen.obj dh_key.obj dh_lib.obj dh_pmeth.obj dh_prn.obj digest.obj dsa.obj dsaparam.obj dsa_ameth.obj dsa_asn1.obj dsa_depr.obj dsa_err.obj dsa_gen.obj dsa_key.obj dsa_lib.obj dsa_ossl.obj dsa_pmeth.obj dsa_prn.obj dsa_sign.obj dsa_vrf.obj dso_beos.obj dso_dl.obj dso_dlfcn.obj dso_err.obj dso_lib.obj dso_null.obj dso_openssl.obj dso_vms.obj dso_win32.obj ebcdic.obj ec.obj ec2_mult.obj ec2_smpl.obj ecb3_enc.obj ecb_enc.obj ech_err.obj ech_key.obj ech_lib.obj ech_ossl.obj eck_prn.obj ecparam.obj ecp_mont.obj ecp_nist.obj ecp_smpl.obj ecs_asn1.obj ecs_err.obj ecs_lib.obj ecs_ossl.obj ecs_sign.obj ecs_vrf.obj ec_ameth.obj ec_asn1.obj ec_check.obj ec_curve.obj ec_cvt.obj ec_err.obj ec_key.obj ec_lib.obj ec_mult.obj ec_pmeth.obj ec_print.obj ede_cbcm_enc.obj enc.obj encode.obj enc_read.obj enc_writ.obj engine.obj eng_all.obj eng_cnf.obj eng_cryptodev.obj eng_ctrl.obj eng_dyn.obj eng_err.obj eng_fat.obj eng_init.obj eng_lib.obj eng_list.obj eng_openssl.obj eng_pkey.obj eng_table.obj err.obj errstr.obj err_all.obj err_prn.obj evp_acnf.obj evp_asn1.obj evp_enc.obj evp_err.obj evp_key.obj evp_lib.obj evp_pbe.obj evp_pkey.obj ex_data.obj e_aes.obj e_bf.obj e_camellia.obj e_cast.obj e_des.obj e_des3.obj e_gost_err.obj e_idea.obj e_null.obj e_old.obj e_rc2.obj e_rc4.obj e_rc5.obj e_seed.obj e_xcbc_d.obj fcrypt.obj fcrypt_b.obj f_enum.obj f_int.obj f_string.obj gendh.obj gendsa.obj genpkey.obj genrsa.obj gost2001.obj gost2001_keyx.obj gost89.obj gost94_keyx.obj gosthash.obj gost_ameth.obj gost_asn1.obj gost_crypt.obj gost_ctl.obj gost_eng.obj gost_keywrap.obj gost_md.obj gost_params.obj gost_pmeth.obj gost_sign.obj hmac.obj hm_ameth.obj hm_pmeth.obj i2d_pr.obj i2d_pu.obj i_cbc.obj i_cfb64.obj i_ecb.obj i_ofb64.obj i_skey.obj krb5_asn.obj kssl.obj lhash.obj lh_stats.obj md4_dgst.obj md4_one.obj md5_dgst.obj md5_one.obj mdc2dgst.obj mdc2_one.obj md_rand.obj mem.obj mem_clr.obj mem_dbg.obj m_dss.obj m_dss1.obj m_ecdsa.obj m_md4.obj m_md5.obj m_mdc2.obj m_null.obj m_ripemd.obj m_sha.obj m_sha1.obj m_sigver.obj m_wp.obj names.obj nseq.obj nsseq.obj n_pkey.obj obj_dat.obj obj_err.obj obj_lib.obj obj_xref.obj ocsp.obj ocsp_asn.obj ocsp_cl.obj ocsp_err.obj ocsp_ext.obj ocsp_ht.obj ocsp_lib.obj ocsp_prn.obj ocsp_srv.obj ocsp_vfy.obj ofb128.obj ofb64ede.obj ofb64enc.obj ofb_enc.obj o_dir.obj o_names.obj o_str.obj o_time.obj p12_add.obj p12_asn.obj p12_attr.obj p12_crpt.obj p12_crt.obj p12_decr.obj p12_init.obj p12_key.obj p12_kiss.obj p12_mutl.obj p12_npas.obj p12_p8d.obj p12_p8e.obj p12_utl.obj p5_crpt.obj p5_crpt2.obj p5_pbe.obj p5_pbev2.obj p8_pkey.obj passwd.obj pcbc_enc.obj pcy_cache.obj pcy_data.obj pcy_lib.obj pcy_map.obj pcy_node.obj pcy_tree.obj pem_all.obj pem_err.obj pem_info.obj pem_lib.obj pem_oth.obj pem_pk8.obj pem_pkey.obj pem_seal.obj pem_sign.obj pem_x509.obj pem_xaux.obj pk12err.obj pk7_asn1.obj pk7_attr.obj pk7_doit.obj pk7_lib.obj pk7_mime.obj pk7_smime.obj pkcs12.obj pkcs7.obj pkcs7err.obj pkcs8.obj pkey.obj pkeyparam.obj pkeyutl.obj pmeth_fn.obj pmeth_gn.obj pmeth_lib.obj pqueue.obj prime.obj pvkfmt.obj p_dec.obj p_enc.obj p_lib.obj p_open.obj p_seal.obj p_sign.obj p_verify.obj qud_cksm.obj rand.obj randfile.obj rand_egd.obj rand_err.obj rand_key.obj rand_lib.obj rand_nw.obj rand_os2.obj rand_unix.obj rand_win.obj rc2cfb64.obj rc2ofb64.obj rc2_cbc.obj rc2_ecb.obj rc2_skey.obj rc4_enc.obj rc4_skey.obj read2pwd.obj req.obj rmd_dgst.obj rmd_one.obj rpc_enc.obj rsa.obj rsautl.obj rsa_ameth.obj rsa_asn1.obj rsa_chk.obj rsa_depr.obj rsa_eay.obj rsa_err.obj rsa_gen.obj rsa_lib.obj rsa_none.obj rsa_null.obj rsa_oaep.obj rsa_pk1.obj rsa_pmeth.obj rsa_prn.obj rsa_pss.obj rsa_saos.obj rsa_sign.obj rsa_ssl.obj rsa_x931.obj s23_clnt.obj s23_lib.obj s23_meth.obj s23_pkt.obj s23_srvr.obj s2_clnt.obj s2_enc.obj s2_lib.obj s2_meth.obj s2_pkt.obj s2_srvr.obj s3_both.obj s3_clnt.obj s3_enc.obj s3_lib.obj s3_meth.obj s3_pkt.obj s3_srvr.obj seed.obj seed_cbc.obj seed_cfb.obj seed_ecb.obj seed_ofb.obj sess_id.obj set_key.obj sha1dgst.obj sha1_one.obj sha256.obj sha512.obj sha_dgst.obj sha_one.obj smime.obj speed.obj spkac.obj ssl_algs.obj ssl_asn1.obj ssl_cert.obj ssl_ciph.obj ssl_err.obj ssl_err2.obj ssl_lib.obj ssl_rsa.obj ssl_sess.obj ssl_stat.obj ssl_txt.obj stack.obj str2key.obj s_cb.obj s_client.obj s_server.obj s_socket.obj s_time.obj t1_clnt.obj t1_enc.obj t1_lib.obj t1_meth.obj t1_reneg.obj t1_srvr.obj tasn_dec.obj tasn_enc.obj tasn_fre.obj tasn_new.obj tasn_prn.obj tasn_typ.obj tasn_utl.obj tb_asnmth.obj tb_cipher.obj tb_dh.obj tb_digest.obj tb_dsa.obj tb_ecdh.obj tb_ecdsa.obj tb_pkmeth.obj tb_rand.obj tb_rsa.obj tb_store.obj ts.obj ts_asn1.obj ts_conf.obj ts_err.obj ts_lib.obj ts_req_print.obj ts_req_utils.obj ts_rsp_print.obj ts_rsp_sign.obj ts_rsp_utils.obj ts_rsp_verify.obj ts_verify_ctx.obj txt_db.obj t_bitst.obj t_crl.obj t_pkey.obj t_req.obj t_spki.obj t_x509.obj t_x509a.obj uid.obj ui_compat.obj ui_err.obj ui_lib.obj ui_openssl.obj ui_util.obj uplink.obj v3err.obj v3_addr.obj v3_akey.obj v3_akeya.obj v3_alt.obj v3_asid.obj v3_bcons.obj v3_bitst.obj v3_conf.obj v3_cpols.obj v3_crld.obj v3_enum.obj v3_extku.obj v3_genn.obj v3_ia5.obj v3_info.obj v3_int.obj v3_lib.obj v3_ncons.obj v3_ocsp.obj v3_pci.obj v3_pcia.obj v3_pcons.obj v3_pku.obj v3_pmaps.obj v3_prn.obj v3_purp.obj v3_skey.obj v3_sxnet.obj v3_utl.obj verify.obj version.obj wp_block.obj wp_dgst.obj x509.obj x509cset.obj x509name.obj x509rset.obj x509spki.obj x509type.obj x509_att.obj x509_cmp.obj x509_d2.obj x509_def.obj x509_err.obj x509_ext.obj x509_lu.obj x509_obj.obj x509_r2x.obj x509_req.obj x509_set.obj x509_trs.obj x509_txt.obj x509_v3.obj x509_vfy.obj x509_vpm.obj xcbc_enc.obj x_algor.obj x_all.obj x_attrib.obj x_bignum.obj x_crl.obj x_exten.obj x_info.obj x_long.obj x_name.obj x_nx509.obj x_pkey.obj x_pubkey.obj x_req.obj x_sig.obj x_spki.obj x_val.obj x_x509.obj x_x509a.obj
      
      







このような長いリストをおaびしますが、このlibファイルのどのobjファイルがアセンブリに必要で、どれが不要かを見つける簡単な方法がわかりません。 マップファイルを作成しても役に立たないため、tmp32dllディレクトリにあるほぼ完全なobjファイルのリストを使用する必要がありました。



make_lib.batコマンドでopenssl.libを作成します



make_lib.bat:

 call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" lib /out:openssl.lib @flist.txt
      
      





必要なハッシュ関数の作成を開始し、GOSTに従ってデジタル署名を検証しましょう。



それらをそれぞれmy_hash_gost()およびmy_verify_gost()と呼びます。 それらを取得するには、既製のOpenSSLテキストを使用しましたが、特にデータの「フリップ」、バイト順の変更を行う場合、ハッシュを反転する必要はありませんが、それ以外のすべてをデバッグするには、デバッグに時間がかかりました。 、公開鍵とデジタル署名を含む-必要。



少し歴史。 最初に、my_verify_gost関数は、32バイトすべての定数に等しいハッシュでテストされました。 そしてそれは私を救った。 関数は十分に速く動作しましたが、かなりランダムなバイトセットで構成される実際のハッシュが挿入されると、その直後にデジタル署名のチェックが停止しました。 長い間、私は定数ハッシュがミラーリングされていることを理解できませんでしたので、関数が反転せずに機能するのに適しています。 テストが実際のハッシュで開始された場合、幸運なことに、OpenSSLライブラリはEDS証明書をチェックするために設定するのに十分困難です。



すべての#includeの直後にこれらの行をxyzcsp.cファイルに貼り付けます

 #include "gosthash.h" #include "gost_lcl.h" static void perevorot_buf(unsigned char *obj, int k) { char buf[64]; int i; for( i = 0; i < k; i++ ) buf[i] = obj[k-1-i]; memcpy(obj, buf, k); } static int pkey_gost01_cp_verify(EC_KEY* pub_key, const unsigned char *sig, size_t siglen, unsigned char *tbs, size_t tbs_len) { int ok = 0; DSA_SIG *s=unpack_cp_signature(sig,siglen); if (!s) return 0; if (pub_key) ok = gost2001_do_verify(tbs,tbs_len,s,pub_key); DSA_SIG_free(s); return ok; } int my_verify_gost(char *in_hash, const BYTE *in_sign, char *in_pub1, char *in_pub2, int nid) { int res, errcode; EC_KEY *eckey = NULL; unsigned char sig[64], tbs[32]; int siglen=64, tbs_len=32; BIGNUM *X=NULL,*Y=NULL; char perevorot_pub[32]; EC_POINT *pub_key; //  memcpy(tbs, in_pub1, 32); perevorot_buf(tbs, 32); X= getbnfrombuf((const unsigned char*)tbs,32); memcpy(tbs, in_pub2, 32); perevorot_buf(tbs, 32); Y= getbnfrombuf((const unsigned char*)tbs,32); memcpy(tbs, in_hash, 32); //   !   perevorot_buf(tbs, 32); memcpy(sig, in_sign, 64); perevorot_buf(sig, 64); //  if (!(eckey = EC_KEY_new())) { errcode = 1; goto err_exit; } if (!fill_GOST2001_params(eckey, nid)) { errcode = 2; goto err_exit; } if (!(pub_key = EC_POINT_new(EC_KEY_get0_group(eckey)))) { errcode = 3; goto err_exit; } if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(eckey) ,pub_key,X,Y,NULL)) { errcode = 4; goto err_exit; } if (!EC_KEY_set_public_key(eckey,pub_key)) { errcode = 5; goto err_exit; } if (!pkey_gost01_cp_verify(eckey, sig, siglen, tbs, tbs_len)) { errcode = 6; goto err_exit; } else errcode = 0; //success err_exit: if (pub_key) EC_POINT_free(pub_key); if (X) BN_free(X); if (Y) BN_free(Y); if (eckey) EC_KEY_free(eckey); return errcode; } void my_hash_gost(const BYTE *buf, int buflen, char *hash_res) { gost_subst_block *b= &GostR3411_94_CryptoProParamSet; gost_hash_ctx ctx; init_gost_hash_ctx(&ctx,b); start_hash(&ctx); hash_block(&ctx,buf,buflen); finish_hash(&ctx,(byte *)hash_res); } //       char hash_gost[32]; char hash_sha1[20]; char public_key[64];
      
      







XYZプロバイダー



最後に、プロバイダーの面倒を見てみましょう。 彼の名前を選択してください: "XYZ Provider"。 したがって、メインファイルはxyzcsp.cと呼ばれ、xyzcsp.defファイルとxyzcsp.rcファイルも必要です。



csp.cファイルのCSPDKにある元のサンプルでは、​​関数CPAcquireContext、CPHashData、CPGetHashParam、CPVerifySignatureのみに関心があります。 これらがプロバイダーのハンドル、ハッシュ関数を作成し、デジタル署名をチェックするための関数であることは簡単にわかります。 これらの関数を以下の関数に置き換えます。



それらに加えて、xyz_ConvertPublicKeyInfoという優れた関数を1つ作成します。この関数は、デジタル署名の公開キーの変換に関与します。 xyz_ConvertPublicKeyInfoをxyzcsp.defファイルに追加して、リンカーがこの名前をエクスポートすることを忘れないでください。 変換は、公開キー表記のASN1レコードの最初の2バイトを無視することで構成されます。これにより、それぞれ32バイトの半分のキーが純粋な形式で取得されます。



DllMain関数と、xyzcsp.cから古いCPAcquireContext、CPHashData、CPGetHashParam、CPVerifySignatureを削除し、xyzcsp.defから廃止されたDESCRIPTIONコマンドと名前DllRegisterServerおよびDllUnregisterServerを削除しましょう。



xyzcsp.cをファイルの最後に追加します。

 BOOL WINAPI CPAcquireContext( OUT HCRYPTPROV *phProv, IN LPCSTR szContainer, IN DWORD dwFlags, IN PVTableProvStruc pVTable) { *phProv = 123; return TRUE; } BOOL WINAPI CPHashData( IN HCRYPTPROV hProv, IN HCRYPTHASH hHash, IN CONST BYTE *pbData, IN DWORD cbDataLen, IN DWORD dwFlags) { my_hash_gost(pbData, cbDataLen, hash_gost); SHA1(pbData, cbDataLen, hash_sha1); return TRUE; } BOOL WINAPI CPGetHashParam( IN HCRYPTPROV hProv, IN HCRYPTHASH hHash, IN DWORD dwParam, OUT LPBYTE pbData, IN OUT LPDWORD pcbDataLen, IN DWORD dwFlags) { switch(dwParam) { case HP_HASHVAL: if(*pcbDataLen == 20) //     sha1 { memcpy(pbData, hash_sha1, 20); break; } default: *pcbDataLen = 0; SetLastError(E_INVALIDARG); return FALSE; } return TRUE; } BOOL WINAPI CPVerifySignature( IN HCRYPTPROV hProv, IN HCRYPTHASH hHash, IN CONST BYTE *pbSignature, IN DWORD cbSigLen, IN HCRYPTKEY hPubKey, IN LPCWSTR szDescription, IN DWORD dwFlags) { #define NTE_IC_ERROR_PREDEF 0x89900000L INT err; err = my_verify_gost(hash_gost, pbSignature, public_key, public_key+32, NID_id_GostR3410_2001_CryptoPro_A_ParamSet); if ( err ) { SetLastError( NTE_IC_ERROR_PREDEF | err ); return FALSE; } return TRUE; } BOOL WINAPI xyz_ConvertPublicKeyInfo( DWORD dwCertEncodingType, VOID *EncodedKeyInfo, DWORD dwAlg, DWORD dwFlags, BYTE** ppStructInfo, DWORD* StructLen ) { memcpy(public_key, ((CERT_PUBLIC_KEY_INFO*)EncodedKeyInfo)->PublicKey.pbData + 2, 64); return TRUE; }
      
      







暗号プロバイダーのソースについて詳しくコメントする必要はないと思います。 すべてはテキストから明らかです。



テストプログラムを書く



別のテストプログラムが必要なのはなぜですか? テストの実行に加えて、ADVAPI32.dllのSystemFunction035関数とCRYPT32.dllのI_CryptGetDefaultCryptProvを「正しい」バージョンに変更するようにシステムにパッチを適用します。 このプログラムは、Windows XPとWindows 7の両方で正常に動作します。



記事の最後に、Windows XP SP3でシステムファイルにパッチを適用する方法が示されています。この場合、特別なテストプログラムは必要ありません。



ファイルtestcsp.cpp:

 #include "stdafx.h" #include <windows.h> #include <wincrypt.h> typedef HCRYPTPROV (WINAPI *pI_CryptGetDefaultCryptProv)(ALG_ID algid); HCRYPTPROV hProv = NULL; typedef int (__stdcall *def_CryptExtOpenCER)( HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow); def_CryptExtOpenCER CryptExtOpenCER; typedef int (__stdcall *def_MyProc)(void); def_MyProc MyProc; #define PATCH_NUM 2 char *patch_list[2*PATCH_NUM]={ "ADVAPI32.dll","SystemFunction035", "CRYPT32.dll","I_CryptGetDefaultCryptProv" }; void WriteMem(int pos, char *patch, int len) { DWORD my_id = GetCurrentProcessId(); HANDLE p_hand = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_OPERATION, NULL, my_id); if (WriteProcessMemory(p_hand, (LPDWORD)pos, patch, len, NULL)==0) { printf("Error write to memory\nHint: run from Administrator rigths"); } CloseHandle(p_hand); } HCRYPTPROV PASCAL old_I_CryptGetDefaultCryptProv(int AlgID) //call MS Provider { __asm mov eax,0; //,  10  __asm mov eax,0; return NULL; } HCRYPTPROV PASCAL my_I_CryptGetDefaultCryptProv(int AlgID) { if (AlgID!=0 && AlgID!=0x2036) return old_I_CryptGetDefaultCryptProv(AlgID); //old MS return hProv; } int StartPatch(void) { BYTE *p; HMODULE h_dll; char buf[10]; DWORD new_addr; for(int i=0;i<PATCH_NUM;i++) { h_dll = LoadLibrary(patch_list[i*2]); if (h_dll==NULL) { printf("Error! Can not LoadLibrary(%s)\n", patch_list[i*2]); return 1; } MyProc = (def_MyProc)GetProcAddress(h_dll, patch_list[i*2+1]); if (MyProc==NULL) { printf("Error! Can not GetProcAddress(%s)\n", patch_list[i*2+1]); return 1; } p = (BYTE*)MyProc; if (i==1) { memcpy(buf, p, 5); buf[5]=0xe9; new_addr = (DWORD)p; new_addr -= (DWORD)old_I_CryptGetDefaultCryptProv; new_addr -= 5; memcpy(buf+6, &new_addr, 4); WriteMem((DWORD)old_I_CryptGetDefaultCryptProv, buf, 10); buf[0]=0xe9; new_addr = (DWORD)my_I_CryptGetDefaultCryptProv; new_addr -= (DWORD)MyProc; new_addr -= 5; memcpy(buf+1, &new_addr, 4); WriteMem((DWORD)MyProc, buf, 5); } else { WriteMem((int)p, "\xb8\x01\x00\x00\x00\xC2\x04\x00", 8); //mov ax,1 - ret 4 } } return 0; } int RunCert(char *certName) { HMODULE h_dll; h_dll = LoadLibrary("C:\\windows\\system32\\CRYPTEXT.dll"); if (h_dll==NULL) return 1; CryptExtOpenCER = (def_CryptExtOpenCER)GetProcAddress(h_dll, "CryptExtOpenCER"); if (CryptExtOpenCER==NULL) return 2; CryptExtOpenCER(NULL, NULL, certName, SW_SHOW); FreeLibrary(h_dll); return 0; } int _tmain(int argc, _TCHAR* argv[]) { if (StartPatch()) { printf("Error Patch\n"); return 1; } if (RCRYPT_FAILED(CryptAcquireContext(&hProv, "test", NULL, 123, 0))) { printf("CryptAcquireConext returned error %x\n", GetLastError()); printf("FAILED\n"); return 1; } printf("SUCCEED\n"); RunCert("gnivc_2006.cer"); RunCert("rootsber.cer"); return 0; }
      
      







ファイル編集



プロバイダーコンパイルファイルcomp_xyzcsp.bat:

 call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" cl /I"..\include" /nologo /MT /O2 /c xyzcsp.c rc /I"..\include" xyzcsp.rc link /SUBSYSTEM:WINDOWS",5.0" /NODEFAULTLIB /DLL /DEF:xyzcsp.def /MACHINE:x86 /OUT:xyzcsp.dll xyzcsp.obj openssl.lib advapi32.lib kernel32.lib msvcrt.lib gdi32.lib user32.lib xyzcsp.res copy xyzcsp.dll ..\testcsp\ rem copy xyzcsp.dll c:\windows\system32
      
      





テストコンパイルファイルcomp_test.bat:

 call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" cl /I"..\include" testcsp.cpp advapi32.lib
      
      







テスト証明書



gnivc_2006.cerファイルには、連邦税務サービスのルート証明書が含まれています。

 -----BEGIN CERTIFICATE----- MIIDGjCCAsegAwIBAgIQPx2a1ZtKRIBLiHKukksltTAKBgYqhQMCAgMFADCBwDEe MBwGCSqGSIb3DQEJARYPdWNpbmZvQGduaXZjLnJ1MQswCQYDVQQGEwJSVTEVMBMG A1UEBwwM0JzQvtGB0LrQstCwMTAwLgYDVQQKDCfQpNCT0KPQnyDQk9Cd0JjQktCm INCk0J3QoSDQoNC+0YHRgdC40LgxMDAuBgNVBAsMJ9Cj0LTQvtGB0YLQvtCy0LXR gNGP0Y7RidC40Lkg0YbQtdC90YLRgDEWMBQGA1UEAxMNR05JVkMgRk5TIFJVUzAe Fw0wNjA5MjcwOTI5NTdaFw0xMjA5MjcwOTM4MjdaMIHAMR4wHAYJKoZIhvcNAQkB Fg91Y2luZm9AZ25pdmMucnUxCzAJBgNVBAYTAlJVMRUwEwYDVQQHDAzQnNC+0YHQ utCy0LAxMDAuBgNVBAoMJ9Ck0JPQo9CfINCT0J3QmNCS0KYg0KTQndChINCg0L7R gdGB0LjQuDEwMC4GA1UECwwn0KPQtNC+0YHRgtC+0LLQtdGA0Y/RjtGJ0LjQuSDR htC10L3RgtGAMRYwFAYDVQQDEw1HTklWQyBGTlMgUlVTMGMwHAYGKoUDAgITMBIG ByqFAwICIwEGByqFAwICHgEDQwAEQCzY8VGw9ged02ijaj2KWOMXJVvzY1FEcg7G xedUtKx0wqyTVti0kmodEmm2cVfAbDkp0xAdBS9/mdDfeIrKXLajgZYwgZMwCwYD VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBMQt5JPv+eiD7j1 nYkVJssQ6/RfMBAGCSsGAQQBgjcVAQQDAgEAMEIGCCsGAQUFBwEBBDYwNDAyBggr BgEFBQcwAoYmaHR0cDovL3d3dy5nbml2Yy5ydS91Yy9HTklWQ0ZOU1JVUy5jcnQw CgYGKoUDAgIDBQADQQDgEyWPI+fdXXiTYMLHdV76v8kVFIxCHCYtastcvZiM3cG1 wTFhio8fDx6sLgHHriOwQFg0zRUYHIs9nZEptLvM -----END CERTIFICATE-----
      
      





Sberbankのルート証明書を含むrootsber.cerファイル:

 -----BEGIN CERTIFICATE----- MIIDKjCCAtmgAwIBAgIGMDBDQT0HMAgGBiqFAwICAzCBwTELMAkGA1UEBhMCUlUx LTArBgNVBAoMJNCh0LHQtdGA0LHQsNC90Log0KDQvtGB0YHQuNC4INCe0JDQnjE4 MDYGA1UECwwv0JTQtdC/0LDRgNGC0LDQvNC10L3RgiDQsdC10LfQvtC/0LDRgdC9 0L7RgdGC0LgxJjAkBgNVBAMMHdCh0LHQtdGA0LHQsNC90Log0KDQvtGB0YHQuNC4 MSEwHwYJKoZIhvcNAQkBFhJjYXNicmZAc2JlcmJhbmsucnUwHhcNMDkwODA1MDAw MDAwWhcNMTcwODA1MDAwMDAwWjCBwTELMAkGA1UEBhMCUlUxLTArBgNVBAoMJNCh 0LHQtdGA0LHQsNC90Log0KDQvtGB0YHQuNC4INCe0JDQnjE4MDYGA1UECwwv0JTQ tdC/0LDRgNGC0LDQvNC10L3RgiDQsdC10LfQvtC/0LDRgdC90L7RgdGC0LgxJjAk BgNVBAMMHdCh0LHQtdGA0LHQsNC90Log0KDQvtGB0YHQuNC4MSEwHwYJKoZIhvcN AQkBFhJjYXNicmZAc2JlcmJhbmsucnUwYzAcBgYqhQMCAhMwEgYHKoUDAgIjAgYH KoUDAgIeAQNDAARAaYzyi29YQ9NC5cb/kq//J1kKhOgcvGWqsQu50mldjADTGfrl JUVXwu4fMUTHoF9TjY0O1kgrLYWT/kI4jABAWKOBsjCBrzAdBgNVHQ4EFgQUZmHo Zo41vw/U74ZlC8k/bcQODuowDAYDVR0TBAUwAwEB/zAzBgNVHR8ELDAqMCigJqAk hiJodHRwOi8vd3d3LnNicmYucnUvY2EvMDAwMHg1MDkuY3JsMAsGA1UdDwQEAwIC hDA+BgcqhQMDewMBBDMMMTAwQ0ExODUzetCa0L7RgNC90LXQstC+0Lkg0LrQu9GO 0Ycg0KPQpiDQodCRINCg0KQwCAYGKoUDAgIDA0EAD9Umnh/EZgjgQvpypdVwe0wa GnTi+dHhVwoNAX1tquxQNbAptbBs2OKzkRU7/mrBfDD4EdVV5xC1f2DTcH8NAg== -----END CERTIFICATE-----
      
      







作業結果



テストプログラムを実行すると、結果が得られます。





最後の障害を取り除くために、推奨されるように、証明書を信頼できるもののリストに含めます。 これを行うには、[証明書のインストール]ボタンをクリックし、[次へ]を数回クリックします。 テストの最後に、システムを危険にさらさないために、信頼されたルートストアからテスト証明書を削除する必要があります。



テストを再開した後、別の画像を観察します。





受信に必要なもの。



Sberbankルート証明書



Sberbankの証明書では、これを行うことはできません。





これは、SberbankがRFC 4357の定数B、つまりGostR3410_2001_CryptoPro_B_ParamSetを使用しているためです。



次に、CPVerifySignature関数のxyzcsp.cファイルで定数AをBに変更します。つまり、my_verify_gostを呼び出すときに、NID_id_GostR3410_2001_CryptoPro_B_ParamSetパラメーターを使用します。



プロバイダーをコンパイルしてテストを開始した後、反対の状況を観察します。連邦税務署の証明書は検証されておらず、Sberbankは正常に機能しています。 これは大きな欠点のように思えますが、最も単純な暗号プロバイダーにとってはこれは許されません。



もちろん、このオプションは可能です。2つのEDSを一度にチェックし、少なくとも1つが収束した場合、EDSが正しいことを宣言しますが、これは根本的に間違っています。 公開鍵のOIDを調べ、そこから楕円曲線の必須パラメーターを探す必要があります。



現在、公開の準備中の次の記事では、この状況を回避する方法を詳細に検討し、さまざまなパラメーターを使用してEDSキーを作成する関数を作成します。



ユニバーサルパッチを作成する



結論として、ユニバーサルパッチの作成に関するいくつかの言葉。



Windows XP SP3の場合、次のファイルを置き換えるだけです。

c:\ windows \ system32 \ advapi32.dll

c:\ windows \ system32 \ dllcache \ advapi32.dll

c:\ windows \ system32 \ crypt32.dll

c:\ windows \ system32 \ dllcache \ crypt32.dll



システム1が解放されるように別のディスクから起動してパッチを適用する必要があります(リカバリモードでWindows起動ディスクからできます)。次に、system32ディレクトリとコピーが保存されているsystem32 \ dllcacheの両方でこれら2つのファイルを置き換えます。 ファイルは「ロックアップ」されており、変更できないため、実行中のシステムでのパッチ適用は機能しません。



その後、暗号化プロバイダーxyzcsp.dllを含むファイルをディレクトリc:\ windows \ system32にコピーして、システムが検出できるようにすることを忘れないでください。



これで、証明書をクリックすると、特別なプログラムを起動せずに、オペレーティングシステムで直接チェックされます。



ファイルをパッチを適用したバージョンに置き換えます。

   advapi32.dll  C:\xyzcsp\PATCH\ADVAPI32.DLL 00017585: 8B B8 00017586: FF 01 00017587: 55 00 00017588: 8B 00 00017589: EC 00 0001758A: 81 C2 0001758B: EC 04 0001758C: 50 00   crypt32.dll  C:\xyzcsp\PATCH\CRYPT32.DLL 00008F66: 8B E9 00008F67: FF 47 00008F68: 55 09 00008F69: 8B 00 00008F6A: EC 00 000098B2: 90 55 000098B3: 90 8B 000098B4: 90 EC 000098B5: 90 8B 000098B6: 90 45 000098B7: 90 08 000098B8: 53 83 000098B9: 00 F8 000098BA: 6F 00 000098BB: 00 74 000098BC: 66 21 000098BD: 00 3D 000098BE: 74 36 000098BF: 00 20 000098C0: 77 00 000098C2: 61 74 000098C3: 00 1A 000098C4: 72 3D 000098C5: 00 35 000098C6: 65 66 000098C8: 5C 00 000098C9: 00 74 000098CA: 50 13 000098CB: 00 3D 000098CC: 6F 37 000098CD: 00 80 000098CE: 6C 00 000098D0: 69 74 000098D1: 00 0C 000098D2: 63 3D 000098D3: 00 38 000098D4: 69 AA 000098D6: 65 00 000098D7: 00 74 000098D8: 73 05 000098D9: 00 E9 000098DA: 5C 8D 000098DB: 00 F6 000098DC: 4D FF 000098DD: 00 FF 000098DE: 69 6A 000098E0: 63 68 000098E1: 00 7B 000098E2: 72 00 000098E4: 6F 00 000098E5: 00 6A 000098E6: 73 00 000098E7: 00 8D 000098E8: 6F 05 000098E9: 00 40 000098EA: 66 A5 000098EB: 00 A7 000098EC: 74 77 000098ED: 00 50 000098EE: 5C 8D 000098EF: 00 45 000098F0: 53 08 000098F1: 00 50 000098F2: 79 FF 000098F3: 00 15 000098F4: 73 00 000098F5: 00 10 000098F6: 74 A7 000098F7: 00 77 000098F8: 65 83 000098F9: 00 F8 000098FA: 6D 00 000098FB: 00 74 000098FC: 43 DC 000098FD: 00 8B 000098FE: 65 45 000098FF: 00 08 00009900: 72 C9 00009901: 00 C2 00009902: 74 04
      
      







Windows 7の場合、ユニバーサルパッチを作成することもできます。希望する場合は、自分でパッチを作成してみてください。



GOST暗号化プロバイダーがインストールされている実際のシステムでは、通常、システムDLLの読み込みを監視してその場でパッチを当てる特別なPatchEngineドライバーをインストールすることにより、パッチの問題を解決します。



1つのアーカイブ内のすべてのファイル



結論として、この記事のすべてのファイルを1つのアーカイブにダウンロードできるリンクを提供します。

files.mail.ru/1OVVDB



All Articles