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