# 验签解密代码示例
* java示例 [Base64包下载](https://file.10ss.net/live_sys_pkg/Base64.java)
```
import org.junit.Test;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
public class verifySignAndDecrypteDemo {
/**
* 应用设置 -> K8推送 -> 设置 -> 接口加签名方式(密钥) -> 平台公钥
*/
public static final String publicKey = "";
/**
* 第一步:验签操作
*/
@Test
public void verifySign() {
// 交易报文中ciphertext与signature
String ciphertext = "";
String signature = "";
byte[] signatureByte = Base64.decodeBase64String(signature);
byte[] publicKeyByte = Base64.decodeBase64String(publicKey);
try {
System.out.println("验签结果:" + verify(ciphertext.getBytes(), signatureByte, publicKeyByte));
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
/**
* 第二步:解析参数
*/
@Test
public void decrypte() throws Exception {
// 交易报文中ciphertext与tag和iv
String ciphertext = "";
String tag = "";
String iv = "";
// 应用设置 -> K8推送 -> 设置 -> 接口加签名方式(密钥) -> 应用公钥
String key = "";
try {
String plaintext = decrypte(Base64.decodeBase64String(ciphertext), key.getBytes(), iv.getBytes(), Base64.decodeBase64String(tag));
System.out.println(plaintext);
} catch (Exception e) {
throw new Exception(e);
}
}
private static boolean verify(byte[] data, byte[] signature, byte[] publicKey) throws GeneralSecurityException {
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pubKey);
sig.update(data);
return sig.verify(signature);
}
/**
* AES-GCM-256对称解密
*/
private static String decrypte(byte[] encryptedBytes, byte[] keyBytes, byte[] ivBytes, byte[] tagBytes) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, ivBytes);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
cipher.updateAAD("transaction".getBytes(StandardCharsets.UTF_8));
cipher.update(encryptedBytes);
byte[] decryptedBytes = cipher.doFinal(tagBytes);
String decryptedString = new String(decryptedBytes, StandardCharsets.UTF_8);
byte[] content = Base64.decodeBase64String(decryptedString);
return new String(content);
}
}
```
* golang示例
```
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
type Args struct {
Ciphertext string `json:"ciphertext"`
Nonce string `json:"nonce"`
Tag string `json:"tag"`
Key string `json:"key"`
}
func decryptAES256GCM(args Args) (string, error) {
var extra []byte
extra = []byte(args.AdditionalData)
key := []byte(args.Key)
nonce, _ := base64.StdEncoding.DecodeString(args.Nonce)
tag, _ := base64.StdEncoding.DecodeString(args.Tag)
ciphertext, _ := base64.StdEncoding.DecodeString(args.Ciphertext)
x := append(ciphertext, tag...)
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("failed to create cipher: %v", err)
}
aesgcm, err := cipher.NewGCMWithNonceSize(block, aes.BlockSize)
if err != nil {
return "", fmt.Errorf("failed to create GCM: %v", err)
}
plaintext, err := aesgcm.Open(nil, nonce, x, extra)
if err != nil {
return "", fmt.Errorf("failed to decrypt: %v", err)
}
return string(plaintext), nil
}
func main() {
args := Args{
Ciphertext: "这里是平台POST过来的加密密文,参数名ciphertext,还没Base64解码的",
Nonce: "这里是平台POST过来的,参数名nonce",
Tag: "这里是平台POST过来的,参数名tag,还没Base64解码的",
AdditionalData: "transaction",
Key: "这里是后台设置的密钥,32位字符",
}
plaintext, err := decryptAES256GCM(args)
if err != nil {
fmt.Printf("Failed to decrypt: %v\n", err)
} else {
fmt.Println(plaintext)
}
}
```
* php示例
```
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Log;
class Index extends BaseController
{
// 开放平台平台公钥
protected static $rsa_public_key = '';
// 开放平台应用公匙
protected static $aes_encryption_key = '';
public function index()
{
$message = '';
$postData = $_POST;
if ($postData) {
$content = json_encode($postData);
Log::info("[推送参数]----[postData][$content]");
$isVerify = self::verifySignature($postData['ciphertext'], self::$rsa_public_key, base64_decode($postData['signature']));
if (!$isVerify) {
$message = '验签失败';
}
$params = self::decode(base64_decode($postData['ciphertext']), self::$aes_encryption_key, $postData['iv'], base64_decode($postData['tag']));
$paramsContent = json_encode($params);
if (!$params) {
$message = '解密失败';
}
Log::info("[推送解密后参数]----[postData][$paramsContent]");
## todo 后续对接自己项目功能
## todo 对接打印机小票打印
}
return json($this->result($message));
}
/**
* Notes: 验证签名
* @param $data
* @param $privateKey
*/
public static function verifySignature($data, $publicKey, $signature)
{
return openssl_verify($data, $signature, $publicKey, OPENSSL_ALGO_SHA256);
}
/**
* Notes: 解密
* @param $string
* @param $key
* @param $iv
* @param $tag
* @param $additionalData
* @return false|string
*/
public static function decode($string, $key, $iv, $tag, $additionalData = 'transaction')
{
$decrypted = openssl_decrypt($string, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, $additionalData);
$decrypted = base64_decode($decrypted);
return $decrypted;
}
/**
* Notes: 返回处理
* @param string $message
* @return array
*/
protected function result($message = '')
{
return [
'message' => 'ok',
'dataMsg' => $message,
];
}
}
```
* C#示例
```
public class AESGCM
{
public static string Decrypt()
{
// AES-256-GCM 使用 BouncyCastle.Crypto 库,从NuGet下载
// 平台POST过来的是Form参数,从Request.Form中提取
var arg = new
{
ciphertext = "这里是平台POST过来的加密密文,参数名ciphertext,还没Base64解码的",
iv = "", // 同 nonce,重复的
nonce = "这里是平台POST过来的,参数名nonce", // 解密用的向量
tag = "这里是平台POST过来的,参数名tag,还没Base64解码的",
additional_data = "transaction",
key = "这里是后台设置的密钥,32位字符"
};
var extra = Encoding.UTF8.GetBytes(arg.additional_data);
var key = Encoding.UTF8.GetBytes(arg.key);
var nonce = Encoding.UTF8.GetBytes(arg.nonce);
var tag = Convert.FromBase64String(arg.tag);
var x = Convert.FromBase64String(arg.ciphertext);
x = x.Concat(tag).ToArray();
try
{
var cipher = new GcmBlockCipher(new AesFastEngine());
var aead = new AeadParameters(new KeyParameter(key), 128, nonce, extra);
cipher.Init(false, aead);
var data = new byte[cipher.GetOutputSize(x.Length)];
var num = cipher.ProcessBytes(x, 0, x.Length, data, 0);
cipher.DoFinal(data, num);
var a = Encoding.UTF8.GetString(data); // 解密成功得到 base64 string
var b = Convert.FromBase64String(a); // base64 转为 byte[]
var c = Encoding.UTF8.GetString(b); // 转为最终的JSON明文,成功了
return c;
}
catch (Exception ex)
{
Console.WriteLine(ex);
// 这里异常说明key 不对,key需要纯32位字符,建议key生成这样的 Guid.NewGuid().ToString("n")
}
return null;
}
}
```
* nodejs示例
```
//验证签名
let verify = crypto.createVerify('SHA256');
verify.update(jo_body.ciphertext);
let verify_result = verify.verify(平台公钥, jo_body.signature, 'base64');
if (!verify_result) throw new Error('签名验证失败');
//数据解密
let ciphertext = Buffer.from(jo_body.ciphertext, 'base64');
let tag = Buffer.from(jo_body.tag, 'base64');
let decipher = crypto.createDecipheriv('aes-256-gcm', 应用公钥, jo_body.iv);
decipher.setAuthTag(tag);
decipher.setAAD(Buffer.from('transaction'));
let decoded = decipher.update(ciphertext, null, 'utf8');
decipher.final();
let payData = JSON.parse(Buffer.from(decoded, 'base64').toString()); //解密后的数据
console.log('解密后的数据', payData);
```
- 使用前准备【必看】
- 开发者服务指引【必看】
- 接口更新动态
- 2024年5月
- 2024年1月
- 2023年11月
- 2023年10月
- 2023年9月
- 2023年6月
- 开发文档【必看】
- 调用协议【必看】
- 授权文档【必接】
- 自有型应用
- 开放型应用(OAuth2.0授权码模式)
- 开放型应用(扫码授权模式)
- SDK使用说明
- API文档【按需对接】
- 设备文档
- 设备绑定
- 设备解绑或取消授权
- 状态获取
- 离线或重启控制
- 打印控制
- logo控制
- 音效音量控制
- 内置语音控制
- 打印宽度获取
- 型号版本获取
- 接单拒单控制
- 打印文档
- 文本打印
- 图片打印
- 面单文档
- 面单生成并打印
- 面单取消
- 打印队列文档
- 订单状态获取(单订单)
- 订单列表获取
- 订单取消打印(单订单)
- 订单取消打印(全量)
- 订单重打(单订单)
- 应用设置文档
- 推送地址设置
- K8支付设置文档
- 推送开关设置
- 关键词设置
- 高级设置
- 打印消息推送
- 打印消息推送说明
- 打印完成推送
- 终端状态推送
- 接单拒单推送
- K8扫码信息推送
- 扫码相关功能流程图
- 产品介绍
- 授权说明
- 消息推送
- http/https推送方式
- 签名验证规则
- 解密规则
- 指令说明
- 验签解密示例
- 打印指令文档
- 指令文档说明
- 文本打印指令集
- 语音指令文档
- 多语言指令文档
- 扫码功能指令
- 常见问题
- 错误码说明
- FAQ