none
RSA Crypt C# и Win32 Crypto API RRS feed

  • Вопрос

  • Здравствуйте.

    Возникла необходимость криптовать данные используя алгоритм 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_ENHANCED_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 ,
    0, 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]); }
    • Перемещено I.Vorontsov 24 августа 2010 г. 5:29 (От:Разработка Windows-приложений)
    • Изменено Vitaly Prozorovsky 20 сентября 2010 г. 14:46
    18 августа 2010 г. 13:42

Ответы

  • Нашел причину того, что код не работал.

    Неправильно вычислялся указатель на 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

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

    • Помечено в качестве ответа Abolmasov Dmitry 20 декабря 2010 г. 17:52
    20 сентября 2010 г. 14:35

Все ответы

  • У вас в C++ флаг CRYPT_OAEP. Возможно в C# метод Decrypt стоит вызывать с вторым параметром true? Проверить некогда, но это первое что пришло в голову.
    17 сентября 2010 г. 0:10
  • У вас в C++ флаг CRYPT_OAEP. Возможно в C# метод Decrypt стоит вызывать с вторым параметром true? Проверить некогда, но это первое что пришло в голову.

    Спасибо, да, действитльно, если флаг CRYPT_OAEP , нужно вызывать в с# коде:

    rsa.Decrypt( encryptedData, true
    )
    20 сентября 2010 г. 14:17
  • Нашел причину того, что код не работал.

    Неправильно вычислялся указатель на 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

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

    • Помечено в качестве ответа Abolmasov Dmitry 20 декабря 2010 г. 17:52
    20 сентября 2010 г. 14:35