有奖:语音产品征文挑战赛火热进行中> HOT
文档中心 > 文字识别 > 快速入门 > 敏感数据加密指引
此指引适用于使用文字识别服务接口,需要对传输敏感数据进行加密的场景。
如果您使用的开发语言是 Java、Go、Nodejs、Python,推荐使用 方式一 实现加解密。如果开发语言不在上述范围,推荐使用 方式二 实现加解密功能。

方式一:使用官方 Demo 实现加解密(推荐)

官方 Demo 当前支持 Java、Go、Nodejs、Python 开发语言,使用步骤如下:

获取加解密 SDK

联系文字识别售后支持,获取对应开发语言的 Demo 代码。

使用 SDK

引入公共依赖

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>

引入加解密 SDK

下载最新的 release 版本 jar 包,并在项目工程中引入。 参考下方的接口 Demo 实现敏感信息加解密功能。

支持敏感信息加解密的接口

身份证识别(安全加密版):RecognizeEncryptedIDCardOCR

方式二:不使用官方 SDK 实现加解密

加解密流程说明

当前敏感信息加解密支持标准加密算法 AES-CBC 和国密算法 SM4-GCM,可以根据业务要求从中选择适合您的加密算法。
敏感信息加解密的本质是对接口传输的请求、响应参数做对称加密后传输,文字识别服务收到加密数据后先解密,然后在进行识别业务。如果文字识别接口返回结果涉及敏感信息,则会使用相同的对称密钥加密,调用方在收到接口响应时需要对敏感信息解密。
对称密钥由调用方本地随机生成,为保证对称密钥的安全传输,需要调用方配合使用非对称加密算法加密对称密钥。加密的公钥可以联系售后支持获取。
sequenceDiagram
participant customer as 客户
participant faceid as 文字识别服务端
participant console as 文字识别加解密服务
console-->>customer: 获取公钥

rect rgba(191, 223, 255, 0.7)
customer->>customer: 本地随机生成对称密钥
customer->>customer: 公钥加密对称密钥
customer->>customer: 用对称密钥加密敏感信息参数
end

customer->>faceid: 调用文字识别接口(加密的对称密钥CiphertextBlob、初始向量IV、密文参数)
faceid->>console: 获取私钥
faceid->>faceid: 解密CiphertextBlob,获得对称密钥
faceid->>faceid: 用对称密钥解密敏感数据
faceid->>faceid: 文字识别
faceid->>faceid: 用客户传入的对称密钥和iv加密返回值
faceid->>customer: 返回加密后的识别结果
rect rgba(191, 223, 255, 0.7)
customer->>customer: 用本地生成的对称密钥明文、IV解密返回值
end




使用 AES-256-CBC 算法

加载 RSA 公钥

加载 RSA 公钥:对获取到的公钥字符串先做 Base64 Decode,然后按对应格式加载。
格式:PKCS1
保存格式:pem 格式 Base64编码
长度:1024
// 加载RSA公钥
bytes, err := base64.StdEncoding.DecodeString(publicKey)
if err != nil {
return nil, err
}
block, _ := pem.Decode(bytes)
x509.ParsePKCS1PublicKey(block.Bytes)

生成对称密钥和向量

随机生成32字节长度的对称密钥以及16字节的初始向量,初始向量表示为 IV。
// 生成对称密钥
key := make([]byte, 32)
rand.Read(key)

// 生成16字节iv
iv := make([]byte, 16)
rand.Read(iv)

RSA 公钥加密对称密钥

使用 RSA 公钥加密前面生成的 对称密钥,将加密后的结果表示为 CiphertextBlob。
// 加密对称密钥Key
buffer := bytes.Buffer{}
bytes, _ := rsa.EncryptPKCS1v15(rand.Reader, publicKey, key)
buffer.Write(bytes)
buffer.Bytes()

加密敏感数据

使用前面生成的 对称密钥和初始向量,采用 AES-256-CBC 算法加密敏感数据(姓名、身份证号)。
// AES-CBC加密明文数据
// 明文密钥key
// 初始向量iv
// 敏感数据plaintext
block, _ := aes.NewCipher(key)
blockSize := block.BlockSize()
pkcs7 := func(cipherText []byte, blockSize int) []byte {
padding := blockSize - len(cipherText)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(cipherText, padText...)
}
plaintext = pkcs7(plaintext, blockSize)
blockMode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
blockMode.CryptBlocks(ciphertext, plaintext)
fmt.Print(ciphertext)

