2015-10-04 6 views
1

Я написал программу, которая шифрует/расшифровывает буфер памяти пользовательской длины. Эквитация заканчивается хорошо; но мой код дешифрования дешифрует данные только один раз в любой позиции буфера, которая соответствует записям блока. Расшифровка других блоков заканчивается NTE_BAD_DATA.CryptoAPI RSA: CryptDecrypt расшифровывает только один раз, после этого NTE_BAD_DATA

Есть ли у вас какие-либо соображения, почему это происходит?

Вот мой код шифрования:

void CWinRSA::FinishEncrypt(const char* pcbRawData, const size_t nDataSize, char** ppcbEcrData, size_t& rnEcrSize) const 
{ 
    if (m_hProvider == NULL) 
    { 
     throw ("Cannot encrypt data with wrong provider!!"); 
    } 

    if (m_hKey == NULL) 
    { 
     throw ("Cannot encrypt data with a wrong key!!"); 
    } 

    size_t nBlockLength = GetBlockLength(); 
    size_t nPaddingSize = nBlockLength - 11; 

    size_t nRemain = nDataSize % nBlockLength; 
    size_t nBlockProcess = (nDataSize/nPaddingSize + (nRemain != 0 ? 1 : 0)); 

    size_t nResultSize = nBlockProcess * nBlockLength; 

    (*ppcbEcrData) = new char[nResultSize]; 

    DWORD dwBufferLength = nBlockLength; 
    DWORD dwDataLength; 

    for (int iBlock = 0; iBlock < nBlockProcess - 1; iBlock++) 
    { 
     memcpy((*ppcbEcrData) + (iBlock * nBlockLength), 
      pcbRawData + (iBlock * nPaddingSize), nPaddingSize); 

     dwDataLength = nPaddingSize; 

     if (!CryptEncrypt(m_hKey, NULL, FALSE, 0, 
      (BYTE*)((*ppcbEcrData) + (iBlock * nBlockLength)), 
      &dwDataLength, dwBufferLength)) 
     { 
      throw ("Cannot encrypt data!!"); 
     } 
    } 

    memcpy((*ppcbEcrData) + ((nBlockProcess - 1) * nBlockLength), 
     pcbRawData + ((nBlockProcess - 1) * nPaddingSize), (nRemain ? nRemain : nPaddingSize)); 

    dwDataLength = (nRemain ? nRemain : nPaddingSize); 

    if (!CryptEncrypt(m_hKey, NULL, TRUE, 0, 
     (BYTE*)((*ppcbEcrData) + ((nBlockProcess - 1) * nBlockLength)), 
     &dwDataLength, dwBufferLength)) 
    { 
     throw ("Cannot encrypt data!!"); 
    } 

    rnEcrSize = nResultSize; 
} 

расшифровка:

void CWinRSA::FinishDecrypt(const char* pcbRawData, const size_t nDataSize, char** ppcbDecData, size_t& rnDecSize) const 
{ 
    if (m_hProvider == NULL) 
    { 
     throw ("Cannot decrypt data with wrong provider!!"); 
    } 

    if (m_hKey == NULL) 
    { 
     throw ("Cannot decrypt data with a wrong key!!"); 
    } 

    size_t nBlockLength = GetBlockLength(); 

    if ((nDataSize % nBlockLength) != 0) 
    { 
     throw ("Cannot decrypt data!! Probably data is corrupted!!"); 
    } 

    size_t nPaddingSize = nBlockLength - 11; 
    size_t nBlockProcess = nDataSize/nBlockLength; 

    size_t nResultSize = nBlockProcess * nPaddingSize; 

    (*ppcbDecData) = new char[nResultSize]; 

    DWORD dwDataLength; 

    char* pcbComputeResult = new char[nBlockLength]; 

    for (int iBlock = 0; iBlock < nBlockProcess - 1; iBlock++) 
    { 
     memcpy(pcbComputeResult, pcbRawData + (iBlock * nBlockLength), nBlockLength); 

     if (!CryptDecrypt(m_hKey, NULL, FALSE, 0, (BYTE*)pcbComputeResult, &dwDataLength)) 
     { 
      throw ("Cannot decrypt data!!"); 
     } 

     memcpy((*ppcbDecData) + (iBlock * nPaddingSize), pcbComputeResult, nPaddingSize); 
    } 

    memcpy(pcbComputeResult, pcbRawData + ((nBlockProcess - 1) * nBlockLength), nBlockLength); 

    if (!CryptDecrypt(m_hKey, NULL, TRUE, 0, (BYTE*)pcbComputeResult, &dwDataLength)) 
    { 
     DWORD dwError = GetLastError(); 

     throw ("Cannot decrypt data!!"); 
    } 

    memcpy((*ppcbDecData) + ((nBlockProcess - 1) * nPaddingSize), pcbComputeResult, nPaddingSize); 

    rnDecSize = ((nBlockProcess - 1) * nPaddingSize) + dwDataLength; 

    delete[] pcbComputeResult; 
    pcbComputeResult = NULL; 
} 

