header
文档中心

Signature的生成方法

更新时间: 2025-08-01 07:54:09

 

1.伪代码流程

 

Algorithm: GenerateSignature
Input:

Output: signature: string

BEGIN
   1. canonicalUri ← normalizeURI(uri)
   2. canonicalQuery ← buildCanonicalQueryString(queryParams)
   3. bodyHash ← calculateSHA256Hash(body)
   4. canonicalRequest ← buildCanonicalRequest(httpMethod, canonicalUri, canonicalQuery, bodyHash)
   5. stringToSign ← buildStringToSign(canonicalRequest)
   6. decodedSecret ← decrypt("aqj", secretKey)
   7. signature ← HMAC_SHA256(stringToSign, decodedSecret)
   8. RETURN signature
END

 

2.核心函数说明

 

2.1 URI规范化 (canonicalURI)

目的: 将URI路径按RFC3986标准编码
处理: 分割路径段,编码特殊字符,重新组合

2.2 查询参数规范化 (canonicalQueryString)

目的: 将查询参数按字母顺序排序并编码
处理: 键值对排序,URI编码,用&连接

2.3 请求体哈希 (calculateBodyHash)

目的: 计算请求体的SHA-256哈希值
处理: 空体返回固定值,非空体计算SHA-256

2.4 规范化请求构建 (buildCanonicalRequest)

目的: 构建用于签名的规范化请求字符串
格式: METHOD\nURI\nQUERY\nBODY_HASH

2.5 签名字符串构建 (buildStringToSign)

目的: 构建最终用于HMAC的字符串
格式: "ACS3-HMAC-SHA256\n" + SHA256(canonicalRequest)

 

 

3.代码示例

 

Python实现
pythonimport hashlib
import hmac
import urllib.parse
from typing import Dict, List

class SignatureGenerator:
   def __init__(self):
       pass

