Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CryptDecrypt with error 0x80090005

1,161 views
Skip to first unread message

Marcio Campos

unread,
May 22, 2008, 9:57:13 AM5/22/08
to
I wrongly posted this question in another group.

I have a simple C# program to encrypt and decrypt a small file using a
smartcard. I can encrypt the file but when I try to decrypit, the
CryptDecrypt call returns with error code 80090005. The troubled part of the
program is below

Can anybody help me ?

private void btnGerarChaveTDES_Click(object sender, EventArgs e)

{

IntPtr hProv = new IntPtr();

string pszContainer = null;

string pszProvider = "SafeSign Standard Cryptographic Service
Provider";

uint dwProvType = 1; // "1 - PROV_RSA_FULL";

uint dwFlags = 32; // "8 - CRYPT_NEWKEYSET";

int erro = 0;

CryptAcquireContext(ref hProv, pszContainer, pszProvider,
dwProvType, dwFlags);

erro = Marshal.GetLastWin32Error();

// Gera a chave TDES

// =============================================================

//IntPtr pnKey = new IntPtr();

IntPtr pnKey = new IntPtr();

uint Aldid = ((3 << 13) | (3 << 9) | (3));

uint dwFlags2 = 1; //1 - CRYPT EXPORTABLE

CryptGenKey(hProv, Aldid, dwFlags2, ref pnKey);

erro = Marshal.GetLastWin32Error();

// Importa a chava para o cartão

// =============================================================

IntPtr hExpKey = new IntPtr();

IntPtr nPubKey = new IntPtr();

uint dwFlags3 = 0;

CryptImportKey(hProv, pbData, pbData.Length, nPubKey, dwFlags3,
ref hExpKey);

erro = Marshal.GetLastWin32Error();

// Exporta a chave

// =============================================================

Int32 dwBlobType = 1; //"1 - SIMPLEBLOB";

Int32 dwFlags4 = 0;

Byte[] pbData2 = null;

Int32 pdwDataLen = 0;

CryptExportKey(pnKey, hExpKey, dwBlobType, dwFlags4, null, ref
pdwDataLen);

erro = Marshal.GetLastWin32Error();

pbData2 = new byte[pdwDataLen];

CryptExportKey(pnKey, hExpKey, dwBlobType, dwFlags4, pbData2,
ref pdwDataLen);

erro = Marshal.GetLastWin32Error();

GravarArquivo(pbData2, "c:\\BlobTDes.blb");

// Ler arquivo texto e encriptar

// =============================================================

IntPtr hHash = new IntPtr(0);

int Final = 1; // ultimo bloco ou não

uint dwFlags5 = 0;

//byte[] bufferArquivo = new byte[11027 + 130];

byte[] bufferArquivo = new byte[128];

byte[] arquivo = LerArquivo("c:\\texto.txt");

int arquivoLen = arquivo.Length;

arquivo.CopyTo(bufferArquivo, 0);

int dwBufLen = bufferArquivo.Length;

CryptEncrypt(pnKey, hHash, Final, dwFlags5, bufferArquivo, ref
arquivoLen, dwBufLen);

erro = Marshal.GetLastWin32Error();

//byte[] aux = new byte[arquivoLen];

//for (int i = 0; i < aux.Length; i++)

// aux[i] = bufferArquivo[i];

////GravarArquivo(bufferArquivo, "c:\\texto_cripto.txt");

//GravarArquivo(aux, "c:\\texto_cripto.txt");

//// Zera o vetor de incializaçao

//// =============================================================

//uint dwParam = 1; // 1 - KP_IV

//byte[] pbData3 = new byte[8];

//uint dwFlags6 = 0;

//for (int i = 0; i < 8; i++)

// pbData3[i] = 0;

//bool bln1 = CryptSetKeyParam(pnKey, dwParam, pbData3, dwFlags6);

//erro = Marshal.GetLastWin32Error();

bool bln2 = CryptDecrypt(pnKey, hHash, Final, dwFlags5, ref
bufferArquivo, ref arquivoLen);

erro = Marshal.GetLastWin32Error();

}


Mounir IDRASSI

unread,
May 22, 2008, 10:18:01 AM5/22/08
to
Hi,

