> ## Documentation Index
> Fetch the complete documentation index at: https://developer.gcashier.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticate Requests with RSA and AES Encryption

> Understand Gcashier Pay's dual-key security model: AES payload encryption, RSA session-key protection, SHA1withRSA signing, and the accessToken for advanced APIs.

Every message you exchange with Gcashier Pay is protected by three overlapping security mechanisms working together. AES/ECB/PKCS7Padding encrypts the JSON payload itself so the body stays confidential in transit. RSA/ECB/PKCS1Padding wraps the ephemeral AES session key so only the intended recipient can recover it. SHA1withRSA signs the plaintext payload so neither party can tamper with the message without detection. Understanding how these three layers interact is the foundation for a correct integration.

## Algorithms at a glance

| Concern                | Algorithm            | Key size            |
| ---------------------- | -------------------- | ------------------- |
| Payload encryption     | AES/ECB/PKCS7Padding | 128-bit session key |
| Session key protection | RSA/ECB/PKCS1Padding | 2048-bit RSA        |
| Message signing        | SHA1withRSA          | 2048-bit RSA        |
| Transport              | HTTPS 1.2            | —                   |
| Text encoding          | UTF-8                | —                   |
| Content-Type           | `application/json`   | —                   |

## POST parameters

Every API call is a single HTTPS POST. The request body carries exactly four top-level fields:

| Parameter    | Type   | Description                                                                                                                   |
| ------------ | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `merchantNo` | String | Your unique merchant identifier, assigned during onboarding. Included in plaintext so the server can look up your public key. |
| `jsonEnc`    | String | Base64-encoded AES ciphertext of your JSON payload.                                                                           |
| `keyEnc`     | String | HEX-encoded RSA ciphertext of the Base64 AES session key. Encrypted with the **recipient's** RSA public key.                  |
| `sign`       | String | HEX-encoded SHA1withRSA signature over the JSON **plaintext**, computed with the **sender's** RSA private key.                |

<Note>
  `merchantNo` travels in plaintext intentionally — Gcashier Pay uses it to retrieve your RSA public key for signature verification before decrypting anything.
</Note>

## Request and response envelope

Before encryption, every payload shares a common JSON envelope with `head` and `body` sections.

### Request structure

```json theme={null}
{
  "head": {
    "version": "1.0.0",
    "tradeType": "00",
    "tradeTime": "1551341750",
    "tradeCode": "sp1301",
    "language": "cn"
  },
  "body": {
    "...": "API-specific fields go here"
  }
}
```

### Response structure

```json theme={null}
{
  "head": {
    "version": "1.0.0",
    "tradeType": "01",
    "tradeTime": "1551341750",
    "tradeCode": "sp1301",
    "language": "cn",
    "respCode": "S00000",
    "respDesc": "Success"
  },
  "body": {
    "...": "API-specific Response Body"
  }
}
```

### Head field reference

| Field       | Direction     | Type   | Description                                                            |
| ----------- | ------------- | ------ | ---------------------------------------------------------------------- |
| `version`   | Both          | String | API version. Current value: `"1.0.0"`.                                 |
| `tradeType` | Both          | String | `"00"` for requests; `"01"` for responses.                             |
| `tradeTime` | Both          | String | Unix timestamp (10-digit seconds). Echo'd back in responses.           |
| `tradeCode` | Both          | String | Identifies the API operation (e.g. `"sp1301"` for RMB payment).        |
| `language`  | Both          | String | Response language preference. `"cn"` for Chinese, `"en"` for English.  |
| `respCode`  | Response only | String | Result code. `"S00000"` = success; all other values indicate an error. |
| `respDesc`  | Response only | String | Human-readable description of `respCode`.                              |

<Warning>
  Always check `respCode` before reading `body` fields in a response. A non-`S00000` code means the body may be empty or contain only partial data.
</Warning>

## Outgoing request: encryption and signing

The following steps describe exactly what you must do to build a valid outgoing request.

