2017-03-25 4 views
-1

Ich bin neu in CNG. Ich spiele mit dem Basisprogramm von msdn site. Ich habe die Eingabe-Plain-String geändert und testen Sie die Ausgabe mit anderen Websites, die die aes cbc-verschlüsselte Ausgabe bietet. Leider nur die erste Hälfte passt und die nächste Hälfte stimmt nicht überein. Es wäre toll, wenn mir jemand zeigen könnte, wo der Fehler liegt,AES-CBC verschlüsselte Ausgabe in CNG passt nicht mit Online-Tools

Original-Code von msdn ist here.

Hier ist die Ausgabe von meinem Code (unten) generiert. Bitte beachten Sie, dass es keinen Unterschied in meinem Code gibt, abgesehen von der Eingabe der einfachen Zeichenfolge. Hier enter image description here

ist die Ausgabe von der Online-Website (http://aes.online-domain-tools.com/ und anothersite) enter image description here

Die erste Hälfte endet mit "B0 C4 29 18" .. nach, dass die zweite Hälfte nicht übereinstimmt.

Hier ist der Code

#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

Die IV ist nicht 256-Bits, es ist in Hex w = hier jedes Zeichen repräsentiert 4-Bit, 32-Zeichen * 4-Bit = 128-Bits. Geben Sie auch nicht die Eingabe, den Schlüssel und die IV in einem Screenshot an. – zaph

+0

Aber ich benutze die gleiche IV in meinem Programm und Online-Websites als auch .. keiner von ihnen beschwerte .. es ist der gleiche Code von msdn, so gehe ich davon aus, dass IV möglicherweise nicht das Problem sein. – ABCDEFG

+0

Die Länge der Daten ist kein exaktes Vielfaches der Blockgröße (16 Bytes für AES), daher wird padding hinzugefügt. Das ist, wo die Implementierung entweder die Daten zurückweist, Pads mit einer Standardmethode wie 0x00 (cryptomathisch), PKCS # 7 (das allgemein verwendete Padding) oder was auch immer junbk den bereitgestellten Daten im Speicher folgt. Es ist am besten, das Auffüllen bei der Instanziierung von AES anzugeben. – zaph

Antwort

2

Die Länge des Daten Schnipsel ist nicht ein genaues Vielfaches der Blockgröße (16-Bytes für AES) so padding wird hinzugefügt, aber. Das ist, wo die Implementierung entweder die Daten zurückweist, Pads mit einer Standardmethode wie 0x00 (cryptomathisch), PKCS # 7 (das allgemein verwendete Padding) oder was auch immer der Junk den bereitgestellten Daten im Speicher folgt.

Sie BCryptEncrypt nicht verwenden AES Class

SymmetricAlgorithm.Padding Property verwenden Hinweis: Die Standard-PaddingMode.PKCS7 ist.

Es ist am besten, das Auffüllen bei Instanziierung von AES anzugeben.

Siehe PaddingMode Enumeration: PKCS7
Der PKCS # 7-padding-String aus einer Folge von Bytes besteht, von denen jeder auf die Gesamtzahl von Füllbytes hinzugefügt gleich ist.

manuell hinzufügen PKCS # 7 padding:

cryptommathic AES:

produziert: 46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936

2

Sie sind nicht im Einklang mit dem Wert für cbPlainText.

Asides:

  • Sie haben auch einige sehr beängstigend copy/realloc Code, in dem Sie eine Zeichenfolge über einen Puffer nicht garantiert so groß wie die string) schreiben.
  • Sie haben NT_SUCCESS auch so definiert, dass es zurückgibt, ob etwas fehlgeschlagen ist oder nicht. 0 ist Erfolg,! 0 ist ein Fehler.

Sie hex-gedruckt bis zu strst von tst_msg. Aber Sie setzen cbPlainText = strlen(tst_msg) + 1. Wenn Sie es auf strlen(tst_msg) setzen, erhalten Sie @ zaphs Antwort (46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936).

Sie stimmen nicht mit der Website überein, weil Sie CNG mit PKCS # 7-Padding verwendet haben und die Website Zero-Padding verwendet. Sie können das auf der Website verwendete Padding identifizieren, indem Sie den ausgegebenen Schlüsseltext als Klartext eingeben und dann entschlüsseln. Es sagt dann Ihre Eingabe war 54686973206973206d792074657374206d736700000000000000000000000000. Oder, wenn Sie 00 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C auf Ihrer Eingabe auf der Website hinzufügen, erhalten Sie Ihre ursprüngliche Antwort. Oder fügen Sie 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D hinzu und Sie erhalten @ Zaphs Antwort. So

, um die Dinge zu tun:

  • Sie nicht die Länge der Dinge neu zu bewerten, zu drucken, machen eine Variable (cbPlainText) und bleiben Sie dabei.
  • AES ist ein Blockchiffrealgorithmus. Alle Blockchiffren benötigen vollständige Blöcke, ein defizitärer letzter Block muss aufgefüllt werden (und unter den entfernbaren Füllschemata benötigt ein kompletter letzter Block noch einen weiteren Block). Erfahren Sie, was das bedeutet, bevor Sie fortfahren. https://en.wikipedia.org/wiki/Padding_(cryptography)#Symmetric_cryptography
  • Wenn etwas mit der Verschlüsselung nicht stimmt, sehen Sie sich die entschlüsselte Ausgabe an.
    • Sehr oft enthüllt die entschlüsselte Ausgabe mit "no padding".
  • Lernen Sie C und wie Speicher funktioniert. Oder wechseln Sie zu C# und haben Sie eine weniger steile Lernkurve.