Re: .NET Crypto Classes Interoperability with Win32 Crypto APIs

From: Ivan Medvedev [MS] (ivanmed_at_online.microsoft.com)
Date: 07/07/03


Date: Mon, 7 Jul 2003 14:19:08 -0700


Rajesh -
the problem is that the key you are using in the managed code is different
from what you are using in the C++ implementation. When you are calling
UnicodeEncoding.GetBytes all it does is giving you the bytes representing
the characters you are feeding into it. In the C++ code you are using
CryptDeriveKey which derives the key by doing complex processing based on
the hash of the string you are feeding in. To fix this problem in managed
code you can use class PasswordDeriveBytes and its method called
CryptDeriveKey to get the functionality matching that of the unmanaged code.
Hope this helps.
--Ivan
This posting is provided "AS IS" with no warranties, and confers no rights.

"Rajesh Sampath" <rajeshs@ctd.hcltech.com> wrote in message
news:22a001c33f02$0fc9e540$a601280a@phx.gbl...
> Hi,
>
> I don't know if this is the right forum to post this
> query, but any help will be greatly appreciated.
>
> I use the RC2CryptoServiceProvider class to perform a
> symmetric encryption with a hard-coded key value. I expect
> a string to be encrypted by a .NET application in this
> manner and the same shall be decrypted by a C++ (Win32)
> application using the same algorithm, but using Win32
> APIs.
>
> The following scenarios work fine.
>
> 1. Encryption and Decryption with .NET
> RC2CryptoServiceProvider class (or any other managed
> crypto class, for that matter) works fine.
>
> 2. Encryption and Decryption with Win32 APIs with CALG_RC2
> algorithm works fine too.
>
> But, when i encrypt a string using .NET classes and try to
> decrypt it using Win32 APIs, i get some problems. The same
> holds good for Win32 Encryption & .NET decryption too.
>
> I've pasted the source i had used for your reference.
>
> C# code
>
> /**********************************************/
> using System;
> using System.IO;
> using System.Security.Cryptography;
> using System.Text;
> using System.Resources;
> using System.Collections;
>
> namespace MySampleCryptoApp
> {
> /// <summary>
> /// Summary description for Class1.
> /// </summary>
> class Class1
> {
> [STAThread]
> static void Main(string[] args)
> {
> Encrypt();
> Decrypt();
> }
>
> private static void Encrypt()
> {
> RC2CryptoServiceProvider RCCrypto
> = new RC2CryptoServiceProvider();
> RCCrypto.Mode = CipherMode.CBC;
> RCCrypto.KeySize = 40;
> RCCrypto.EffectiveKeySize = 40;
> RCCrypto.BlockSize = 64;
>
> UnicodeEncoding UE = new
> UnicodeEncoding();
> byte[] Key = UE.GetBytes
> ("abcdefgh");
>
> byte[] IV = {0x00, 0x00,0x00,
> 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
> 0x00,0x00, 0x00};
>
>
> FileStream oFStream = new
> FileStream
> (@"E:\Users\SRajesh\Tekies\RnD\DotNet\SampleCryptoApp\Outpu
> t.txt", FileMode.OpenOrCreate, FileAccess.Write);
>
> //Create a CryptoStream, pass it
> the NetworkStream, and encrypt
> //it with the RC2Crypto class.
> CryptoStream CryptStream = new
> CryptoStream(oFStream,
> RCCrypto.CreateEncryptor
> (Key, IV),
> CryptoStreamMode.Write);
>
>
> //Create a StreamWriter for easy
> writing to the
> //file stream.
> StreamWriter SWriter = new
> StreamWriter(CryptStream);
>
> long lLength = oFStream.Length;
> //Write to the stream.
> SWriter.WriteLine("How is it???");
>
> //Inform the user that the message
> was written
> //to the stream.
> Console.WriteLine("The message was
> sent.");
>
> //Close all of the connections.
> SWriter.Close();
> CryptStream.Close();
> oFStream.Close();
>
> }
>
> private static void Decrypt()
> {
> UnicodeEncoding UE = new
> UnicodeEncoding();
> byte[] Key = UE.GetBytes
> ("abcdefgh");
>
> byte[] IV = {0x00, 0x00,0x00,
> 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
> 0x00,0x00, 0x00};
>
> FileStream oFStream = new
> FileStream
> (@"E:\Users\SRajesh\Tekies\RnD\DotNet\SampleCryptoApp\Outpu
> t.txt", FileMode.Open, FileAccess.Read);
>
> //Create a new instance of the
> RC2Crypto class
> // and decrypt the stream.
>
> RC2CryptoServiceProvider RCCrypto
> = new RC2CryptoServiceProvider();
> RCCrypto.Mode = CipherMode.CBC;
> RCCrypto.KeySize = 40;
> RCCrypto.EffectiveKeySize = 40;
> RCCrypto.BlockSize = 64;
>
> //Create a CryptoStream, pass it
> the NetworkStream, and decrypt
> //it with the Rijndael class using
> key and IV.
> CryptoStream CryptStream = new
> CryptoStream(oFStream,
> RCCrypto.CreateDecryptor
> (Key, IV),
> CryptoStreamMode.Read);
>
> //Read the stream.
> StreamReader SReader = new
> StreamReader(CryptStream);
>
> //Display the message.
> Console.WriteLine("The decrypted
> original message: {0}", SReader.ReadToEnd());
>
> //Close the streams.
> CryptStream.Close();
> SReader.Close();
> oFStream.Close();
>
>
> }
> }
> }
> /**********************************************/
>
> Here is the C++ Win32 code
>
> /**********************************************/
>
> // SampleCryptoNativeApp.cpp : Defines the entry point for
> the console application.
> //
>
>
> #include "stdafx.h"
> #include "windows.h"
> #include <wincrypt.h>
> #include <TCHAR.h>
>
> int main(int argc, char* argv[])
> {
>
> BOOL bResult;
> HCRYPTPROV hProv;
> HCRYPTHASH hHash;
> HCRYPTKEY hKey;
>
> char pEncryptedString[100];
> memset(pEncryptedString, 0,100);
>
> FILE *fp = fopen
> ("E:\\Users\\SRajesh\\Tekies\\RnD\\DotNet\\SampleCryptoApp\
> \Output.txt", "rb");
> fscanf(fp, "%s", &pEncryptedString);
> fclose(fp);
>
>
> int nLen = strlen(pEncryptedString);
>
> BYTE *pByte = NULL;
> pByte = new BYTE[100];
> memset(pByte, 0, 100);
> memcpy(pByte, pEncryptedString, nLen);
>
> DWORD dwError;
>
> bResult = CryptAcquireContext( &hProv,
> NULL, //generates default (username) keystore,
> MS_ENHANCED_PROV,
> PROV_RSA_FULL,
> CRYPT_NEWKEYSET);
> if(!bResult)
> dwError = GetLastError();
>
>
> bResult = CryptAcquireContext(&hProv, NULL,
> MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
> //bResult = CryptAcquireContext(&hProv, NULL,
> MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
> if(!bResult)
> dwError = GetLastError();
>
> bResult = CryptCreateHash(hProv, CALG_MD5, 0, 0,
> &hHash);
> if(!bResult)
> dwError = GetLastError();
>
> BYTE pByteBaseData[] =
> {97,0,98,0,99,0,100,0,101,0,102,0,103,0,104,0};
> int nKeyLen = 16;
>
>
> bResult = CryptHashData(hHash, pByteBaseData,
> (DWORD) nKeyLen, 0);
> if(!bResult)
> dwError = GetLastError();
>
> //bResult = CryptDeriveKey(hProv, CALG_RC2, hHash,
> CRYPT_CREATE_SALT, &hKey);
> bResult = CryptDeriveKey(hProv, CALG_RC2, hHash,
> CRYPT_NO_SALT, &hKey);
> if(!bResult)
> dwError = GetLastError();
>
> BYTE pByteIV[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
> bResult = CryptSetKeyParam(hKey,KP_IV, pByteIV, 0);
> if(!bResult)
> dwError = GetLastError();
>
> char pToEncryptString[] = "How is it???";
> //TCHAR pToEncryptString[] = L"How is it???";
> BYTE *pToEncryptBuffer = new BYTE[100];
> memset(pToEncryptBuffer, 0, 100);
> memcpy(pToEncryptBuffer, pToEncryptString, strlen
> (pToEncryptString));
>
> DWORD dwInputLen = strlen(pToEncryptString);
> bResult = CryptEncrypt(hKey, NULL, TRUE, 0,
> pToEncryptBuffer, &dwInputLen, 16);
> if(!bResult)
> dwError = GetLastError();
>
> fp = fopen
> ("E:\\Users\\SRajesh\\Tekies\\RnD\\DotNet\\SampleCryptoNati
> veApp\\Win32Output.txt", "w");
> for(int nIndex = 0; nIndex < (int) dwInputLen;
> nIndex++)
> {
> fprintf(fp, "%c", pToEncryptBuffer
> [nIndex]);
> }
> fclose(fp);
>
> DWORD dwOutputLen = nLen;
>
> bResult = CryptDecrypt(hKey, NULL, TRUE, 0, pByte,
> &dwOutputLen);
> if(!bResult)
> dwError = GetLastError();
>
> bResult = CryptDecrypt(hKey, NULL, TRUE, 0,
> pToEncryptBuffer, &dwOutputLen);
> if(!bResult)
> dwError = GetLastError();
>
> return 0;
> }
>
> /**********************************************/
>
> When i try to decrypt the string encrypted using .NET, i
> get an error (2148073487).
>
> Any help in sorting this out would be appreciated. The
> last option i have is to use PInvoke to call the Win32
> APIs themselves in .NET.
>
> Thanx & Rgds
> Rajesh Sampath,
> Project Lead,
> HCL Technologies,
> Chennai
>
>
> ***********************************************************
> ************
> Disclaimer:
> This document is intended for transmission to the named
> recipient only. If you are not that person, you should
> note that legal rights reside in this document and you are
> not authorized to access, read, disclose, copy, use or
> otherwise deal with it and any such actions are prohibited
> and may be unlawful. The views expressed in this document
> are not necessarily those of HCL Technologies Ltd. Notice
> is hereby given that no representation, contract or other
> binding obligation shall be created by this e-mail, which
> must be interpreted accordingly. Any representations,
> contractual rights or obligations shall be separately
> communicated in writing and signed in the original by a
> duly authorized officer of the relevant company.
> ***********************************************************
> ************
> .
>
>



Relevant Pages

  • RE: NTE_BAD_DATA
    ... They are NOT used DIRECTLY to encrypt / decrypt data; ... you should generate a RANDOM SESSION KEY and select a SYMMETRIC ENCRYPTION ... // imported from a BLOB read in from the source file or having ...
    (microsoft.public.platformsdk.security)
  • Re: Back Doors
    ... >> Design into the system a master key. ... Encrypt that with public key. ... Decrypt random symmetric key with private key. ...
    (sci.crypt)
  • Re: CAPI and RC4: can not decrypt when Final parameter is set to F
    ... to store ASYMMETRIC key pairs - never symmetric keys like RC4, ... Now when you need to encrypt at one place and decrypt at the other normally ... Get a HCRYPTPROV handle to a key container with CryptAcquireContext ...
    (microsoft.public.platformsdk.security)
  • Re: RSA - Public vs. Private Keys
    ... This is a common pattern for license software ... your client will send a unique machine hash to the ... will let us decrypt with a Public Key (or simply not ... |> RSA is intended to encrypt messages with public keys only. ...
    (microsoft.public.dotnet.security)

Loading