OpenSSL 错误"data greater than mod len"
OpenSSL error "data greater than mod len"
我有一个客户端/服务器设置,它包括一个使用OpenSSL
用C++编写的服务器和一个使用Aes/RSACryptoServiceProvider
用C#编写的客户端。我在两边生成一个RSA密钥对,并向两边发送公钥。然后,当我准备发送消息时,我生成一个Aes密钥/iv,并用它加密消息,然后用接收方的公钥加密Aes密钥(还有iv?我试过加密和不加密,但都给了我相同的错误,我稍后会提到),然后发送Aes加密密钥、iv和加密消息。然而,当我尝试从客户端发送到服务器时,我会收到一个OpenSSL错误,在使用EVP_OpenInit
时读取"大于mod-len的数据"。
以下是我如何在C#中生成数据:
var keyPair = new RSACryptoServiceProvider(2048); //server uses 2048 too (added on Edit)
var aes = new AesCryptoServiceProvider();
//OpenSSL uses the EVP_CIPHER* EVP_aes_256_cbc()
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.KeySize = 256; //bits
aes.GenerateKey();
aes.GenerateIV();
var message = Encoding.Default.GetBytes("test data");
var eMessage = new byte[4096];
using (var stream = new MemoryStream(eMessage))
{
var encryptor = aes.CreateEncryptor();
using (var cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
{
await cryptoStream.WriteAsync(message, 0, message.Length);
}
}
string eMessageString = null;
for (int i = 0; i < eMessage.Length; i++)
{
if (eMessage[i] == ' ')
{
eMessageString = Convert.ToBase64String(eMessage, 0, i-1);
}
}
var eKey = Convert.ToBase64String(keyPair.Encrypt(aes.Key, false));
var eIV = Convert.ToBase64String(aes.IV); //may not need to encrypt
我知道我的C++实现是在OpenSSL正确读取客户端公钥时工作的,并且当在服务器上使用通过OpenSSL
生成的不同密钥时,我可以使用EVP_Seal
/EVP_Open
函数加密/解密数据。所以,我不确定是什么导致了这个错误,但我想我有一个主意。当我将数据发送到服务器时,会不会是密钥/iv/加密消息的编码方式?或者可能是OpenSSL
和C#在实现上的差异?或者可能是我完全没有抓到的东西?
编辑:这是我如何使用EVP_OpenInit
的请求代码。
BlueSOD::Encryption::DecryptionData BlueSOD::Encryption::EncryptionFactory::Decrypt2(DecryptionWork2 && work)
{
DecryptionData data;
EVP_PKEY* privateKey = work.privateKey.get();
auto encryptionKey = (unsigned char*)work.info.key.c_str();
auto encryptionIV = (unsigned char*)work.info.iv.c_str();
EVP_CIPHER_CTX_ptr cipherCtxPtr{ AcquireCipherCtx() };
EVP_CIPHER_CTX* cipher = cipherCtxPtr.get();
int status;
//ERROR HAPPENS HERE
status = EVP_OpenInit(cipher, m_Cipher, encryptionKey, work.info.key.size(), encryptionIV, privateKey);
cout << ERR_error_string(ERR_get_error(), nullptr) << endl;
CheckForError(status, "EVP_OpenInit failed.");
int bufferLength = work.cipherText.size() + EVP_MAX_BLOCK_LENGTH;
auto buffer = make_unique<unsigned char[]>(bufferLength);
auto cipherTemp = (unsigned char*)work.cipherText.c_str();
status = EVP_OpenUpdate(cipher, buffer.get(), &bufferLength, cipherTemp, work.cipherText.size());
CheckForError(status, "EVP_OpenUpdate failed.");
status = EVP_OpenFinal(cipher, buffer.get(), &bufferLength);
CheckForError(status, "EVP_OpenFinal failed.");
data.plainText = CreateSecureString(buffer.get(), bufferLength);
return move(data);
}
Encoding.Default.GetString
无法工作。IV、包装密钥和密文都是二进制的,(与随机一样)无法区分。这意味着编码可能会出错,因为并非所有字节都映射到字符。这意味着信息丢失。请尝试使用base64编码。
您的IV、封装密钥和密文也应该相互区分。然而,这并不难,因为IV具有底层密码的块大小(AES/CBC为16个字节),封装的密钥具有相同的模数字节大小(或RSA密钥大小),而密文是其余的。换句话说,你还可以简单地将它们全部连接起来。
所以你的预感是对的。
RSA 4096 w/OAEP只能加密446字节的数据(请参阅RSA RFC 2437的7.1),而RSA 2048 w/OAEP只可以加密245字节(IV和对称密钥的16+32字节应该还有足够的空间)。我没有看到您为RSA提供程序设置密钥长度的任何地方,因此它可能由于某种原因而无法加密AES密钥。
你能至少提供服务器代码抛出异常的那一行吗?您为EVP_OpenInit
中的eki
参数(对称密钥长度)提供了什么?在服务器上尝试使用RSA解密对称密钥之前,是否对其执行Base64解码?
记录在案,在传输之前不需要对IV进行加密,但这样做没有负面影响(除了计算成本)
更新:
在调试加密问题时,减少每条语句中的步骤数总是很有帮助的,这样您就可以找到错误发生的位置。我建议您将客户端代码的最后几句语句分解为单独的步骤,并逐步完成(即RSA加密和Base64编码在单独的行上)。
所以您现在可以在客户端和服务器上比较以下值,它们是字节对字节相等的(没有额外的0x00
等)?
Reference | Client | Server
------------------------------------------------------------------
A | keyPair.Encrypt(aes.Key, false) | ek
Base64E(A) | eKey | ??
len(A) | len(A) | len(ek)
您在另一条评论中提到,您比较了客户端和服务器上Base64解码加密密钥的十六进制编码值,结果是相同的?你可以试着只使用客户端&服务器使用该密钥对任意明文消息(<<245字节,以确保OAEP或PKCS#1v1.5填充不超过245字节)进行加密和解密,以确保一切正确?
我对C#实现不是特别熟悉——在客户端上复制EVP_SealInit
还需要做些什么吗?
我的问题在于如何在客户端对消息、密钥和iv进行编码,并在服务器上进行解码。客户端用base64对它们进行编码,因此必须在服务器上对其进行解码,以便OpenSSL理解它们(OpenSSL使用原始字节而不是编码方案)。
EDIT:C#实现和OpenSSL实现之间似乎也存在冲突。C#Aes的实现似乎与OpenSSL并不完全匹配。在OpenSSL中解密时,我得到了正确的纯文本,但后面有一堆垃圾数据,EVP_OpenFinal
会导致一个错误,上面写着"解密错误"。如果有人知道解决这个问题的方法,请告诉我!我尝试过openssl.net API,但如果我尝试使用BIO.,它会抛出一个错误
- MOD 1000000007似乎不正确
- 在给定的代码中,有人可以解释一下(int i = 0; i<len; i++)count[str[i]]++的代码片段;
- 调用 'make_pair(char [len], int&) 没有匹配函数
- 为什么当我从语句检查中删除"+ mod"时,以下程序给出错误的答案。问题链接:https://www.codechef.com/problems/FFC219B
- "[ptr, ptr+len) must be a valid range"是什么意思?
- 使用加法链接计算 (a^x)mod n.C++算法
- 为什么字符串(常量字符* s,size_t pos,size_t len = npos)有效?
- 非常基本的MurmurHash问题:len的变量描述,C++实现的关键
- 数组中的"Maximum Sum mod M"范围:求和和计数
- 请说明这种怪异的行为C 乘法数字,然后说明mod
- 在等式的右侧使用 mod 和相等
- 这是什么意思 *ptr = len
- C ++递归与大数字查找mod
- 如果 len>0
- 如何将"fmod()"替换为整数"mod()"函数
- 矩阵Mod.稀疏行运算符*(矩阵,向量)
- OpenCV 错误:断言失败(a_size.width == len)
- 在使用按位移位而不是 mod 时,CUDA 中存在显着的时差
- OpenSSL 错误"data greater than mod len"
- 第 N 个四面体数 mod m