Ivona请求签名问题-签名不匹配(AWS签名版本4) [英] Ivona Request Signing Issue - signature does not match (AWS Signature Version 4)

查看:90
本文介绍了Ivona请求签名问题-签名不匹配(AWS签名版本4)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试基于此文档 来实现Ivona请求签名>

一切正常,除签名结果外,所有结果均与示例值匹配.所以我的签名结果是cf1141e33a8fbba23913f8f36f29faa524a57db37690a1b819f43bbeaabf3b76,但在文档中它等于2cdfef28d5c5f6682280600a6141a8940c608cfefacb47f172329cbadb5864cc

是我的错误还是Ivona文档中的错误?

以下是我正在使用的C#代码:

class Program
{
    static void Main()
    {
        try
        {
            Console.WriteLine(SendIvonaRequest());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private static string SendIvonaRequest()
    {
        var date = new DateTime(2013, 09, 13, 09, 20, 54, DateTimeKind.Utc);

        const string algorithm = "AWS4-HMAC-SHA256";
        const string regionName = "eu-west-1";
        const string serviceName = "tts";
        const string method = "POST";
        const string canonicalUri = "/CreateSpeech";
        const string canonicalQueryString = "";
        const string contentType = "application/json";
        const string accessKey = "MyAccessKey";
        const string secretKey = "MySecretKey";

        const string host = serviceName + "." + regionName + ".ivonacloud.com";

        const string requestPayload = "{\"Input\":{\"Data\":\"Hello world\"}}";

        var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));

        Debug.Assert(hashedRequestPayload.Equals("f43e25253839f2c3feae433c5e477d79f7dfafdc0e4af19a952adb44a60265ba"));

        var dateStamp = date.ToString("yyyyMMdd");
        var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
        var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);

        var headers = new SortedDictionary<string, string>
        {
            {"content-type", "application/json"},
            {"host", "tts.eu-west-1.ivonacloud.com"},
            {"x-amz-content-sha256", hashedRequestPayload},
            {"x-amz-date", requestDate}
        };

        string canonicalHeaders =
            string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
        const string signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";

        // Task 1: Create a Canonical Request For Signature Version 4

        var canonicalRequest = method + '\n' + canonicalUri + '\n' + canonicalQueryString +
                               '\n' + canonicalHeaders + '\n' + signedHeaders + '\n' + hashedRequestPayload;

