c# - OpenSSL 错误 "data greater than mod len"

标签 c# c++ encryption openssl cryptography

我有一个客户端/服务器设置,它包含一个使用 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/

相关文章:

c++ - 验证 EXE 上的 Authenticode 签名 - 没有 CAPICOM 的 C++

linux - Linux 中的字符串加密

javascript - Ajax 之后单击按钮后禁用按钮 - ASP.NET MVC5

c++ - 如何使用 QT 4.5 和 Linux 发送和接收广播消息?

c++ - 如何只删除不是数字的字符串的第一个字符? (MFC, C++)

Android 虚拟设备/Android 模拟器 - 解密失败

github - GitHub 如何知道我的密码较弱?

c# - 从方法签名中删除通用参数

c# - C# 中的 Windows 应用程序支持 gif 动画吗?

c# - xulrunner,C# : how to change html?