ответ

0

Я нашел ответ. Я должен инициализировать dwDataLength с длиной блока в байтах перед всеми вызовами дешифрования.

dwDataLength = nBlockLength; 

if (!CryptDecrypt(m_hKey, NULL, TRUE, 0, (BYTE*)pcbComputeResult, &dwDataLength)) 
{ 
    DWORD dwError = GetLastError(); 

    throw ("Cannot decrypt data!!"); 
} 

Весь метод дешифрования

void CWinRSA::FinishDecrypt(const char* pcbRawData, const size_t nDataSize, char** ppcbDecData, size_t& rnDecSize) const 
{ 
    if (m_hProvider == NULL) 
    { 
     throw ("Cannot decrypt data with wrong provider!!"); 
    } 

    if (m_hKey == NULL) 
    { 
     throw ("Cannot decrypt data with a wrong key!!"); 
    } 

    size_t nBlockLength = GetBlockLength(); 

    if ((nDataSize % nBlockLength) != 0) 
    { 
     throw ("Cannot decrypt data!! Probably data is corrupted!!"); 
    } 

    size_t nPaddingSize = nBlockLength - 11; 
    size_t nBlockProcess = nDataSize/nBlockLength; 

    size_t nResultSize = nBlockProcess * nPaddingSize; 

    (*ppcbDecData) = new char[nResultSize]; 

    DWORD dwDataLength; 

    char* pcbComputeResult = new char[nBlockLength]; 

    for (int iBlock = 0; iBlock < nBlockProcess - 1; iBlock++) 
    { 
     memcpy(pcbComputeResult, pcbRawData + (iBlock * nBlockLength), nBlockLength); 

     dwDataLength = nBlockLength; 

     if (!CryptDecrypt(m_hKey, NULL, FALSE, 0, (BYTE*)pcbComputeResult, &dwDataLength)) 
     { 
      throw ("Cannot decrypt data!!"); 
     } 

     memcpy((*ppcbDecData) + (iBlock * nPaddingSize), pcbComputeResult, nPaddingSize); 
    } 

    memcpy(pcbComputeResult, pcbRawData + ((nBlockProcess - 1) * nBlockLength), nBlockLength); 

    dwDataLength = nBlockLength; 

    if (!CryptDecrypt(m_hKey, NULL, TRUE, 0, (BYTE*)pcbComputeResult, &dwDataLength)) 
    { 
     throw ("Cannot decrypt data!!"); 
    } 

    memcpy((*ppcbDecData) + ((nBlockProcess - 1) * nPaddingSize), pcbComputeResult, nPaddingSize); 

    rnDecSize = ((nBlockProcess - 1) * nPaddingSize) + dwDataLength; 

    delete[] pcbComputeResult; 
    pcbComputeResult = NULL; 
} 
1

RSA не предназначен для использования таким образом. Это действительно не блочный шифр (или потоковый шифр, если на то пошло). Его понимание того, что у него действительно нет криптологического использования, за исключением одного «короткого» сообщения, поэтому меня не удивляет, что библиотека не работает после одного расшифровки ключа.

Если вам необходимо защитить произвольный размер данных, используйте RSA для обмена симметричным ключом для потока или блочного шифрования (например, AES).

+2

В строке принципе _can_ быть использован в качестве блочного шифра, но это ни предполагаемое использование, ни последствия для безопасности выполнения так были изучены. –