2015-06-08 14 views
10

Windows CNG API'sini kullanarak, GCM modunda AES kullanarak kimlik doğrulama ile tek tek veri bloklarını şifreleyebilir ve şifresini çözebilirim. Şimdi üst üste birden fazla arabellek şifrelemek ve şifresini çözmek istiyorum.GCM modunda AES kullanarak BCryptEncrypt ve BCryptDecrypt çağrıları nasıl zincirlenir?

documentation for CNG göre, aşağıdaki senaryo desteklenir:

şifreleme veya şifre çözme için giriş çoklu tamponları dağılmış ise, o zaman gerekir BCryptEncrypt ve BCryptDecrypt işlevlerine zincir aramaları. Zincirleme, dwFlags üyesindeki BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG bayrağını ayarlayarak belirtilir. Eğer doğru anlamak

bu birden çok tamponlar BCryptEncrypt ardışık çağırmak bir ucunda araya tamponlar için kimlik doğrulama etiketinin elde anlamına gelir. Benzer şekilde, gerçek kimlik denetimi kontrolünün sonuna kadar ertelenirken, BCryptDecrypt'u birden fazla arabelleğe sıralı olarak çağırabilirim. Bunu işe yaramayabilirim, dwFlags'un değeri göz ardı ediliyor gibi görünüyor. Ne zaman ben BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG kullanıyorum, ntstatus.h içinde tanımlandığı gibi STATUS_AUTH_TAG_MISMATCH eşit olan bir 0xc000a002 dönüş değeri olsun.

pbIV parametresi giriş/çıkış olarak işaretlense bile, pbIV parametresi tarafından işaret edilen öğeler BCryptEncrypt() tarafından değiştirilmez. Bu beklenen mi? Ayrıca, pPaddingInfo işaretçisiyle işaret edilen BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO yapısında pbNonce alanına baktım, ancak bu da değiştirilemedi. Ayrıca, IV'ü ilerleterek "el ile" denedim, içerikleri kendimi karşı şemasına göre değiştirdim, fakat bu da işe yaramadı.

BCryptEncrypt ve/veya BCryptDecrypt işlevlerini başarıyla işlemek için doğru yöntem nedir?

cevap

6

Çalışmayı başardım. Sorun, MSDN'de olduğu gibi, BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG yerine BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG ayarından bahsetmelidir.

#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

Öneri için teşekkürler, bu mantıklı. Yine de işe yaramıyor gibi görünmüyor, bu konuyla ilgili ek bir metin ekledim. –

+0

Cevabımı tamamen değiştirdim. – Codeguard

+0

Fantastik, çok teşekkürler. Bir not: 'trashIV' aslında gelişmiş IV'ü tutuyor, dolayısıyla zincirleme modunda düzgün çalışma için gereklidir. Benim hatam, IV'ü nonce ile aynı boyuta getirdim ('yanlış' 'dwFlags' değerinin kullanılmasına ek olarak). –

İlgili konular