        var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));

        Debug.Assert(hashedCanonicalRequest.Equals("73ff17c0bf9da707afb02bbceb77d359ab945a460b5ac9fff7a0a61cfaab95e6"));

        // Task 2: Create a String to Sign for Signature Version 4
        // StringToSign  = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HashedCanonicalRequest

        var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}", algorithm, requestDate, credentialScope,
            hashedCanonicalRequest);

        Debug.Assert(stringToSign.Equals("AWS4-HMAC-SHA256" + "\n" +
                                         "20130913T092054Z" + "\n" +
                                         "20130913/eu-west-1/tts/aws4_request" + "\n" +
                                         "73ff17c0bf9da707afb02bbceb77d359ab945a460b5ac9fff7a0a61cfaab95e6"));

        // Task 3: Calculate the AWS Signature Version 4

        // HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20130913"),"eu-west-1"),"tts"),"aws4_request")
        byte[] signingKey = GetSignatureKey(secretKey, dateStamp, regionName, serviceName);

        // signature = HexEncode(HMAC(derived-signing-key, string-to-sign))
        var signature = HexEncode(HmacSha256(stringToSign, signingKey));

        Debug.Assert(signature.Equals("2cdfef28d5c5f6682280600a6141a8940c608cfefacb47f172329cbadb5864cc"));

        // Task 4: Prepare a signed request
        // Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature

        var authorization =
            string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
                algorithm, accessKey, dateStamp, regionName, serviceName, signedHeaders, signature);

        // Send the request

        var webRequest = WebRequest.Create("https://" + host + canonicalUri);

        webRequest.Method = method;
        webRequest.Timeout = 2000;
        webRequest.ContentType = contentType;
        webRequest.Headers.Add("X-Amz-date", requestDate);
        webRequest.Headers.Add("Authorization", authorization);
        webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
        webRequest.ContentLength = requestPayload.Length;

        using (Stream newStream = webRequest.GetRequestStream())
        {
            newStream.Write(ToBytes(requestPayload), 0, requestPayload.Length);
        }

        var response = (HttpWebResponse) webRequest.GetResponse();

        using (Stream responseStream = response.GetResponseStream())
        {
            if (responseStream != null)
            {
                using (var streamReader = new StreamReader(responseStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }

        return string.Empty;
    }

    private static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
    {
        byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
        byte[] kRegion = HmacSha256(regionName, kDate);
        byte[] kService = HmacSha256(serviceName, kRegion);
        return HmacSha256("aws4_request", kService);
    }

    private static byte[] ToBytes(string str)
    {
        return Encoding.UTF8.GetBytes(str.ToCharArray());
    }

    private static string HexEncode(byte[] bytes)
    {
        return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
    }

    private static byte[] Hash(byte[] bytes)
    {
        var sha256 = SHA256.Create();
        return sha256.ComputeHash(bytes);
    }

    private static byte[] HmacSha256(String data, byte[] key)
    {
        return new HMACSHA256(key).ComputeHash(ToBytes(data));
    }
}

UPD1:

我还尝试了 http://docs.aws中的示例.amazon.com/general/latest/gr/sigv4_signing.html ,并注意到我的代码生成的签名与这些示例相同.因此,我假设Ivona文档中存在问题...

UPD2:

一切正常!我已经根据说明实现了CreateSpeech方法,并上传了完整的示例GitHub的用法 https://github.com/MalyutinS/DotNetIvonaAPI

解决方案

已解决!实际上,文档示例中存在问题.因此代码可以正常工作.

I am trying to implement Ivona request signing based on this documnent

Everything works good and all the results match to the example value, except Signature result. So my result for the signature is cf1141e33a8fbba23913f8f36f29faa524a57db37690a1b819f43bbeaabf3b76 but in the document it is equal to 2cdfef28d5c5f6682280600a6141a8940c608cfefacb47f172329cbadb5864cc

Is it my mistake or a mistake in the Ivona document?

Below is the C# code I am using:

class Program
{
    static void Main()
    {
        try
        {
            Console.WriteLine(SendIvonaRequest());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private static string SendIvonaRequest()
    {
        var date = new DateTime(2013, 09, 13, 09, 20, 54, DateTimeKind.Utc);

        const string algorithm = "AWS4-HMAC-SHA256";
        const string regionName = "eu-west-1";
        const string serviceName = "tts";
        const string method = "POST";
        const string canonicalUri = "/CreateSpeech";
        const string canonicalQueryString = "";
        const string contentType = "application/json";
        const string accessKey = "MyAccessKey";
        const string secretKey = "MySecretKey";

        const string host = serviceName + "." + regionName + ".ivonacloud.com";

        const string requestPayload = "{\"Input\":{\"Data\":\"Hello world\"}}";

        var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));

        Debug.Assert(hashedRequestPayload.Equals("f43e25253839f2c3feae433c5e477d79f7dfafdc0e4af19a952adb44a60265ba"));

        var dateStamp = date.ToString("yyyyMMdd");
        var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
        var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);

        var headers = new SortedDictionary<string, string>
        {
            {"content-type", "application/json"},
            {"host", "tts.eu-west-1.ivonacloud.com"},
            {"x-amz-content-sha256", hashedRequestPayload},
            {"x-amz-date", requestDate}
        };

        string canonicalHeaders =
            string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
        const string signedHeaders = "content-type;host;x-amz-content-sha256;x-amz-date";

        // Task 1: Create a Canonical Request For Signature Version 4

        var canonicalRequest = method + '\n' + canonicalUri + '\n' + canonicalQueryString +
                               '\n' + canonicalHeaders + '\n' + signedHeaders + '\n' + hashedRequestPayload;

        var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));

        Debug.Assert(hashedCanonicalRequest.Equals("73ff17c0bf9da707afb02bbceb77d359ab945a460b5ac9fff7a0a61cfaab95e6"));

        // Task 2: Create a String to Sign for Signature Version 4
        // StringToSign  = Algorithm + '\n' + RequestDate + '\n' + CredentialScope + '\n' + HashedCanonicalRequest

        var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}", algorithm, requestDate, credentialScope,
            hashedCanonicalRequest);

        Debug.Assert(stringToSign.Equals("AWS4-HMAC-SHA256" + "\n" +
                                         "20130913T092054Z" + "\n" +
                                         "20130913/eu-west-1/tts/aws4_request" + "\n" +
                                         "73ff17c0bf9da707afb02bbceb77d359ab945a460b5ac9fff7a0a61cfaab95e6"));

        // Task 3: Calculate the AWS Signature Version 4

        // HMAC(HMAC(HMAC(HMAC("AWS4" + kSecret,"20130913"),"eu-west-1"),"tts"),"aws4_request")
        byte[] signingKey = GetSignatureKey(secretKey, dateStamp, regionName, serviceName);

        // signature = HexEncode(HMAC(derived-signing-key, string-to-sign))
        var signature = HexEncode(HmacSha256(stringToSign, signingKey));

        Debug.Assert(signature.Equals("2cdfef28d5c5f6682280600a6141a8940c608cfefacb47f172329cbadb5864cc"));

        // Task 4: Prepare a signed request
        // Authorization: algorithm Credential=access key ID/credential scope, SignedHeadaers=SignedHeaders, Signature=signature

        var authorization =
            string.Format("{0} Credential={1}/{2}/{3}/{4}/aws4_request, SignedHeaders={5}, Signature={6}",
                algorithm, accessKey, dateStamp, regionName, serviceName, signedHeaders, signature);

        // Send the request

        var webRequest = WebRequest.Create("https://" + host + canonicalUri);

        webRequest.Method = method;
        webRequest.Timeout = 2000;
        webRequest.ContentType = contentType;
        webRequest.Headers.Add("X-Amz-date", requestDate);
        webRequest.Headers.Add("Authorization", authorization);
        webRequest.Headers.Add("x-amz-content-sha256", hashedRequestPayload);
        webRequest.ContentLength = requestPayload.Length;

        using (Stream newStream = webRequest.GetRequestStream())
        {
            newStream.Write(ToBytes(requestPayload), 0, requestPayload.Length);
        }

        var response = (HttpWebResponse) webRequest.GetResponse();

        using (Stream responseStream = response.GetResponseStream())
        {
            if (responseStream != null)
            {
                using (var streamReader = new StreamReader(responseStream))
                {
                    return streamReader.ReadToEnd();
                }
            }
        }

        return string.Empty;
    }

    private static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
    {
        byte[] kDate = HmacSha256(dateStamp, ToBytes("AWS4" + key));
        byte[] kRegion = HmacSha256(regionName, kDate);
        byte[] kService = HmacSha256(serviceName, kRegion);
        return HmacSha256("aws4_request", kService);
    }

    private static byte[] ToBytes(string str)
    {
        return Encoding.UTF8.GetBytes(str.ToCharArray());
    }

    private static string HexEncode(byte[] bytes)
    {
        return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();
    }

    private static byte[] Hash(byte[] bytes)
    {
        var sha256 = SHA256.Create();
        return sha256.ComputeHash(bytes);
    }

    private static byte[] HmacSha256(String data, byte[] key)
    {
        return new HMACSHA256(key).ComputeHash(ToBytes(data));
    }
}

UPD1:

I have also tried the examples from http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html and noticed that my code generate the same signature as in those examples. So I am assuming that there is an issue in Ivona document...

UPD2:

Everything works fine! I have implemented CreateSpeech method according to the description and uploaded a full example of the usage to GitHub https://github.com/MalyutinS/DotNetIvonaAPI

解决方案

Solved! Actually there is an issue in documentation example. So the code works fine.

这篇关于Ivona请求签名问题-签名不匹配(AWS签名版本4)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