# Security

### Request Signature

**1、Request header**

| Name                                           | Type   | Description                      |
| ---------------------------------------------- | ------ | -------------------------------- |
| Content-Type<mark style="color:red;">\*</mark> | string | application/json; chartset=UTF-8 |

**2、Request body**

<pre class="language-javascript" data-full-width="false"><code class="lang-javascript"><strong>{
</strong>    "app_id": "2017051914172236111",
    "partner_id": "000000000000001",
    "timestamp": "2011-09-23 04:24:03",
    "version": "1.0",
    "request_id": "bO8lENHnboElE",
    "sign_type": "RSA",
    "random_key": "OvUp0Z7zhLfYdBR1lOKLfYdBR1lOKLfYdBR1lOK", //need to be encrypted
    "biz_data": "Z7zhLfYdBR1lOKLfYdBR7zhLfYdBR1lOKLfYdBR" //need to be encrypted
}
</code></pre>

**3、Signature**

`randomKey:` A randomly generated 16-byte **AES key**, encrypted with **Pagsmile RSA public key** (2048-bit).

{% hint style="info" %}
Pagsmile RSA public key is available in your app’s configuration of the **Pagsmile Dashboard**.
{% endhint %}

`biz_Data:` Encrypted data, secured with the randomly generated **AES key**.

### Response Signature

**1、Response body**

{% code fullWidth="false" %}

```javascript
{
    "code": "10000",
    "msg": "Success",
    "data": { }, //need to be decrypted
    "random_key":"OvUp0Z7zhLfYdBR1lOK/F1fE0jKGiwsIea9XD9urkav",//need to be decrypted
    "total":1,
    "sign_type": "RSA",
    "app_id": "2017051914172236111"
}
```

{% endcode %}

**2、Signature**

`random_key:` Decrypt using the **Merchant RSA private key**.

{% hint style="info" %}
The response is encrypted with your **Merchant RSA Public Key**. Please ensure that you have updated the **Merchant RSA Public Key** in your app’s configuration of the **Pagsmile Dashboard.**
{% endhint %}

`data:` Use the decrypted **AES key** to decode the message content.

### Example &#x20;

{% tabs %}
{% tab title="JAVA" %}

<pre><code><strong>
</strong>public class CryptoUtil {
    private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
    public static IvParameterSpec generateIvValue() {
        return new IvParameterSpec(generateRandom16Chars().getBytes());
    }
    private static String generateRandom16Chars() {
        byte[] array = new byte[8];
        SecureRandom random = new SecureRandom();
        random.nextBytes(array);
        return bytesToHex(array);
    }
    private static String bytesToHex(byte[] bytes) {
        byte[] hexChars = new byte[bytes.length * 2];
        for (int j = 0; j &#x3C; bytes.length; j++) {
            int v = bytes[j] &#x26; 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v &#x26; 0x0F];
        }
        return new String(hexChars, StandardCharsets.UTF_8);
    }
}

public class CryptoExample {

    //encrypt random_key
    public static String encryptSecret(PublicKey publicKey, String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // PKCS1 or OAEP padding "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" can be used
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedSign = cipher.doFinal(secret.getBytes());
        return Base64.getEncoder().encodeToString(encryptedSign);
    }
    //encrypt biz_data
    public static String encryptContentMode(String content, String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        IvParameterSpec iv = CryptoUtil.generateIvValue();
        SecretKey secretKey = new SecretKeySpec(secret.getBytes(), "AES");
        Cipher dataCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        dataCipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        byte[] encryptedDataBytes = dataCipher.doFinal(content.getBytes());
        return new String(iv.getIV()) + Base64.getEncoder().encodeToString(encryptedDataBytes);
    }
    //decrypt random_key
    public static String decryptSecretMode(PrivateKey privateKey, String sign) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        byte[] encryptedDataBytes = Base64.getDecoder().decode(sign);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // PKCS1 or OAEP padding "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" can be used
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] secretByte = cipher.doFinal(encryptedDataBytes);
        return new String(secretByte);
    }
    //decrypt data
    public static String decryptContentMode(String encryptedContent, String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        String ivString = encryptedContent.substring(0, 16);
        String correctEncryptedData = encryptedContent.substring(16);
        byte[] encryptedDataBytes = Base64.getDecoder().decode(correctEncryptedData);
        IvParameterSpec iv = new IvParameterSpec(ivString.getBytes());
        SecretKey secretKey = new SecretKeySpec(secret.getBytes(), "AES");
        Cipher dataCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        dataCipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
        byte[] decryptedDataBytes = dataCipher.doFinal(encryptedDataBytes);
        return new String(decryptedDataBytes);
    }
}
</code></pre>

