Я работаю над частью кросс-платформенного (Windows и Mac OS X) кода на C, который должен шифровать/дешифровать капли с использованием AES-256 с CBC и блочным размером 128 бит. Среди различных библиотек и API я выбрал OpenSSL.
Этот кусок кода затем загрузит blob с помощью многостраничного PUT на сервер, который затем расшифровывает его, используя те же настройки в .NET crypto framework (Aes, CryptoStream и т.д.).
Проблема, с которой я сталкиваюсь, заключается в том, что дешифрование сервера отлично работает, когда локальное шифрование выполняется в Windows, но оно не выполняется, когда шифрование выполняется в Mac OS X - сервер выдает "Недопустимое заполнение и исключение исключений".
Я рассматривал это со многих точек зрения:
- Я подтвердил правильность транспортировки - массив байтов, полученный по методу дешифрования сервера, точно такой же, как и от Mac OS X и Windows
- Фактическое содержимое зашифрованного blob для одного и того же ключа отличается от Windows и Mac OS X. Я протестировал это с помощью жесткого ключа и запустил этот патч в Windows и Mac OS X для того же blob
- Я уверен, что исправление правильное, так как оно позаботится OpenSSL и поскольку тот же код работает для Windows. Тем не менее, я попробовал реализовать схему дополнений , как это в исходном источнике Microsoft для .NET, но все же, не хочешь
- Я подтвердил, что IV одинаково для Windows и Mac OS X (я подумал, может быть, возникла проблема с некоторыми из специальных символов, таких как ETB, которые появляются в IV, но не было)
- Я пробовал LibreSSL и mbedtls без положительных результатов. В mbedtls мне также пришлось реализовать дополнение, потому что, насколько мне известно, отладчик несет ответственность за пользователя API.
- Я занимаюсь этой проблемой почти две недели, и я начинаю вытаскивать свои (когда-нибудь скудные) волосы.
В качестве справочной системы я отправлю код клиента 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;
}
}
Кто-нибудь знает, почему это может произойти? Для справки, это метод .NET из исходного источника Microsoft.sln, который (я думаю) делает дешифрование: https://gist.github.com/Metaluim/fcf9a4f1012fdeb2a44f#file-rijndaelmanagedtransform-cs