ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 说明如何为 Signature 派生签名密钥的示例 本页以多种编程语言说明示例,介绍如何为 Signature 派生签名密钥。此页面上的示例仅说明如何派生签名密钥,它只是 GSDATA 请求签名过程的一部分。 ### **主题** * 使用 Java 派生签名密钥 * 使用 Php 派生签名密钥 * 使用 .NET (C#) 派生签名密钥 * 使用 Python 派生签名密钥 * 使用 Ruby 派生签名密钥 * 使用 JavaScript 派生签名密钥 * 使用其他语言派生签名密钥 * 常见编码错误 #### **使用 Java 派生签名密钥** ~~~ static byte[] HmacSHA256(String data, byte[] key) throws Exception { String algorithm="HmacSHA256"; Mac mac = Mac.getInstance(algorithm); mac.init(new SecretKeySpec(key, algorithm)); return mac.doFinal(data.getBytes("UTF8")); } static byte[] getSignatureKey(String key, String dateStamp, String serviceName) throws Exception { byte[] kSecret = ("GSDATA" + key).getBytes("UTF8"); byte[] kDate = HmacSHA256(dateStamp, kSecret); byte[] kService = HmacSHA256(serviceName, kDate); byte[] kSigning = HmacSHA256("gsdata_request", kService); return kSigning; } ~~~ #### **使用 Php 派生签名密钥** ~~~ function getSigningKey($shortDate, $service, $secretKey) { $dateKey = hash_hmac( 'sha256', $shortDate, "GSDATA{$secretKey}", true ); $serviceKey = hash_hmac('sha256', $service, $dateKey, true); $signingKey = hash_hmac( 'sha256', 'gsdata_request', $serviceKey, true ); return $signingKey; } ~~~ #### **使用 .NET (C#) 派生签名密钥** ~~~ static byte[] HmacSHA256(String data, byte[] key) { String algorithm = "HmacSHA256"; KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm); kha.Key = key; return kha.ComputeHash(Encoding.UTF8.GetBytes(data)); } static byte[] getSignatureKey(String key, String dateStamp, String serviceName) { byte[] kSecret = Encoding.UTF8.GetBytes(("GSDATA" + key).ToCharArray()); byte[] kDate = HmacSHA256(dateStamp, kSecret); byte[] kService = HmacSHA256(serviceName, kDate); byte[] kSigning = HmacSHA256("gsdata_request", kService); return kSigning; } ~~~ #### **使用 Python 派生签名密钥** ~~~ def sign(key, msg): return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() def getSignatureKey(key, dateStamp, serviceName): kDate = sign(("GSDATA" + key).encode("utf-8"), dateStamp) kService = sign(kDate, serviceName) kSigning = sign(kService, "gsdata_request") return kSigning ~~~ #### **使用 Ruby 派生签名密钥** ~~~ def getSignatureKey key, dateStamp, serviceName kDate = OpenSSL::HMAC.digest('sha256', "GSDATA" + key, dateStamp) kService = OpenSSL::HMAC.digest('sha256', kDate, serviceName) kSigning = OpenSSL::HMAC.digest('sha256', kService, "gsdata_request") kSigning end ~~~ #### **使用 JavaScript 派生签名密钥** 以下示例使用 crypto-js 库。有关更多信息,请参阅 https://www.npmjs.com/package/crypto-js 和 https://code.google.com/archive/p/crypto-js/。 ~~~ var crypto = require("crypto-js"); function getSignatureKey(Crypto, key, dateStamp, serviceName) { var kDate = Crypto.HmacSHA256(dateStamp, "GSDATA" + key); var kService = Crypto.HmacSHA256(serviceName, kDate); var kSigning = Crypto.HmacSHA256("aws4_request", kService); return kSigning; } ~~~ #### **使用其他语言派生签名密钥** 如果您需要用不同编程语言实施此逻辑,我们建议您使用本节中的值来测试密钥派生算法的中间步骤。以下 Ruby 示例在算法的每个步骤后使用 hexEncode 函数输出结果。 ~~~ def hexEncode bindata result="" data=bindata.unpack("C*") data.each {|b| result+= "%02x" % b} result end ~~~ 如果使用以下测试输入: ~~~ key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY' dateStamp = '20170620' serviceName = '/weixin/v1/users' ~~~ 您的程序将为 getSignatureKey 中的值生成以下值。请注意,这些值是二进制数据的十六进制编码表示形式;密钥本身和中间值应该是二进制格式。 ~~~ kSecret = '475344415441774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559' kDate = 'c2277c20105bf5dd08eb94dcc074280c4cc63318c204c486c8139730bfc541ec' kService = '27f3ff0a25623d38ab12f57a6d5ae6a85dd0498c951b164a7f4b2f6a15d00a55' kSigning = 'bea45c9d5c59da3dc8e1051fb824df588031538e376a01dd344765238f982fd2' ~~~ #### **常见编码错误** 要简化您的任务,请避免下列常见编码错误。 提示 使用能显示原始 HTTP 请求的工具检查要发送给 GSDATA 的 HTTP 请求。这样能帮助您找到代码中并不明显的问题。 * 不要包含多余的换行符,或忘记在必要的位置使用换行符。 * 不要在凭证范围中不正确地设置日期格式,如使用时间戳而不是 YYYYMMDD 格式。 * 确保规范标头和签名标头中的标头相同。 * 不要在计算中间密钥时意外交换密钥和数据 (消息)。上一步的计算结果是密钥,而不是数据。仔细检查文档中的加密基元,确保以正确顺序放置参数。 * 不要忘记在第一步在密钥之前添加字符串“GSDATA”。如果使用 for 循环或迭代程序来实施密钥派生,不要忘记第一次迭代的特殊情况,以便包含“GSDATA”字符串。