這段兒時間正在研究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);
}
麻煩各位大神幫忙看看問題所在,在此祝愿各位大神財源滾滾。
uj5u.com熱心網友回復:
新人自己頂貼uj5u.com熱心網友回復:
將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++不懂啊
uj5u.com熱心網友回復:
怎么沒有人回帖啊
uj5u.com熱心網友回復:
你找到解決的辦法了嗎?uj5u.com熱心網友回復:
直接用openssl估計有難度,為啥不試試winapi呢?uj5u.com熱心網友回復:
http://blog.csdn.net/zhout2009/article/details/51020277uj5u.com熱心網友回復:
這里的 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){
應該就可以了
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/64536.html
上一篇:c++提問
