I need to use RSA for signature but I am weak on SSL thingy so I find some code in internet.
I have find below code which I can used to sign ansistring successfully :
function GenarateRSASign(PrivateKey, Content: AnsiString): AnsiString;
var
buffer: PAnsiChar;
rsa_out, md: array[0..1023] of AnsiChar;
r: PRSA;
rsa_out_len: Cardinal;
key: PBIO;
hIdCrypto: HMODULE;
hash: array[0..SHA_DIGEST_LENGTH - 1] of AnsiChar;
type
Trsa_sign = function(_type: LongInt; const m: PAnsiChar; m_length: LongWord; sigret: PAnsiChar; var siglen: Cardinal; const rsa: PRSA): LongInt; cdecl;
Tsha1 = function(d: PAnsiChar; n: Cardinal; md: PAnsiChar): PAnsiChar; cdecl;
function LoadFunctionCLib(const FceName: string; const ACritical: Boolean = True): Pointer;
begin
Result := GetProcAddress(hIdCrypto, PChar(FceName));
end;
var
rsa_sign: Trsa_sign;
sha1: Tsha1;
bytes: TIdBytes;
begin
LoadOpenSSLLibrary;
hIdCrypto := LoadLibrary('libeay32.dll');
Assert(hIdCrypto <> 0, 'Cannot load libeay32.dll');
try
key := BIO_new_mem_buf(@PrivateKey[1], Length(PrivateKey));
r := PEM_read_bio_RSAPrivateKey(key, nil, nil, nil);
if r = nil then
Exit;
buffer := PAnsiChar(Content);
FillChar(md[0], 1024, 0);
FillChar(hash[0], SHA_DIGEST_LENGTH, 0);
sha1 := LoadFunctionCLib('SHA1');
Assert(@sha1 <> nil, 'Cannot load SHA1');
sha1(buffer, Length(Content), @hash[0]);
rsa_sign := LoadFunctionCLib('RSA_sign');
Assert(@rsa_sign <> nil, 'Cannot load RSA_sign');
FillChar(rsa_out[0], 1024, 0);
rsa_sign(EVP_sha1()._type, @hash[0], SHA_DIGEST_LENGTH, @rsa_out[0], rsa_out_len, r);
SetLength(bytes, rsa_out_len);
if rsa_out_len > 0 then
Move(rsa_out[0], bytes[0], rsa_out_len);
Result := AnsiString(TIdEncoderMIME.EncodeBytes(bytes));
BIO_free(key);
RSA_free(r);
finally
FreeLibrary(hIdCrypto);
UnLoadOpenSSLLibrary;
end;
end;
However, I need to sign utf8 string As I don't know if there is widestring version of 'rsa_sign' and 'sha1' functions inside libeay32.dll and their names, I just don't know how to alter the code to suit for utf8 string signature.
I would like to have some suggestion on how to modify these code or have other alternative to do the same work. Thank you.
Edit 1 : Based on David's Advice, I had modify the code as below :
function GenarateRSASign(PrivateKey: AnsiString, Content: String): String;
var
buffer : TBytes;
rsa_out, md: array[0..1023] of Byte;
r: PRSA;
rsa_out_len: Cardinal;
key: PBIO;
hIdCrypto: HMODULE;
hash: array[0..SHA_DIGEST_LENGTH - 1] of Byte;
type
Trsa_sign = function(_type: LongInt; const m: PBype; m_length: LongWord; sigret: PBype; var siglen: Cardinal; const rsa: PRSA): LongInt; cdecl;
Tsha1 = function(d: PBype; n: Cardinal; md: PBype): PByte; cdecl;
function LoadFunctionCLib(const FceName: string; const ACritical: Boolean = True): Pointer;
begin
Result := GetProcAddress(hIdCrypto, PChar(FceName));
end;
var
rsa_sign: Trsa_sign;
sha1: Tsha1;
bytes: TIdBytes;
begin
LoadOpenSSLLibrary;
hIdCrypto := LoadLibrary('libeay32.dll');
Assert(hIdCrypto <> 0, 'Cannot load libeay32.dll');
try
key := BIO_new_mem_buf(@PrivateKey[1], Length(PrivateKey));
r := PEM_read_bio_RSAPrivateKey(key, nil, nil, nil);
if r = nil then
Exit;
FillChar(md[0], 1024, 0);
FillChar(hash[0], SHA_DIGEST_LENGTH, 0);
sha1 := LoadFunctionCLib('SHA1');
Assert(@sha1 <> nil, 'Cannot load SHA1');
buffer := TEncoding.UTF8.GetBytes(Content);
sha1(@buffer[0], Length(Buffer), @hash[0]);
rsa_sign := LoadFunctionCLib('RSA_sign');
Assert(@rsa_sign <> nil, 'Cannot load RSA_sign');
FillChar(rsa_out[0], 1024, 0);
rsa_sign(EVP_sha1()._type, @hash[0], SHA_DIGEST_LENGTH, @rsa_out[0], rsa_out_len, r);
SetLength(bytes, rsa_out_len);
if rsa_out_len > 0 then
Move(rsa_out[0], bytes[0], rsa_out_len);
Result := TIdEncoderMIME.EncodeBytes(bytes);
BIO_free(key);
RSA_free(r);
finally
FreeLibrary(hIdCrypto);
UnLoadOpenSSLLibrary;
end;
end;
I get successful result when the content contain only English, which is same as before. However, when there is some Chinese Content, the result is rejected by the other party (Alipay) which reported "Illegal Sign". The input_charset is specified as 'UTF8'. Anythings else which I had done wrong here? Thank you.