在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>