# 说明如何为 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”字符串。