def generate\_signature(self, http\_method: str, uri: str,                     query\_params: Dict[str, List[str]],                     body: bytes, secret\_key: str) -> str:    """生成签名"""    canonical\_uri = self.\_canonical\_uri(uri)    canonical\_query = self.\_canonical\_query\_string(query\_params)    body\_hash = self.\_calculate\_body\_hash(body)        canonical\_request = self.\_build\_canonical\_request(        http\_method, canonical\_uri, canonical\_query, body\_hash    )        string\_to\_sign = self.\_build\_string\_to\_sign(canonical\_request)    decoded\_secret = self.\_decrypt("aqj", secret\_key)        return self.\_hmac\_sha256(string\_to\_sign, decoded\_secret) def \_canonical\_uri(self, uri: str) -> str:    """规范化URI"""    if not uri:        return "/"        segments = [seg for seg in uri.split("/") if seg]    encoded\_segments = [self.\_encode\_rfc3986(seg) for seg in segments]        return "/" + "/".join(encoded\_segments) def \_canonical\_query\_string(self, params: Dict[str, List[str]]) -> str:    """规范化查询参数"""    if not params:        return ""        items = []    for key in sorted(params.keys()):        value = params[key][0] if params[key] else ""        encoded\_key = self.\_encode\_rfc3986(key)        encoded\_value = self.\_encode\_rfc3986(value)        items.append(f"{encoded\_key}={encoded\_value}")        return "&".join(items) def \_encode\_rfc3986(self, s: str) -> str:    """RFC3986编码"""    unreserved = set('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-\_.~')    return ''.join(c if c in unreserved else f'%{ord(c):02X}' for c in s) def \_calculate\_body\_hash(self, body: bytes) -> str:    """计算请求体哈希"""    if not body:        return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"    return hashlib.sha256(body).hexdigest() def \_build\_canonical\_request(self, method: str, uri: str,                            query: str, body\_hash: str) -> str:    """构建规范化请求"""    return f"{method}\n{uri}\n{query}\n{body\_hash}" def \_build\_string\_to\_sign(self, canonical\_request: str) -> str:    """构建签名字符串"""    hash\_obj = hashlib.sha256(canonical\_request.encode())    return f"ACS3-HMAC-SHA256\n{hash\_obj.hexdigest()}" def \_hmac\_sha256(self, source: str, secret: str) -> str:    """HMAC-SHA256签名"""    return hmac.new(secret.encode(), source.encode(), hashlib.sha256).hexdigest() def \_decrypt(self, key: str, encrypted: str) -> str:    """解密密钥(需要根据实际加密方式实现)"""    # 此处需要根据实际的解密逻辑实现    return encrypted  # 简化处理

Java实现
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class SignatureGenerator {

public String generateSignature(String httpMethod, String uri,                              Map<String, List<String>> queryParams,                              byte[] body, String secretKey) {    try {        String canonicalUri = canonicalURI(uri);        String canonicalQuery = canonicalQueryString(queryParams);        String bodyHash = calculateBodyHash(body);                String canonicalRequest = buildCanonicalRequest(            httpMethod, canonicalUri, canonicalQuery, bodyHash        );                String stringToSign = buildStringToSign(canonicalRequest);        String decodedSecret = decrypt("aqj", secretKey);                return hmacSha256(stringToSign, decodedSecret);    } catch (Exception e) {        throw new RuntimeException("签名生成失败", e);    } } private String canonicalURI(String uri) {    if (uri == null || uri.isEmpty()) {        return "/";    }        String[] segments = uri.split("/");    List<String> encodedSegments = new ArrayList<>();        for (String segment : segments) {        if (!segment.isEmpty()) {            encodedSegments.add(encodeRFC3986(segment));        }    }        return "/" + String.join("/", encodedSegments); } private String canonicalQueryString(Map<String, List<String>> params) {    if (params == null || params.isEmpty()) {        return "";    }        List<String> sortedKeys = new ArrayList<>(params.keySet());    Collections.sort(sortedKeys);        List<String> items = new ArrayList<>();    for (String key : sortedKeys) {        String value = params.get(key).isEmpty() ? "" : params.get(key).get(0);        String encodedKey = encodeRFC3986(key);        String encodedValue = encodeRFC3986(value);        items.add(encodedKey + "=" + encodedValue);    }        return String.join("&", items); } private String encodeRFC3986(String s) {    StringBuilder result = new StringBuilder();    for (byte b : s.getBytes(StandardCharsets.UTF\_8)) {        if (isUnreserved(b)) {            result.append((char) b);        } else {            result.append(String.format("%%%02X", b & 0xFF));        }    }    return result.toString(); } private boolean isUnreserved(byte b) {    return (b >= 'A' && b <= 'Z') ||           (b >= 'a' && b <= 'z') ||           (b >= '0' && b <= '9') ||           b == '-' || b == '\_' || b == '.' || b == '~'; } private String calculateBodyHash(byte[] body) {    try {        if (body == null || body.length == 0) {            return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";        }                MessageDigest digest = MessageDigest.getInstance("SHA-256");        byte[] hash = digest.digest(body);                StringBuilder hexString = new StringBuilder();        for (byte b : hash) {            hexString.append(String.format("%02x", b));        }        return hexString.toString();    } catch (NoSuchAlgorithmException e) {        throw new RuntimeException("SHA-256算法不可用", e);    } } private String buildCanonicalRequest(String method, String uri,                                   String query, String bodyHash) {    return method + "\n" + uri + "\n" + query + "\n" + bodyHash; } private String buildStringToSign(String canonicalRequest) {    try {        MessageDigest digest = MessageDigest.getInstance("SHA-256");        byte[] hash = digest.digest(canonicalRequest.getBytes(StandardCharsets.UTF\_8));                StringBuilder hexString = new StringBuilder();        for (byte b : hash) {            hexString.append(String.format("%02x", b));        }                return "ACS3-HMAC-SHA256\n" + hexString.toString();    } catch (NoSuchAlgorithmException e) {        throw new RuntimeException("SHA-256算法不可用", e);    } } private String hmacSha256(String source, String secret) {    try {        Mac mac = Mac.getInstance("HmacSHA256");        SecretKeySpec secretKey = new SecretKeySpec(            secret.getBytes(StandardCharsets.UTF\_8), "HmacSHA256"        );        mac.init(secretKey);                byte[] hash = mac.doFinal(source.getBytes(StandardCharsets.UTF\_8));        StringBuilder hexString = new StringBuilder();        for (byte b : hash) {            hexString.append(String.format("%02x", b));        }        return hexString.toString();    } catch (Exception e) {        throw new RuntimeException("HMAC-SHA256计算失败", e);    } } private String decrypt(String key, String encrypted) {    // 需要根据实际加密方式实现    return encrypted; // 简化处理 }

}
 

 PHP实现
<?php

class SignatureGenerator {

public function generateSignature($httpMethod, $uri, $queryParams, $body, $secretKey) {    $canonicalUri = $this->canonicalURI($uri);    $canonicalQuery = $this->canonicalQueryString($queryParams);    $bodyHash = $this->calculateBodyHash($body);        $canonicalRequest = $this->buildCanonicalRequest(        $httpMethod, $canonicalUri, $canonicalQuery, $bodyHash    );        $stringToSign = $this->buildStringToSign($canonicalRequest);    $decodedSecret = $this->decrypt("aqj", $secretKey);        return $this->hmacSha256($stringToSign, $decodedSecret); } private function canonicalURI($uri) {    if (empty($uri)) return "/";        $segments = array\_filter(explode("/", $uri));    $encodedSegments = array\_map([$this, 'encodeRFC3986'], $segments);        return "/" . implode("/", $encodedSegments); } private function canonicalQueryString($params) {    if (empty($params)) return "";        ksort($params);    $items = [];        foreach ($params as $key => $values) {        $value = !empty($values) ? $values[0] : "";        $encodedKey = $this->encodeRFC3986($key);        $encodedValue = $this->encodeRFC3986($value);        $items[] = "$encodedKey=$encodedValue";    }        return implode("&", $items); } private function encodeRFC3986($str) {    $unreserved = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-\_.~';    $result = '';        for ($i = 0; $i < strlen($str); $i++) {        $char = $str[$i];        if (strpos($unreserved, $char) !== false) {            $result .= $char;        } else {            $result .= '%' . strtoupper(sprintf('%02x', ord($char)));        }    }        return $result; } private function calculateBodyHash($body) {    if (empty($body)) {        return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";    }        return hash('sha256', $body); } private function buildCanonicalRequest($method, $uri, $query, $bodyHash) {    return "$method\n$uri\n$query\n$bodyHash"; } private function buildStringToSign($canonicalRequest) {    $hash = hash('sha256', $canonicalRequest);    return "ACS3-HMAC-SHA256\n$hash"; } private function hmacSha256($source, $secret) {    return hash\_hmac('sha256', $source, $secret); } private function decrypt($key, $encrypted) {    // 需要根据实际加密方式实现    return $encrypted; // 简化处理 }

}
?>

 

Go语言实现

package main

import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"fmt"
"net/url"
"sort"
"strings"
)

type SignatureGenerator struct{}

type SignRequest struct {
HttpMethod  string
Uri         string
QueryParams map[string][]string
Body        []byte
}

func NewSignatureGenerator() *SignatureGenerator {
return &SignatureGenerator{}
}

func (sg *SignatureGenerator) GenerateSignature(req *SignRequest, secretKey string) string {
canonicalUri := sg.canonicalURI(req.Uri)
canonicalQuery := sg.canonicalQueryString(req.QueryParams)
bodyHash := sg.calculateBodyHash(req.Body)

canonicalRequest := sg.buildCanonicalRequest(
req.HttpMethod, canonicalUri, canonicalQuery, bodyHash,
)

stringToSign := sg.buildStringToSign(canonicalRequest)
decodedSecret := sg.decrypt("aqj", secretKey)

return sg.hmacSha256(stringToSign, decodedSecret)
}

func (sg *SignatureGenerator) canonicalURI(uri string) string {
if uri == "" {
return "/"
}

segments := strings.Split(uri, "/")
encodedSegments := make([]string, 0, len(segments))

for _, segment := range segments {
if segment == "" {
continue
}
encodedSegments = append(encodedSegments, sg.encodeWithRFC3986(segment))
}

return "/" + strings.Join(encodedSegments, "/")
}

func (sg *SignatureGenerator) canonicalQueryString(params map[string][]string) string {
if len(params) == 0 {
return ""
}

keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)

var buf bytes.Buffer
for _, k := range keys {
value := ""
if len(params[k]) > 0 {
value = params[k][0]
}

if buf.Len() > 0 {
buf.WriteByte('&')
}

encodedKey := sg.encodeWithRFC3986(k)
encodedValue := sg.encodeWithRFC3986(value)

buf.WriteString(encodedKey)
buf.WriteByte('=')
buf.WriteString(encodedValue)
}

return buf.String()
}

func (sg *SignatureGenerator) encodeWithRFC3986(s string) string {
var buf bytes.Buffer
for _, b := range []byte(s) {
if sg.isUnreserved(b) {
buf.WriteByte(b)
} else {
buf.WriteString(fmt.Sprintf("%%%02X", b))
}
}
return buf.String()
}

func (sg *SignatureGenerator) isUnreserved(b byte) bool {
return (b >= 'A' && b <= 'Z') ||
(b >= 'a' && b <= 'z') ||
(b >= '0' && b <= '9') ||
b == '-' || b == '_' || b == '.' || b == '~'
}

func (sg *SignatureGenerator) calculateBodyHash(body []byte) string {
if len(body) == 0 {
return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}

hash := sha256.Sum256(body)
return fmt.Sprintf("%x", hash)
}

func (sg *SignatureGenerator) buildCanonicalRequest(method, uri, query, bodyHash string) string {
return fmt.Sprintf("%s\n%s\n%s\n%s", method, uri, query, bodyHash)
}

func (sg *SignatureGenerator) buildStringToSign(canonicalRequest string) string {
hash := sha256.Sum256([]byte(canonicalRequest))
return fmt.Sprintf("ACS3-HMAC-SHA256\n%x", hash)
}

func (sg *SignatureGenerator) hmacSha256(source, secret string) string {
key := []byte(secret)
h := hmac.New(sha256.New, key)
h.Write([]byte(source))
return fmt.Sprintf("%x", h.Sum(nil))
}

func (sg *SignatureGenerator) decrypt(key, encrypted string) string {
// 需要根据实际加密方式实现
return encrypted // 简化处理
}

// 使用示例
func main() {
generator := NewSignatureGenerator()

req := &SignRequest{
HttpMethod: "POST",
Uri:        "/api/v1/users",
QueryParams: map[string][]string{
"page": {"1"},
"size": {"10"},
},
Body: []byte(`{"name":"test"}`),
}

signature := generator.GenerateSignature(req, "your_secret_key")
fmt.Printf("生成的签名: %s\n", signature)
}
 

C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>

#define MAX_URL_LEN 2048
#define MAX_QUERY_LEN 4096
#define MAX_BODY_LEN 8192
#define MAX_SIGNATURE_LEN 128
#define EMPTY_BODY_HASH "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

typedef struct {
   char key[256];
   char value[1024];
} QueryParam;

typedef struct {
   char http_method[16];
   char uri[MAX_URL_LEN];
   QueryParam query_params[64];
   int param_count;
   unsigned char *body;
   size_t body_len;
} SignRequest;

// 检查字符是否为RFC3986未保留字符
int is_unreserved(unsigned char c) {
   return (c >= 'A' && c <= 'Z') ||
          (c >= 'a' && c <= 'z') ||
          (c >= '0' && c <= '9') ||
          c == '-' || c == '_' || c == '.' || c == '~';
}

// RFC3986编码
void encode_rfc3986(const char *src, char *dest, size_t dest_size) {
   size_t src_len = strlen(src);
   size_t dest_pos = 0;

for (size\_t i = 0; i < src\_len && dest\_pos < dest\_size - 1; i++) {    unsigned char c = src[i];    if (is\_unreserved(c)) {        dest[dest\_pos++] = c;    } else {        if (dest\_pos < dest\_size - 3) {            sprintf(&dest[dest\_pos], "%%%02X", c);            dest\_pos += 3;        }    } } dest[dest\_pos] = '\0';

}

// 规范化URI
void canonical_uri(const char *uri, char *result, size_t result_size) {
   if (!uri || strlen(uri) == 0) {
       strcpy(result, "/");
       return;
   }

char temp\_uri[MAX\_URL\_LEN]; strncpy(temp\_uri, uri, sizeof(temp\_uri) - 1); temp\_uri[sizeof(temp\_uri) - 1] = '\0'; char \*segments[128]; int segment\_count = 0; // 分割路径 char \*token = strtok(temp\_uri, "/"); while (token && segment\_count < 128) {    if (strlen(token) > 0) {        segments[segment\_count++] = token;    }    token = strtok(NULL, "/"); } // 重新组合 strcpy(result, "/"); for (int i = 0; i < segment\_count; i++) {    char encoded[512];    encode\_rfc3986(segments[i], encoded, sizeof(encoded));        if (i > 0) strcat(result, "/");    strcat(result, encoded); }

}

// 比较函数用于排序
int compare_params(const void *a, const void *b) {
   const QueryParam *param_a = (const QueryParam *)a;
   const QueryParam *param_b = (const QueryParam *)b;
   return strcmp(param_a->key, param_b->key);
}

// 规范化查询参数
void canonical_query_string(QueryParam *params, int param_count, 
                          char *result, size_t result_size) {
   if (param_count == 0) {
       result[0] = '\0';
       return;
   }

// 排序参数 qsort(params, param\_count, sizeof(QueryParam), compare\_params); result[0] = '\0'; for (int i = 0; i < param\_count; i++) {    char encoded\_key[512], encoded\_value[1024];    encode\_rfc3986(params[i].key, encoded\_key, sizeof(encoded\_key));    encode\_rfc3986(params[i].value, encoded\_value, sizeof(encoded\_value));        if (i > 0) strcat(result, "&");    strcat(result, encoded\_key);    strcat(result, "=");    strcat(result, encoded\_value); }

}

// 计算SHA256哈希
void sha256_hash(const unsigned char *data, size_t len, char *output) {
   unsigned char hash[SHA256_DIGEST_LENGTH];
   SHA256(data, len, hash);

for (int i = 0; i < SHA256\_DIGEST\_LENGTH; i++) {    sprintf(output + (i \* 2), "%02x", hash[i]); } output[SHA256\_DIGEST\_LENGTH \* 2] = '\0';

}

// 计算请求体哈希
void calculate_body_hash(const unsigned char *body, size_t body_len, char *result) {
   if (!body || body_len == 0) {
       strcpy(result, EMPTY_BODY_HASH);
       return;
   }

sha256\_hash(body, body\_len, result);

}

// 构建规范化请求
void build_canonical_request(const char *method, const char *uri,
                          const char *query, const char *body_hash,
                          char *result, size_t result_size) {
   snprintf(result, result_size, "%s\n%s\n%s\n%s", 
            method, uri, query, body_hash);
}

// 构建签名字符串
void build_string_to_sign(const char *canonical_request, char *result, size_t result_size) {
   char hash[65];
   sha256_hash((const unsigned char *)canonical_request, strlen(canonical_request), hash);
   snprintf(result, result_size, "ACS3-HMAC-SHA256\n%s", hash);
}

// HMAC-SHA256签名
void hmac_sha256(const char *source, const char *secret, char *result) {
   unsigned char digest[EVP_MAX_MD_SIZE];
   unsigned int digest_len;

HMAC(EVP\_sha256(), secret, strlen(secret),     (const unsigned char \*)source, strlen(source),     digest, &digest\_len); for (unsigned int i = 0; i < digest\_len; i++) {    sprintf(result + (i \* 2), "%02x", digest[i]); } result[digest\_len \* 2] = '\0';

}

// 解密函数(需要根据实际情况实现)
void decrypt_secret(const char *key, const char *encrypted, char *result, size_t result_size) {
   // 简化处理,直接返回原值
   strncpy(result, encrypted, result_size - 1);
   result[result_size - 1] = '\0';
}

// 生成签名主函数
void generate_signature(SignRequest *req, const char *secret_key, 
                      char *signature, size_t signature_size) {
   char canonical_uri_str[MAX_URL_LEN];
   char canonical_query_str[MAX_QUERY_LEN];
   char body_hash[65];
   char canonical_request[MAX_BODY_LEN];
   char string_to_sign[MAX_BODY_LEN];
   char decoded_secret[256];

// 1. 规范化URI canonical\_uri(req->uri, canonical\_uri\_str, sizeof(canonical\_uri\_str)); // 2. 规范化查询参数 canonical\_query\_string(req->query\_params, req->param\_count,                      canonical\_query\_str, sizeof(canonical\_query\_str)); // 3. 计算请求体哈希 calculate\_body\_hash(req->body, req->body\_len, body\_hash); // 4. 构建规范化请求 build\_canonical\_request(req->http\_method, canonical\_uri\_str,                       canonical\_query\_str, body\_hash,                       canonical\_request, sizeof(canonical\_request)); // 5. 构建签名字符串 build\_string\_to\_sign(canonical\_request, string\_to\_sign, sizeof(string\_to\_sign)); // 6. 解密密钥 decrypt\_secret("aqj", secret\_key, decoded\_secret, sizeof(decoded\_secret)); // 7. 生成HMAC签名 hmac\_sha256(string\_to\_sign, decoded\_secret, signature);

}

// 使用示例
int main() {
   // 初始化请求
   SignRequest req;
   strcpy(req.http_method, "POST");
   strcpy(req.uri, "/api/v1/users");

// 添加查询参数 req.param\_count = 2; strcpy(req.query\_params[0].key, "page"); strcpy(req.query\_params[0].value, "1"); strcpy(req.query\_params[1].key, "size"); strcpy(req.query\_params[1].value, "10"); // 设置请求体 const char \*body\_str = "{\"name\":\"test\"}"; req.body = (unsigned char \*)body\_str; req.body\_len = strlen(body\_str); // 生成签名 char signature[MAX\_SIGNATURE\_LEN]; generate\_signature(&req, "your\_secret\_key", signature, sizeof(signature)); printf("生成的签名: %s\n", signature); return 0;

}
 

 

4.使用示例

 

python# Python使用示例
generator = SignatureGenerator()
signature = generator.generate_signature(
"POST",
"/api/v1/users", 
{"page": ["1"], "size": ["10"]},
b'{"name":"test"}',
"your_secret_key"
)
print(f"生成的签名: {signature}")

 

 

5.注意事项

 

密钥解密: decrypt函数需要根据实际的加密算法实现
字符编码: 确保所有字符串使用UTF-8编码
参数处理: 查询参数需要按字母顺序排序
空值处理: 空请求体使用固定的SHA-256值
错误处理: 实际使用中需要添加完整的异常处理机制

 

×
×