Please try to simplify your code and narrow the use case if you want someone
to help you. In the posted code, the problem can come from different causes.
For examples, instead of using an external file (texto.txt), use a hard-coded
buffer to simplify the problem analyze. Also, check the boolean return value
of the Crypt function (not only the GetLastError) to be sure which function
fails. You must also verify the output buffer used in CryptEncrypt is larger
enough to hold the result (don't forget that there will be paddings).

Cheers,
--
Mounir IDRASSI
IDRIX
http://www.idrix.fr

to reach : mounir_idrix_fr (replace the underscores with the at and dot
characters respectively)

Marcio Campos

unread,
May 22, 2008, 11:46:01 AM5/22/08
to
Thanks for you answer.

I can simplify the program according to your suggestion but we did a lot of
debbuging and:

1) "For examples, instead of using an external file (texto.txt), use a

hard-coded
> buffer to simplify the problem analyze. "

The buffer is correct. We tryed alsoo with a hard coded buffer and the
result is same (fails).

2) "Crypt function (not only the GetLastError) to be sure which function
> fails. "

The CryptEncrypt functions always fail. We verified with the debbuger.

3) "You must also verify the output buffer used in CryptEncrypt is larger

> enough to hold the result (don't forget that there will be paddings)."

The buffer is larger enough to hold the result.

To clarify a little more. All the other crypt functions works fine. The same
sequence of functions call are done in C++ and works OK.

I wonder if the Key Handler is in some kind of state that makes the function
CrypDecrypt Fails. See in the code that the Key Handler for Encrypt is the
same of the Decrypt.

Thanks for your help!

Cheers!!!

"Mounir IDRASSI" wrote:

> Hi,
>
> Please try to simplify your code and narrow the use case if you want someone
> to help you. In the posted code, the problem can come from different causes.
>

Also, check the boolean return value

Mounir IDRASSI

unread,
May 22, 2008, 1:39:01 PM5/22/08
to
Hi,

From what I see, there is no obvious reason for the CryptDecrypt to fail.
The only explanation I have is that there is a limitation on the SafeSign CSP
you are using. The same sequence of calls (in C++) executed with MS CSP and
with a smart card CSP of another vendor (not SafeSign) goes well with no
errors.
I advise you to contact the SafeSign CSP vendor to see if they can help you.

Marcio Campos

unread,
May 27, 2008, 11:33:01 AM5/27/08
to
Mounir

I´m still strugling with the same error despite using CSP from Safesign or
Microsoft. I wonder if it is possible to use CryptApi from a C# since the
same code in C++ works whithout any problem.

Another possibility is that we are not defining the Cryptapi (dllimport)
whit the correct type. Below is the code of the dllimport. Do you see any
problem ?


[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

[return: MarshalAs(UnmanagedType.Bool)]

static extern bool CryptAcquireContext( ref IntPtr hProv, string
pszContainer,

string pszProvider, uint
dwProvType, uint dwFlags);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

static extern Boolean CryptGetUserKey( IntPtr hProv,

uint dwKeySpec,

ref IntPtr hKey);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

static extern Boolean CryptGetKeyParam( IntPtr hKey,

uint dwParam,

byte[] pbData,

ref uint pdwDataLen,

uint dwFlags);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

static extern Boolean CryptSetKeyParam(IntPtr hKey,

uint dwParam,

byte[] pbData,

uint dwFlags);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

static extern bool CryptExportKey( IntPtr hKey,

IntPtr hExpKey,

Int32 dwBlobType,

Int32 dwFlags,

Byte[] pbData,

ref Int32 pdwDataLen);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptGenKey(IntPtr hProv, uint Algid, uint
dwFlags, ref IntPtr phKey);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptImportKey(IntPtr hProv, byte[]
pbKeyData, int dwDataLen, IntPtr hPubKey, uint dwFlags, ref IntPtr hKey);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptEncrypt(IntPtr hKey, IntPtr hHash,
int Final, uint dwFlags, byte[] pbData, ref int pdwDataLen, int dwBufLen);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptDecrypt(IntPtr hKey, IntPtr hHash,
int Final, uint dwFlags, ref byte[] pbData, ref int pdwDataLen);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptDuplicateKey(IntPtr hKey, ref IntPtr
pdwReserved, uint dwFlags, ref IntPtr phKey);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptDestroyKey(IntPtr phKey);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]

public static extern bool CryptReleaseContext(IntPtr hProv, uint
dwFlags);

Thanks

Marcio

Mounir IDRASSI

unread,
May 27, 2008, 12:10:00 PM5/27/08
to
Hi Marcio,

I think the problem comes from the declaration of the type of parameter
Final in CryptEncrypt and CryptDecrypt. You should declare it as "bool" not
"int". Try with this and tell me if it corrects your problem.

Marcio Campos

unread,
May 28, 2008, 4:42:00 PM5/28/08
to
Mounir

It still doesn´t work!

I get this message error:

"An unhandled exception of type 'System.ArgumentException' occurred in
WindowsApplication1.exe

Additional information: Method's type signature is not Interop compatible."

Mounir IDRASSI

unread,
May 29, 2008, 7:13:01 AM5/29/08
to
Hi Marcio,

I managed to write and test a .net wrapper for CryptoAPI that works very
well with the set of functions you are using. You can download it from the
following link :

http://www.idrix.fr/Root/Samples/Capi.cs

I didn't use anything special so I guess you have a well hidden error in
your code.
Let me know if you still have a problem using my wrapper.

Cheers,

--
Mounir IDRASSI
IDRIX
http://www.idrix.fr

to reach : mounir_idrix_fr (replace the underscores with the at and dot
characters respectively)


"Marcio Campos" wrote:

> Mounir
>

Marcio Campos

unread,
May 29, 2008, 10:28:02 AM5/29/08
to
Mounir
I changed the code and worked. The problem was that the definition of
encrypt and decrypt was wrog. Besides the change suggested by you (boolen) I
had to change the definition of the buffer for IntPtr and do all the
necessary buffer allocation in the code. Below it is the code in case anybody
needs it in the future. I got also ypur code.

Thank you very much

Cheers

MArcio

--------------- the code -----------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;

using System.Collections;
using System.IO;


namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private Byte[] pbData = null;

bool Final, uint dwFlags, IntPtr pbData, ref uint pdwDataLen, uint dwBufLen);

[DllImport("ADVAPI32.DLL", CharSet = CharSet.Auto, SetLastError =
true)]
public static extern bool CryptDecrypt(IntPtr hKey, IntPtr hHash,

bool Final, uint dwFlags, IntPtr pbData, ref uint pdwDataLen);


private void btnObterCertificadoDigital_Click(object sender,

EventArgs e)
{
IntPtr hProv = new IntPtr();
string pszContainer = null;

string pszProvider = "SafeSign Basic Cryptographic Service

Provider";
uint dwProvType = 1; // "1 - PROV_RSA_FULL";
uint dwFlags = 32; // "8 - CRYPT_NEWKEYSET";


int erro = 0;

CryptAcquireContext(ref hProv, pszContainer, pszProvider,
dwProvType, dwFlags);

erro = Marshal.GetLastWin32Error();

// Obtem a chave do cartao
// =============================================================
uint dwKeySpec = 2; // "1 - AT_KEYEXCHANGE"; "2 - AT_SIGNATURE";
IntPtr hKey = new IntPtr();

CryptGetUserKey(hProv, dwKeySpec, ref hKey);

erro = Marshal.GetLastWin32Error();

// Obtem os parametros da chave
// =============================================================
uint dwParam = 26; // "26 - KP_CERTIFICATE"
byte[] pbData = null;
uint pdwDataLen = 0;
uint dwFlags2 = 0;

CryptGetKeyParam(hKey, dwParam, pbData, ref pdwDataLen, dwFlags2);

pbData = new byte[pdwDataLen];

CryptGetKeyParam(hKey, dwParam, pbData, ref pdwDataLen, dwFlags2);

erro = Marshal.GetLastWin32Error();

GravarArquivo(pbData, "c:\\certificado.cer");

}


private static void GravarArquivo(byte[] imagem, string nomeArquivo)
{
BinaryWriter lobjbinWriter;

try
{
lobjbinWriter = new BinaryWriter(File.Open(nomeArquivo,
FileMode.Create));
lobjbinWriter.Write(imagem);
lobjbinWriter.BaseStream.Close();
lobjbinWriter.Close();
}
catch (Exception ex)
{
throw new Exception("Não foi possível gravar o arquivo: " +
ex.Message);
}
}

private void btnObterChavePublica_Click(object sender, EventArgs e)


