要为我的一个项目使用API,我需要验证请求中提供的SHA-512哈希(sha_sign
)。 API的制造商提供了一个PHP示例脚本,我需要将其移植到C#(ASP.NET Core 2.1)。
我有以下PHP源代码:
function compute_signature( $secret, $array)
{
unset($array[ 'sha_sign' ]);
$keys = array_keys($array);
sort($keys);
$sha_string = "";
foreach ($keys as $key)
{
$value = html_entity_decode( $array[ $key ] );
$value = $array[ $key ];
$is_empty = !isset($value) || $value === "" || $value === false;
if ($is_empty)
{
continue;
}
$sha_string .= "$key=$value$secret";
}
$sha_sign = strtoupper(hash("sha512", $sha_string));
return $sha_sign;
}
您可能已经注意到,$value
被解码一次,但随后被原始值覆盖。
我需要将此移植到C#;这是我产生的:
// Validate the hash signature of the request.
{
string secret = "1234";
// Parse HTTP query string manually (need the raw string for hash computation).
Regex httpParamRegex = new Regex(@"^([^=]+)=(.*)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
SortedList<string, string> array = new SortedList<string, string>();
foreach (string pairStr in Request.QueryString.Value.Substring(1).Split('&'))
{
Match match = httpParamRegex.Match(pairStr);
if (match.Success)
{
array.Add(
match.Groups[1].Value.ToString(CultureInfo.InvariantCulture),
match.Groups[2].Value.ToString(CultureInfo.InvariantCulture)
);
}
}
// Remove the submitted hash.
array.Remove("sha_sign");
// Extract the keys, and sort them.
List<string> keys = new List<string>(array.Keys.ToArray<string>());
keys.Sort();
string sha_string = "";
foreach (string key in keys)
{
string value = array[key];
bool is_empty = string.IsNullOrEmpty(value);
if (is_empty)
{
continue;
}
sha_string += $"{key}={value}{secret}";
}
using (SHA512 sha = SHA512.Create())
{
sha_string = BitConverter.ToString(
sha.ComputeHash(
Encoding.UTF8.GetBytes(
sha_string
)
)
).Replace("-", "", StringComparison.InvariantCultureIgnoreCase);
}
if (sha_string.Equals(Request.Query["sha_sign"][0], StringComparison.InvariantCultureIgnoreCase))
{
return new ContentResult()
{
StatusCode = 200,
ContentType = @"text/plain",
Content = @"OK"
};
}
else
{
return new ContentResult()
{
StatusCode = 401, // 401 (Unauthorized)
ContentType = @"text/plain",
Content = @"Error: sha_sign invalid"
};
}
}
问题是C#哈希始终与PHP哈希不同。 PHP脚本来自制造商,作为API使用示例。我做错了什么?
以下是一些测试数据:
秘密是:1234
HTTP GET查询字符串
order_id=9R27Q7B8&quantity=1&email=e%40mail.invalid&language=de%2Cen&buyer_id=10226794&variant_id=V2&variant_name=Variante+2&address_first_name=FirstName&address_last_name=LastName&merchant_id=354530&country=DE&affiliate_id=&orderform_id=98318&campaignkey=¤cy=EUR&amount=30.00&vat_amount=4.79&vat_rate=0.00&monthly_amount=0.00&monthly_vat_amount=0.00&number_of_installments=0&billing_type=single_payment&product_id=308152&product_language=de%2Cen&product_name=Demonstrationsprodukt+%28Dauerhafte+Lizenz%29&product_delivery_type=digital&address_id=12019159&address_street=StreetName+StreetNo&address_street2=2ndAddressLine&address_city=CityName&address_state=&address_zipcode=12345&address_country=DE&address_phone_no=%2B49123456789&address_mobile_no=&address_company=Company&address_salutation=M&address_title=Title&address_street_name=StreetName&address_street_number=StreetNo&sha_sign=DF2B0F587FA05D495CC61B7F74ADC5C709110A83D89655675F4DBBB9D9E85063212EAA7EC96661AB2449CBA30F44B339B0437B98781EA724F90A429BCE8DD0EE
调试输出:
Keys before remove: address_city, address_company, address_country, address_first_name, address_id, address_last_name, address_mobile_no, address_phone_no, address_salutation, address_state, address_street, address_street_name, address_street_number, address_street2, address_title, address_zipcode, affiliate_id, amount, billing_type, buyer_id, campaignkey, country, currency, email, language, merchant_id, monthly_amount, monthly_vat_amount, number_of_installments, order_id, orderform_id, product_delivery_type, product_id, product_language, product_name, quantity, sha_sign, variant_id, variant_name, vat_amount, vat_rate
Keys after remove: address_city, address_company, address_country, address_first_name, address_id, address_last_name, address_mobile_no, address_phone_no, address_salutation, address_state, address_street, address_street_name, address_street_number, address_street2, address_title, address_zipcode, affiliate_id, amount, billing_type, buyer_id, campaignkey, country, currency, email, language, merchant_id, monthly_amount, monthly_vat_amount, number_of_installments, order_id, orderform_id, product_delivery_type, product_id, product_language, product_name, quantity, variant_id, variant_name, vat_amount, vat_rate
Keys after sort: address_city, address_company, address_country, address_first_name, address_id, address_last_name, address_mobile_no, address_phone_no, address_salutation, address_state, address_street, address_street_name, address_street_number, address_street2, address_title, address_zipcode, affiliate_id, amount, billing_type, buyer_id, campaignkey, country, currency, email, language, merchant_id, monthly_amount, monthly_vat_amount, number_of_installments, order_id, orderform_id, product_delivery_type, product_id, product_language, product_name, quantity, variant_id, variant_name, vat_amount, vat_rate
Key address_city(True): CityName
Key address_company(True): Company
Key address_country(True): DE
Key address_first_name(True): FirstName
Key address_id(True): 12019159
Key address_last_name(True): LastName
Key address_mobile_no(False):
Key address_phone_no(True): %2B49123456789
Key address_salutation(True): M
Key address_state(False):
Key address_street(True): StreetName+StreetNo
Key address_street_name(True): StreetName
Key address_street_number(True): StreetNo
Key address_street2(True): 2ndAddressLine
Key address_title(True): Title
Key address_zipcode(True): 12345
Key affiliate_id(False):
Key amount(True): 30.00
Key billing_type(True): single_payment
Key buyer_id(True): 10226794
Key campaignkey(False):
Key country(True): DE
Key currency(True): EUR
Key email(True): e%40mail.invalid
Key language(True): de%2Cen
Key merchant_id(True): 354530
Key monthly_amount(True): 0.00
Key monthly_vat_amount(True): 0.00
Key number_of_installments(True): 0
Key order_id(True): 9R27Q7B8
Key orderform_id(True): 98318
Key product_delivery_type(True): digital
Key product_id(True): 308152
Key product_language(True): de%2Cen
Key product_name(True): Demonstrationsprodukt+%28Dauerhafte+Lizenz%29
Key quantity(True): 1
Key variant_id(True): V2
Key variant_name(True): Variante+2
Key vat_amount(True): 4.79
Key vat_rate(True): 0.00
Compare sha_sign(DF2B0F587FA05D495CC61B7F74ADC5C709110A83D89655675F4DBBB9D9E85063212EAA7EC96661AB2449CBA30F44B339B0437B98781EA724F90A429BCE8DD0EE) to computed hash(5532253C8F64EC5F97004778109375F1B92C6994ECE5C7D2FF003007A35DC062D5149131FC4B1BB403B98EC4CB1795A63835131DBC8CF5FC6A5A15570071E446).
仅使用两种语言的SHA512哈希码,在将sha_sign
值从尾部切掉后,我就可以为您的示例输入生成相同的哈希。
PHP:
<?php
$sha_sign = strtoupper(hash("sha512", "order_id=9R27Q7B8&quantity=1&email=e%40mail.invalid&language=de%2Cen&buyer_id=10226794&variant_id=V2&variant_name=Variante+2&address_first_name=FirstName&address_last_name=LastName&merchant_id=354530&country=DE&affiliate_id=&orderform_id=98318&campaignkey=¤cy=EUR&amount=30.00&vat_amount=4.79&vat_rate=0.00&monthly_amount=0.00&monthly_vat_amount=0.00&number_of_installments=0&billing_type=single_payment&product_id=308152&product_language=de%2Cen&product_name=Demonstrationsprodukt+%28Dauerhafte+Lizenz%29&product_delivery_type=digital&address_id=12019159&address_street=StreetName+StreetNo&address_street2=2ndAddressLine&address_city=CityName&address_state=&address_zipcode=12345&address_country=DE&address_phone_no=%2B49123456789&address_mobile_no=&address_company=Company&address_salutation=M&address_title=Title&address_street_name=StreetName&address_street_number=StreetNo"));
echo $sha_sign;
?>
PHP输出:3FD8F9AB34A6AA9F892B6D013A1D120D466FFA6C04281FF86D9DB05168AAA292C027E44503CFB9234A0B316C2D13416650F1D41A5864124516D9903EEAAA8292
C#:
using System;
using System.Text;
using System.Security.Cryptography;
namespace Test
{
class Program
{
static void Main(string[] args)
{
string sha_string = string.Empty;
using (SHA512 sha = SHA512.Create())
{
sha_string = BitConverter.ToString(
sha.ComputeHash(
Encoding.UTF8.GetBytes(
"order_id=9R27Q7B8&quantity=1&email=e%40mail.invalid&language=de%2Cen&buyer_id=10226794&variant_id=V2&variant_name=Variante+2&address_first_name=FirstName&address_last_name=LastName&merchant_id=354530&country=DE&affiliate_id=&orderform_id=98318&campaignkey=¤cy=EUR&amount=30.00&vat_amount=4.79&vat_rate=0.00&monthly_amount=0.00&monthly_vat_amount=0.00&number_of_installments=0&billing_type=single_payment&product_id=308152&product_language=de%2Cen&product_name=Demonstrationsprodukt+%28Dauerhafte+Lizenz%29&product_delivery_type=digital&address_id=12019159&address_street=StreetName+StreetNo&address_street2=2ndAddressLine&address_city=CityName&address_state=&address_zipcode=12345&address_country=DE&address_phone_no=%2B49123456789&address_mobile_no=&address_company=Company&address_salutation=M&address_title=Title&address_street_name=StreetName&address_street_number=StreetNo"
)
)
).Replace("-", "", StringComparison.InvariantCultureIgnoreCase);
}
Console.WriteLine(sha_string);
}
}
}
C#输出:3FD8F9AB34A6AA9F892B6D013A1D120D466FFA6C04281FF86D9DB05168AAA292C027E44503CFB9234A0B316C2D13416650F1D41A5864124516D9903EEAAA8292
[这使我相信提供给SHA512哈希调用的输入有所不同,因此我建议您先打印出该调用的输入,然后再比较两个解决方案并确保两个输入相同。] >