{% endtab %}

{% tab title="PHP" %}
**Encryption algorithm in PHP-**&#x65;ncrypt with RSA Public Key

```
<?php

// public key
$publicKey = 'public key';

function encryptSecret(string $secret, string $publicKey): string
{

    openssl_public_encrypt($secret, $encryptedData, $publicKey, OPENSSL_PKCS1_PADDING);

    return base64_encode($encryptedData);
}

function encryptContent(string $content, string $secret): string
{
    $iv = bin2hex(random_bytes(8));
    $encryptedData = openssl_encrypt($content, 'aes-256-cbc', $secret, OPENSSL_RAW_DATA, $iv);

    return $iv.base64_encode($encryptedData);
}

// usage
$secret = 'RandomString32CharactersLength12'; // 32 characters; must be randomly generated for every response 
$random_key = encryptSecret($secret, $publicKey); // add to 'random_key'
$biz_data = '{"responseCode":"00","billingAmount":"11186","holderAmount":"11186","availableBalance":100008814,"settledBalance":100020000}';
$encryptedContent = encryptContent($content, $secret); // set this to be the response body

// Optional outputs that show the result
echo $sign.PHP_EOL;
echo $encryptedContent.PHP_EOL;
```

**Decryption algorithm in PHP**

```
<?php

// Client private key
$privateKey = 'insert your private key here';
$encryptedContent = 'raw response body'; // Get from the webhook body

function decryptSecret(string $sign, string $privateKey): string
{

    openssl_private_decrypt(base64_decode($sign), $secret, $privateKey, OPENSSL_PKCS1_PADDING);

    return $secret;
}

function decryptContent(string $encryptedContent, string $secret): string
{
    $iv = substr($encryptedContent, 0, 16);
    $encryptedData = base64_decode(substr($encryptedContent, 16));

    return openssl_decrypt($encryptedData, 'aes-256-cbc', $secret, OPENSSL_RAW_DATA, $iv);
}

// usage
$decryptedSecret = decryptSecret($sign, $privateKey);
$decryptedContent = decryptContent($encryptedContent, $decryptedSecret);

// Optional output that shows the result
echo $decryptedContent.PHP_EOL;
```

{% endtab %}

{% tab title="C#" %}
**Encryption algorithm in C# (encrypt with RSA public key)**

```

// ISAC public key
string publicKey = "insert ISAC public key here";

static string EncryptSecret(string secret, string publicKey)
{
    var encryptEngine = new Pkcs1Encoding(new RsaEngine());
    using (var reader = new StringReader(publicKey))
    {
        encryptEngine.Init(true, (AsymmetricKeyParameter)new PemReader(reader).ReadObject());
    }

    var data = Encoding.UTF8.GetBytes(secret);
    var encryptedData = encryptEngine.ProcessBlock(data, 0, data.Length);

    return Convert.ToBase64String(encryptedData);
}

static string EncryptContent(string content, string secret)
{
    var iv = Hex.Encode(new SecureRandom().GenerateSeed(8));

    var cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7PADDING");
    var keyParam = new KeyParameter(Encoding.UTF8.GetBytes(secret));
    var keyParamWithIv = new ParametersWithIV(keyParam, iv, 0, 16);
    cipher.Init(true, keyParamWithIv);

    var encryptedData = cipher.DoFinal(Encoding.UTF8.GetBytes(content));

    return Encoding.UTF8.GetString(iv) + Convert.ToBase64String(encryptedData);
}

string secret = "RandomString32CharactersLength12"; // 32 characters; must be randomly generated for every response
string sign = EncryptSecret(secret, publicKey); //
string bizData = "{"responseCode":"00","billingAmount":"11186","holderAmount":"11186","availableBalance":100008814,"settledBalance":100020000}";
string encryptedContent = EncryptContent(content, secret); // set this to be the response body
// Optional outputs that show the result
Console.WriteLine(sign);
Console.WriteLine(encryptedContent);

```

**Decryption algorithm in C#**&#x20;

