MAC Signature Generation and Validation
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The MAC (Message Authentication Code) signature is a critical security feature within the ZaloPay integration. Its primary purpose is to ensure the integrity and authenticity of data exchanged between this application and the ZaloPay gateway. It guarantees that the request data has not been tampered with and that the request originates from a trusted source.
This system uses HMAC-SHA256 (Hash-based Message Authentication Code with SHA-256) for both generating signatures for outgoing payment requests and for validating the signatures of incoming callbacks from ZaloPay. The process involves concatenating specific request parameters into a single string, which is then hashed with a secret key. Two distinct secret keys are used: one for creating orders (key1) and another for validating callbacks (key2).
Sources: helper/crypto.go, controller/payment.go, gateway/zalopay.go
Core Cryptographic Function
The foundation of the MAC signature mechanism is the HmacSHA256 function. This utility function is responsible for creating the HMAC-SHA256 hash.
Sources: helper/crypto.go:5-11
Hashing Logic
The function takes a data string and a secret key as input and produces a hexadecimal string representation of the hash.
This diagram illustrates the process within the HmacSHA256 function.
Sources: helper/crypto.go:5-11
Implementation
// helper/crypto.go:5-11
func HmacSHA256(data string, key string) string {
mac := hmac.New(sha256.New, []byte(key))
mac.Write([]byte(data))
return hex.EncodeToString(mac.Sum(nil))
}
This code snippet shows the direct implementation using Go's standard crypto/hmac, crypto/sha256, and encoding/hex libraries.
Sources: helper/crypto.go:5-11
Signature Generation for Order Creation
When a user initiates a payment, the application sends a "create order" request to the ZaloPay gateway. A MAC signature must be generated and included in this request.
Sources: gateway/zalopay.go:21-59, controller/payment.go:17-36
Data Flow
The following sequence diagram shows the process from an API call to the final request sent to ZaloPay.
This diagram shows how the controller uses the gateway to build and sign the request before sending it to the ZaloPay API.
Sources: controller/payment.go:17-36, gateway/zalopay.go:21-59
MAC Data String Composition
The MAC signature for order creation is generated from a specific set of fields concatenated with a | delimiter. The secret key used for this operation is key1.
| Field | Description | Source |
|---|---|---|
app_id | The application's unique ID. | gateway/zalopay.go:40 |
app_trans_id | The application's transaction ID. | gateway/zalopay.go:41 |
app_user | The user ID within the application. | gateway/zalopay.go:42 |
amount | The transaction amount. | gateway/zalopay.go:43 |
app_time | The timestamp of the transaction (ms). | gateway/zalopay.go:44 |
embed_data | JSON string of additional data. | gateway/zalopay.go:45 |
item | JSON string representing the items. | gateway/zalopay.go:46 |
The final data string is constructed as follows:
app_id + "|" + app_trans_id + "|" + app_user + "|" + amount + "|" + app_time + "|" + embed_data + "|" + item
Sources: gateway/zalopay.go:39-48
Signature Validation for Callbacks
After a transaction's status changes, ZaloPay sends a POST request to the application's /callback endpoint. The application must validate the MAC signature in this callback to ensure it is a legitimate notification from ZaloPay.
Sources: controller/payment.go:38-60
Validation Logic
The validation process involves re-computing the MAC signature using the data from the callback and comparing it to the signature provided by ZaloPay. A different secret key, key2, is used for this validation.
This flowchart details the steps taken within the Callback controller to verify an incoming notification from ZaloPay.
Sources: controller/payment.go:46-56
Implementation Details
The Callback function in controller/payment.go handles this logic.
- It binds the incoming JSON to a
CallbackRequeststruct. - It retrieves the
dataandmacfields from the request. - It calls
helper.HmacSHA256with thedatastring and the configuredkey2. - It performs a constant-time comparison between the received MAC and the generated MAC.
- If they do not match, it returns an error. Otherwise, it proceeds with processing the payment update.
// controller/payment.go:49-56
// check mac
reqMac := req.Mac
mac := helper.HmacSHA256(req.Data, c.zp.Key2)
// invalid mac
if reqMac != mac {
ctx.JSON(http.StatusOK, gin.H{
"return_code": -1,
"return_message": "mac not match",
})
return
}
This snippet shows the core validation logic. Using key2 is essential for the callback validation process.
Sources: controller/payment.go:49-56, gateway/zalopay.go:16
Configuration
The MAC generation and validation rely on several configuration values that are initialized when the application starts.
| Parameter | Description | Source File |
|---|---|---|
AppID | The application ID provided by ZaloPay. | gateway/zalopay.go:14 |
Key1 | The secret key for signing order creation requests. | gateway/zalopay.go:15 |
Key2 | The secret key for validating callback requests. | gateway/zalopay.go:16 |
These values are loaded from environment variables and used to instantiate the ZaloPayGateway.
Sources: main.go:21-27, gateway/zalopay.go:10-18
Summary
The MAC signature mechanism is a cornerstone of the security model for integrating with ZaloPay. It leverages the standard HMAC-SHA256 algorithm to protect against data tampering and ensure message authenticity. The system correctly segregates duties by using two different secret keys: key1 for signing outgoing requests to create payments and key2 for validating the authenticity of incoming callbacks from ZaloPay. This dual-key approach enhances security by limiting the exposure of any single key.
Sources: helper/crypto.go, controller/payment.go, gateway/zalopay.go