Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 RSACryptoServiceProvider и ф-ии CryptoAPI из advapi32.dll: своё расшифровывают, чужое нет  [new]
Андрей Усачёв
Member

Откуда: Рига, Латвия
Сообщений: 114
Я пытаюсь наладить обмен данными между приложением, написанным на .NET, и приложением, которому доступно только Windows API.
Для удобства изучения проблемы я объединил оба приложения в одно, см. код ниже.

В System.Security.Cryptography.RSACryptoServiceProvider создаю 1024-битную пару RSA, шифрую фразу "Hello, world!" публичным ключом в 128 байт и успешно расшифровываю их секретным ключом.
Передаю оба ключа через BLOB в CryptoAPI, где они нормально читаются (потому что если изменить любой байт ключа, то при чтении возникает ошибка).
С помощью CryptoAPI ту же самую фразу "Hello, world" публичным ключом шифрую в 128 байт и успешно расшифровываю их секретным ключом.

Проблема: зашифрованные 128 байт из System.Security.Cryptography.RSACryptoServiceProvider не может расшифровать CryptoAPI и, наоборот, зашифрованные 128 байт из CryptoAPI не может расшифровать System.Security.Cryptography.RSACryptoServiceProvider. В обоих случаях возникает ошибка "Bad data", в случае CryptoAPI можно посмотреть её номер: 0x80090005 (константа NTE_BAD_DATA).

Пожалуйста, помогите от этой проблемы избавиться.

Imports System.Security.Cryptography
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Text.Encoding

