How to hash a string using RSA-SHA1?
How to hash a string using RSA-SHA1?
Delphi supports HMAC-SHA1 through TRESTHTTPProcs.HashHMACSHA1(). Is there a similar function for RSA-SHA1?
Delphi supports HMAC-SHA1 through TRESTHTTPProcs.HashHMACSHA1(). Is there a similar function for RSA-SHA1?
Do softwareguru.com - The Guru's Blog - Delphi/RAD Studio XE 5 OAuth1 Authentication issue with Twitter and Tumblr (Solution) and http://docwiki.embarcadero.com/Libraries/XE6/en/REST.Authenticator.OAuth.TOAuth1Authenticator help?
ReplyDeleteFinally got it working. Add this unit to your project and add 'OAuth1SignatureMethod_RSA_SHA1' to the uses. Then set TOAuth1Authenticator.SigningClassName to 'TOAuth1SignatureMethod_RSA_SHA1'
ReplyDeleteunit OAuth1SignatureMethod_RSA_SHA1;
interface
uses System.Classes, System.SysUtils, REST.Authenticator.OAuth;
type
TOAuth1SignatureMethod_RSA_SHA1 = class(TOAuth1SignatureMethod_HMAC_SHA1)
protected
// returns RSA-SHA1 signature (not HMAC-SHA1)
function Hash_HMAC_SHA1(const AData, AKey: string): string; override;
public
class function GetName: string; override;
end;
implementation
uses IdSSLOpenSSL, IdSSLOpenSSLHeaders, idCTypes, idGlobal, System.NetEncoding;
function TOAuth1SignatureMethod_RSA_SHA1.Hash_HMAC_SHA1(const AData, AKey: string): string;
var
buffer: TBytes;
mdLength: TIdC_UInt;
mdctx: EVP_MD_CTX;
outbuf: TBytes;
KeyBuffer: pBIO;
FRSA: PRSA;
md: PEVP_MD;
rc: Integer;
key: EVP_PKEY;
begin
if not IdSSLOpenSSL.LoadOpenSSLLibrary then
raise Exception.Create('LoadOpenSSLLibrary failed');
// Load private key (key must include header and footer)
//----BEGIN PRIVATE KEY----
// ....
// ....
//----END PRIVATE KEY----
buffer := TEncoding.ANSI.GetBytes(AKey);
KeyBuffer := BIO_new_mem_buf(buffer, Length(buffer));
if KeyBuffer = nil then
raise Exception.Create('RSA out of memory');
try
FRSA := PEM_read_bio_RSAPrivateKey(KeyBuffer, nil, nil, nil);
if not Assigned(FRSA) then
raise Exception.Create('Private key error');
finally
BIO_free(KeyBuffer);
end;
md := EVP_get_digestbyname('SHA1');
rc := EVP_DigestInit(@mdctx, md);
if rc <> 1 then
raise Exception.Create('EVP_DigestInit failed: ' + rc.ToString);
rc := EVP_PKEY_set1_RSA(@key, FRSA);
if rc <> 1 then
raise Exception.Create('EVP_PKEY_set1_RSA failed: ' + rc.ToString);
rc := EVP_DigestSignInit(@mdctx, nil, md, nil, @key);
if rc <> 1 then
raise Exception.Create('EVP_DigestSignInit failed: ' + rc.ToString);
buffer := TEncoding.ANSI.GetBytes(AData);
rc := EVP_DigestSignUpdate(@mdctx, buffer, Length(buffer));
if rc <> 1 then
raise Exception.Create('EVP_DigestSignUpdate failed: ' + rc.ToString);
rc := EVP_DigestSignFinal(@mdctx, nil, @mdLength);
if rc <> 1 then
raise Exception.Create('EVP_DigestFinal failed: ' + rc.ToString);
SetLength(outbuf, mdLength);
rc := EVP_DigestSignFinal(@mdctx, PIdAnsiChar(@outbuf[0]), @mdLength);
if rc <> 1 then
raise Exception.Create('EVP_DigestFinal failed: ' + rc.ToString);
EVP_Cleanup();
SetLength(outbuf, mdLength);
Result := TNetEncoding.Base64.EncodeBytesToString(outbuf);
end;
class function TOAuth1SignatureMethod_RSA_SHA1.GetName: string;
begin
result := 'RSA-SHA1'; // do not localize
end;
initialization
RegisterClasses([TOAuth1SignatureMethod_RSA_SHA1]);
end.