Зашифрованный вывод AES-CBC в CNG не соответствует онлайн-инструментам

Я новичок в CNG. Я играю с основной программой с сайта MSDN.
Я изменил входную простую строку и протестировал вывод, используя другие веб-сайты, которые предоставляют зашифрованный вывод aes cbc.
К сожалению, только первая половина соответствует, а следующая половина не соответствует.
Было бы здорово, если бы кто-то мог указать мне, где лежит ошибка,

Исходный код из MSDN является Вот.

Вот вывод, сгенерированный из моего кода (ниже). Обратите внимание, что в моем коде нет никакой разницы, кроме изменения входной простой строки.
введите описание изображения здесь

Вот вывод с интернет-сайта (http://aes.online-domain-tools.com/ а также anothersite)
введите описание изображения здесь

Первая половина заканчивается в «B0 C4 29 18» .. после этого вторая половина не совпадает.

Вот фрагмент кода

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>

#pragma comment(lib, "bcrypt.lib")

#ifndef STATUS_UNSUCCESSFUL
#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)
#endif // !STATUS_UNSUCCESSFUL

#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif

void
print_inhex(char *buf, int len) {
for (int i = 0; i < len; i++)
printf(" %02x", buf[i]);
printf("\n");
}

const BYTE rgbPlaintext[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};

static const BYTE rgbIV[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};

static const BYTE rgbAES128Key[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};void
CNG_aes_cbc()
{

BCRYPT_ALG_HANDLE       hAesAlg = NULL;
BCRYPT_KEY_HANDLE       hKey = NULL;
NTSTATUS                status = STATUS_UNSUCCESSFUL;
DWORD                   cbCipherText = 0,
cbPlainText = 0,
cbData = 0,
cbKeyObject = 0,
cbBlockLen = 0,
cbBlob = 0;
PBYTE                   pbCipherText = NULL,
pbPlainText = NULL,
pbKeyObject = NULL,
pbIV = NULL,
pbBlob = NULL;

// Open an algorithm handle.
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}

// Calculate the size of the buffer to hold the KeyObject.
if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbData, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}

// Allocate the key object on the heap.
pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
if (NULL == pbKeyObject) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}

// Calculate the block length for the IV.
if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_BLOCK_LENGTH, (PBYTE)&cbBlockLen, sizeof(DWORD), &cbData, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}

// Determine whether the cbBlockLen is not longer than the IV length.
if (cbBlockLen > sizeof(rgbIV)) {
wprintf(L"**** block length is longer than the provided IV length\n");
goto Cleanup;
}

// Allocate a buffer for the IV. The buffer is consumed during the
// encrypt/decrypt process.
pbIV = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlockLen);
if (NULL == pbIV) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}

memcpy(pbIV, rgbIV, cbBlockLen);

if (!NT_SUCCESS(status = BCryptSetProperty(hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) {
wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
goto Cleanup;
}

// Generate the key from supplied input key bytes.
if (!NT_SUCCESS(status = BCryptGenerateSymmetricKey(hAesAlg, &hKey, pbKeyObject, cbKeyObject, (PBYTE)rgbAES128Key, sizeof(rgbAES128Key), 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n", status);
goto Cleanup;
}// Save another copy of the key for later.
if (!NT_SUCCESS(status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, NULL, 0, &cbBlob, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status);
goto Cleanup;
}// Allocate the buffer to hold the BLOB.
PUCHAR pbBlob_1 = (PUCHAR)malloc(sizeof(PUCHAR) * cbBlob);
//pbBlob = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlob);
if (NULL == pbBlob_1) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}

if (!NT_SUCCESS(status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, pbBlob_1, cbBlob, &cbBlob, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status);
goto Cleanup;
}

PUCHAR blob = pbBlob_1 + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
int len = cbBlob - sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
printf("key:");
print_inhex(blob, len);

cbPlainText = sizeof(rgbPlaintext);
pbPlainText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbPlainText);
if (NULL == pbPlainText) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}

/*memcpy(pbPlainText, rgbPlaintext, sizeof(rgbPlaintext));*/
char *test_msg = "This is my test msg";
cbPlainText = strlen(test_msg) + 1;
memcpy(pbPlainText, test_msg, cbPlainText);

printf("plain text:");
print_inhex(test_msg, strlen(test_msg));

// Get the output buffer size.
if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING)))  {
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}

pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
if (NULL == pbCipherText) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}

// Use the key to encrypt the plaintext buffer.
// For block sized messages, block padding will add an extra block.
if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV,
cbBlockLen, pbCipherText, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING))){
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}

printf("cipher text:");
for (int i = 0; i < cbCipherText; i++)
printf(" %02x", pbCipherText[i]);

wprintf(L"\nSuccess!\n");

Cleanup:
if (hAesAlg)
BCryptCloseAlgorithmProvider(hAesAlg, 0);

if (hKey)
BCryptDestroyKey(hKey);

if (pbCipherText)
HeapFree(GetProcessHeap(), 0, pbCipherText);

if (pbKeyObject)
HeapFree(GetProcessHeap(), 0, pbKeyObject);

if (pbIV)
HeapFree(GetProcessHeap(), 0, pbIV);
}

0

Решение

Длина данных не является точным кратным размеру блока (16 байт для AES), поэтому добавляется дополнение. Именно здесь реализация либо отклоняет данные, планшеты с методом по умолчанию, таким как 0x00 (криптоматический), PKCS # 7 (обычно используемый заполнитель) или любой другой мусор, следующий за предоставленными данными в памяти.

Не использовать BCryptEncryptиспользовать AES Класс

Свойство SymmetricAlgorithm.Padding Примечание. По умолчанию используется PaddingMode.PKCS7.

Лучше всего указывать отступ при создании AES.

Увидеть Перечисление PaddingMode: PKCS7
Строка заполнения PKCS # 7 состоит из последовательности байтов, каждый из которых равен общему количеству добавленных байтов заполнения.

Добавление вручную дополнения PKCS # 7 к:

криптоматический AES:

производит: 46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936

3

Другие решения

Вы не согласны с вашей ценностью для cbPlainText,

Asides:

  • У вас также есть какой-то очень страшный код copy / realloc, где вы записываете строку в буфер, который не гарантированно такой же большой, как строка).
  • Вы также определили NT_SUCCESS таким образом, чтобы он возвращал, что-то не получилось. 0 — успех,! 0 — неудача.

Вы распечатали в шестнадцатеричном формате до стр. Tst_msg. Но вы установили cbPlainText = strlen(tst_msg) + 1, Если вы установите его strlen(tst_msg) тогда вы получите ответ @ zaph (46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936).

Вы не соответствуете веб-сайту, потому что вы использовали CNG с заполнением PKCS # 7, а веб-сайт использует заполнение нулями. Вы можете определить заполнение, используемое на веб-сайте, взяв зашифрованный текст на выходе и поместив его в виде открытого текста, а затем нажав дешифрование. Затем он говорит, что ваш вклад был 54686973206973206d792074657374206d736700000000000000000000000000, Или, если вы добавите 00 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C при входе на сайт вы получите свой оригинальный ответ. Или добавить 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D и вы получите ответ @ zaph.

Итак, чем заняться:

  • Не переоценивайте длину вещей для печати, сделайте одну переменную (cbPlainText) и придерживайтесь ее.
  • AES — это алгоритм блочного шифрования. Все блочные шифры требуют полных блоков, недостающий последний блок должен быть дополнен (а в схемах со сменным заполнением для полного окончательного блока требуется еще один блок). Узнайте, что это значит, прежде чем продолжить. https://en.wikipedia.org/wiki/Padding_(cryptography)#Symmetric_cryptography
  • Когда что-то не так с шифрованием, посмотрите на расшифрованный вывод.
    • Очень часто выявляется расшифрованный вывод без заполнения.
  • Узнайте C, и как работает память. Или переключитесь на C # и получите менее крутую кривую обучения.
3

По вопросам рекламы [email protected]