2015-06-08 10 views
10

Sử dụng API CNG của Windows, tôi có thể mã hóa và giải mã các khối dữ liệu riêng lẻ bằng xác thực, sử dụng chế độ AES ở chế độ GCM. Bây giờ tôi muốn mã hóa và giải mã nhiều bộ đệm liên tiếp.Làm thế nào để chuỗi các cuộc gọi BCryptEncrypt và BCryptDecrypt bằng AES ở chế độ GCM?

Theo documentation for CNG, kịch bản sau đây được hỗ trợ:

Nếu đầu vào để mã hóa hoặc giải mã được rải rác trên nhiều bộ đệm, sau đó bạn phải cuộc gọi liên kết đến cái chức năng BCryptDecrypt BCryptEncrypt và. Chuỗi được chỉ định bằng cách đặt cờ BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG trong thành viên dwFlags.

Nếu tôi hiểu chính xác, điều này có nghĩa là tôi có thể gọi BCryptEncrypt tuần tự trên nhiều bộ đệm để nhận thẻ xác thực cho bộ đệm kết hợp ở cuối. Tương tự, tôi có thể gọi BCryptDecrypt tuần tự trên nhiều bộ đệm trong khi trì hoãn kiểm tra xác thực thực tế cho đến khi kết thúc. Tôi không thể làm điều đó để làm việc mặc dù, có vẻ như giá trị cho dwFlags bị bỏ qua. Bất cứ khi nào tôi sử dụng BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG, tôi nhận được giá trị trả lại là 0xc000a002, tương đương với STATUS_AUTH_TAG_MISMATCH như được định nghĩa trong ntstatus.h.

Mặc dù tham số pbIV được đánh dấu là vào/ra, các phần tử được trỏ đến bởi tham số pbIV không bị sửa đổi bởi BCryptEncrypt(). Điều đó có được mong đợi không? Tôi cũng đã xem xét trường pbNonce trong cấu trúc BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO, được trỏ tới bởi con trỏ pPaddingInfo, nhưng con trỏ đó cũng không bị sửa đổi. Tôi cũng đã thử "thủ công" tiến IV, sửa đổi nội dung bản thân theo kế hoạch truy cập, nhưng điều đó cũng không giúp được gì.

Quy trình đúng để kết nối các chức năng BCryptEncrypt và/hoặc BCryptDecrypt thành công là gì?

Trả lời

6

Tôi đã cố gắng làm cho nó hoạt động. Dường như vấn đề là trong MSDN, nên đề cập đến việc thiết lập BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG thay vì BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG.

#include <windows.h> 
#include <assert.h> 
#include <vector> 
#include <Bcrypt.h> 
#pragma comment(lib, "bcrypt.lib") 

std::vector<BYTE> MakePatternBytes(size_t a_Length) 
{ 
    std::vector<BYTE> result(a_Length); 
    for (size_t i = 0; i < result.size(); i++) 
    { 
     result[i] = (BYTE)i; 
    } 

    return result; 
} 

