C++用openssl进行rsa加密,java用crypto rsa解密的问题

旋zi 2014-11-15 04:28:15
这段儿时间正在研究rsa加密解密的问题,由于没用过C++所以简直是啪啪打自己脸啊
废话不多说了,先说下环境,我是用C++在ALT控件中用openssl的rsa库进行加密,公钥是用js调用控件方法传入,加密结果转16进制字符串返回给jsp页面的js代码中,js发送ajax请求到java后台进行解密。现在遇到一些问题,如下:
1.公钥长度1024,openssl加密结果长度为128,但是偶尔会出现长度很小的情况,会导致java私钥解密javax.crypto.BadPaddingException: Data must start with zero错误。
2.比如输入明文:test1234,解密结果为:TEST1234后面一堆乱码如下图所示


求各位大神解救,我已经快要放弃治疗了

下面贴上关键代码求各位大神指正,由于小弟不才,希望大神们指正的时候详细说明一下,小弟感激不尽。

C++代码如下:

/*RSA公钥加密方法*/
STDMETHODIMP CsafeEdit::RsaEncrypt(BSTR strPublicKey)
{
//g_m_string保存了明文字符,这段代码可以忽略 BEGIN
int len = g_m_String.Length() + 2;
BSTR str = (BSTR)ALLOC(len * 2);
if (str == NULL)
{
return S_FALSE;
}
if (!g_m_String.B_STR(str, len * 2))
{
FREE(str);
return S_FALSE;
}
char *mingwen = _com_util::ConvertBSTRToString(str);
FREE(str);
g_m_String.Clear();
//g_m_string保存了明文字符,这段代码可以忽略 END

char *p_en; //接收加密后的密文
int flen, rsa_len;

//这段代码是将jsp页面传过来的公钥转换成OPENSSL可识别的公钥 BEGIN
_bstr_t bstr_t(strPublicKey);
string pubKey(bstr_t);

int nPublicKeyLen = pubKey.size();
for (int i = 64; i < nPublicKeyLen; i += 64)
{
if (pubKey[i] != '\n')
{
pubKey.insert(i, "\n");
}
i++;
}
pubKey.insert(0, "-----BEGIN PUBLIC KEY-----\n");
pubKey.append("\n-----END PUBLIC KEY-----\n");
//这段代码是将jsp页面传过来的公钥转换成OPENSSL可识别的公钥 END

//接下来就是OPENSSL RSA公钥加密 BEGIN
BIO *bio = NULL;
RSA *rsa = NULL;
char *chPublicKey = const_cast<char *>(pubKey.c_str());
if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) //从字符串读取RSA公钥
{
cout << "BIO_new_mem_buf failed!" << endl;
}
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL); //从bio结构中得到rsa结构
if (!rsa)
{
ERR_load_crypto_strings();
char errBuf[512];
ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf));
cout << "load public key failed[" << errBuf << "]" << endl;
BIO_free_all(bio);
return NULL;
}
flen = strlen(mingwen); //获取明文长度,好像没用到
rsa_len = RSA_size(rsa);

//下面的一段儿代码是有疑问的地方,包括给密文分配空间p_en = (char *)malloc(rsa_len + 1); 还有
//RSA_PKCS1_PADDING方式rsa_len - 11是否正确等等

p_en = (char *)malloc(rsa_len + 1);
memset(p_en, 0, rsa_len + 1);

if (RSA_public_encrypt(rsa_len - 11, (unsigned char *)mingwen, (unsigned char*)p_en, rsa, RSA_PKCS1_PADDING)<0){
return NULL;
}
RSA_free(rsa);

//下面是将密文转为16进制字符串
BIGNUM *rs;

rs = BN_new();
BN_bin2bn((unsigned char *)p_en, strlen(p_en), rs);
char *tmpData = BN_bn2hex(rs); //将密文转为16进制字符串
int dest_len = strlen(tmpData);
for (size_t i = 0; i < dest_len; i++)
{
g_m_String.Append(tmpData[i]); //添加到返回jsp页面的字符串中
}

return S_OK;
}


java代码:

/*
encryptedData:是16进制密文调用hexStringToBytes方法得到的字节数组
*/
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
throws Exception {



//获取私钥
byte[] keyBytes = Base64Utils.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache = null;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > 128) {
cache = cipher.doFinal(encryptedData, offSet, 128);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}

public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}


麻烦各位大神帮忙看看问题所在,在此祝愿各位大神财源滚滚。
...全文
9661 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
鬼鬼2017 2017-03-16
  • 打赏
  • 举报
回复
这里的 rsa_len-11 网上貌似都是这样的。其实这样貌似是错误。(也可能是我的 误解,不过确确实实测试正常通过了。)再pkcs1的时候 第一个参数 应该是 明文的长度,文档中说了 至少减少 11字节。至少 二字很重要。也就是说 参数可以是 1 到 rsa_len-12之间的任意值。 即 strlen(mingwen)。 if (RSA_public_encrypt(rsa_len - 11, (unsigned char *)mingwen, (unsigned char*)p_en, rsa, RSA_PKCS1_PADDING)<0) 改成 if (RSA_public_encrypt(strlen(mingwen), (unsigned char *)mingwen, (unsigned char*)p_en, rsa, RSA_PKCS1_PADDING)<0){ 应该就可以了
醉趋醍 2016-04-06
  • 打赏
  • 举报
回复
http://blog.csdn.net/zhout2009/article/details/51020277
laowang2 2015-05-23
  • 打赏
  • 举报
回复
直接用openssl估计有难度,为啥不试试winapi呢?
mickey_51 2015-05-15
  • 打赏
  • 举报
回复
你找到解决的办法了吗?
旋zi 2014-11-17
  • 打赏
  • 举报
回复
怎么没有人回帖啊
旋zi 2014-11-17
  • 打赏
  • 举报
回复
将16行代码:char *mingwen = _com_util::ConvertBSTRToString(str); 改成char *mingwen = new char[128]; //公钥用的1024长度 mingwen = _com_util::ConvertBSTRToString(str); 68行代码:if (RSA_public_encrypt(rsa_len - 11, (unsigned char *)mingwen, (unsigned char*)p_en, rsa, RSA_PKCS1_PADDING)<0){ return NULL; } 改为: if (RSA_public_encrypt(flen, (unsigned char *)mingwen, (unsigned char*)p_en, rsa, RSA_PKCS1_PADDING)<0){ return NULL; } 这样修改之后终于后面没有乱码了,但是不稳定,经常出现密文长度变化的情况,怀疑是存储分配问题,求大神帮帮忙啊,快崩溃了,对C++不懂啊
旋zi 2014-11-15
  • 打赏
  • 举报
回复
新人自己顶贴

703

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder ActiveX/COM/DCOM
社区管理员
  • ActiveX/COM/DCOM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