Module Module1

    Const PROV_RSA_FULL = 1
    Const CRYPT_VERIFYCONTEXT = &HF0000000
    Const CRYPT_DECRYPT_RSA_NO_PADDING_CHECK = &H20

    Private Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Int32, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Int32, ByVal dwFlags As Int32) As Int32
    Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Int32, ByVal dwFlags As Int32) As Int32
    Private Declare Function CryptImportKey Lib "advapi32.dll" (ByVal hProv As Int32, ByRef pbData As Byte, ByVal dwDataLen As Int32, ByVal hPubKey As Int32, ByVal dwFlags As Int32, ByRef phPrivateKey As Int32) As Int32
    Private Declare Function CryptDestroyKey Lib "advapi32.dll" (ByVal hPrivateKey As Int32) As Int32
    Private Declare Function CryptEncrypt Lib "advapi32.dll" (ByVal hPrivateKey As Int32, ByVal hHash As Int32, ByVal Final As Int32, ByVal dwFlags As Int32, ByRef pbData As Byte, ByRef pdwDataLen As Int32, ByVal dwBufLen As Int32) As Int32
    Private Declare Function CryptDecrypt Lib "advapi32.dll" (ByVal hPrivateKey As Int32, ByVal hHash As Int32, ByVal Final As Int32, ByVal dwFlags As Int32, ByRef pbData As Byte, ByRef pdwDataLen As Int32) As Int32

    Const KEY_SIZE_BITS = 1024
    Const KEY_SIZE_BYTES = KEY_SIZE_BITS \ 8
    Const TEST_STRING = "Hello, world!"

    Sub Main()
        Dim PrivateRSA As RSACryptoServiceProvider
        Dim PublicRSA As RSACryptoServiceProvider
        Dim PrivateKeyBLOB() As Byte
        Dim PublicKeyBLOB() As Byte
        Dim Plain() As Byte
        Dim EncryptedByNET() As Byte
        Dim EncryptedByNET_DecryptedByNET() As Byte

        Dim hProv As Int32
        Dim hPrivateKey As Int32
        Dim hPublicKey As Int32
        Dim dwDataLenEncrypted As Int32
        Dim dwDataLenDecrypted As Int32
        Dim EncryptedByNET_DecryptedByCryptoAPI() As Byte
        Dim EncryptedByCryptoAPI() As Byte
        Dim EncryptedByCryptoAPI_DecryptedByCryptoAPI() As Byte

        Dim EncryptedByCryptoAPI_DecryptedByNET() As Byte

        '--------------------------------------------------------------------------------

        PrivateRSA = New RSACryptoServiceProvider(KEY_SIZE_BITS)
        PrivateKeyBLOB = PrivateRSA.ExportCspBlob(True)
        PublicKeyBLOB = PrivateRSA.ExportCspBlob(False)
        PublicRSA = New RSACryptoServiceProvider()
        PublicRSA.ImportCspBlob(PublicKeyBLOB)

        Plain = UTF8.GetBytes(TEST_STRING)
        EncryptedByNET = PublicRSA.Encrypt(Plain, False)

        EncryptedByNET_DecryptedByNET = PrivateRSA.Decrypt(EncryptedByNET, False)
        Debug.WriteLine("Encrypted by .NET, decrypted by .Net: " & Text.Encoding.UTF8.GetString(EncryptedByNET_DecryptedByNET))
        ' Encrypted by .NET, decrypted by .Net: Hello, world!

        '--------------------------------------------------------------------------------

        If CryptAcquireContext(hProv, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptImportKey(hProv, PrivateKeyBLOB(0), PrivateKeyBLOB.Length, 0, 0, hPrivateKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptImportKey(hProv, PublicKeyBLOB(0), PublicKeyBLOB.Length, 0, 0, hPublicKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())

        Try
            EncryptedByNET_DecryptedByCryptoAPI = EncryptedByNET
            dwDataLenDecrypted = EncryptedByNET_DecryptedByCryptoAPI.Length
            If CryptDecrypt(hPrivateKey, 0, 1, 0, EncryptedByNET_DecryptedByCryptoAPI(0), dwDataLenDecrypted) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
            Debug.WriteLine("Encrypted by .NET, decrypted by CryptoAPI: " & Text.Encoding.UTF8.GetString(EncryptedByNET_DecryptedByCryptoAPI, 0, dwDataLenDecrypted))
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
            ' Exception thrown: 'System.ComponentModel.Win32Exception' in EncryptDecrypt.exe
            ' Bad Data
        End Try

        EncryptedByCryptoAPI = New Byte(0 To KEY_SIZE_BYTES - 1) {}
        UTF8.GetBytes(TEST_STRING, 0, TEST_STRING.Length, EncryptedByCryptoAPI, 0)
        dwDataLenEncrypted = Len(TEST_STRING)
        If CryptEncrypt(hPublicKey, 0, 1, 0, EncryptedByCryptoAPI(0), dwDataLenEncrypted, EncryptedByCryptoAPI.Length) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())

        EncryptedByCryptoAPI_DecryptedByCryptoAPI = EncryptedByCryptoAPI
        dwDataLenDecrypted = dwDataLenEncrypted
        If CryptDecrypt(hPrivateKey, 0, 1, 0, EncryptedByCryptoAPI_DecryptedByCryptoAPI(0), dwDataLenDecrypted) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        Debug.WriteLine("Encrypted by CryptoAPI, decrypted by CryptoAPI: " & UTF8.GetString(EncryptedByCryptoAPI_DecryptedByCryptoAPI, 0, dwDataLenDecrypted))
        ' Encrypted by CryptoAPI, decrypted by CryptoAPI: Hello, world!

        If CryptDestroyKey(hPrivateKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptDestroyKey(hPublicKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptReleaseContext(hProv, 0) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())

        '--------------------------------------------------------------------------------

        Try
            EncryptedByCryptoAPI_DecryptedByNET = PrivateRSA.Decrypt(EncryptedByCryptoAPI, False)
            Debug.WriteLine("Encrypted by CryptoAPI, decrypted by .Net: " & Text.Encoding.UTF8.GetString(EncryptedByCryptoAPI_DecryptedByNET))
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
            ' Exception thrown: 'System.Security.Cryptography.CryptographicException' in mscorlib.dll
            ' Bad data.
        End Try
    End Sub

End Module
5 окт 17, 13:16    [20845189]     Ответить | Цитировать Сообщить модератору
 Re: RSACryptoServiceProvider и ф-ии CryptoAPI из advapi32.dll: своё расшифровывают, чужое нет  [new]
buser
Member

Откуда: Санкт-Петербург
Сообщений: 3997
Андрей Усачёв, http://rsdn.org/forum/dotnet/4111151?tree=tree
5 окт 17, 14:53    [20845566]     Ответить | Цитировать Сообщить модератору
 Re: RSACryptoServiceProvider и ф-ии CryptoAPI из advapi32.dll: своё расшифровывают, чужое нет  [new]
Андрей Усачёв
Member

Откуда: Рига, Латвия
Сообщений: 114
Спасибо вам огромное.
В обоих случаях помогло выполнение перед расшифровкой:

Array.Reverse(<зашифрованный массив из другого источника>)
5 окт 17, 16:00    [20845810]     Ответить | Цитировать Сообщить модератору
 Re: RSACryptoServiceProvider и ф-ии CryptoAPI из advapi32.dll: своё расшифровывают, чужое нет  [new]
Андрей Усачёв
Member

Откуда: Рига, Латвия
Сообщений: 114
Добавил 2 строки, переворачивающие массив, и в 1 строке поменял копирование ссылки на массив на копирование данных массива:

+ Работающий вариант
Imports System.Security.Cryptography
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Text.Encoding

Module Module1

    Const PROV_RSA_FULL = 1
    Const CRYPT_VERIFYCONTEXT = &HF0000000
    Const CRYPT_DECRYPT_RSA_NO_PADDING_CHECK = &H20

    Private Declare Function CryptAcquireContext Lib "advapi32.dll" Alias "CryptAcquireContextA" (ByRef phProv As Int32, ByVal pszContainer As String, ByVal pszProvider As String, ByVal dwProvType As Int32, ByVal dwFlags As Int32) As Int32
    Private Declare Function CryptReleaseContext Lib "advapi32.dll" (ByVal hProv As Int32, ByVal dwFlags As Int32) As Int32
    Private Declare Function CryptImportKey Lib "advapi32.dll" (ByVal hProv As Int32, ByRef pbData As Byte, ByVal dwDataLen As Int32, ByVal hPubKey As Int32, ByVal dwFlags As Int32, ByRef phPrivateKey As Int32) As Int32
    Private Declare Function CryptDestroyKey Lib "advapi32.dll" (ByVal hPrivateKey As Int32) As Int32
    Private Declare Function CryptEncrypt Lib "advapi32.dll" (ByVal hPrivateKey As Int32, ByVal hHash As Int32, ByVal Final As Int32, ByVal dwFlags As Int32, ByRef pbData As Byte, ByRef pdwDataLen As Int32, ByVal dwBufLen As Int32) As Int32
    Private Declare Function CryptDecrypt Lib "advapi32.dll" (ByVal hPrivateKey As Int32, ByVal hHash As Int32, ByVal Final As Int32, ByVal dwFlags As Int32, ByRef pbData As Byte, ByRef pdwDataLen As Int32) As Int32

    Const KEY_SIZE_BITS = 1024
    Const KEY_SIZE_BYTES = KEY_SIZE_BITS \ 8
    Const TEST_STRING = "Hello, world!"

    Sub Main()
        Dim PrivateRSA As RSACryptoServiceProvider
        Dim PublicRSA As RSACryptoServiceProvider
        Dim PrivateKeyBLOB() As Byte
        Dim PublicKeyBLOB() As Byte
        Dim Plain() As Byte
        Dim EncryptedByNET() As Byte
        Dim EncryptedByNET_DecryptedByNET() As Byte

        Dim hProv As Int32
        Dim hPrivateKey As Int32
        Dim hPublicKey As Int32
        Dim dwDataLenEncrypted As Int32
        Dim dwDataLenDecrypted As Int32
        Dim EncryptedByNET_DecryptedByCryptoAPI() As Byte
        Dim EncryptedByCryptoAPI() As Byte
        Dim EncryptedByCryptoAPI_DecryptedByCryptoAPI() As Byte

        Dim EncryptedByCryptoAPI_DecryptedByNET() As Byte

        '--------------------------------------------------------------------------------

        PrivateRSA = New RSACryptoServiceProvider(KEY_SIZE_BITS)
        PrivateKeyBLOB = PrivateRSA.ExportCspBlob(True)
        PublicKeyBLOB = PrivateRSA.ExportCspBlob(False)
        PublicRSA = New RSACryptoServiceProvider()
        PublicRSA.ImportCspBlob(PublicKeyBLOB)

        Plain = UTF8.GetBytes(TEST_STRING)
        EncryptedByNET = PublicRSA.Encrypt(Plain, False)

        EncryptedByNET_DecryptedByNET = PrivateRSA.Decrypt(EncryptedByNET, False)
        Debug.WriteLine("Encrypted by .NET, decrypted by .Net: " & Text.Encoding.UTF8.GetString(EncryptedByNET_DecryptedByNET))
        ' Encrypted by .NET, decrypted by .Net: Hello, world!

        '--------------------------------------------------------------------------------

        If CryptAcquireContext(hProv, vbNullString, vbNullString, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptImportKey(hProv, PrivateKeyBLOB(0), PrivateKeyBLOB.Length, 0, 0, hPrivateKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptImportKey(hProv, PublicKeyBLOB(0), PublicKeyBLOB.Length, 0, 0, hPublicKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())

        EncryptedByNET_DecryptedByCryptoAPI = EncryptedByNET
        dwDataLenDecrypted = EncryptedByNET_DecryptedByCryptoAPI.Length
        Array.Reverse(EncryptedByNET_DecryptedByCryptoAPI) ' <-- Added
        If CryptDecrypt(hPrivateKey, 0, 1, 0, EncryptedByNET_DecryptedByCryptoAPI(0), dwDataLenDecrypted) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        Debug.WriteLine("Encrypted by .NET, decrypted by CryptoAPI: " & Text.Encoding.UTF8.GetString(EncryptedByNET_DecryptedByCryptoAPI, 0, dwDataLenDecrypted))
        ' Encrypted by .NET, decrypted by CryptoAPI: Hello, world!

        EncryptedByCryptoAPI = New Byte(0 To KEY_SIZE_BYTES - 1) {}
        UTF8.GetBytes(TEST_STRING, 0, TEST_STRING.Length, EncryptedByCryptoAPI, 0)
        dwDataLenEncrypted = Len(TEST_STRING)
        If CryptEncrypt(hPublicKey, 0, 1, 0, EncryptedByCryptoAPI(0), dwDataLenEncrypted, EncryptedByCryptoAPI.Length) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())

        EncryptedByCryptoAPI_DecryptedByCryptoAPI = EncryptedByCryptoAPI.Clone ' <-- Changed (reference assignment to data cloning)
        dwDataLenDecrypted = dwDataLenEncrypted
        If CryptDecrypt(hPrivateKey, 0, 1, 0, EncryptedByCryptoAPI_DecryptedByCryptoAPI(0), dwDataLenDecrypted) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        Debug.WriteLine("Encrypted by CryptoAPI, decrypted by CryptoAPI: " & UTF8.GetString(EncryptedByCryptoAPI_DecryptedByCryptoAPI, 0, dwDataLenDecrypted))
        ' Encrypted by CryptoAPI, decrypted by CryptoAPI: Hello, world!

        If CryptDestroyKey(hPrivateKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptDestroyKey(hPublicKey) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())
        If CryptReleaseContext(hProv, 0) = 0 Then Throw New Win32Exception(Marshal.GetLastWin32Error())

        '--------------------------------------------------------------------------------

        Array.Reverse(EncryptedByCryptoAPI) ' <-- Added
        EncryptedByCryptoAPI_DecryptedByNET = PrivateRSA.Decrypt(EncryptedByCryptoAPI, False)
        Debug.WriteLine("Encrypted by CryptoAPI, decrypted by .Net: " & Text.Encoding.UTF8.GetString(EncryptedByCryptoAPI_DecryptedByNET))
        ' Encrypted by CryptoAPI, decrypted by .Net: Hello, world!
    End Sub

End Module


Теперь вывод такой:

Encrypted by .NET, decrypted by .Net: Hello, world!
Encrypted by .NET, decrypted by CryptoAPI: Hello, world!
Encrypted by CryptoAPI, decrypted by CryptoAPI: Hello, world!
Encrypted by CryptoAPI, decrypted by .Net: Hello, world!
5 окт 17, 16:14    [20845850]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить