Re: Trouble verifying RSA signature generated with c#



Mitch,
Reversing the signature bits fixed my problem. I sincerely appreciate your
help.

-Jeff

"Mitch Gallant" wrote:

That comment "compatible" refers to the format for the key itself
(not the signature blobs).
i.e. dotnet uses a slightly different format of publickeyblob than cryptoapi.
See the comments in the paragraph "Microsoft CryptoAPI Public Key Formats" here:
http://www.jensign.com/JavaScience/dotnet/JKeyNet

..NET 2 ExportCSPBblob(false), for example exports the capi-friendly PUBLICKEYBLOB
format (148 bytes for a 1025 bit RSA key) as opposed to the PUBLICKEY that is
also found in .NET of 160 bytes!

The signature blob generated oRSA.Sign is in standard big-endian order.
But CryptoAPI expects a reversed byte order (for CryptVerifySignature).
That is a different type of issue. You'll definitely have to reverse the SIGNATURE
bytes .. key bytes are ok.

- Mitch Gallant

"Jeff Mastry" <jmastry@xxxxxxxxxxxxxxx> wrote in message news:8B8C65BA-9002-464D-BC6C-3FFC101E0E6A@xxxxxxxxxxxxxxxx
That's interesting - I thought the new ExportCSPBlob method created a blob
that was byte-order compatible with the native API. Here's the doc link for
it:

http://msdn2.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.exportcspblob.aspx

Note that it doesn't actually say "byte-order" compatible, so I might have
made a bad assumption. I'll try reversing the bits while I wait to hear from
you (or anyone) on ExportCSPBlob compatibility.

Thanks,
-Jeff

"Mitch Gallant" wrote:

CryptSignHash and CryptVerifySignature expect the pkcs#1 blob to be
in reverse (little-endian) order compared to what .NET and Java use.
Try reversing the byte order (either in .NET or in C++).

See 1st paragraph here:
http://www.jensign.com/JavaScience/dotnet/JKeyNet

Same issue applies to capi CryptEncrypt versus .NET Encrpt calls:
http://www.jensign.com/JavaScience/dotnet/RSAEncrypt

- Mitch

"Jeff Mastry" <jmastry@xxxxxxxxxxxxxxx> wrote in message news:8175772E-F7BB-41D6-8195-38EA18A2CFE6@xxxxxxxxxxxxxxxx
I am having difficulty verifying an RSA signature generated with c# (2.0) in
c++ with the CryptoAPI.

With c#, I base64 encode the signature and save it to a unicode (utf-16)
encoded text file. With c++, I read the text file and use CryptStringToBinary
to decode from base64. All that seems to work fine, but CryptVerifySignature
always returns NTE_BAD_SIGNATURE. I am able to verify the same file in c#, so
I'm confident that the signature file is OK.

I suspect that either I'm improperly importing the public key, or I'm
improperly importing the signature file.

Here's the code for importing the publik key:

...
//-- Read the public key into memory
ULONGLONG blobLength = 0;
BYTE* blob = NULL;
GetFileBytes( L"public.dat", &blob, blobLength );

//-- Import the public key
HCRYPTKEY key;
CryptImportKey(
provider,
blob,
static_cast<DWORD>(blobLength),
NULL,
0,
&key );

...

//-- Reads all the bytes from the specified file and copies them to buffer
BOOL GetFileBytes( LPCWSTR path, BYTE** buffer, ULONGLONG& bufferSize )
{
CAtlFile file;

*buffer = NULL;
bufferSize = 0;

//-- Open the file for reading
file.Create( path, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING );

//-- Get the length of the file in bytes
file.GetSize( bufferSize );

if( 0 == bufferSize )
return TRUE;

//-- Move to the beginning of the file
file.Seek( 0, FILE_BEGIN );

//-- Read the raw file bytes into memory
DWORD sz = static_cast<DWORD>(bufferSize);
*buffer = new BYTE[ sz ];
ZeroMemory( *buffer, sz );
file.Read( *buffer, sz );
file.Close();

return TRUE;
}


Here's the code for importing the signature file:

BOOL LoadSignatureFile( BYTE** binData, DWORD& binDataLen )
{
//-- Read the signature from the file
wchar_t* textSig = NULL;
ULONGLONG textSigBytes = 0;
GetFileBytes( L"signature.dat", (BYTE**)&textSig, textSigBytes );

//-- Get the length needed for the binary signature
DWORD len = static_cast<DWORD>( textSigBytes / sizeof(wchar_t) );
CryptStringToBinary(
textSig,
len,
CRYPT_STRING_BASE64,
NULL,
&binDataLen,
NULL,
NULL );

//-- Convert the signature to binary from base64
*binData = new BYTE[binDataLen];
CryptStringToBinary(
textSig,
len,
CRYPT_STRING_BASE64,
*binData,
&binDataLen,
NULL,
NULL );

delete [] textSig;
return TRUE;
}

The puclic key file (public.dat) was generated in c# with ExportCspBlob:

CspParameters csp = new CspParameters( PROV_RSA_FULL );
csp.KeyNumber = (int)KeyNumber.Signature;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider( csp );

byte[] fullKey = rsa.ExportCspBlob( true );
byte[] publicKey = rsa.ExportCspBlob( false );

File.WriteAllBytes( "full.dat", fullKey );
File.WriteAllBytes( "public.dat", publicKey );

For clarity, I removed all error checking from the code samples. Thanks.
-Jeff






.



Relevant Pages

  • Re: Trouble verifying RSA signature generated with c#
    ... Send me a signature blob and keyblob you generated and i'll have a look. ... Thanks for your reply Mitch - much appreciated. ... BOOL GetFileBytes(LPCWSTR path, BYTE** buffer, ULONGLONG& bufferSize) ... BOOL LoadSignatureFile(BYTE** binData, DWORD& binDataLen) ...
    (microsoft.public.platformsdk.security)
  • Trouble verifying RSA signature generated with c#
    ... I base64 encode the signature and save it to a unicode ... BOOL GetFileBytes(LPCWSTR path, BYTE** buffer, ULONGLONG& bufferSize) ... BOOL LoadSignatureFile(BYTE** binData, DWORD& binDataLen) ...
    (microsoft.public.platformsdk.security)
  • Re: Trouble verifying RSA signature generated with c#
    ... See the comments in the paragraph "Microsoft CryptoAPI Public Key Formats" here: ... for example exports the capi-friendly PUBLICKEYBLOB ... The signature blob generated oRSA.Sign is in standard big-endian order. ... BOOL GetFileBytes(LPCWSTR path, BYTE** buffer, ULONGLONG& bufferSize) ...
    (microsoft.public.platformsdk.security)
  • Re: questoin abt pkcs7 BLOB CAPI
    ... > i have a digital signature that is in PKCS7 format. ... save the BLOB in a file and name it as "smime.p7s". ... S/MIME is just a higher-level wrapper to ... your MIME program will b64 transfer-encode that blob anyway. ...
    (microsoft.public.platformsdk.security)
  • Re: Serial Driver mod
    ... But if i were to use that static buffer to hold my signature, ... Correct me if im wrong but this driver seems to be closely tied in with the ...
    (microsoft.public.windowsce.embedded)