Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > RSA Crypt C# и Win32 Crypto API


Автор: Sokil 18.8.2010, 13:22
Здравствуйте.

Возникла необходимость криптовать данные используя алгоритм RSA на сервере(с#) и на клиенте(с++).
Отдельно в с# и отдельно в с++ криптование работает отлично.

Генерю пару ключей в С# и импортирую открытый ключ в с++, криптую, закриптованые данные передаю обратно в с#.
И пробую декриптовать, выдает ошибку: "Encryption failed.Bad Data.

Подскажите, пожалуйста, в чем может быть проблема?

Код с#(код минимальный, без обработки ошибок):
Код

                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512/*key size*/);
                RSAParameters rsaParams = rsa.ExportParameters(false);

                Console.WriteLine("RSA Exponent: {0}", toHexStr(rsaParams.Exponent));
                Console.WriteLine("RSA PublicKey: {0}", toHexStr(rsaParams.Modulus));

                byte[] encryptedData;
                string sEncHex = Console.ReadLine();
                encryptedData = toBytes(sEncHex);

                byte[] decryptedData = rsa.Decrypt( encryptedData, false);


Код с++(код минимальный, без обработки ошибок):
Код

    HCRYPTPROV    hCryptProv = NULL;
    CryptAcquireContext(&hCryptProv, 
                               A2W("1ContainerName"), 
                               MS_DEF_PROV, 
                               PROV_RSA_FULL, 
                   CRYPT_NEWKEYSET);

    //RSA Public Key беру сгенеренный из c#
        char* cPublKeyStr = "DF726C2D8D4D1447C9C6395F4DD96743015DB83D6D5A704D9436D2EDFCDE8105EB8F77E72CC06AAD42769289EE8A5E97A71B2FCD404088C3B17667A96B7C52F7";
    BYTE* pModulus = new BYTE[64];     // Byte array that contains the modulus.
    memset(pModulus, 0, 64);
    DWORD cbModulus = (DWORD)strlen(cPublKeyStr); // Size of the modulus in bytes.
    DWORD dwExponent = 0x10001;   // RSA Exponent

    hexToBA( cPublKeyStr, pModulus, &cbModulus );

    DWORD cbKeyBlob = cbModulus + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY);
    BYTE *pBlob = new BYTE[cbKeyBlob];

    PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pBlob;
    pPublicKey->bType = PUBLICKEYBLOB; 
    pPublicKey->bVersion = CUR_BLOB_VERSION;  // Always use this value.
    pPublicKey->reserved = 0;                 // Must be zero.
    pPublicKey->aiKeyAlg = CALG_RSA_KEYX;     // RSA public-key key exchange. 

    RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pBlob + sizeof(PUBLICKEYSTRUC));
    pRsaPubKey->magic = RSA1;            // RSA1 0x31415352 Public key.
    pRsaPubKey->bitlen = cbModulus * 8;  // Number of bits in the modulus.
    pRsaPubKey->pubexp = dwExponent;     // Exponent.

    // Copy the modulus into the blob. Put the modulus directly after the
    // RSAPUBKEY structure in the blob.
    BYTE *pKey = (BYTE*)(pRsaPubKey + sizeof(RSAPUBKEY));
    CopyMemory(pKey, pModulus, cbModulus);

    // Now import the key.
    HCRYPTKEY hCryptKey = NULL;  // Receives a handle to the key.
    CryptImportKey(hCryptProv, pBlob, cbKeyBlob, 0, 0, &hCryptKey);

    char* testStr = "test";
    BYTE byteArrayText[ 256 ]; memset(byteArrayText, 0, 256);
    for ( UINT nI = 0; nI < strlen(testStr); ++nI )
        byteArrayText[ nI ] = testStr[ nI ];

    DWORD dwTextLength = (DWORD)strlen(testStr);
    DWORD dwBufferLength = 256;

    CryptEncrypt(        hCryptKey, 
                            0, 
                            true, 
                            CRYPT_OAEP,
                            byteArrayText,
                            &dwTextLength,
                            dwBufferLength );


    wprintf(L"\n\nCryptedText = \"");
    for (UINT i = 0; i < dwTextLength; i++ )
    {
        wprintf(L"%02x",byteArrayText[i]);
    }
    wprintf(L"\n\nCryptedTextReversed = \"");
    for (int i = dwTextLength-1; i >= 0; i-- )
    {
        wprintf(L"%02x",byteArrayText[i]);
    }


НАШЕЛ ПРИЧИНУ:

Неправильно вычислялся указатель на Public Key  в структуре PUBLICKEYBLOB :

Код

 BYTE *pKey = (BYTE*)(pRsaPubKey + sizeof(RSAPUBKEY));


pRsaPubKey здесь указатель на RSAPUBKEY , потому если его увеличить на  12(размер в байтах RSAPUBKEY), то указатель увеличится не на 12 байт, как нужно, в нашем случае, а на 12*sizeof(RSAPUBKEY ) и потому адрес начала ключа будет неправильным.

Правильный код:


Код

 BYTE* pKey = pBlob + sizeof(BLOBHEADER)+ sizeof(RSAPUBKEY); 

Код импорта ключа брал из MSDN, там он с ошибкой: http://msdn.microsoft.com/en-us/library/dd376685%28VS.85%29.aspx

Так что, будьте бдительны, не попадайтесь, как я. )

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)