21.04.2006 14:54:58CryptSignMessage again... Ответов: 3
Dickie
This seems to be a good forum I cannot find similar in english anywhere else. So excuse me if I am not welcome.
I need to encode some strings by means of CryptSignMessage, everything works fine without error but the encoded string is probably wrong.
With Capicom the string looks good: "MIIEzwYJKoZIhvc....", but with CryptoApi(CryptSignMessage) it starts like "0‚'#4'ò'#6#9'*†H†÷'"
How can I get to the encoded string?
The code I use is as follows...

procedure TForm1.Button5Click(Sender: TObject);
var SigParams: CRYPT_SIGN_MESSAGE_PARA;
MessageArray: pacarPByte;
MessageSize: pacarDWORD;
Signed_MessageBlob: String;
cbSignedMessageBlob: DWord;
pSignerCert: PCCERT_CONTEXT;
hStoreHandle: HCERTSTORE;
aStr: String;
pWChar: PWideChar;
sSubjStr: String;
pSubjName: PWideChar;
sMess: String;
begin
// Open a certificate store...

aStr := 'my';
GetMem(pWChar,2*Length(aStr)+1);
StringToWideChar(aStr,pWChar,2*Length(aStr)+1);

hStoreHandle := CertOpenStore(CERT_STORE_PROV_SYSTEM,
0,
0,
CERT_SYSTEM_STORE_CURRENT_USER,
pWChar);

if hStoreHandle = nil then
raise Exception.Create('The "my" store could not be opened.');

// Find a certificate...

sSubjStr := 'Petr';
GetMem(pSubjName,2*Length(sSubjStr)+1);
StringToWideChar(sSubjStr,pSubjName,2*Length(sSubjStr)+1);

pSignerCert := CertFindCertificateInStore(hStoreHandle,
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
pSubjName,
nil);

if pSignerCert = nil then
raise Exception.Create('Signer certificate not found.');

FillChar(SigParams, sizeof(CRYPT_SIGN_MESSAGE_PARA), #0);
with SigParams do begin
cbSize := sizeof(CRYPT_SIGN_MESSAGE_PARA);
dwMsgEncodingType := X509_ASN_ENCODING or PKCS_7_ASN_ENCODING;
pSigningCert := pSignerCert;
HashAlgorithm.pszObjId := szOID_RSA_MD2; // szOID_RSA_MD2 or szOID_RSA_MD5
cMsgCert := 1;
rgpMsgCert := @pSignerCert;
end;

sMess := 'Trial message to encode.';

SetLength(MessageArray, sizeof(PByte));
SetLength(MessageSize, sizeof(DWORD));

MessageArray[0]:= @sMess[1];
MessageSize[0]:= Length(sMess);

if CryptSignMessage(@SigParams,False,1,MessageArray,MessageSize,nil,@cbSignedMessageBlob) then
ShowMessage(Format('CryptSignMessage first - done.'+#13#10+
'The size of the BLOB is %d.',[cbSignedMessageBlob]))
else
raise Exception.Create('CryptSignMessage first - Error');

SetLength(Signed_MessageBlob, cbSignedMessageBlob);
if CryptSignMessage(@SigParams,False,1,MessageArray,MessageSize,@Signed_MessageBlob[1],@cbSignedMessageBlob) then begin
ShowMessage(Format('CryptSignMessage second - done'+#13#10+
'The size of the BLOB is %d.',[cbSignedMessageBlob]));
ShowMessage(Signed_MessageBlob); // ???????????????????????????????
end else
raise Exception.Create('CryptSignMessage second - Error');

CertCloseStore(pSignerCert,0);
end;

I would be grateful if someone could help me... can be written even in russian, I hope I'll be able to cope with the language. Petr&Dickie
 
Ответы:
24.04.2006 14:35:15Kirill Sobolev
When calling CAPICOM SignedData.Sign method you probably omit last parameter EncodingType. So, Sign produces base64 encoded data, while CryptSignMessage produces pure binary. If you pass CAPICOM_ENCODE_BINARY (1), Sign will produce binary output too. To convert it between each other you can use CAPICOM.Utilities.Base64Decode/Encode methods or any component shipped with Delphi (I believe there exist some)
24.04.2006 17:42:10Petr
I added this code (to CryptSignMessage version):

Utilities := CreateOleObject('CAPICOM.utilities');
try
aStr := Utilities.Base64Encode(Signed_MessageBlob);
ShowMessage(aStr);
finally
Utilities := Null;
end;

Now the encoded string starts with "MAAaIAQASA" and does not resemble (not speaking it should be the same I think) the Capicom SignedData.sign string.
It is even much longer - "The size of the blob is 1270." unlike relatively short string displayed with Capicom.

So where might be the bug now?
25.04.2006 12:12:58Kirill Sobolev
"Bug" lies in passing parameters to Base64Encode method.
This is Delphi feature afaik, type String is automatically converted to Unicode when passed as argument which requires Unicode string. And in this particular case it is done incorrectly, since original data changes. If you do Base64Decode after encoding and compare it to decoded CAPICOM output you will see that binary data is also different.
However I don't know solution to this problem, since I don't know Delphi, you need to search appropriate forums or rather switch to C/C++ :)