调用文字识别接口

身份证识别(安全加密版)RecognizeEncryptedIDCardOCR 接口为例:
原始数据为:
{
"Action": "RecognizeEncryptedIDCardOCR",
"Version": "2018-11-19",
"ImageUrl": "https://xx/a.jpg",
"Config": "{\\"TempIdWarn\\":true}",
"CardSide": "FRONT"
}
CiphertextBlob、IV、TAG、加密后请求入参在传输前均需要做一次 Base64 编码:
生成的对称密钥为:aqPpVPUV9XMCCr5QQSu4p6mI8BAgbMz3(32字节)
生成的初始向量(IV):Pcr1F3d9Bkn6ub7jduJcBw==(16字节IV,Base64编码)
公钥加密后的对称密钥(CiphertextBlob):
Ows39pc3d7x34m/g6uWmo/HlQbxw+1IA4C1QiTCbbYuMt1W3tzxG7Wp3UEAB38kE1PTgUt2tHKOE8FDboEbkR9Bgnti+Hj1aNiGOlxiI9ABz6vTKA4Rx3FlFvnsM9+PulDPQWb7PgCEYIYWOAXNtfaa6iDAMW+qT0H8LBEg4Mss=(Base64编码)
使用对称密钥加密请求入参,加密后的结果分别为:
加密后的请求入参EncryptedBody:
MrUQbU7Tkva7sWSxEScx7U9zOikFtM5fCf7weC21z96kPE93MFnGbbMKR+CgsTSCLpqmfBKSDeErek4HAyyRGwzctETaJOJ7cFD8E4gBXk0R7yZhFn9INamfTMJusIhWGkmXPP0/+lrZoqGhOm01FNTAaUf6qHNwWUXOiaMntBSRmC5vscx9+arg4IW9XtTwENsK2ho68s7bw21uKNNJPw==(Base64编码)
最终加密后的接口数据为:
{
"Action": "RecognizeEncryptedIDCardOCR",
"Version": "2018-11-19",
"ImageUrl": "",
"Config": "",
"CardSide": "",
"EncryptedBody": "MrUQbU7Tkva7sWSxEScx7U9zOikFtM5fCf7weC21z96kPE93MFnGbbMKR+CgsTSCLpqmfBKSDeErek4HAyyRGwzctETaJOJ7cFD8E4gBXk0R7yZhFn9INamfTMJusIhWGkmXPP0/+lrZoqGhOm01FNTAaUf6qHNwWUXOiaMntBSRmC5vscx9+arg4IW9XtTwENsK2ho68s7bw21uKNNJPw==",
"Encryption": {
"EncryptList": [
"EncryptedBody"
],
"TagList": [],
"CiphertextBlob": "Ows39pc3d7x34m/g6uWmo/HlQbxw+1IA4C1QiTCbbYuMt1W3tzxG7Wp3UEAB38kE1PTgUt2tHKOE8FDboEbkR9Bgnti+Hj1aNiGOlxiI9ABz6vTKA4Rx3FlFvnsM9+PulDPQWb7PgCEYIYWOAXNtfaa6iDAMW+qT0H8LBEg4Mss=",
"Iv": "Pcr1F3d9Bkn6ub7jduJcBw==",
"Algorithm": "AES-256-CBC"
}
}

使用 SM4-GCM 算法

加载 SM2公钥

加载 SM2公钥:对控制台获取到的公钥字符串先做 Base64 Decode,然后按对应格式加载。
格式:PKCS8
保存格式:pem格式Base64编码
长度:512
// 加载SM2公钥
bytes, err := base64.StdEncoding.DecodeString(publicKey)
if err != nil {
return nil, err
}
x509.ReadPublicKeyFromPem(bytes)

生成对称密钥和向量

随机生成16字节长度的对称密钥以及12字节的初始向量,初始向量表示为 IV。
// 生成对称密钥
key := make([]byte, 16)
rand.Read(key)

// 生成16字节iv
iv := make([]byte, 12)
rand.Read(iv)

