English
Request Signing
Algorithm and keys
- Digest:
SHA-256 - Signature:
ECDSA ES256(curveP-256+SHA-256; signature value is DER, then Base64) - Key generation:
bash
openssl ecparam -name prime256v1 -genkey -noout -out priKey.pem
openssl ec -in priKey.pem -pubout -out pubKey.pem
# Recommended: convert to PKCS#8
openssl pkcs8 -topk8 -nocrypt -in priKey.pem -out priKey_pkcs8.pemKeep the private key for signing; submit the public key to the platform for verification.
Digest
text
Digest = "SHA-256=" + Base64(SHA256(raw_body_bytes))POST/PUT/PATCH: hash the exact raw HTTP body bytes that will be sent (do not re-serialize JSON)GET/DELETE: hash an empty byte string
Canonical Signing String
Exactly these 4 lines, in this order; lowercase field names; one space after the colon; \n (LF) line breaks:
text
(request-target): <lowercase-method> <path>[?<query>]
x-timestamp: <X-Timestamp>
x-nonce: <X-Nonce>
digest: <Digest>Example:
text
(request-target): post /coin/v1/exchange/quote
x-timestamp: 1710000000
x-nonce: a9f3c1d47e8b9a2c
digest: SHA-256=Base64DigestValueAuthorization
text
hashBytes = SHA256(UTF8(canonicalString))
signature = ECDSA_SIGN_DER(privateKey, hashBytes)
signatureB64 = Base64(signature)
Authorization =
Signature keyId="<X-Merchant-Id>",alg="ES256",headers="(request-target) x-timestamp x-nonce digest",signature="<signatureB64>"Server verification and replay protection
- Verify
Digestmatches the raw body - Rebuild the Canonical String and verify
Authorization.signature X-Timestampwindow:±300sX-Nonceanti-replay: the sameX-Merchant-Id + X-Noncemust not repeat within 5 minutes
