C# server side (encode) -> C++ client side (decode) ?

J

jtfaulk

I need to encode some information on the server side using ASP.NET with
C#; sending via HTTP to a client side application, that needs to be
decoded in an MFC C++ application.

I'm not sure if I can encode something using:

C#: System.Security.Cryptography (to encode)

and

C++: wincrypt.h (to decode)

Does anybody have any idea about this? Thank you in advance; it is
greatly appreciated.

J
 
N

Nicholas Paldino [.NET/C# MVP]

J,

Sure you can. The classes in the System.Security.Cryptography namespace
use well established algorithms to encrypt/decrypt information. You just
have to use the same algorithms in your C++ code (which are supported, by
the way), along with the same key and iv values for encryption/decryption.

Hope this helps.
 
J

jtfaulk

Ok, So my code is listed below. I'm not sure where to put the iv value
for the C++ portion:

I'm trying to encrypt a piece of information (a string of text from an
..INI file) on the server side (C# .net) and pass that information to
the client side app which has to decrypt it. I'm trying to use (in c#)
the System.Security.Cryptography and in c++ the wincrypt.h file. I'm
not sure if this is possible (although I believe it is); so I was
wondering if anybody had any ideas?

The C# Server Code:

// -----------------------------------------------------------
// ENCRYPT (C# SERVER SIDE)
// -----------------------------------------------------------
using System.Security.Cryptography;
private string Encrypt_Try2(string strKey, string strText)
{
PasswordDeriveBytes cdk = new PasswordDeriveBytes(strKey, null);

// generate an RC2 key
byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] key = cdk.CryptDeriveKey("RC2", "MD5", 128, iv);
Console.WriteLine(key.Length * 8);

// setup an RC2 object to encrypt with the derived key
RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider();
rc2.Key = key;
rc2.IV = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28};

// now encrypt with it
byte[] plaintext = Encoding.UTF8.GetBytes(strText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, rc2.CreateEncryptor(),
CryptoStreamMode.Write);

cs.Write(plaintext, 0, plaintext.Length);
cs.Close();
byte[] encrypted = ms.ToArray();

// Convert to Base64
string txtOut = Convert.ToBase64String(encrypted);

// THIS IS THE ENCRYPTED TEXT
return txtOut;
}

// -----------------------------------------------------------
// DECRYPT (FOR VERIFICATION - (C# SERVER SIDE))
// -----------------------------------------------------------
private string Decrypt_Try2(string strKey, string strText)
{
PasswordDeriveBytes cdk = new PasswordDeriveBytes(strKey, null);

// generate an RC2 key
byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
byte[] key = cdk.CryptDeriveKey("RC2", "MD5", 128, iv);
Console.WriteLine(key.Length * 8);

// setup an RC2 object to encrypt with the derived key
RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider();
rc2.Key = key;
rc2.IV = new byte[] { 21, 22, 23, 24, 25, 26, 27, 28};

// now encrypt with it
//byte[] plaintext = Encoding.UTF8.GetBytes(strText);
byte[] plaintext = Convert.FromBase64String(strText);
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, rc2.CreateDecryptor(),
CryptoStreamMode.Write);

cs.Write(plaintext, 0, plaintext.Length);
cs.Close();
byte[] encrypted = ms.ToArray();

System.Text.Encoding encoding = System.Text.Encoding.UTF8;

// THIS IS THE DECRYPTED TEXT
return encoding.GetString(encrypted);

//this.txtOut.Text = txtOut;
}


// -----------------------------------------------------------
// DECRYPT (C++ CLIENT SIDE)
// -----------------------------------------------------------

CString CJCrypt::Decrypt(char *key, char *txtOut)
{
char *szPassword = key;

CBase64Utils bu;
int iTxtOutLen = strlen(txtOut);
char *result = bu.Decode(txtOut, &iTxtOutLen);

DWORD dwBufLen = 1+strlen(result);
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHashKey;
DWORD sts=0;
DWORD errc = 0;

sts = CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV,
PROV_RSA_FULL, 0);
if(sts == 0) errc=GetLastError();

sts = CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHashKey);
if(sts == 0) errc=GetLastError();

sts = CryptHashData(hHashKey, (BYTE *)szPassword,
strlen(szPassword), 0);
if(sts == 0) errc=GetLastError();

//sts = CryptDeriveKey(hCryptProv, CALG_DES, hHashKey, (56)<<16,
&hKey);

sts = CryptDeriveKey(hCryptProv, CALG_RC2, hHashKey, 128, &hKey);
//sts = CryptDeriveKey(hCryptProv, CALG_3DES, hHashKey, (168)<<16,
&hKey);
//sts = CryptDeriveKey(hCryptProv, CALG_RC4, hHashKey, (56)<<16,
&hKey);
if(sts == 0) errc=GetLastError();

DWORD dwCryptBuffLen = dwBufLen;
sts = CryptEncrypt(hKey,0,TRUE,0,NULL,&dwCryptBuffLen,0);
BYTE *bCryptoBuffer = new BYTE[dwCryptBuffLen];
memset(bCryptoBuffer,0,dwCryptBuffLen);
memcpy(bCryptoBuffer,result,dwBufLen + 3);

sts = CryptDecrypt(hKey, 0, TRUE,0,(BYTE *)result,
&dwCryptBuffLen);

if(sts == 0) errc=GetLastError();
// else do something with the dwBufLen bytes of encrypted data in
bCryptoBuffer

sts = CryptDestroyKey(hKey);
sts = CryptDestroyHash(hHashKey);
sts = CryptReleaseContext(hCryptProv, 0);

CString strOut;
strOut.Format("%s", result);

return strOut;

}

