ANDROID接入华为SDK遇到的SHA256withRSA的问题解决
2016-12-27 11:21
405 查看
华为的SDK在登录时原来的实现思路是:
1、C->SDK-C
2、SDK-C->C
3、C->S
4、S->SDK-S
5、SDK-S->S
6、S->C
新版本中,把步骤4和步骤5省了,官方原文:
后来华为接完了,接酷派的时候,拿到一个旧版本的酷派的文档,对比了一下PHP与华为的PHP,十分类似,而酷派居然提供了c++的samples!太良心了!下次我手机坏了一定要买COOLPAD!顺便吐槽一下华为的技术,问什么问题他们都会回:你们是JAVA吗?你们是PHP吗?(前面已经说过一百遍了他们还会继续问)。
酷派的旧版本sample的c++代码(我简化了一下):
顺便贴上新版COOLPAD的代码我整理的下载链接(他们的技术居然把这个算法不知道是从OPENSSL还是从LIBCRYPTO还是哪个数学库中扒了出来,真是太良心了!!!下次一定要买COOLPAD手机!) :
SHA1withRSA算法不依赖第三方库COOLPAD提供uniqs整理
1、C->SDK-C
2、SDK-C->C
3、C->S
4、S->SDK-S
5、SDK-S->S
6、S->C
新版本中,把步骤4和步骤5省了,官方原文:
游戏可以将gameAuthSign、 playerId、 appId和ts提交到游戏自己的服务器,使用文档附 录一中的公钥进行验签,验签方式如下: a. 将 appId、 ts 和 playerId 的值进行连接; b. 将 a 的值使用 SHA256 计算 HASH; c. 将 b 的值使用公钥采用 RSA 算法进行验签,公钥值请参考本文档的“ 7.1 登录鉴权 签名的验签公钥”。官方java核心代码:
public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { byte[] keyBytes = Base64Util.decode(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("SHA256WithRSA"); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64Util.decode(sign)); }官方php核心代码:(参考http://club.huawei.com/thread-5443470-1-1-2851.html)
$pubKey = @file_get_contents($filename); $openssl_public_key = @openssl_get_publickey($pubKey); $ok = @openssl_verify($content, base64_decode($sign), $openssl_public_key, OPENSSL_ALGO_SHA256); @openssl_free_key($openssl_public_key); if($ok) { $result = "0";// success } else { $result = "1";// failure }当时为了这个SHA256+RSA弄的焦头烂额,写了JAVA的测试用例,确定算法正确,可是这8行JAVA代码看不完全懂,逆出来的JAVART的代码又十分难看。写了PHP的测试用例,确定算法正确。于是乎我钻了牛角尖,一定要用C++实现出来。找代码,尝试OPENSSL,尝试所有的参数,尝试其他数学库......于是乎浪费了两天时间。在第二天快结束的时候,我终于放弃了,直接用PHP吧,C++给PHP发个消息不是什么难事。于是乎2个小时不到问题解决。(用的PHP)
后来华为接完了,接酷派的时候,拿到一个旧版本的酷派的文档,对比了一下PHP与华为的PHP,十分类似,而酷派居然提供了c++的samples!太良心了!下次我手机坏了一定要买COOLPAD!顺便吐槽一下华为的技术,问什么问题他们都会回:你们是JAVA吗?你们是PHP吗?(前面已经说过一百遍了他们还会继续问)。
酷派的旧版本sample的c++代码(我简化了一下):
#ifndef CRYPTOHELPER_H_ #define CRYPTOHELPER_H_ #include <openssl/md5.h> #include <openssl/evp.h> #include <openssl/rsa.h> #include <openssl/x509.h> #include <openssl/err.h> #include <openssl/pem.h> #include <iostream> #include <stdint.h> #include <string.h> namespace UTILS { enum EkeyType { kPubKey = 0, kPrivateKey = 1, }; class CryptHelper { private: CryptHelper(){} ~CryptHelper(){} public: static EVP_PKEY* getKeyByPKCS1(const std::string &key, const int32_t keyType, std::string& strError) { RSA* rsa = getRsaKey(key, keyType); if (!rsa) { strError = "getRsaKey failed ! "; return NULL; } EVP_PKEY* pkey = EVP_PKEY_new(); if (1 != EVP_PKEY_assign_RSA(pkey, rsa)) { strError = "EVP_PKEY_assign_RSA failed !"; RSA_free(rsa); EVP_PKEY_free(pkey); return NULL; } return pkey; } static RSA* getRsaKey(const std::string &key, const int32_t keyType, std::string& strError) { uint8_t *keyBuf; uint8_t *p; keyBuf = (uint8_t *)alloca(key.length()); size_t keyLen(0); keyLen = base64Decode(keyBuf, (const uint8_t *)key.c_str(), key.length(), strError); if (0 > keyLen) { strError = "base64Decode key failed !"; return NULL; } //d2i_RSA_PUBKEY p = keyBuf; RSA *rsa = (keyType == 0) ? d2i_RSA_PUBKEY(NULL, (const uint8_t **)&p, keyLen, strError) : d2i_RSAPrivateKey(NULL, (const uint8_t **)&p, keyLen, strError); return rsa; } static void freeKey(RSA* key) { if (key) RSA_free(key); } static void freeKey(EVP_PKEY* key){ if (key) EVP_PKEY_free(key); } static int32_t signWithRsa(const std::string &data, const EVP_MD *type, EVP_PKEY* key, std::string &sign, std::string strError) { EVP_MD_CTX mdCtx; EVP_SignInit(&mdCtx, type); EVP_SignUpdate(&mdCtx, data.c_str(), data.length()); uint32_t signLen(EVP_PKEY_size(priKey)), outLen(0); uint8_t* signBuf = (uint8_t *)OPENSSL_malloc(signLen); uint8_t* outBuf = (uint8_t *)OPENSSL_malloc(signLen * 2); int32_t ret = EVP_SignFinal(&mdCtx, signBuf, &signLen, priKey); if (1 != ret) { strError = "EVP_SignFinal failed ! "; } else { if (0 > (outLen = EVP_EncodeBlock(outBuf, signBuf, signLen))) { ret = -1; strError = "EVP_EncodeBlock failed! "; } else { sign.assign((char*)outBuf, outLen); } } OPENSSL_free(signBuf); OPENSSL_free(outBuf); return 1 == ret ? 0 : -1; } static int32_t verifySignWithRsa(const std::string &data, const std::string &sign, const EVP_MD *type, EVP_PKEY* key, std::string& strError) { EVP_MD_CTX mdCtx; uint8_t* signSrc = (uint8_t *)OPENSSL_malloc(sign.length()); int32_t signSrcLen = base64Decode(signSrc, (const uint8_t *)sign.c_str(), sign.length(), strError); if (0 > signSrcLen) { strError = "sign base64Decode failed"; OPENSSL_free(signSrc); return -1; } EVP_VerifyInit(&mdCtx, type); EVP_VerifyUpdate(&mdCtx, data.c_str(), data.length()); int32_t ret = EVP_VerifyFinal(&mdCtx, signSrc, signSrcLen, pubKey); OPENSSL_free(signSrc); return 1 == ret ? 0 : -2; } static int32_t md5WithRsa(const std::string &data, std::string &sign, EVP_PKEY* priKey, std::string& strError) { return signWithRsa(data, EVP_md5(), priKey, sign, strError); } static int32_t verifyMd5WithRsa(const std::string &data, const std::string &sign, EVP_PKEY* pubKey, , std::string& strError) { return verifySignWithRsa(data, sign, EVP_md5(), pubKey, strError); } static int32_t base64Encode(uint8_t *out, const uint8_t *in, int32_t inl, , std::string& strError) { int32_t outl(0); outl = EVP_EncodeBlock(out, in, inl); if (0 > outl) { strError = "EVP_EncodeBlock failed\n"; return -1; } return outl; } static int32_t base64Decode(uint8_t *out, const uint8_t *in, int32_t inl, , std::string& strError) { int32_t outl(0), ret(0); if ('=' == in[inl - 1]) { ret++; } if ('=' == in[inl - 2]) { ret++; } outl = EVP_DecodeBlock(out, in, inl); if (0 > outl) { strError = "EVP_DecodeBlock failed\n"; return -1; } out[outl - ret] = '\0'; return outl - ret; } }; } //end namespace UTILS #endif /* CRYPTOHELPER_H_ */然后,爱钻牛角尖的我,拿这个算法(verifySignWithRsa)去验证了一把华为的SDK,居然验证通过了!原来华为用的根本不是SHA256,而是SHA1!真是无力吐槽!害我加班到十一点半的华为!
顺便贴上新版COOLPAD的代码我整理的下载链接(他们的技术居然把这个算法不知道是从OPENSSL还是从LIBCRYPTO还是哪个数学库中扒了出来,真是太良心了!!!下次一定要买COOLPAD手机!) :
SHA1withRSA算法不依赖第三方库COOLPAD提供uniqs整理
相关文章推荐
- Android平台接入微信所遇到问题并且解决方法
- cocos2dx android 接入移动MM 遇到问题及解决方法
- 关于SDK更新遇到Failed to fetch URL http://dl-ssl.google.com/android refused问题的解决办法
- android 微信 以及QQ的SDK接入分享功能遇到的些问题小结
- Android 调试遇到RSA key导致手机Offline或Unauthorized问题的终极解决方法
- iOS开发小记:初次接入环信SDK3.0时遇到的问题及解决办法汇总
- 【Android】导入低版本 project到高版本sdk后,遇到的兼容问题的解决
- Android升级sdk遇到的问题的解决办法
- 线程问题 之 登陆问题(91 Android版本SDK接入闪屏问题解决)
- cocos2d-x 接入android ,登录第三方SDK时屏幕不断闪烁刷屏的问题解决
- 关于Android SDK Manager启动时闪一下,就没反应的问题解决方法
- blcr加速android启动速度遇到的问题及解决方法
- Android中使用cmwap接入点访问互联网的问题及解决办法
- [原]用Eclipse开发Android应用,用svn管理源码时遇到的问题及解决方法
- Android 开发环境搭建中--- “An SDK Target must be specified.” 问题解决
- 安装android-ndk-1.5_r1遇到的问题及解决方法
- android更新sdk 时Failed to rename directory 问题的解决
- Android SDK到3.0版本时,遇到Failed to rename directory E:/android/tools to E:/android/temp/ToolPackage.old01问题
- Android 开发环境搭建中--- “An SDK Target must be specified.” 问题解决(转载)
- Python2.5使用新浪微博Python SDK遇到的问题与解决方法