Encrypt Key 加解密
使用 Encrypt Key 加密数据
如果你对消息内容的安全级别要求较高,可以通过与伙伴云约定密钥的方式进行消息加密。伙伴云推送事件时会使用该密钥对消息内容做对称加密。
企业可在企业后台的“接口授权”中的每个 API Key 上设置回调地址的 Encrypt Key ,服务商可调用“设置订阅回调地址”的接口设置回调地址的 Encrypt Key。
如果设置了 Encrypt Key ,事件推送的请求将会变成:
{
"encrypted": "oIMJ+3ruZZPVl4NICT//1RGfYT3+EmN7VxptWNIZEan5tLjbJj7eXm4UdU9pJdj6agSUOR3KIg6Le/wKpAqC/qXkJbs5C0Iiep4iXYY5Z4UXx1BavNuRiTtA+ET+4NcMXJjnbTJNV8Mq5lpXOGymSctfSkcPOIcCKeZWq1UG8796WdRyfZaouTb9qWLairar4LhuS0PCWgry7PlTTxQluLHPoHHT0KKXiKZcI8UpO+FNwc1J35ZHffi4ut9PpIC7+JicpYcVbVjWDLKTl67ER2vDbgfgYPacC1kbbXqc7mze2AygtFXy84Lc9yIPYC43BFyoEtMINvdrnCM1c1vcK0JXkemPgMNPCKFGIyghc9T7vTpgFhIQoxLG1y/iTpYkxCXxZ7GeXiF+ntcr4ZQptb30J7TMAnCSCemrFGCdoFfH5sAdtd2OP0NqAH8mxmrOUTwRF8Zqo4Ad9aEOO6ZevQjEDxLbJW+lKehf6qqqDk72JoGW++SyOHhXu4C164s3HZknhSuU5eFPtNR4tUUrowjJ8btJrr+3m69tMR39mkxIZI0BeQiwkjqSSA4PxglljR0zIt7ABA62nNSyU4g9UvydSUZCUTb6GNr1bqx+pD9mY+CEMERXiGOG9n+xkz9ZRZf0qAqQBuotiDYrwF3tAo8vRCB0zifWAX60IUmNkM+i0kLXtCS+1aXMRYbu67tH+FonQbu+PiF8o9GJn1UazsH8vWK5E0wiOARw3X/cK2AxD+n/IGamUJZykPrKLrBeqQoOfAEqeDgu38IqZGxqATVRHw6NLEaLpsq/E62e1khd0/zo837WqycnfhtipECgi2VRZzYyK9DtGSUnloCrE0pnEhEg42pO0AsaiL74oT5HjIm+KZrzYM6FGxhsRjG5yBvfq3ITapNPv7f3qvhtwSSQrFA2VDtWMbL+ZiZNztDhV0r6hb7ezBbsJwavSOmBCIB9yJwZW51QVQ9fAmRLEa+tiDYD4GU/SsEc/+NSnIiEpIvqE8TP12572cj+l0XynNVjEiliriiniKBmr9h63u5R8aPyxtb7oCfOG8Kg1PwWuSUthuELpqze755w4hRO31+Z6AJhrILXNTokxoaq22a2thTHX/sQsEdub5UAKrUzODD0f5mEl4bkRXYQsfSAodxvgeM6IOUhoqIP4/D6whRbZrIfG2Sw4uJC3lKQTcpQIwc0poLKS3mqlA2t8GRyhQzxVUBHf9X2ZYTRXQFw00R274Xvp3uAsCgY1Gf16P2Rt2vCHyhcBNDbXJ+eZ1LCo5f87Z8aVAKaaEBVm+21QJGesLUHUv8Ll9Zany5ctWidk6a66tYsNjQRBsYqpnRfwVmNyGHmJxaPty0KUMTMLUFXaA+vF9lQ70RtvhuOLRtn5AqhmZ0xujP249cjyDrY3lZ9iTla7hveWvAx9ZyX9vjMumpMjy+c4KUz2cfYvFkzgsm8921jaHWJP59kmCjHAV2EuoibU7cRczHu4CCMjBOouMiAI/MQ8TBoHdrA5sYnS0seVVWEM1x19OOxtd0hf27nL9XejlNooTadhiDe40JOKbd3z7nVOaCgiJNagL/hNIRec9pktZ/V/5x1n8lamR53OXiSl8Q+SgGsMxF7FoBQ8yBroNAbdIvcUy0r7yzgRX6Fv9D9B8b/YqHyNcW/xU5Ebd9ZC3G/jtmLrVwxr5k8QIM2M9/W2zL9CUunmXMCNBdX/do+IN/HK0JdS3VRMmjgEICgBCVep1YyeoDYtSGxqf/JfHmFrvtydaz29RXBMpBFLm18G0SozdM8ub1wv+gvZgG5jDy7/vXfLjIL4UJH8LS5A0zwTift8FKFSlKE8nuxlB4cMO03Frz6ionOcbrkJsiPFAR51E1N9KQ0WnZ3cgajwm0fzCjlVhyjhfm/N3pjA6jPOf3NdBi9+q8wB9WhbIkl5OTt0OxT47Gz80/Mkz2QAxbOr7TcnoNAWWx63xl2tHwYv7iKKUmHwUPe"
}
这段密文对应的 Encrypt Key
为 thisisakey2022
。
解密后就会得到:
{
"schema": "1.0",
"header": {
"event_id": "f7984f25108f8137722bb63cee927e66",
"event_type": "item.create"
},
"data": {
"table_id": "2100000000000001",
"bulk": false,
"item": {
"item_id": "2300000000000001",
"title": "数据标题",
"created_by": {
"user_id": "1024",
"name": "接口",
"avatar": "https://hb-v4-public-oss.huoban.com/user_avatar/317474452/0?imageMogr2/thumbnail/128x128>"
},
"created_on": "2021-12-15 20:45:25",
"updated_by": {
"user_id": "1024",
"name": "接口",
"avatar": "https://hb-v4-public-oss.huoban.com/user_avatar/317474452/0?imageMogr2/thumbnail/128x128>"
},
"updated_on": "2022-03-31 18:33:15",
"fields": {
"2200000137788628": "单行文本",
"2200000137788629": "多行文本1<br>多行文本2<br>多行文本3",
"2200000137788630": "<p><b>富文本1</b></p><p><font color=\"#dc0000\">富文本2</font></p><ol><li>富文本3</li><li>富文本4</li></ol>",
"2200000137788631": "18612345678",
"2200000137788632": "6954432710706",
"2200000137788634": 23456,
"2200000137788635": 0.85,
"2200000137788642": 234.56,
"2200000137788643": "2022-03-03",
"2200000137788644": "2022-03-03 00:00:00",
"2200000137788645": 23456,
"2200000137788646": 0.85,
"2200000137788647": "2022-03-03",
"2200000137788648": "2022-03-03 00:00:00"
}
}
}
}
加密方式
事件内容采用标准的 AES-256-CBC 加密,加密过程:
- 使用 SHA256 对 Encrypt Key 进行哈希得到密钥 key ;
- 使用 PKCS7Padding 方式将事件内容进行填充;
- 生成 16 个字节的随机数作为初始向量 iv ;
- 使用 iv 和 key 对事件内容加密得到 encrypted_data ;
- 接收到的密文 encrypted 为 base64(iv+encrypted_data) 。
解密示例代码
Java
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Decrypt {
public static void main(String[] args) throws Exception {
Decrypt decrypt = new Decrypt("thisisakey2022");
System.out.println(decrypt.decrypt("Krus6gVY79RpG6NfPtsQuLMjMMAKd6zB1zjVQg/eBr4=")); // hello world
}
private byte[] keyBytes;
public Decrypt(String key) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
// exception
}
keyBytes = digest.digest(key.getBytes(StandardCharsets.UTF_8));
}
public String decrypt(String base64) throws Exception {
// base64 decode
byte[] decode = Base64.getDecoder().decode(base64);
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
// iv
byte[] iv = new byte[16];
System.arraycopy(decode, 0, iv, 0, 16);
byte[] data = new byte[decode.length - 16];
System.arraycopy(decode, 16, data, 0, data.length);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(iv));
byte[] result = cipher.doFinal(data);
if (result.length > 0) {
int len = result.length - 1;
for (; len >= 0 && result[len] <= 16; len--) {
}
if (len != result.length - 1) {
byte[] tmp = new byte[len + 1];
System.arraycopy(result, 0, tmp, 0, len + 1);
result = tmp;
}
}
return new String(result, StandardCharsets.UTF_8);
}
}
Golang
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/base64"
"errors"
"fmt"
)
func main() {
key := "thisisakey2022"
encrypted := "Krus6gVY79RpG6NfPtsQuLMjMMAKd6zB1zjVQg/eBr4=" // hello world
// base64 decode
base64Decodedbuf, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
panic(err)
}
plaintextByts, err := Decrypt(base64Decodedbuf, []byte(key))
if err != nil {
panic(err)
}
fmt.Println(string(plaintextByts))
}
func Decrypt(buf, key []byte) (byts []byte, err error) {
if len(buf) < aes.BlockSize {
err = errors.New("cipher length err")
return
}
keySum := sha256.Sum256(key)
block, err := aes.NewCipher(keySum[:sha256.Size])
if err != nil {
return
}
iv := buf[:aes.BlockSize]
buf = buf[aes.BlockSize:]
if len(buf)%aes.BlockSize != 0 {
err = errors.New("cipher text length error")
return
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(buf, buf)
m := len(buf)
bufLast := buf[m-1]
if bufLast > byte(aes.BlockSize) || m-int(bufLast) < 0 {
err = errors.New("unpadding error")
return
}
m = m - int(bufLast)
byts = buf[0:m]
return
}
Python
import hashlib
import base64
from Crypto.Cipher import AES
class AES256CBCCipher(object):
def __init__(self, key):
self.key = hashlib.sha256(key.encode('utf8')).digest()
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
def decrypt(self, encode):
iv = encode[:AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(encode[AES.block_size:]))
def decrypt_string(self, encode):
encode = base64.b64decode(encode)
return self.decrypt(encode).decode('utf8')
encrypt = "Krus6gVY79RpG6NfPtsQuLMjMMAKd6zB1zjVQg/eBr4="
cipher = AES256CBCCipher("thisisakey2022")
print(format(cipher.decrypt_string(encrypt))) # hello world
Node.js
const crypto = require("crypto");
class AES256CBCCipher {
constructor(key) {
const hash = crypto.createHash('sha256');
hash.update(key);
this.key = hash.digest();
}
decrypt(encrypt) {
const encryptBuffer = Buffer.from(encrypt, 'base64');
const decipher = crypto.createDecipheriv('aes-256-cbc', this.key, encryptBuffer.slice(0, 16));
let decrypted = decipher.update(encryptBuffer.slice(16).toString('hex'), 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}
encrypt = "Krus6gVY79RpG6NfPtsQuLMjMMAKd6zB1zjVQg/eBr4="
cipher = new AES256CBCCipher("thisisakey2022")
console.log(cipher.decrypt(encrypt))
// hello world
最后修改时间: 2 年前