views:

591

answers:

4

Hi,

I have following native code (Powerbuilder) with uses the Crypto API to encrypt a string. I need C# code to decrypt the encrypted data. Can somebody give me a hint or sample?

Thanks, Jaap

private function blob of_encryptdecrypt (blob ablob_data, string as_password, boolean ab_encrypt)
// -----------------------------------------------------------------------------
// SCRIPT:     n_cryptoapi.of_EncryptDecrypt
//
// PURPOSE:    This function will encrypt/decrypt the blob passed to it. Both
//      encrypt/decrypt have the same api calls except one so they
//      are combined to save coding.
//
// ARGUMENTS:  ablob_data   - The blob to be decrypted
//      as_password - The secret password
//
// RETURN:   Blob containing the decrypted data.
//
// DATE        PROG/ID   DESCRIPTION OF CHANGE / REASON
// ----------  --------  -----------------------------------------------------
// 12/26/2006   RolandS  Initial Coding
// -----------------------------------------------------------------------------

ULong hCryptProv, hHash, hKey
ULong lul_datalen, lul_buflen, lul_error
Blob lblob_buffer, lblob_value
String ls_msgtext
string ls_password

// Get handle to CSP
If Not CryptAcquireContext(hCryptProv, KEY_CONTAINER, is_cryptoservice, PROV_RSA_FULL, 0) Then
    If Not CryptAcquireContext(hCryptProv, KEY_CONTAINER, is_cryptoservice, PROV_RSA_FULL, CRYPT_NEWKEYSET) Then
     of_GetLastError(lul_error, ls_msgtext)
     SignalError(lul_error, "CryptAcquireContext:~r~n~r~n" + ls_msgtext)
    End If
End If

// Create a hash object
If Not CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, hHash) Then
    of_GetLastError(lul_error, ls_msgtext)
    SignalError(lul_error, "CryptCreateHash:~r~n~r~n" + ls_msgtext)
End If

// Hash the password
If Not CryptHashData(hHash,as_password, Len(as_password), 0) Then
    of_GetLastError(lul_error, ls_msgtext)
    SignalError(lul_error, "CryptHashData:~r~n~r~n" + ls_msgtext)
End If

// Derive a session key from the hash object
If Not CryptDeriveKey(hCryptProv, ENCRYPT_ALGORITHM, hHash, 0, hKey) Then
    of_GetLastError(lul_error, ls_msgtext)
    SignalError(lul_error, "CryptDeriveKey:~r~n~r~n" + ls_msgtext)
End If

// allocate buffer space
lul_datalen = Len(ablob_data)
lblob_buffer = ablob_data + Blob(Space(8))
lul_buflen = Len(lblob_buffer)

If ab_encrypt Then
    // Encrypt data
    If CryptEncrypt(hKey, 0, True, 0, lblob_buffer, lul_datalen, lul_buflen) Then
     lblob_value = BlobMid(lblob_buffer, 1, lul_datalen)
    Else
     of_GetLastError(lul_error, ls_msgtext)
     SignalError(lul_error, "CryptEncrypt:~r~n~r~n" + ls_msgtext)
    End If
Else
    // Decrypt data
    If CryptDecrypt(hKey, 0, True, 0, lblob_buffer, lul_datalen) Then
     lblob_value = BlobMid(lblob_buffer, 1, lul_datalen)
    Else
     of_GetLastError(lul_error, ls_msgtext)
     SignalError(lul_error, "CryptDecrypt:~r~n~r~n" + ls_msgtext)
    End If
End If

// Destroy session key
If hKey > 0 Then
    CryptDestroyKey(hKey)
End If

// Destroy hash object
If hHash > 0 Then
    CryptDestroyHash(hHash)
End If

// Release CSP handle
If hCryptProv > 0 Then
    CryptReleaseContext(hCryptProv, 0)
End If

Return lblob_value
end function
+2  A: 

Without going over the code you provided - you can start at Walkthrough: Creating a Cryptographic Application - this will show you basic stuff on System.Security.Cryptography namespace.

Dror
A: 

You may check this site for PInvoke reference to the CryptoAPI functions: http://www.pinvoke.net

For example: [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptHashData(IntPtr hHash, byte[] pbData, uint dataLen, uint flags);

Sergiu
Why would you suggest PInvoke code when .Net has built in crypto libraries?
Nathan Ridley
Yes, .NET has its own crypto library. But that was an example of how to call the same win32 functions from .NET (if thats what he wanted in the first place)
Sergiu
+3  A: 

You can do the same in C# using classes from System.Security.Cryptography.

You're effectively doing an MD5 hash of the password and then using the algorithm defined in a global constant ENCRYPT_ALGORITHM. You'd have to post the value of that variable to get a better answer. However, if you're using anything common, then there is likely to be a *CryptoServiceProvider wrapper for you. For example, AesCryptoServiceProvider.

By the way, using a straight (e.g. non-salted) MD5 hash of the password can be bad. See this article for more information.

Jeff Moser
ENCRYPT_ALGORITHM has in fact the value CALG_RC4. Problem is that there is no RC4CrypteServiceProvicer in .NET. Changed it to RC2 now and have it working now with help of the link to the sample Tjipke mentioned.
JaapM
I'd strongly advise against using RC2. It has some known weaknesses. If at all possible, I'd advise using the AES cipher on both sides. They're both supported by CAPI/CSP and have much better support.
Jeff Moser
+1  A: 

Maybe you can get some hints on how to translate this from native cryptoapi to .Net using the VB example at:

How to encrypt a string in Visual Basic 6.0 and how to decrypt the string in Visual Basic .NET or in Visual Basic 2005

Tjipke
This is just the sample I was searching for. Thanks.
JaapM