0

我正在尝试让我的产品使用 C# 连接到 Cyber​​Source,但是我遇到了麻烦。

简而言之,我试图在这里重现 Java 代码并将其翻译成C#.

我最终得到的结果与他们不同。

我注释掉的东西我也试过了。

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;

namespace encoder
{
    class Program
    {
        static void Main(string[] args)
        {

            string body = "{\n \"encryptionType\": \"RsaOaep\","
+"\n \"targetOrigin\": \"https://example.com\"\n}";
            Console.WriteLine(body);
            string _merchantId = "merchant";
            string keyID = "01dbbc88-0736-4d31-94ed-7b84579731b2";
            string secret = "SXQgaXMgc2hhcmVkIHNlY3JldA==";
            string url = "https://apitest.cybersource.com/flex/v1/keys";

            //HashAlgorithm digester = new SHA256CryptoServiceProvider();
            //byte[] digest = digester.ComputeHash(Encoding.UTF8.GetBytes(body));
            //string value = string.Format("SHA-256={0}", System.Convert.ToBase64String(digest));

            byte[] bytes = Encoding.UTF8.GetBytes(body);
            SHA256Managed hashstring = new SHA256Managed();
            byte[] digest = hashstring.ComputeHash(bytes);
            string value = string.Format("SHA-256={0}", System.Convert.ToBase64String(digest));

            Console.WriteLine("Digest: " + value);
            Console.ReadLine();
            string todaysDate = DateTime.Now.ToString("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'");
            //string todaysDate = "Mon, 01 Jan 2018 00:00:00 GMT";
            Console.WriteLine("Current Time: " + todaysDate);

            Dictionary<string, string> signedHeaders = new Dictionary<string, string>();
            signedHeaders.Add("host", "apitest.cybersource.com");
            signedHeaders.Add("date", todaysDate);
            signedHeaders.Add("(request-target)", "post /flex/va/keys/");
            signedHeaders.Add("digest", value);
            //signedHeaders.Add("digest", "SHA-256=fRDzptXm4RRRD3pC/eoIBoHShRzjRAf7Xkj18upMtI8=");
            //signedHeaders.Add("digest", "SHA-256=YljtibTei+du4xVIDxMr3HBsyLAEDuiYaag9TcU9jHA=");
            signedHeaders.Add("v-c-merchant-id", _merchantId);

            Console.WriteLine("Signed Headers: " + signedHeaders);
            Console.ReadLine();

            StringBuilder signatureString = new StringBuilder();
            StringBuilder headersString = new StringBuilder();

            foreach (KeyValuePair<string, string> s in signedHeaders)
            {
                signatureString.Append('\n').Append(s.Key).Append(": ").Append(s.Value);
                headersString.Append(' ').Append(s.Key);
            }
            signatureString.Remove(0, 1);
            headersString.Remove(0, 1);


            HMACSHA256 sha256HMAC = new HMACSHA256(System.Convert.FromBase64String(secret));
            sha256HMAC.Initialize();

            StringBuilder signature = new StringBuilder();
            byte[] hashBytes = sha256HMAC.ComputeHash(Encoding.UTF8.GetBytes(signatureString.ToString()));
            signature.Append("keyid=\"").Append(keyID)
                .Append("\", ").Append("algorithm=\"HmacSHA256\", ")
                .Append("headers=\"").Append(headersString).Append("\", ")
                .Append("digest: signature=\"").Append(System.Convert.ToBase64String(hashBytes)).Append("\"");

            Console.WriteLine("Signature: " + signature);
            Console.ReadLine();


            System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
            HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
            myHttpWebRequest.Method = "POST";
            myHttpWebRequest.ContentType = "application/json";
            myHttpWebRequest.Headers["v-c-merchant-id"] = _merchantId;
            myHttpWebRequest.Host = "apitest.cybersource.com";
            //myHttpWebRequest.Headers["v-c-date"] = DateTime.Now.ToString();
            myHttpWebRequest.Timeout = 30000;  //' 30 second timeout'
            myHttpWebRequest.KeepAlive = false;
            myHttpWebRequest.Date = DateTime.Now;
            //myHttpWebRequest.Date = new DateTime(2018, 1, 1, 0, 0, 0);

            string strResponse = string.Empty;

            byte[] myBytes;
            using (Stream myOutputStream = myHttpWebRequest.GetRequestStream())
            {
                myBytes = System.Text.Encoding.ASCII.GetBytes(body);
                myOutputStream.Write(myBytes, 0, myBytes.Length);
                myOutputStream.Close();
            }

            //http://msdn.microsoft.com/en-us/library/system.net.webresponse.getresponsestream%28v=vs.71%29.aspx
            using (WebResponse myWebResponse = myHttpWebRequest.GetResponse())
            {
                Stream RecieveStream = myWebResponse.GetResponseStream();
                Encoding encode = Encoding.UTF8;
                StreamReader readStream = new StreamReader(RecieveStream, encode);

                strResponse = readStream.ReadToEnd();

            }

            Console.WriteLine("Response: " + strResponse);
            Console.ReadLine();
        }

    }

我应该得到 Cyber​​Source 的回复,但我不断收到401 unauthorized error.

我还注意到第一个 console.writeline 得到了一个非常不同的SHA-256=lJooQmwcasZC4okGe61dGdcdlE672vGi5x0D/vmcZx8=.
我应该得到SHA-256=YljtibTei+du4xVIDxMr3HBsyLAEDuiYaag9TcU9jHA=

更新

我还应该补充一点,我们无法使用 Cyber​​Source SDK,因为我们无法使用 ILMerge 与我们的 DLL 合并。

谢谢!

4

2 回答 2

1

如果我对 OP 的游戏为时已晚,我希望我的回答对面临类似问题的其他人有所帮助。尽管我的示例正在 POST 到 PAYMENT 方法,但同样的问题也适用于我无法在请求标头中获取我的 Digest 和 Signature 哈希以匹配示例,因此除了来自 Cyber​​Source 的 401 Unauthorized 响应之外什么也没有。

简单的答案是使用可以在此处找到的“官方”C# 散列函数: https ://developer.cybersource.com/api/developer-guides/dita-gettingstarted/GenerateHeader/httpSignatureAuthentication.html#id191TE000FUI_id1925AC001Y4

尽管如此,当您将代码与示例进行比较时,您可能不会得到相同的哈希值,除非您正在比较的内容的主体有效负载被缩小并且您的示例的主体有效负载也被缩小。我怀疑这是由于在将哈希与可能具有相同内容但在缩进、间距、换行符等方面不同的两个消息体进行比较时,最终哈希的差异造成的。一个小的额外空间会使最终的哈希消失. 但我向您保证,只要您的代码正确地对消息正文进行哈希处理,您的哈希值与您正在比较的示例不同是无关紧要的。因为摘要哈希最有可能用于验证请求的主体是否没有经过调整。

我在这里有我的工作示例代码:https ://github.com/sarn1/example-cybersource-csharp-api-rest和那里的详细解释链接。

于 2019-03-31T21:49:01.233 回答
0

我会将其添加为评论,但我还没有足够的声誉。我不知道您的代码有什么问题,但这里是预构建的 Cyber​​Source C# 客户端,可用于请求 Flex 密钥 - https://github.com/Cyber ​​Source/cybersource-rest-samples-csharp

于 2019-01-24T18:46:57.890 回答