std::vector<BYTE> MakeRandomBytes(size_t a_Length) 
{ 
    std::vector<BYTE> result(a_Length); 
    for (size_t i = 0; i < result.size(); i++) 
    { 
     result[i] = (BYTE)rand(); 
    } 

    return result; 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    NTSTATUS bcryptResult = 0; 
    DWORD bytesDone = 0; 

    BCRYPT_ALG_HANDLE algHandle = 0; 
    bcryptResult = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_AES_ALGORITHM, 0, 0); 
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptOpenAlgorithmProvider"); 

    bcryptResult = BCryptSetProperty(algHandle, BCRYPT_CHAINING_MODE, (BYTE*)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0); 
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptSetProperty(BCRYPT_CHAINING_MODE)"); 

    BCRYPT_AUTH_TAG_LENGTHS_STRUCT authTagLengths; 
    bcryptResult = BCryptGetProperty(algHandle, BCRYPT_AUTH_TAG_LENGTH, (BYTE*)&authTagLengths, sizeof(authTagLengths), &bytesDone, 0); 
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptGetProperty(BCRYPT_AUTH_TAG_LENGTH)"); 

    DWORD blockLength = 0; 
    bcryptResult = BCryptGetProperty(algHandle, BCRYPT_BLOCK_LENGTH, (BYTE*)&blockLength, sizeof(blockLength), &bytesDone, 0); 
    assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptGetProperty(BCRYPT_BLOCK_LENGTH)"); 

    BCRYPT_KEY_HANDLE keyHandle = 0; 
    { 
     const std::vector<BYTE> key = MakeRandomBytes(blockLength); 
     bcryptResult = BCryptGenerateSymmetricKey(algHandle, &keyHandle, 0, 0, (PUCHAR)&key[0], key.size(), 0); 
     assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptGenerateSymmetricKey"); 
    } 

    const size_t GCM_NONCE_SIZE = 12; 
    const std::vector<BYTE> origNonce = MakeRandomBytes(GCM_NONCE_SIZE); 
    const std::vector<BYTE> origData = MakePatternBytes(256); 

    // Encrypt data as a whole 
    std::vector<BYTE> encrypted = origData; 
    std::vector<BYTE> authTag(authTagLengths.dwMinLength); 
    { 
     BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo; 
     BCRYPT_INIT_AUTH_MODE_INFO(authInfo); 
     authInfo.pbNonce = (PUCHAR)&origNonce[0]; 
     authInfo.cbNonce = origNonce.size(); 
     authInfo.pbTag = &authTag[0]; 
     authInfo.cbTag = authTag.size(); 

     bcryptResult = BCryptEncrypt 
      (
      keyHandle, 
      &encrypted[0], encrypted.size(), 
      &authInfo, 
      0, 0, 
      &encrypted[0], encrypted.size(), 
      &bytesDone, 0 
      ); 

     assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptEncrypt"); 
     assert(bytesDone == encrypted.size()); 
    } 

    // Decrypt data in two parts 
    std::vector<BYTE> decrypted = encrypted; 
    { 
     DWORD partSize = decrypted.size()/2; 

     std::vector<BYTE> macContext(authTagLengths.dwMaxLength); 

     BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo; 
     BCRYPT_INIT_AUTH_MODE_INFO(authInfo); 
     authInfo.pbNonce = (PUCHAR)&origNonce[0]; 
     authInfo.cbNonce = origNonce.size(); 
     authInfo.pbTag = &authTag[0]; 
     authInfo.cbTag = authTag.size(); 
     authInfo.pbMacContext = &macContext[0]; 
     authInfo.cbMacContext = macContext.size(); 

     // IV value is ignored on first call to BCryptDecrypt. 
     // This buffer will be used to keep internal IV used for chaining. 
     std::vector<BYTE> contextIV(blockLength); 

     // First part 
     authInfo.dwFlags = BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG; 
     bcryptResult = BCryptDecrypt 
      (
      keyHandle, 
      &decrypted[0*partSize], partSize, 
      &authInfo, 
      &contextIV[0], contextIV.size(), 
      &decrypted[0*partSize], partSize, 
      &bytesDone, 0 
      ); 

     assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptDecrypt"); 
     assert(bytesDone == partSize); 

     // Second part 
     authInfo.dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG; 
     bcryptResult = BCryptDecrypt 
      (
      keyHandle, 
      &decrypted[1*partSize], partSize, 
      &authInfo, 
      &contextIV[0], contextIV.size(), 
      &decrypted[1*partSize], partSize, 
      &bytesDone, 0 
      ); 

     assert(BCRYPT_SUCCESS(bcryptResult) || !"BCryptDecrypt"); 
     assert(bytesDone == partSize); 
    } 

    // Check decryption 
    assert(decrypted == origData); 

    // Cleanup 
    BCryptDestroyKey(keyHandle); 
    BCryptCloseAlgorithmProvider(algHandle, 0); 

    return 0; 
} 
+0

Cảm ơn đề xuất, điều đó có ý nghĩa. Nó không có vẻ làm việc mặc dù, tôi đã thêm một số văn bản bổ sung về điều này cho câu hỏi của tôi. –

+0

Tôi đã thay đổi câu trả lời của mình hoàn toàn. – Codeguard

+0

Tuyệt vời, cảm ơn rất nhiều. Một nhận xét: 'trashIV' thực sự giữ IV tiên tiến như vậy là cần thiết cho hoạt động đúng trong chế độ chuỗi. Sai lầm của tôi là tôi đã làm cho IV có cùng kích thước với nonce (ngoài việc sử dụng giá trị 'sai' 'dwFlags'). –

Các vấn đề liên quan