PHP and C# HMAC SHA256
我需要在C#中转换以下php代码:
1 2 | $res = mac256($ent, $key); $result = encodeBase64($res); |
哪里
1 2 3 4 5 | function encodeBase64($data) { $data = base64_encode($data); return $data; } |
和
1 2 3 4 5 | function mac256($ent,$key) { $res = hash_hmac('sha256', $ent, $key, true);//(PHP 5 >= 5.1.2) return $res; } |
我使用以下C#代码:
1 2 | byte[] res = HashHMAC(ent, key); string result = System.Convert.ToBase64String(res); |
哪里
1 2 3 4 5 6 7 | public byte[] HashHMAC(string ent, byte[] key) { byte[] toEncryptArray =System.Text.Encoding.GetEncoding(28591).GetBytes(ent); HMACSHA256 hash = new HMACSHA256(key); return hash.ComputeHash(toEncryptArray); } |
完整的PHP源代码可在此链接获得
我也在php和c#中检查了这篇帖子hmac_sha256
这个C#相当于PHP中的hash_hmac
但是结果不一样。
这段代码应该可以解决这个问题:
1 2 3 4 5 6 7 | static byte[] hmacSHA256(String data, String key) { using (HMACSHA256 hmac = new HMACSHA256(Encoding.ASCII.GetBytes(key))) { return hmac.ComputeHash(Encoding.ASCII.GetBytes(data)); } } |
如果我调用此代码:
1 | Console.WriteLine(BitConverter.ToString(hmacSHA256("1234","1234")).Replace("-","").ToLower()); |
它返回:
1 | 4e4feaea959d426155a480dc07ef92f4754ee93edbe56d993d74f131497e66fb |
当我在PHP中运行时:
1 | echo hash_hmac('sha256',"1234","1234", false); |
它返回
1 | 4e4feaea959d426155a480dc07ef92f4754ee93edbe56d993d74f131497e66fb |
我很确定您正在处理新的RedSys SHA256签名实现。我还看到您在PHP和C#之间的3DES加密方面遇到了一些问题。
首先,您必须获得带有所有付款参数的base 64字符串。您可以使用以下代码来实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public static string GetParameters(string merchantCode, string terminal, int currency, string transactionType, decimal amount, string merchantOrder, string merchantIdentifier, string merchantPost, string urlOk, string urlKo) { var jsonValues = new Dictionary<string, string> { {"Ds_Merchant_Amount", amount.ToString().Replace(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator,"") }, {"Ds_Merchant_Order", merchantOrder}, {"Ds_Merchant_MerchantCode", merchantCode }, {"Ds_Merchant_Currency", currency.ToString() }, {"Ds_Merchant_TransactionType", transactionType }, {"Ds_Merchant_Terminal", terminal }, {"Ds_Merchant_Identifier", merchantIdentifier }, {"Ds_Merchant_MerchantURL", merchantPost }, {"Ds_Merchant_UrlOK", urlOk}, {"Ds_Merchant_UrlKO", urlKo} }.Select(kvp =>"\"{0}\":\"{1}\"".Formato(kvp.Key.ToUpper(), kvp.Value)); var jsonString ="{" + string.Join(",", jsonValues) +"}"; return Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(jsonString)); } |
一旦在base 64中具有JSON字符串,就必须使用RedSys提供的密钥将3DES应用于商户订单参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static string GetTransactionEncryptionKey(string merchantOrder, string encryptKey) { using (var tdes = new TripleDESCryptoServiceProvider()) { tdes.IV = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; tdes.Key = Convert.FromBase64String(encryptKey); tdes.Padding = PaddingMode.Zeros; tdes.Mode = CipherMode.CBC; var toEncrypt = ASCIIEncoding.ASCII.GetBytes(merchantOrder); var result = tdes.CreateEncryptor().TransformFinalBlock(toEncrypt, 0, toEncrypt.Length); return Convert.ToBase64String(result); } } |
如您所见,RedSys提供的加密密钥是64位字符串,因此您无需为3DES算法计算MD5哈希。
然后我们使用SHA256签名:
1 2 3 4 5 6 7 8 9 | public static string GetSignature(string base64Parameters, string base64tranEncryptKey) { using (var sha = new HMACSHA256(Convert.FromBase64String(base64tranEncryptKey))) { var hash = sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(base64Parameters)); return Convert.ToBase64String(hash); } } |
祝好运!
Redsys提供了用于php和java的库。
从Java库开始,我已经将ApiMacSha256类转换为C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | public class ApiMacSha256 { ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// //////////// FUNCIONES AUXILIARES: /////////// ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// /** 3DES Function */ private byte[] encrypt_3DES(byte[] key, string data) { //http://www.mywebexperiences.com/2012/12/11/crypting-data-using-3des-c/ //http://stackoverflow.com/a/33479952/2938518 using (var tdes = new TripleDESCryptoServiceProvider()) { tdes.IV = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; tdes.Key = key; tdes.Padding = PaddingMode.Zeros; tdes.Mode = CipherMode.CBC; var toEncrypt = Encoding.ASCII.GetBytes(data); var result = tdes.CreateEncryptor().TransformFinalBlock(toEncrypt, 0, toEncrypt.Length); return result; } } /** MAC Function */ private byte[] mac256(string dsMerchantParameters, byte[] secretKo) { //http://stackoverflow.com/a/17315619/2938518 byte[] hash; using (var hmac = new HMACSHA256(secretKo)) { hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(dsMerchantParameters)); } return hash; } /** Base64 Functions */ private string encodeB64String(byte[] data) { return Convert.ToBase64String(data, Base64FormattingOptions.None); } ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// //////////// FUNCIONES PARA LA GENERACIóN DEL FORMULARIO DE PAGO: //////////// ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////// public String createMerchantSignature(string merchantParamsB64, string claveComercio, string OrderId) { byte[] clave = Convert.FromBase64String(claveComercio); byte[] secretKo = encrypt_3DES(clave, OrderId); // Se hace el MAC con la clave de la operación"Ko" y se codifica en BASE64 byte[] hash = mac256(merchantParamsB64, secretKo); String res = encodeB64String(hash); return res; } } |
主要方法" createMerchantSignature"需要一个字符串,该字符串编码为嵌入在json结构中的商人参数的base64,商人的密钥和OrderId。