```

// Client private key
string privateKey = "Client private key";

string sign = "response"; // Get from response 'random_Key'
string encryptedContent = "raw response body"; // Get from Get from response 'data'

static string DecryptSecret(string sign, string privateKey)
{
    var encryptEngine = new Pkcs1Encoding(new RsaEngine());
    using (var reader = new StringReader(privateKey))
    {
        decryptEngine.Init(false, (AsymmetricKeyParameter)new PemReader(reader).ReadObject());
    }

    var data = Convert.FromBase64String(sign);
    var decryptedData = decryptEngine.ProcessBlock(data, 0, data.Length);

    return Encoding.UTF8.GetString(decryptedData);
}

static string DecryptContent(string encryptedContent, string secret)
{
    var iv = Encoding.UTF8.GetBytes(encryptedContent.Substring(0, 16));
    var encryptedData = Convert.FromBase64String(encryptedContent.Substring(16));

    var cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7PADDING");
    var keyParam = new KeyParameter(Encoding.UTF8.GetBytes(secret));
    var keyParamWithIv = new ParametersWithIV(keyParam, iv, 0, 16);
    cipher.Init(false, keyParamWithIv);

    var data = cipher.DoFinal(encryptedData);

    return Encoding.UTF8.GetString(data);
}

// usage
string decryptedSecret = DecryptSecret(sign, privateKey);
string decryptedContent = DecryptContent(encryptedContent, decryptedSecret);

// Optional output that shows the result
Console.WriteLine(decryptedContent);
```

<br>
{% endtab %}

{% tab title="NodeJs" %}
**Encryption algorithm in Node.js (encrypt with RSA public key)**

```
// Import necessary modules
const crypto = require('crypto');

// ISAC public key
const publicKey = `insert public key here`;

function encryptSecret(secret, publicKey) {
    const encryptedData = crypto.publicEncrypt({
        key: publicKey,
        padding: crypto.constants.RSA_PKCS1_PADDING
    }, Buffer.from(secret));

    return encryptedData.toString('base64');
}

function encryptContent(content, secret) {
    const iv = crypto.randomBytes(8).toString('hex');
    const cipher = crypto.createCipheriv('aes-256-cbc', secret, iv);

    let encryptedData = cipher.update(content, 'utf8', 'base64');
    encryptedData += cipher.final('base64');

    return iv + encryptedData;
}
// usage
const secret = 'RandomString32CharactersLength12'; // 32 characters; must be randomly generated for every response to a webhook
const sign = encryptSecret(secret, publicKey); // add to 'random_key'
const content = `{"responseCode":"00","billingAmount":"11186","holderAmount":"11186","availableBalance":100008814,"settledBalance":100020000}`;
const encryptedContent = encryptContent(content, secret); //  add to 'biz_data'

console.log(sign);
console.log(encryptedContent);
```

**Decryption algorithm in Node.js**&#x20;

```
// Import necessary modules
const crypto = require('crypto');

//  private key
const publicKey = `insert your private key here`;
const sign = ``; // Get from response as 'random_key'
const encryptedContent = `raw response body`; // Get from response as 'data'

function decryptSecret(sign, privateKey) {
    const decryptedData = crypto.privateDecrypt({
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_PADDING
    }, Buffer.from(sign, 'base64'));

    return decryptedData.toString();
}

function decryptContent(encryptedContent, secret) {
    const iv = encryptedContent.slice(0, 16);
    const encryptedData = Buffer.from(encryptedContent.slice(16), 'base64');

    const decipher = crypto.createDecipheriv('aes-256-cbc', secret, iv);
    decipher.setAutoPadding(false);
    let decryptedData = decipher.update(encryptedData);
    decryptedData = Buffer.concat([decryptedData, decipher.final()]);

    return decryptedData.toString();
}
// usage
decryptedSecret = decryptSecret(sign, privateKey);
decryptedContent = decryptContent(encryptedContent, decryptedSecret);
console.log(decryptedContent);
```

<br>
{% endtab %}

{% tab title="Python" %}
**Encryption algorithm Python (encrypt with RSA public key)**

```
def encrypt_secret(public_key_pem: str, secret: str) -> str:

    rsa_key = RSA.import_key(public_key_pem)

    cipher = PKCS1_v1_5.new(rsa_key)
    encrypted_sign = cipher.encrypt(secret.encode('utf-8'))

    return base64.b64encode(encrypted_sign).decode('utf-8')


def encrypt_content(content, secret):
    iv = os.urandom(8).hex()

    cipher = AES.new(secret.encode(), AES.MODE_CBC, iv.encode())
    encrypted_data = cipher.encrypt(pad(content.encode(), AES.block_size))

    return iv + base64.b64encode(encrypted_data).decode()
   
 
def decrypt_secret(sign, private_key):
    private_key = PKCS1_v1_5.new(RSA.import_key(private_key))

    return private_key.decrypt(base64.b64decode(sign)).decode()

def decrypt_content(encrypted_content, secret):
    iv = encrypted_content[:16]
    encrypted_data = base64.b64decode(encrypted_content[16:])

    cipher = AES.new(secret.encode(), AES.MODE_CBC, iv.encode())
    data = unpad(cipher.decrypt(encrypted_data), AES.block_size)

    return data.decode()
```

{% endtab %}
{% endtabs %}

### &#x20;        &#x20;

```
```
