Azure Blob授权标头|HMAC-SHA256|OpenSSL,cURL与Java|签名不匹配



我一直在测试各种Azure Blob web服务的使用情况(List、Get、Put、Delete(。我在shell脚本上使用cURL的测试成功了。然而,我尝试在Java上模拟这个功能是行不通的。确切地说,Java上生成的签名值与OpenSSL的签名值不匹配。

以下是运行良好的脚本

#!/bin/bash
# List the blobs in an Azure storage container.
echo "usage: ${0##*/} <storage-account-name> <container-name> <access-key>"
storage_account="ABC"
container_name="XYZ"
access_key="abc=="
blob_store_url="blob.core.windows.net"
authorization="SharedKey"
request_method="GET"
request_date=$(TZ=GMT date "+%a, %d %h %Y %H:%M:%S %Z")
storage_service_version="2015-02-21"
# HTTP Request headers
x_ms_date_h="x-ms-date:$request_date"
x_ms_version_h="x-ms-version:$storage_service_version"
# Build the signature string
canonicalized_headers="${x_ms_date_h}n${x_ms_version_h}"
canonicalized_resource="/${storage_account}/${container_name}"
string_to_sign="${request_method}nnnnnnnnnnnn${canonicalized_headers}n${canonicalized_resource}ncomp:listnrestype:container"
# Decode the Base64 encoded access key, convert to Hex.
decoded_hex_key="$(printf $access_key | base64 -d -w0 | xxd -p -c256)"
# Create the HMAC signature for the Authorization header
signature=$(printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary |  base64 -w0)
authorization_header="Authorization: $authorization $storage_account:$signature"
# -v or --trace to enable tracing
curl -v 
-H "$x_ms_date_h" 
-H "$x_ms_version_h" 
-H "$authorization_header" 
"https://${storage_account}.${blob_store_url}/${container_name}?restype=container&comp=list" -o Azure_ListBlob_Output.dat

这是Java函数,它产生的输出与前者不匹配:

public static String computeHMac256(final String base64Key, final String stringToSign) {

//Signature=Base64(HMAC-SHA256(UTF8(StringToSign), Base64.decode(<your_azure_storage_account_shared_key>)))  
try {

byte[] key = Base64.getDecoder().decode(base64Key);
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
hmacSHA256.init(new SecretKeySpec(key, "HmacSHA256"));
byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8);
byte[] output = hmacSHA256.doFinal(utf8Bytes);
return Base64.getEncoder().encodeToString(output);              
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} 
return null;
}

这是stringToSign值,提供给Java函数:

"GET\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"\n" + 
"x-ms-date:Tue, 30 Mar 2021 10:19:17 GMT\n" + 
"x-ms-version:2015-02-21\n" + 
"/ABC/XYZ\n" + 
"comp:list\n" + 
"restype:container";

当Java生成的签名传递到请求时,Azure会报告以下内容:

HTTP/1.1 403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

从这里获取的java函数有什么不正确的地方吗?请协助。

修正变量stringToSign的以下值,修复了问题:

"GETn" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"n" + 
"x-ms-date:Tue, 30 Mar 2021 10:19:17 GMTn" + 
"x-ms-version:2015-02-21n" + 
"/ABC/XYZn" + 
"comp:listn" + 
"restype:container

注意换行符从\\n更改为\n

现在,签名值匹配。感谢@GauravMantri伸出援手。

最新更新