// -----------------------------------------------------------
// ENCRYPT (FOR VERFICATION - (C++ CLIENT SIDE))
// -----------------------------------------------------------
CString CJCrypt::Encrypt(char *key, char *txtIn)
{
char *szPassword = key;

DWORD dwBufLen = 1+strlen(txtIn);
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHashKey;
DWORD sts=0;
DWORD errc = 0;

sts = CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV,
PROV_RSA_FULL, 0);
if(sts == 0) errc=GetLastError();

sts = CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHashKey);
if(sts == 0) errc=GetLastError();

sts = CryptHashData(hHashKey, (BYTE *)szPassword,
strlen(szPassword), 0);
if(sts == 0) errc=GetLastError();

//sts = CryptDeriveKey(hCryptProv, CALG_DES, hHashKey, (56)<<16,
&hKey);
sts = CryptDeriveKey(hCryptProv, CALG_RC2, hHashKey, 128, &hKey);
//sts = CryptDeriveKey(hCryptProv, CALG_3DES, hHashKey, (168)<<16,
&hKey);
//sts = CryptDeriveKey(hCryptProv, CALG_RC4, hHashKey, (56)<<16,
&hKey);
if(sts == 0) errc=GetLastError();

DWORD dwCryptBuffLen = dwBufLen;
sts = CryptEncrypt(hKey,0,TRUE,0,NULL,&dwCryptBuffLen,0);
BYTE *bCryptoBuffer = new BYTE[dwCryptBuffLen];
memset(bCryptoBuffer,0,dwCryptBuffLen);
memcpy(bCryptoBuffer,txtIn,dwBufLen);

sts = CryptEncrypt(hKey, 0, TRUE, 0, bCryptoBuffer, &dwBufLen,
dwCryptBuffLen);

// Convert To Base64
CBase64Utils bu;
char *result = bu.Encode((char *)bCryptoBuffer, dwBufLen + 1);

if(sts == 0) errc=GetLastError();
// else do something with the dwBufLen bytes of encrypted data in
bCryptoBuffer

sts = CryptDestroyKey(hKey);
sts = CryptDestroyHash(hHashKey);
sts = CryptReleaseContext(hCryptProv, 0);

CString strOut;
strOut.Format("%s", result);
return strOut;
}

Both the c# and c++ encrypt/decrypt work with them selves (i.e. I can
encrypt and decrypt things using only the c++ OR the C#, but I cannot
encrypt with C# and decrypt with C++). I'm not sure this is possible
and I just don't have the parameters set up correctly; or if they use
completely separate algorythms and will not work.

Does anybody have any idea?

Thank you very much
J,

Sure you can. The classes in the System.Security.Cryptography namespace
use well established algorithms to encrypt/decrypt information. You just
have to use the same algorithms in your C++ code (which are supported, by
the way), along with the same key and iv values for encryption/decryption.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I need to encode some information on the server side using ASP.NET with
C#; sending via HTTP to a client side application, that needs to be
decoded in an MFC C++ application.

I'm not sure if I can encode something using:

C#: System.Security.Cryptography (to encode)

and

C++: wincrypt.h (to decode)

Does anybody have any idea about this? Thank you in advance; it is
greatly appreciated.

J
 
J

Jon Skeet [C# MVP]

Ok, So my code is listed below. I'm not sure where to put the iv value
for the C++ portion:

I'm trying to encrypt a piece of information (a string of text from an
.INI file) on the server side (C# .net) and pass that information to
the client side app which has to decrypt it. I'm trying to use (in c#)
the System.Security.Cryptography and in c++ the wincrypt.h file. I'm
not sure if this is possible (although I believe it is); so I was
wondering if anybody had any ideas?

Having had a brief look at the C++ API, I believe you want to call
CryptSetKeyParam, passing in KP_IV as the second parameter.
 
J

jtfaulk

Yeah, the problem is that I'm unable to generate the same key on both
c# and c++. This is the problem - does anybody have any ideas how to
solve this?
 
J

Jon Skeet [C# MVP]

Yeah, the problem is that I'm unable to generate the same key on both
c# and c++. This is the problem - does anybody have any ideas how to
solve this?

Hang on - you're unable to generate the same *key*, or the same IV? You
shouldn't be generating the key at all - that should be known
information.
 
J

jtfaulk

Ok, let say I assign the key (ie. hard code). That's fine; but I'm not
even sure how to do this. I simply cannot pass the same key to the c#
anc c++ encryption functions; therefore the output is not the same.

Do you have any ideas as to how to accomplish this? Let's say I want
to start (in c#) with the key:

byte[] testKey = {32, 44, 185, 98, 172, 89, 7, 91, 150, 75, 7, 21, 45,
35, 75, 112};

I have tried this and it works fine (it encrypts the original text).
But my problem is that now I cannot pass this same key to the
encryption process in c++.

How can I turn the above key into HCRYPTKEY and get the same results?

Thank you,
 
J

Jon Skeet [C# MVP]

Ok, let say I assign the key (ie. hard code). That's fine; but I'm not
even sure how to do this. I simply cannot pass the same key to the c#
anc c++ encryption functions; therefore the output is not the same.

Do you have any ideas as to how to accomplish this? Let's say I want
to start (in c#) with the key:

byte[] testKey = {32, 44, 185, 98, 172, 89, 7, 91, 150, 75, 7, 21, 45,
35, 75, 112};

I have tried this and it works fine (it encrypts the original text).
But my problem is that now I cannot pass this same key to the
encryption process in c++.

How can I turn the above key into HCRYPTKEY and get the same results?

I'm afraid I don't know - I think you'd be best off asking that in a
Win32-specific group (or a Windows Security/Cryptography group).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top