I'm trying to utilize the OVH API in Delphi using the REST client. For this OVH requires me to generate a signature, but their documentation does not provide much info on this other than:
"$1$" SHA1_HEX(AS " " CK " " METHOD " " QUERY " " BODY " " TSTAMP)
They do provide thin wrappers for other languages so I thought I could take a look at those and try to replicate it. I found the following for generating the signature in C# and have extracted the function to be used in a test application.
Test app C# code:
textBox1.Text = GenerateSignature("appSecret", "consKey", 123456789, "PUT", "/path/to/api", "TEST DATA");
The C# result is:
$1$8336ecc5d03640b976e0b3ba005234a3046ab695
I attempted the rewrite the function in Delphi and came up with the following function:
function GenerateSignature(const appSecret, consKey: string;
const currentTimeStamp: LongInt; const method, target: string;
const data: string = ''): string;
begin
var
toSign := string.Join(' ', [appSecret, consKey, method, target, data,
currentTimeStamp]);
var
binaryHash := THashSHA1.GetHashBytes(toSign);
var
signature := '';
for var byte in binaryHash do
begin
signature := signature byte.ToHexString.ToLower;
end;
Result := '$1$' signature;
end;
And to test it:
procedure Main;
const
APP_SECRET = 'appSecret';
CONSUMER_KEY = 'consKey';
method = 'PUT';
target = '/path/to/api';
data = 'TEST DATA';
CURRENT_TIMESTAMP = 123456789;
begin
Writeln(GenerateSignature(APP_SECRET, CONSUMER_KEY, CURRENT_TIMESTAMP,
method, data));
end;
Both test applications in C# and in Delphi use the same data but produce different outputs. My expected output is:
$1$8336ecc5d03640b976e0b3ba005234a3046ab695
But I end up getting the following output from delphi:
$1$d99fd5086853e388056d6fe37a9e2d0723de151b
I do not know C# very well but it seems to get the hashbytes then convert it to hex and stitch it together. How can I modify the Delphi function I wrote so that I can get my expected result?
CodePudding user response:
Thanks to the last parameter being optional you didn't notice (because no compiler error/warning) that you actually missed one parameter when calling/testing your function, resulting in a text of
'appSecret consKey PUT TEST DATA 123456789'
to be hashed. Which is indeed
d99fd5086853e388056d6fe37a9e2d0723de151b
Let me reformat your test to make it more obvious:
const
APP_SECRET = 'appSecret';
CONSUMER_KEY = 'consKey';
CURRENT_TIMESTAMP = 123456789;
method = 'PUT';
target = '/path/to/api'; // Where is this used?
data = 'TEST DATA';
begin
GenerateSignature
( APP_SECRET
, CONSUMER_KEY
, CURRENT_TIMESTAMP
, method
// Forgotten parameter
, data // becomes "target"
);
end;
Consider making const data: string = ''
mandatory, too, instead of optional.