我正在尝试使用OAuth从Delphi应用程序登录Jira。获取请求令牌时失败。我无法弄清楚如何将私有RSA密钥正确编码到HTML标头中。
如何在Delphi中实现?
答案 0 :(得分:0)
终于搞定了。将此单元添加到您的项目中,然后添加“OAuth1SignatureMethod_RSA_SHA1'用途。然后将TOAuth1Authenticator.SigningClassName设置为' TOAuth1SignatureMethod_RSA_SHA1'
unit 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);
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.