<Steps>
  <Step title="Build the JSON plaintext">
    Assemble your complete request object — `head` plus all required `body` fields for the target API operation. Serialize it to a UTF-8 JSON string. This is the value you sign and then encrypt.

    ```json theme={null}
    {
      "head": {
        "version": "1.0.0",
        "tradeType": "00",
        "tradeTime": "1672531200",
        "tradeCode": "sp1301",
        "language": "en"
      },
      "body": {
        "merchantNo": "M10000001",
        "orderNo": "ORD20240101001",
        "amount": "100.00",
        "currency": "USD"
      }
    }
    ```
  </Step>

  <Step title="Sign the plaintext with SHA1withRSA → HEX">
    Compute a digital signature over the JSON plaintext using your RSA private key and the SHA1withRSA algorithm. Encode the raw signature bytes as a lowercase HEX string. This becomes the `sign` POST parameter.

    ```
    sign = HEX( SHA1withRSA_sign( jsonPlaintext, yourPrivateKey ) )
    ```

    <Tip>
      Sign the **plaintext** — not the encrypted ciphertext. Gcashier Pay verifies the signature after decrypting, against the recovered plaintext.
    </Tip>
  </Step>

  <Step title="Generate an AES session key → Base64">
    Use a cryptographically secure random generator to produce a fresh 128-bit AES key for this request. Base64-encode the raw key bytes. This is your session key `SK`.

    ```
    SK = Base64( randomBytes(16) )
    ```

    A new `SK` must be generated for every request. Reusing session keys undermines forward secrecy.
  </Step>

  <Step title="Encrypt the JSON plaintext with SK → Base64">
    Encrypt the JSON plaintext bytes using AES/ECB/PKCS7Padding with the session key `SK`. Base64-encode the resulting ciphertext. This becomes the `jsonEnc` POST parameter.

    ```
    jsonEnc = Base64( AES_ECB_PKCS7_encrypt( jsonPlaintext, SK ) )
    ```
  </Step>

  <Step title="Encrypt SK with Gcashier Pay's RSA public key → HEX">
    Encrypt the Base64-encoded session key string using Gcashier Pay's RSA public key with RSA/ECB/PKCS1Padding. HEX-encode the resulting ciphertext. This becomes the `keyEnc` POST parameter.

    ```
    keyEnc = HEX( RSA_PKCS1_encrypt( SK, gcashierPayPublicKey ) )
    ```
  </Step>

  <Step title="POST the four parameters">
    Submit an HTTPS POST with `Content-Type: application/json` to the target endpoint. The request body must contain exactly these four fields:

    ```json theme={null}
    {
      "merchantNo": "M10000001",
      "jsonEnc":    "<Base64 AES ciphertext>",
      "keyEnc":     "<HEX RSA-encrypted session key>",
      "sign":       "<HEX SHA1withRSA signature>"
    }
    ```
  </Step>
</Steps>

## Incoming response: decryption and verification

When Gcashier Pay responds, you receive the same four-field envelope. Process it in this order:

<Steps>
  <Step title="Recover the session key from keyEnc">
    HEX-decode the `keyEnc` value to get the raw encrypted bytes, then decrypt those bytes with **your own RSA private key** using RSA/ECB/PKCS1Padding. The result is the Base64-encoded session key `SK`.

    ```
    SK = RSA_PKCS1_decrypt( HEX_decode( keyEnc ), yourPrivateKey )
    ```
  </Step>

  <Step title="Decrypt the payload from jsonEnc">
    Base64-decode both `jsonEnc` and `SK` to their raw byte forms, then apply AES/ECB/PKCS7Padding decryption. The result is the UTF-8 JSON plaintext.

    ```
    jsonPlaintext = AES_ECB_PKCS7_decrypt( Base64_decode( jsonEnc ), Base64_decode( SK ) )
    ```
  </Step>

  <Step title="Verify the signature from sign">
    HEX-decode the `sign` value to get the raw signature bytes, then verify those bytes against the recovered JSON plaintext using **Gcashier Pay's RSA public key** and SHA1withRSA.

    ```
    valid = SHA1withRSA_verify( jsonPlaintext, HEX_decode( sign ), gcashierPayPublicKey )
    ```

    <Warning>
      Always verify the signature before trusting any field in the decrypted response. A failed verification means the message was tampered with in transit and must be discarded.
    </Warning>
  </Step>
</Steps>

## The `merchantNo` field

Your `merchantNo` is assigned by Gcashier Pay during merchant onboarding. It appears as both a top-level POST parameter (in plaintext) and often as a field inside the encrypted `body` for certain API operations. The plaintext copy allows Gcashier Pay to resolve your public key before performing any cryptographic operation.

## The `accessToken` field

Some APIs — particularly FX trading and workflows that follow merchant onboarding — require an additional `accessToken` field inside the `head` object of the encrypted payload.

```json theme={null}
{
  "head": {
    "version": "1.0.0",
    "tradeType": "00",
    "tradeTime": "1672531200",
    "tradeCode": "sp1202",
    "language": "en",
    "accessToken": "eyJhbGciOiJSUzI1NiJ9..."
  },
  "body": { "..." : "..." }
}
```

You obtain an `accessToken` after your merchant account has been approved through the onboarding API. The token proves your merchant entity has been verified and is required for operations that carry regulatory or financial risk. When an `accessToken` is required, the individual API reference page will say so explicitly.

<Tip>
  Store your `accessToken` securely and refresh it according to its expiry. Passing an expired or invalid token returns an authentication error in `respCode`, not an HTTP 4xx status.
</Tip>