{
IntPtr hProv = new IntPtr();
string pszContainer = null;
string pszProvider = "SafeSign Standard Cryptographic Service
Provider";
uint dwProvType = 1; // "1 - PROV_RSA_FULL";
uint dwFlags = 32; // "8 - CRYPT_NEWKEYSET";


int erro = 0;

CryptAcquireContext(ref hProv, pszContainer, pszProvider,
dwProvType, dwFlags);

erro = Marshal.GetLastWin32Error();

// Obtem a chave do cartao
// =============================================================
uint dwKeySpec = 2; // "1 - AT_KEYEXCHANGE"; "2 - AT_SIGNATURE";
IntPtr hKey = new IntPtr();

CryptGetUserKey(hProv, dwKeySpec, ref hKey);

erro = Marshal.GetLastWin32Error();

// Obtem a chave pública
// =============================================================

IntPtr hExpKey = new IntPtr();

Int32 dwBlobType = 6; //"6 - PUBLICKEYBLOB";
Int32 dwFlags3 = 0;
//Byte[] pbData = null;
Int32 pdwDataLen = 0;

CryptExportKey(hKey, hExpKey, dwBlobType, dwFlags3, pbData, ref
pdwDataLen);

erro = Marshal.GetLastWin32Error();

pbData = new byte[pdwDataLen];

CryptExportKey(hKey, hExpKey, dwBlobType, dwFlags3, pbData, ref
pdwDataLen);

erro = Marshal.GetLastWin32Error();

GravarArquivo(pbData, "c:\\chave_publica.blb");

}

private void btnGerarChaveTDES_Click(object sender, EventArgs e)
{
IntPtr hProv = new IntPtr();
string pszContainer = null;

string pszProvider = null;


uint dwProvType = 1; // "1 - PROV_RSA_FULL";

uint dwFlags = 0; // "8 - CRYPT_NEWKEYSET";

int erro = 0;

CryptAcquireContext(ref hProv, pszContainer, pszProvider,
dwProvType, dwFlags);

erro = Marshal.GetLastWin32Error();

// Gera a chave TDES
// =============================================================
//IntPtr pnKey = new IntPtr();
IntPtr pnKey = new IntPtr();
uint Aldid = ((3 << 13) | (3 << 9) | (3));
uint dwFlags2 = 1; //1 - CRYPT EXPORTABLE

CryptGenKey(hProv, Aldid, dwFlags2, ref pnKey);

erro = Marshal.GetLastWin32Error();

// Importa a chava para o cartão
// =============================================================
IntPtr hExpKey = new IntPtr();
IntPtr nPubKey = new IntPtr();
uint dwFlags3 = 0;

// CryptImportKey(hProv, pbData, pbData.Length, nPubKey,
dwFlags3, ref hExpKey);

// erro = Marshal.GetLastWin32Error();

// Exporta a chave
// =============================================================
Int32 dwBlobType = 1; //"1 - SIMPLEBLOB";
Int32 dwFlags4 = 0;
Byte[] pbData2 = null;
Int32 pdwDataLen = 0;

// CryptExportKey(pnKey, hExpKey, dwBlobType, dwFlags4, null,
ref pdwDataLen);

// erro = Marshal.GetLastWin32Error();

// pbData2 = new byte[pdwDataLen];

// CryptExportKey(pnKey, hExpKey, dwBlobType, dwFlags4, pbData2,
ref pdwDataLen);

// erro = Marshal.GetLastWin32Error();

// GravarArquivo(pbData2, "c:\\BlobTDes.blb");


// Ler arquivo texto e encriptar
// =============================================================
IntPtr hHash = new IntPtr(0);

bool Final = true; // ultimo bloco ou não
uint dwFlags5 = 0;


//byte[] bufferArquivo = new byte[11027 + 130];
byte[] bufferArquivo = new byte[128];
byte[] arquivo = LerArquivo("c:\\texto.txt");
int arquivoLen = arquivo.Length;

// arquivo.CopyTo(bufferArquivo, 0);

uint dwBufLen = (uint) arquivo.Length;
IntPtr pbBuffer = IntPtr.Zero;

pbBuffer = Marshal.AllocHGlobal(arquivo.Length + 256 );
Marshal.Copy(arquivo, 0, pbBuffer, arquivo.Length);
uint length = (uint)arquivo.Length + 256;
CryptEncrypt(pnKey, hHash, Final, dwFlags5, pbBuffer, ref
dwBufLen, length);

erro = Marshal.GetLastWin32Error();

