我正在尝试使用Delphi 10.2将Coinbase Pro API集成到我的程序中。
Coinbase Pro API需要四个不同的标头,其中之一是已加密的签名。我在形成有效签名时遇到问题。根据Coinbase Pro API文档:
CB-ACCESS-SIGN标头是通过使用prehash字符串时间戳+方法+ requestPath +正文(其中+表示字符串串联)上的base64解码密钥创建sha256 HMAC并生成base64编码输出而生成的。时间戳记值与CB-ACCESS-TIMESTAMP标头相同。主体为请求主体字符串,如果没有请求主体(通常用于GET请求),则省略。方法应为UPPER CASE。
我知道时间戳是正确的,因为我首先要从币库服务器获取时间戳,然后将其传递给签名。因此,我猜测它与base64解码/编码或sha256 hmac有关。
我的签名功能是:
function Signature(RequestPath, TimeStamp, Method : String) : ANSIString;
var
skeydecode : AnsiString;
sha256 : AnsiString;
prehash : AnsiString;
Body : String;
begin
Body := '';
prehash := TimeStamp + Method + RequestPath + Body ;
////Option 1 - [Coinbase] Invalid Signature
skeydecode := TIdDecoderMIME.DecodeString(APISecret);
sha256 := trim(CalculateHMACSHA256(prehash ,skeydecode));
result := Tidencodermime.EncodeString(sha256);
end;
然后我要使用的HMAC函数是:
function CalculateHMACSHA256(const value, salt: String): String;
var
hmac: TIdHMACSHA256;
hash: TIdBytes;
begin
LoadOpenSSLLibrary;
if not TIdHashSHA256.IsAvailable then
raise Exception.Create('SHA256 hashing is not available!');
hmac := TIdHMACSHA256.Create;
try
hmac.Key := IndyTextEncoding_UTF8.GetBytes(salt);
hash := hmac.HashValue(IndyTextEncoding_UTF8.GetBytes(value));
Result := ToHex(hash);
finally
hmac.Free;
end;
end;
我可以通过REST请求成功连接到Coinbase API,因为我可以连接到时间端点,但这不需要签名标头。
[当尝试将签名标头包含在其他REST请求中时,coinbase api返回无效签名。
不要将AnsiString
用于二进制数据。您的数据正在通过AnsiUnicode转换。
将base64密钥解码为字节,并按原样将其用于hmac密钥,然后base64照原样对所得的字节进行编码,而不是字节的十六进制编码表示形式。
尝试一下:
function CalculateHMACSHA256(const value: String; const salt: TIdBytes): TIdBytes;
var
hmac: TIdHMACSHA256;
begin
LoadOpenSSLLibrary;
if not TIdHashSHA256.IsAvailable then
raise Exception.Create('SHA256 hashing is not available!');
hmac := TIdHMACSHA256.Create;
try
hmac.Key := salt;
Result := hmac.HashValue(IndyTextEncoding_UTF8.GetBytes(value));
finally
hmac.Free;
end;
end;
function Signature(const RequestPath, TimeStamp, Method : String) : String;
var
key : TIdBytes;
sha256 : TIdBytes;
prehash : String;
Body : String;
begin
Body := '';
prehash := TimeStamp + UpperCase(Method) + RequestPath + Body;
key := TIdDecoderMIME.DecodeBytes(APISecret);
sha256 := CalculateHMACSHA256(prehash, key);
Result := TIdEncoderMIME.EncodeBytes(sha256);
end;