SM2 公钥加密对称密钥

使用 SM2 公钥加密前面生成的 对称密钥,将加密后的结果表示为 CiphertextBlob。
注意输出密文时采用 C1C3C2数据拼接方式
数据类型转换时,均使用 PC=04的方式,即未压缩。
// 加密对称密钥Key
ciphertext, err := sm2.Encrypt(publicKey, plaintext, rand.Reader, sm2.C1C3C2)
if err != nil {
return nil, err
}
return cipherText, nil

加密敏感数据

使用前面生成的 对称密钥和初始向量,采用 SM4-GCM 算法加密敏感数据(请求入参)。
// SM4-GCM加密明文数据
// 明文密钥key
// 初始向量iv
// 敏感数据plaintext
block, err := sm4.NewCipher(key)
if err != nil {
return nil, nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, err
}
ciphertext := gcm.Seal(nil, iv, plaintext, nil)
tag := ciphertext[len(ciphertext)-gcm.Overhead():]
ciphertextWithoutTag := ciphertext[:len(ciphertext)-gcm.Overhead()]
return ciphertextWithoutTag, tag, nil

调用文字识别接口

以身份证识别(安全加密版)RecognizeEncryptedIDCardOCR 接口为例: 原始数据为:
{
"Action": "RecognizeEncryptedIDCardOCR",
"Version": "2018-11-19",
"ImageUrl": "https://xx/a.jpg",
"Config": "{\\"TempIdWarn\\":true}",
"CardSide": "FRONT"
}
CiphertextBlob、IV、TAG、加密后的请求参数在传输前均需要做一次Base64编码
生成的对称密钥为:zpBn0BkD44bvJuSF(16字节)
生成的初始向量(IV):MUZsKuqk7N2u7Ayh(12字节IV,Base64编码)
公钥加密后的对称密钥(CiphertextBlob):BHknHJ1Wgzg8DAONoGJ7ch+ijF/rsrs7mmvxER1WlFKSJHY66BSJbmzc5OtQyVK84Ye2zAD2x63nmr4ZXoEyw1T2zqKcAbDWP2DTypjsbijvqdU6oSVOrlWE3TlQpA+k6ID3YoRdNdJOCjKnsMOnEls=(Base64编码)
使用对称密钥加密请求入参,加密后的结果分别为:
加密后的请求入参EncryptedBody:
12nTF6/CcyMqUDmbU63FPMFRpsye8NdZDwfGceRZIjpSr9ClHKAqWJBhcbqOGolvuOqG+ES1Eru94+5NlJtK/1UE+BgUb9+1571TgS/7Nn0d8zpR320ZZoFZO3djdpkkyXL32sM3FyuwdOkQXMOYcS+3y8A8YCOSLjDL6L7rAC2fP8sqqWWGndZAUdyK9fshwZ+rbCtf3zMl0uWY(Base64编码)
最终加密后的接口数据为:
{
"Action": "RecognizeEncryptedIDCardOCR",
"Version": "2018-11-19",
"ImageUrl": "",
"Config": "",
"CardSide": "",
"EncryptedBody": "12nTF6/CcyMqUDmbU63FPMFRpsye8NdZDwfGceRZIjpSr9ClHKAqWJBhcbqOGolvuOqG+ES1Eru94+5NlJtK/1UE+BgUb9+1571TgS/7Nn0d8zpR320ZZoFZO3djdpkkyXL32sM3FyuwdOkQXMOYcS+3y8A8YCOSLjDL6L7rAC2fP8sqqWWGndZAUdyK9fshwZ+rbCtf3zMl0uWY",
"Encryption": {
"EncryptList": [
"EncryptedBody"
],
"TagList": [],
"CiphertextBlob": "BHknHJ1Wgzg8DAONoGJ7ch+ijF/rsrs7mmvxER1WlFKSJHY66BSJbmzc5OtQyVK84Ye2zAD2x63nmr4ZXoEyw1T2zqKcAbDWP2DTypjsbijvqdU6oSVOrlWE3TlQpA+k6ID3YoRdNdJOCjKnsMOnEls=",
"Iv": "MUZsKuqk7N2u7Ayh",
"Algorithm": "AES-256-CBC"
}
}