gpt4 book ai didi

c - 平台间加密结果不同,使用OpenSSL

转载 作者:太空狗 更新时间:2023-10-29 16:39:08 25 4
gpt4 key购买 nike

我正在使用 C 编写一段跨平台(Windows 和 Mac OS X)代码,需要使用 AES-256 和 CBC 以及 128 位的 block 大小来加密/解密 blob。在各种库和 API 中,我选择了 OpenSSL。

然后,这段代码将使用多部分形式的 PUT 将 blob 上传到服务器,然后服务器使用 .NET 加密框架(Aes、CryptoStream 等)中的相同设置对其进行解密。

我面临的问题是,当本地加密在 Windows 上完成时服务器解密工作正常,但当加密在 Mac OS X 上完成时服务器解密失败 - 服务器抛出“填充无效且无法删除异常".

我从多个角度看待这个问题:

  1. 我验证了传输是正确的——服务器解密方法接收到的字节数组与从 Mac OS X 和 Windows 发送的字节数组完全相同
  2. 对于相同的 key ,加密 blob 的实际内容在 Windows 和 Mac OS X 之间是不同的。我使用硬编码 key 对此进行了测试,并在 Windows 和 Mac OS X 上针对相同的 blob 运行了这个补丁
  3. 我确定填充是正确的,因为它由 OpenSSL 处理,并且相同的代码适用于 Windows。即便如此,我尝试实现填充方案因为它在 Microsoft 的 .NET 引用源中但仍然不行
  4. 我验证了 Windows 和 Mac OS X 上的 IV 是相同的(我认为 IV 中出现的一些特殊字符(例如 ETB)可能存在问题,但事实并非如此)
  5. 我已经尝试过 LibreSSL 和 mbedtls,但没有得到积极的结果。在 mbedtls 中,我还必须实现填充,因为据我所知,填充是 API 用户的责任
  6. 我已经解决这个问题将近两周了,我开始拔掉我(一直稀少的)头发

作为引用,我将发布用于加密的 C 客户端代码和用于解密的服务器 C# 代码。服务器端的一些次要细节将被省略(它们不会干扰加密代码)。

客户:

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
__setup_aes(EVP_CIPHER_CTX *ctx, const char *key, qvr_bool encrypt)
{
static const char *iv = ""; /* for security reasons, the actual IV is omitted... */

if (encrypt)
EVP_EncryptInit(ctx, EVP_aes_256_cbc(), key, iv);
else
EVP_DecryptInit(ctx, EVP_aes_256_cbc(), key, iv);
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
__encrypt(void *buf,
size_t buflen,
const char *key,
unsigned char **outbuf,
size_t *outlen)
{
EVP_CIPHER_CTX ctx;
int blocklen = 0;
int finallen = 0;
int remainder = 0;

__setup_aes(&ctx, key, QVR_TRUE);

EVP_CIPHER *c = ctx.cipher;
blocklen = EVP_CIPHER_CTX_block_size(&ctx);

//*outbuf = (unsigned char *) malloc((buflen + blocklen - 1) / blocklen * blocklen);
remainder = buflen % blocklen;
*outlen = remainder == 0 ? buflen : buflen + blocklen - remainder;
*outbuf = (unsigned char *) calloc(*outlen, sizeof(unsigned char));

EVP_EncryptUpdate(&ctx, *outbuf, outlen, buf, buflen);
EVP_EncryptFinal_ex(&ctx, *outbuf + *outlen, &finallen);

EVP_CIPHER_CTX_cleanup(&ctx);
//*outlen += finallen;
}

服务器:

static Byte[] Decrypt(byte[] input, byte[] key, byte[] iv)
{
try
{
// Check arguments.
if (input == null || input.Length <= 0)
throw new ArgumentNullException("input");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("iv");

byte[] unprotected;


using (var encryptor = Aes.Create())
{
encryptor.Key = key;
encryptor.IV = iv;
using (var msInput = new MemoryStream(input))
{
msInput.Position = 0;
using (
var cs = new CryptoStream(msInput, encryptor.CreateDecryptor(),
CryptoStreamMode.Read))
using (var data = new BinaryReader(cs))
using (var outStream = new MemoryStream())
{
byte[] buf = new byte[2048];
int bytes = 0;
while ((bytes = data.Read(buf, 0, buf.Length)) != 0)
outStream.Write(buf, 0, bytes);

return outStream.ToArray();
}
}
}
}
catch (Exception ex)
{
throw ex;
}

}

有人知道为什么会发生这种情况吗?作为引用,这是来自 Microsoft 引用源 .sln 的 .NET 方法(我认为)进行解密:https://gist.github.com/Metaluim/fcf9a4f1012fdeb2a44f#file-rijndaelmanagedtransform-cs

最佳答案

OpenSSL 版本差异很困惑。首先,我建议您明确强制并验证双方的 key 长度、 key 、IV 和加密模式。我没有在代码中看到这一点。然后我建议你在服务器端解密而不用填充。这将总是成功,然后您可以检查最后一个 block 是否符合您的预期。

使用 Windows-Encryption 和 MacOS-Encryption 变体执行此操作,您会看到差异,很可能是在填充中。

C++ 代码中的 outlen 填充看起来很奇怪。加密 16 字节长的明文会产生 32 字节的密文,但您只提供 16 字节长的缓冲区。这是行不通的。你会写出界。可能由于更宽敞的内存布局,它在 Windows 上工作得恰到好处,但在 MacOS 上却失败了。

关于c - 平台间加密结果不同,使用OpenSSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33017333/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com