# 处理敏感数据

当你需要处理 getUserInfo 接口请求到的敏感数据时，可以参考本文进行操作。敏感数据的处理分为校验数据合法性、解密敏感数据两个步骤。

## 操作步骤

1. 校验数据合法性。

当你通过 [getUserInfo](https://open.feishu.cn/document/uYjL24iN/ucjMx4yNyEjL3ITM) 接口请求到敏感数据时，返回的`signature`字段是在小程序服务器端内，通过以下算法获取。

```
    signature = sha1(`${rawData}${base64(session_key)}`)
    ```

相应的，你可以在自己的服务器端执行同样的算法，校验数据是否合法。

2. 解密敏感数据。

本步骤主要说明解密数据的方式，具体的代码配置可参见下文的[示例代码](https://open.feishu.cn/document/uYjL24iN/ugjMx4COyEjL4ITM#b6512f46)。

- 对称解密使用的算法为 `AES-128-CBC`，数据采用 `PKCS#5` 填充。
    - 对称解密的目标密文为 `encryptedData`。
    - 对称解密秘钥 `aeskey = Base64_Decode(session_key)`，`aeskey` 长度为 16 Byte。
    - 对称解密算法初始向量为 `Base64_Decode(iv)`。

## 示例代码
示例代码中的 `sessionKey` 为会话密钥， 由 [code2session](https://open.feishu.cn/document/uYjL24iN/ukjM04SOyQjL5IDN) 返回。

### Node.js

```js
const crypto = require("crypto");

sessionKey = '36f764e22be7fc5edb07f56073a4xxxx';
iv = 'f210af090c830cd5c47e67eeb4f5xxxx';
message = 'Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypxxxxODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s=';
function decrypt_with_aes() {
    message = Buffer.from(message, 'base64');
    const decipher = crypto.createDecipheriv(
        'aes-128-cbc',
        Buffer.from(sessionKey, 'hex'),
        Buffer.from(iv, 'hex'),
    );
    let decrypted = decipher.update(message);
    decrypted += decipher.final();
    const data = decrypted.toString();
    const json = JSON.parse(data);
    return json;
}
console.log(decrypt_with_aes())
```

### Java 语言

```JAVA
import org.junit.jupiter.api.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class DecryptTest {
    @Test
    public void test_decrypt() throws Exception {
        System.out.println(decrypt_with_aes());
    }

public static String decrypt_with_aes() throws Exception {

String session_key = "36f764e22be7fc5edb07f56073a4xxxx";
        String iv = "f210af090c830cd5c47e67eeb4f5xxxx";
        String message = "Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypxxxxODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s=";

Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(hexToBytes(session_key), "AES"), new IvParameterSpec(hexToBytes(iv)));

byte[] r = cipher.doFinal(Base64.getDecoder().decode(message));

byte lastByte = r[r.length - 1];
        if (lastByte <= 16) {
            byte[] rr = new byte[r.length - lastByte];
            System.arraycopy(r, 0, rr, 0, rr.length);
            r = rr;
        }

return new String(r);
    }

private static byte[] hexToBytes(String s) {
        s = s.toLowerCase();
        String hexVal = "0123456789abcdef";
        byte[] out = new byte[s.length() / 2];

int n = s.length();
        for (int i = 0; i < n; i += 2) {
            int hn = hexVal.indexOf(s.charAt(i));
            int ln = hexVal.indexOf(s.charAt(i + 1));
            out[i / 2] = (byte) ((hn << 4) | ln);
        }
        return out;
    }
}
``` 

### Golang 语言

```go
import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"testing"
)

func decrypt_with_aes(message_ string, sessionKey_ string, iv_ string) (string, error) {
	sessionKey, err := hex.DecodeString(sessionKey_)
	if err != nil {
		return "", err
	}

iv, err := hex.DecodeString(iv_)
	if err != nil {
		return "", err
	}

message, err := base64.StdEncoding.DecodeString(message_)
	if err != nil {
		return "", err
	}

block, err := aes.NewCipher(sessionKey)
	if err != nil {
		return "", err
	}

res := make([]byte, len(message))
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(res, message)

unpaddingLen := 0
	if p := res[len(res)-1]; p <= 16 {
		unpaddingLen = int(p)
	}

res = res[0 : len(res)-unpaddingLen]
	return string(res), nil
}

func TestAES(t *testing.T) {
	session_key := "36f764e22be7fc5edb07f56073a4xxxx"
	iv := "f210af090c830cd5c47e67eeb4f5xxxx"
	message := "Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypxxxxODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s="

fmt.Println(decrypt_with_aes(message, session_key, iv))
}
```

### Python3 语言

```python
import base64
import json
from Crypto.Cipher import AES

def decrypt_with_aes():
    session_key = '36f764e22be7fc5edb07f56073a4xxxx';
    iv = "f210af090c830cd5c47e67eeb4f5xxxx";
    message = "Ssy006/cEV4+a2wUWTGvHuXIkU+vX1KCNUkLntKKVXzggx6yfycO/RDkx55A8TvhI5EUGKJ8X4x3NBCypxxxxODaCSDw6uUBhqbDaRS9vH57Dk9nVcw+u2ANGU4PmW/WX2ihze8hDMpofD/pDfZCkEjnvmqkeZ+jPxq351bpDwTUJ+mae92iL9DuHd+xz6WC5cUx9HE8AbxUD18dGUwt2KcNNi9ePvgcvGZBEgZGG2s=";
    session_key = bytes.fromhex(session_key)
    iv = bytes.fromhex(iv)
    message = base64.b64decode(message)
    print(session_key, len(session_key), type(session_key))
    print(len(message))
    decipher = AES.new(session_key, AES.MODE_CBC, iv)
    decodedMessage = decipher.decrypt(message)
    unpad = lambda s: s[0:-s[-1]]
    decodedMessage = unpad(decodedMessage)
    data = json.loads(decodedMessage)
    return data

print(decrypt_with_aes())
```