我有一个客户端/服务器设置,它包含一个使用 OpenSSL
用 C++ 编写的服务器和一个使用 Aes/RSACryptoServiceProvider
用 C# 编写的客户端。我在两侧生成一个 RSA key 对,并向每一侧发送公钥。然后,当我准备发送消息时,我生成一个 Aes key /iv 并用它加密消息,然后加密 Aes key (还有 iv?我试过加密和不加密,但是两者都给我同样的错误,我将在稍后提到)使用收件人的公钥,然后发送 Aes 加密 key 、iv 和加密消息。但是,当我尝试从客户端发送到服务器时,在使用 EVP_OpenInit
时,我收到一个 OpenSSL 错误,显示“数据大于 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] == '\0')
{
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 正确读取客户端公钥,并且我可以在使用不同 key 时使用 EVP_Seal
/EVP_Open
函数加密/解密数据通过服务器上的 OpenSSL
生成。所以,我不确定是什么导致了这个错误,但我想我有一个主意。这可能是我将数据发送到服务器时对 key /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、包装 key 和密文都是二进制的,并且(与随机的)无法区分。这意味着编码可能会出错,因为并非所有字节都会映射到字符。这意味着信息丢失了。尝试改用 base 64 编码。
您的 IV、包装 key 和密文也应该相互区分。然而,这并不难,因为 IV 具有底层密码的 block 大小(AES/CBC 为 16 字节),包装 key 具有与模数(或 RSA key 大小)和密文相同的字节大小,嗯,就是剩下的。换句话说,您不妨简单地将它们全部连接起来。
所以你的预感是正确的。
关于c# - OpenSSL 错误 "data greater than mod len",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41470767/