//byte[] aux = new byte[arquivoLen];

////GravarArquivo(bufferArquivo, "c:\\texto_cripto.txt");
//GravarArquivo(aux, "c:\\texto_cripto.txt");


//// Zera o vetor de incializaçao
//// =============================================================
//uint dwParam = 1; // 1 - KP_IV
//byte[] pbData3 = new byte[8];
//uint dwFlags6 = 0;

//for (int i = 0; i < 8; i++)
// pbData3[i] = 0;

//bool bln1 = CryptSetKeyParam(pnKey, dwParam, pbData3, dwFlags6);

byte[] arquivo2 = new byte[256];
length=dwBufLen;
CryptDecrypt(pnKey, IntPtr.Zero, Final, 0, pbBuffer, ref length);

erro = Marshal.GetLastWin32Error();
Marshal.Copy(pbBuffer, arquivo2, 0,(int) length);

System.IO.File.WriteAllText("c:\\texto_descripto.txt",
System.Text.Encoding.ASCII.GetString(arquivo2));


}


public void Gravar(string mensagem, string _arquivo)
{
StreamWriter swrite;

try
{
swrite = new StreamWriter(_arquivo, true);
swrite.WriteLine(mensagem);
swrite.Close();
}
catch (Exception ex)
{
throw ex;
}
}


public static byte[] LerArquivo(string nomeArquivo)
{
BinaryReader lobjbinReader;
byte[] b;

try
{
lobjbinReader = new BinaryReader(File.Open(nomeArquivo,
FileMode.Open));
b =
lobjbinReader.ReadBytes(int.Parse(lobjbinReader.BaseStream.Length.ToString()));
lobjbinReader.BaseStream.Close();
lobjbinReader.Close();

return b;
}
catch (Exception ex)
{
throw new Exception("Não foi possível ler arquivo: " +
ex.Message);
}
}

private void button1_Click(object sender, EventArgs e)
{

IntPtr hProv = new IntPtr();
string pszContainer = null;
string pszProvider = "SafeSign Standard Cryptographic Service
Provider";
uint dwProvType = 1; // "1 - PROV_RSA_FULL";
uint dwFlags = 32; // "8 - CRYPT_NEWKEYSET";

bool bln;

int erro = 0;

bln = CryptAcquireContext(ref hProv, pszContainer, pszProvider,
dwProvType, dwFlags);

erro = Marshal.GetLastWin32Error();

// Obtem a chave do cartao
// =============================================================
uint dwKeySpec = 1; // "1 - AT_KEYEXCHANGE"; "2 - AT_SIGNATURE";
IntPtr hKey = new IntPtr();

CryptGetUserKey(hProv, dwKeySpec, ref hKey);

erro = Marshal.GetLastWin32Error();

// Importa a chava para o cartão
// =============================================================

IntPtr hImpKey = new IntPtr(0);
uint dwFlags3 = 0;
Byte[] pbData2 = null;

IntPtr hHash = new IntPtr(0);
bool Final = true; // ultimo bloco ou não
uint dwFlags5 = 0;

pbData2 = LerArquivo("c:\\BlobTDes.blb");

bln = CryptImportKey(hProv, pbData2, pbData2.Length, hKey,
dwFlags3, ref hImpKey);

erro = Marshal.GetLastWin32Error();


// Zera o vetor de incializaçao

// =============================================================


uint dwParam = 1; // 1 - KP_IV

byte[] pbData = new byte[8];
uint dwFlags6 = 0;

for (int i = 0; i < 8; i++)

pbData[i] = 0;


CryptSetKeyParam(hImpKey, dwParam, pbData, dwFlags6);

//erro = Marshal.GetLastWin32Error();


// Le o arquivo encriptado
// =============================================================

byte[] bufferArquivo = new byte[11027 + 400];
byte[] arquivo = LerArquivo("c:\\texto_cripto.txt");
int arquivoLen = arquivo.Length;

arquivo.CopyTo(bufferArquivo, 0);

int dwBufLen = bufferArquivo.Length;
Final = true;


// Grava o arquivo dencriptado
// =============================================================

// bln = CryptDecrypt(hImpKey, hHash, Final, dwFlags5, pb, ref
arquivoLen);

erro = Marshal.GetLastWin32Error();

GravarArquivo(bufferArquivo, "c:\\texto_decripto.txt");

0 new messages