저는 CNG를 처음 사용합니다. 나는 msdn 사이트에서 기본 프로그램으로 놀고있다. aes cbc 암호화 된 출력을 제공하는 다른 웹 사이트를 사용하여 입력 일반 문자열을 수정하고 출력을 테스트했습니다. 불행히도 전반전 만 일치하고 다음 절반은 일치하지 않습니다. 실수가 어디에 있는지 누군가가 나를 가리킬 수 있다면 좋을 것입니다.CNG에서 AES-CBC로 암호화 된 출력이 온라인 도구와 일치하지 않습니다.
msdn의 원본 코드는 here입니다.
다음은 내 코드에서 생성 된 출력입니다 (아래). 입력 문자열을 수정하는 것과 별개로 코드에 차이가 없음에 유의하십시오. 하반기가 일치하지 않음을 한 후 여기에
은 .. 상반기는 "B0의 C4 (29) (18)"로 끝나는 온라인 웹 사이트 (http://aes.online-domain-tools.com/ 및 anothersite)
의 출력이다.
여기서 코드는 데이터의 길이가 블록 크기 (AES 16 바이트)의 정확한 배수가 아닌 때문에 패딩이 추가되어 있지만
#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);
}
IV는 256 비트가 아니며 16 진수입니다. 여기서 각 문자는 4 비트, 32 문자 * 4 비트 = 128 비트를 나타냅니다. 또한 스크린 샷에 입력, 키 및 IV를 제공하지 마십시오. – zaph
하지만 내 프로그램과 온라인 웹 사이트에서도 같은 IV를 사용하고 있습니다. 그들 중 누구도 불평하지 않았습니다. msdn과 동일한 코드이므로 IV가 문제가되지 않을 수도 있습니다. – ABCDEFG
데이터 길이가 블록 크기의 정확한 배수 (AES의 경우 16 바이트)가 아니므로 패딩이 추가되지만. 구현시 데이터를 거부하거나 0x00 (cryptomathic), PKCS # 7 (일반적으로 사용되는 패딩) 또는 junbk가 제공 한 데이터를 메모리에 저장하는 등의 기본 방법으로 패드를 거부합니다. AES의 인스턴스 생성시 패딩을 지정하는 것이 가장 좋습니다. – zaph