看雪论坛
发新帖

[已解决] [悬赏]一个RSA的c++和Java版本不能互通,头发都白了 100.00元

mastercom 2017-8-31 14:31 389

这是客户端代码,公钥加密,私钥解密。公钥由服务器端提供,加密后数据用Base64编码发送出去。用Java代码是没有问题的,用C++版本对方就解密失败了。
C++平台使用的是OPenSSL库。都使用PKCS1填充模式。
找了几天没找出问题,什么大端,填充都看了,貌似都不是这些问题,确实找不出原因了

Java平台的代码如下(只贴核心代码,或者称为伪代码)

      //这是公钥
      byte[] arrayOfBytePublic = Base64.decode("
      MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+D4pTERUemPtGIsteri\r
      eWoTbRTNHgZ0DN9Z4qfrS03eWP339/JBkGyKwlBykCzYDt8L0YMW/1Xg1appYGvf\r
      o4mnVvxzIbc1tuanH1Z+wnXbrHqgW5ndlMjZ328mDyDIRHPmzA8FMYSvPGJtnrv4\r
      H9Tc+CeKrmiWskbzxBg4T/MUxYsk/+WWg6y5dUU61rwr19HyBZKq93xH8IOctgeR\r
      xsf6oItQJ1y1Nd55XVEul2Lh5KtTZzZMWAwreIq/EhZJH0XdbOeHhy78/fMmQtkK\r
      pJqLpRMTas1ZBWmVnqHxgBQcvheOu6cNGJYbadisJDk7Yo6MW3M7kRbybeU7C9yf\r
      7QIDAQAB", 0);

      X509EncodedKeySpec localX509EncodedKeySpec = new X509EncodedKeySpec(arrayOfBytePublic);
      PublicKey PublicKey = KeyFactory.getInstance("RSA").generatePublic(localX509EncodedKeySpec);
      Cipher localCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
      localCipher.init(1, PublicKey);
      Object localObject = arraymingwen.length;//明文
      ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
      //下面的是分段加密,2048bit的。最大长度是256
      int m = 0;
      if (localObject - n > 0)
      {
        if (localObject - n > (256-11));
        int i3;
        for (localObject1 = localCipher.doFinal(arrayOfByte1, n, (256-11)); ; localObject1 = localCipher.doFinal(arrayOfByte1, localObject1, i3))
        {
          int n = localObject1.length;
          localByteArrayOutputStream.write(localObject1, 0, n);
          int i1 = m + 1;
          Object localObject3 = i1 * (256-11);
          int i2 = i1;
          localObject1 = localObject3;
          m = i2;
          break;
          i3 = localObject - localObject1;
        }
      }
       localObject1 = localByteArrayOutputStream.toByteArray();
      localByteArrayOutputStream.close();
     //返回Base64的字符串
      return Base64.encodeToString(localObject1, 2);

windwos7平台的c++版本,Intel处理器,加密后用Base64编码,代码如下

int RsaEncrypt(CString str,char* encrypted)
{
CString key="-----BEGIN PUBLIC KEY-----\n" \
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw+D4pTERUemPtGIsteri\n" \
"eWoTbRTNHgZ0DN9Z4qfrS03eWP339/JBkGyKwlBykCzYDt8L0YMW/1Xg1appYGvf\n" \
"o4mnVvxzIbc1tuanH1Z+wnXbrHqgW5ndlMjZ328mDyDIRHPmzA8FMYSvPGJtnrv4\n" \
"H9Tc+CeKrmiWskbzxBg4T/MUxYsk/+WWg6y5dUU61rwr19HyBZKq93xH8IOctgeR\n" \
"xsf6oItQJ1y1Nd55XVEul2Lh5KtTZzZMWAwreIq/EhZJH0XdbOeHhy78/fMmQtkK\n" \
"pJqLpRMTas1ZBWmVnqHxgBQcvheOu6cNGJYbadisJDk7Yo6MW3M7kRbybeU7C9yf\n" \
"7QIDAQAB\n" \
"-----END PUBLIC KEY-----\n"; 


int padding = RSA_PKCS1_PADDING;
RSA * rsa = createRSA((unsigned char *)key.GetBuffer(0), 1);  

//分段加密
int inputLen=str.GetLength();
char* pSource=str.GetBuffer(0);
str.ReleaseBuffer();

int offSet = 0;
int i = 0; 
int result=0;
     
while (inputLen - offSet > 0)
{
if (inputLen - offSet > (256-11))
{
int retLen = RSA_public_encrypt(245, (const unsigned char*)(pSource+offSet),(unsigned char*) encrypted, rsa, padding);
encrypted=encrypted+retLen;
result+=retLen;
}
else
{
int retLen = RSA_public_encrypt(inputLen - offSet, (const unsigned char*)(pSource+offSet),(unsigned char*) encrypted, rsa, padding);
encrypted=encrypted+retLen;
result+=retLen;
}

i++;  
offSet = i * (256-11);  
}

return result;
}
//下面的代码用base64编码加密后的数据
CBase64 base;
string strbase= base.Encode((const unsigned char*)encoded,nLen);

本主题帖已收到 0 次赞赏,累计¥0.00
最新回复 (12)
aavk 2017-8-31 15:24
(+¥5.00) 2

填充问题,两边选择不自动填充。
自己填充。

注意,不填充少的部分你要自己补全的(用0补全也好)
不能互通一般就是这个问题。

yegu 2017-8-31 15:28
(+¥30.00) 3
你上面的公钥证书解码出来的公钥和公钥指数是下面这个值,能不能把待加密的数据和加密出来的结果发出来,我调试下C++版本的代码给你
pubkey=  C3E0F8A5311151E98FB4622CB5EAE2796A136D14CD1E06740CDF59E2A7EB4B4DDE58FDF7F7F241906C8AC25072902CD80EDF0BD18316FF55E0D5AA69606BDFA389A756FC7321B735B6E6A71F567EC275DBAC7AA05B99DD94C8D9DF6F260F20C84473E6CC0F053184AF3C626D9EBBF81FD4DCF8278AAE6896B246F3C418384FF314C58B24FFE59683ACB975453AD6BC2BD7D1F20592AAF77C47F0839CB60791C6C7FAA08B50275CB535DE795D512E9762E1E4AB5367364C580C2B788ABF1216491F45DD6CE787872EFCFDF32642D90AA49A8BA513136ACD590569959EA1F180141CBE178EBBA70D18961B69D8AC24393B628E8C5B733B9116F26DE53B0BDC9FED
pubExponent=010001
3
malokch 2017-8-31 15:32
(+¥10.00) 4
遇到过类似的坑,是填充问题。某些情况下(记不清了)c++解密后的明文是在缓冲区尾部的~~  一不注意看到的就是一堆乱码~
7
demoscene 2017-8-31 15:45
(+¥10.00) 5
做过C++和PHP的通信,是因为填充的方法不一样,要选择自己填充
验证方法:
        两边都选择不填充(RSA_NO_PADDING),然后加密一个256字节数据(因为你的密钥是2048bit的,256字节不需要填充,否则要自己填充到256),看能否正常解密
如果能正常解密就说明是填充问题了

最后就是要自己实现填充
rrrfff 2017-8-31 16:19
(+¥10.00) 6
malokch 遇到过类似的坑,是填充问题。某些情况下(记不清了)c++解密后的明文是在缓冲区尾部的~~ 一不注意看到的就是一堆乱码~
是的,  比如js的RSA套件NoPadding的情况下就会颠倒,  填充字节在缓冲区开始
yezhulove 2017-8-31 16:58
(+¥5.00) 7
rrrfff 是的, 比如js的RSA套件NoPadding的情况下就会颠倒, 填充字节在缓冲区开始
大部分大数存储,都是大端。
rrrfff 2017-8-31 17:37
(+¥10.00) 8
yezhulove 大部分大数存储,都是大端。
我说的这个似乎牵扯不到大数问题,  它是在padding时故意这么做的,  另一种OHDave就没颠倒
missdiog 2017-8-31 18:08
(+¥10.00) 9

RSA跨平台有2个注意:一个padding方式(如nopadding,pkcs8);另外一个是加密模式(ECB,CBC等)。两者一致了肯定可以通。

10
cvcvxk 2017-8-31 18:57
(+¥5.00) 10
java里用jni方式使用openssl库就好了,当年我也遇到了,我选择了jni调用openssl放弃java那套莫名其妙的玩意。

mastercom 2017-9-1 11:28
11
已经解决,加密没有问题的,是因为base64编码的时候,出现了\r\n字符导致的。请问怎么结款,见者有份哦
yezhulove 2017-9-1 11:29
(+¥5.00) 12
mastercom 已经解决,加密没有问题的,是因为base64编码的时候,出现了\r\n字符导致的。请问怎么结款,见者有份哦
啊哈,估计只能给一个人。
zyla 2017-9-12 09:36
13
感觉错过几百亿~~
返回



©2000-2017 看雪学院 | Based on Xiuno BBS | 域名 加速乐 保护 | SSL证书 又拍云 提供 | 微信公众号:ikanxue
Time: 0.012, SQL: 9 / 京ICP备10040895号-17