C# 为CyberSource集成创建HTTP签名

C# 为CyberSource集成创建HTTP签名,c#,cybersource,C#,Cybersource,我试图让我的产品连接到CyberSource与C,但我有麻烦 简言之,我试图重现Java代码,并用C语言进行翻译 我最终得到的结果与他们不同 我评论过的东西我也试过了。 我应该从CyberSource得到回复,但我一直收到一个未经授权的错误 我还注意到,第一个console.writeline得到的SHA-256=lJooQmwcasZC4okGe61dGdcdlE672vGi5x0D/vmcZx8=的摘要非常不同。 我应该得到SHA-256=YljtibTei+du4xVIDxMr3HBsy

我试图让我的产品连接到CyberSource与C,但我有麻烦

简言之,我试图重现Java代码,并用C语言进行翻译

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

我评论过的东西我也试过了。

我应该从CyberSource得到回复,但我一直收到一个未经授权的错误

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

更新

我还应该补充一点,我们无法使用CyberSourceSDK,因为我们无法使用ILMerge与DLL合并


谢谢

我想加上这句话作为评论,但我还没有足够的声誉。我不知道你的代码出了什么问题,但这里有一个预构建的CyberSource C客户端,可以用来请求一个Flex key-

如果我来不及参加游戏,我希望我的回答能对其他面临类似问题的人有所帮助。虽然我的示例是发布到支付方法,但同样的问题也适用于我无法在请求头中获得与示例匹配的摘要和签名哈希,因此只能从CyberSource获得401未经授权的响应

简单的答案是使用官方的C哈希函数,可以在这里找到:

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


这里有我的工作示例代码:这里有详细的解释链接。

此示例非常简单,功能不全。我尝试使用API下载报告,但没有成功。此外,几乎所有与内部记录器、控制台和其他不需要在库中的东西相关的逻辑。正因为如此,我为主库创建了一个表单,也许可以做一些基本的更新。另外,获得CyberSource.Authorization library for.NET的源代码也很好。看起来它们的设计和实现都很糟糕。在如此大的产品中看到这一点,我感到非常难过,甚至可能是严重的。很奇怪…:
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();
        }

    }