在c/c++中解决SHA1WithRSA/ras/X509的过程记录
GOOSasha
8年前
<p>这里记录了一种简单的办法,在遇到写c/c++找不到答案时的最简单找代码办法。</p> <p><img src="https://simg.open-open.com/show/7366bc941216891d1de3a75f900506cb.jpg"></p> <p>方法是:google找php怎么解决,大把的答案,然后看php源代码是怎么用c实现的。</p> <h2>提出</h2> <p>我们server端在对接google play的时候,遇到了ras加密来验证参数的实现,官方也没有什么c的参考代码,java和php的网上倒是能找到一堆。</p> <h2>java怎么解决</h2> <p>java的实现和本文要说的内容无关,只是随带一列:</p> <pre> <code class="language-cpp">public static boolean verify(String publicKey, byte[] data, String sign) throws Exception { // 解密由base64编码的公钥 byte[] keyBytes = Base64.decodeBase64(publicKey); System.out.println(keyBytes.length); // 构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); // KEY_ALGORITHM 指定的加密算法 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // 取公钥匙对象 PublicKey pubKey = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initVerify(pubKey); signature.update(data); // 验证签名是否正常 return signature.verify(Base64.decodeBase64(sign)); }</code></pre> <h2><code>php怎么解决</code></h2> <p><code>php的实现比较多,随便找了一个,没有验证过:</code></p> <pre> <code class="language-cpp"><?php $public_key = file_get_contents(dirname(__FILE__).’/rsa_public_key.pem’); $pkeyid = openssl_pkey_get_public($public_key); $data = ‘abc’; $sign = ‘WkMaSsx9Fbj9/YyjoM1X0SLYvaFbsz9VmMaxc42fXxamEEIj5AfqQLrygEZRq0gkLNT4heIwOiSWEAWbfD4imaERKk07ANXEtZJ9jPJvyvg70IVvaYMKAr7bX0dJXmYw4aHnkcWR1kz27Drr6fxPmchB9WCsRmi4VfhVoF1+HRFOp28nIVReGRcbwbW1/bcMisXbitirz9Wq396vY88GUSgbgNdhFXX/kzjRBTjnG+CIhXq4HPdOWovqtPhQoxmK55+V+vxNZk9OPPHHaN3vVswk062NOs2/05yNVObL+PWeg/m43buXYalmkrwEhemdGfjIdNEoSO2D4gikvm43cg==’; $sign = base64_decode($sign); if ($pkeyid) { $verify = openssl_verify($data, $sign, $pkeyid, OPENSSL_ALGO_MD5); openssl_free_key($pkeyid); } var_dump($verify); ?></code></pre> <h2><code><code>找到代码</code></code></h2> <p><code><code>看到上面的php代码,关键的几个函数有:openssl_pkey_get_public openssl_verify</code></code></p> <p><code><code>然后转战最新的php源代码, <a href="/misc/goto?guid=4959673785194452902" rel="nofollow,noindex">https://github.com/php/php-src/blob/80f91fd9d513b83ca88345a2a8c76523e0164789/ext/openssl/openssl.c</a> 。 </code></code></p> <p><code><code>别问为什么可以定位到这个文件的,github可以直接搜一个库里的源文件。</code></code></p> <p><code><code>忽略一切以zend、zval开头的逻辑,直接找上面关键的函数。</code></code></p> <p><code><code>于是就找到了关键的头文件:</code></code></p> <pre> <code class="language-cpp">/* OpenSSL includes */ #include <openssl/evp.h> #include <openssl/bn.h> #include <openssl/rsa.h> #include <openssl/dsa.h> #include <openssl/dh.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/crypto.h> #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/conf.h> #include <openssl/rand.h> #include <openssl/ssl.h> #include <openssl/pkcs12.h></code></pre> <p><code><code><code>关键的一行key生成代码:</code></code></code></p> <pre> <code class="language-cpp">key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);</code></pre> <p><code><code><code><code>关键的核心逻辑:</code></code></code></code></p> <pre> <code class="language-cpp">EVP_VerifyInit (&md_ctx, mdtype); EVP_VerifyUpdate (&md_ctx, data, data_len); err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey); EVP_MD_CTX_cleanup(&md_ctx); if (keyresource == NULL) { EVP_PKEY_free(pkey); }</code></pre> <p><code><code><code><code><code>这么些核心代码都找到了,还不会抄吗?</code></code></code></code></code></p> <h2><code><code><code><code><code>最终解决</code></code></code></code></code></h2> <p><code><code><code><code><code>通过上面的过程,进行自己的组装,已经再简单不过了,为了让写c/c++的同学们快速得到google play的rsa验证代码,特别贴一下:</code></code></code></code></code></p> <pre> <code class="language-cpp">int verifiedByRsaPublicKey(const string& publicKey, const string& signature, char* message) { char *chPublicKey = const_cast<char *>(publicKey.c_str()); BIO* mem_bio = NULL; if ((mem_bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) { //从字符串读取RSA公钥 BIO_free(mem_bio); return -3; } EVP_PKEY *publicRsa = PEM_read_bio_PUBKEY(mem_bio, NULL, NULL, NULL); unsigned int slen = signature.length(); EVP_MD_CTX md_ctx; EVP_VerifyInit(&md_ctx, EVP_sha1()); EVP_VerifyUpdate(&md_ctx, message, strlen(message)); int err = EVP_VerifyFinal(&md_ctx, (unsigned char*) signature.data(), slen, publicRsa); EVP_MD_CTX_cleanup(&md_ctx); EVP_PKEY_free(publicRsa); return err; }</code></pre> <h2><code><code><code><code><code><code>结论</code></code></code></code></code></code></h2> <p><code><code><code><code><code><code>通过php的解决方案去找到php的实现,是写c/c++同学们不可不学的一招。</code></code></code></code></code></code></p> <h2><code><code><code><code><code><code>EOF</code></code></code></code></code></code></h2> <h2><code><code><code><code><code><code>English Version</code></code></code></code></code></code></h2> <h2><code><code><code><code><code><code>a story about SHA1WithRSA/ras/X509 with c/c++</code></code></code></code></code></code></h2> <p><code><code><code><code><code><code>This is a simple solution when you do not know how to develop with c/c++.</code></code></code></code></code></code></p> <p><code><code><code><code><code><code>The solution is,it will have lots of answer ho to do with php in Google,and then look up the desgin in the source codes of php.</code></code></code></code></code></code></p> <h2><code><code><code><code><code><code>Question</code></code></code></code></code></code></h2> <p><code><code><code><code><code><code>We need to verify the parameters by RSA when we devlop the Google Play apps.There is not any reference codes with c/c++.The java or php example are too many in internet.</code></code></code></code></code></code></p> <h2><code><code><code><code><code><code>How to resolve in java</code></code></code></code></code></code></h2> <p><code><code><code><code><code><code>It no connection with what we are talking about.Just BTW:</code></code></code></code></code></code></p> <pre> <code class="language-cpp">public static boolean verify(String publicKey, byte[] data, String sign) throws Exception { // 解密由base64编码的公钥 byte[] keyBytes = Base64.decodeBase64(publicKey); System.out.println(keyBytes.length); // 构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); // KEY_ALGORITHM 指定的加密算法 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // 取公钥匙对象 PublicKey pubKey = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initVerify(pubKey); signature.update(data); // 验证签名是否正常 return signature.verify(Base64.decodeBase64(sign)); }</code></pre> <h2><code><code><code><code><code><code><code>How to resolve in php</code></code></code></code></code></code></code></h2> <p><code><code><code><code><code><code><code>There are too many php examples.Find one without checking:</code></code></code></code></code></code></code></p> <pre> <code class="language-cpp"><?php $public_key = file_get_contents(dirname(__FILE__).’/rsa_public_key.pem’); $pkeyid = openssl_pkey_get_public($public_key); $data = ‘abc’; $sign = ‘WkMaSsx9Fbj9/YyjoM1X0SLYvaFbsz9VmMaxc42fXxamEEIj5AfqQLrygEZRq0gkLNT4heIwOiSWEAWbfD4imaERKk07ANXEtZJ9jPJvyvg70IVvaYMKAr7bX0dJXmYw4aHnkcWR1kz27Drr6fxPmchB9WCsRmi4VfhVoF1+HRFOp28nIVReGRcbwbW1/bcMisXbitirz9Wq396vY88GUSgbgNdhFXX/kzjRBTjnG+CIhXq4HPdOWovqtPhQoxmK55+V+vxNZk9OPPHHaN3vVswk062NOs2/05yNVObL+PWeg/m43buXYalmkrwEhemdGfjIdNEoSO2D4gikvm43cg==’; $sign = base64_decode($sign); if ($pkeyid) { $verify = openssl_verify($data, $sign, $pkeyid, OPENSSL_ALGO_MD5); openssl_free_key($pkeyid); } var_dump($verify); ?></code></pre> <h2><code><code><code><code><code><code><code><code>Find the codes</code></code></code></code></code></code></code></code></h2> <p><code><code><code><code><code><code><code><code>The key functions are openssl_pkey_get_public and openssl_verify in the codes above mentioned.</code></code></code></code></code></code></code></code></p> <p><code><code><code><code><code><code><code><code>Go to the newest php source codes, <a href="/misc/goto?guid=4959673785194452902" rel="nofollow,noindex">https://github.com/php/php-src/blob/80f91fd9d513b83ca88345a2a8c76523e0164789/ext/openssl/openssl.c</a> </code></code></code></code></code></code></code></code></p> <p><code><code><code><code><code><code><code><code>Dont ask me how to find the file.You can search the file in a project at Github.</code></code></code></code></code></code></code></code></p> <p><code><code><code><code><code><code><code><code>Ignore all the codes start with zval and zend.Go to the codes which include the key functions.</code></code></code></code></code></code></code></code></p> <p><code><code><code><code><code><code><code><code>And then there is the key header file:</code></code></code></code></code></code></code></code></p> <pre> <code class="language-cpp">/* OpenSSL includes */ #include <openssl/evp.h> #include <openssl/bn.h> #include <openssl/rsa.h> #include <openssl/dsa.h> #include <openssl/dh.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/crypto.h> #include <openssl/pem.h> #include <openssl/err.h> #include <openssl/conf.h> #include <openssl/rand.h> #include <openssl/ssl.h> #include <openssl/pkcs12.h></code></pre> <p><code><code><code><code><code><code><code><code><code>The key codes generated pkey:</code></code></code></code></code></code></code></code></code></p> <pre> <code class="language-cpp">key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);</code></pre> <p><code><code><code><code><code><code><code><code><code><code>The core logic:</code></code></code></code></code></code></code></code></code></code></p> <pre> <code class="language-cpp">EVP_VerifyInit (&md_ctx, mdtype); EVP_VerifyUpdate (&md_ctx, data, data_len); err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey); EVP_MD_CTX_cleanup(&md_ctx); if (keyresource == NULL) { EVP_PKEY_free(pkey); }</code></pre> <p><code><code><code><code><code><code><code><code><code><code><code>All of the codes are ready,cant you copy?</code></code></code></code></code></code></code></code></code></code></code></p> <h2><code><code><code><code><code><code><code><code><code><code><code>Final</code></code></code></code></code></code></code></code></code></code></code></h2> <p><code><code><code><code><code><code><code><code><code><code><code>It is easy to merge the codes above mentioned.</code></code></code></code></code></code></code></code></code></code></code></p> <p><code><code><code><code><code><code><code><code><code><code><code>To get the codes faster for any other people,there are the codes about Google play Ras verifying:</code></code></code></code></code></code></code></code></code></code></code></p> <pre> <code class="language-cpp">int verifiedByRsaPublicKey(const string& publicKey, const string& signature, char* message) { char *chPublicKey = const_cast<char *>(publicKey.c_str()); BIO* mem_bio = NULL; if ((mem_bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) { //从字符串读取RSA公钥 BIO_free(mem_bio); return -3; } EVP_PKEY *publicRsa = PEM_read_bio_PUBKEY(mem_bio, NULL, NULL, NULL); unsigned int slen = signature.length(); EVP_MD_CTX md_ctx; EVP_VerifyInit(&md_ctx, EVP_sha1()); EVP_VerifyUpdate(&md_ctx, message, strlen(message)); int err = EVP_VerifyFinal(&md_ctx, (unsigned char*) signature.data(), slen, publicRsa); EVP_MD_CTX_cleanup(&md_ctx); EVP_PKEY_free(publicRsa); return err; }</code></pre> <h2><code><code><code><code><code><code><code><code><code><code><code><code>Conclusion</code></code></code></code></code></code></code></code></code></code></code></code></h2> <p><code><code><code><code><code><code><code><code><code><code><code><code>Is is a good solution for c/c++ developer.You can find the answer in php at first,go to see the c source codes of php at last.</code></code></code></code></code></code></code></code></code></code></code></code></p> <p><code><code><code><code><code><code><code><code><code><code><code><code>原创文章如转载,请注明:转载自五四陈科学院[ <a href="/misc/goto?guid=4959554774296479438" rel="nofollow,noindex">http://www.54chen.com</a> ] </code></code></code></code></code></code></code></code></code></code></code></code></p> <p> </p> <p><code><code><code><code><code><code>来自: <a href="/misc/goto?guid=4959673785316987461" rel="nofollow">http://2014.54chen.com/blog/2016/05/25/a-story-about-sha1withrsa-slash-ras-slash-x509-with-c-slash-c-plus-plus/</a></code></code></code></code></code></code></p> <p> </p>