Skip to content

Commit 8a5ab91

Browse files
committed
update tlv tool
1 parent 6224734 commit 8a5ab91

File tree

8 files changed

+567
-0
lines changed

8 files changed

+567
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ dist/*
55
.editorconfig
66
.env
77
.ufbt
8+
tools/ResponseDecoder/cmd/tlvtool/tlvtool

apdu_script/.DS_Store

0 Bytes
Binary file not shown.

tools/ResponseDecoder/cmd/tlv.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/fatih/color"
8+
"github.com/spensercai/nfc_apdu_runner/tools/ResponseDecoder/pkg/tlv"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var (
13+
hexData string
14+
tagList string
15+
dataType string
16+
)
17+
18+
// tlvCmd 表示tlv命令
19+
var tlvCmd = &cobra.Command{
20+
Use: "tlv",
21+
Short: "解析TLV数据并提取指定标签的值",
22+
Long: `解析TLV数据并提取指定标签的值。
23+
24+
示例:
25+
# 解析所有标签
26+
response_decoder tlv --hex 6F198407A0000000031010A50E500A4D617374657243617264
27+
28+
# 解析指定标签
29+
response_decoder tlv --hex 6F198407A0000000031010A50E500A4D617374657243617264 --tag 84,50
30+
31+
# 指定数据类型
32+
response_decoder tlv --hex 6F198407A0000000031010A50E500A4D617374657243617264 --tag 50 --type ascii`,
33+
RunE: func(cmd *cobra.Command, args []string) error {
34+
if hexData == "" {
35+
return fmt.Errorf("必须提供十六进制数据 (--hex)")
36+
}
37+
38+
// 解析TLV数据
39+
tlvList, err := tlv.ParseHex(hexData)
40+
if err != nil {
41+
return fmt.Errorf("解析TLV数据失败: %w", err)
42+
}
43+
44+
// 如果没有指定标签,则显示所有标签
45+
if tagList == "" {
46+
return displayAllTags(tlvList)
47+
}
48+
49+
// 解析标签列表
50+
tags := strings.Split(tagList, ",")
51+
for _, tag := range tags {
52+
tag = strings.TrimSpace(tag)
53+
if tag == "" {
54+
continue
55+
}
56+
57+
// 查找标签
58+
tlvItem, err := tlvList.FindTagRecursive(tag)
59+
if err != nil {
60+
fmt.Printf("标签 %s 未找到: %v\n", tag, err)
61+
continue
62+
}
63+
64+
// 显示标签值
65+
displayTagValue(tag, tlvItem)
66+
}
67+
68+
return nil
69+
},
70+
}
71+
72+
// displayAllTags 显示所有标签
73+
func displayAllTags(tlvList tlv.TLVList) error {
74+
titleColor := color.New(color.FgCyan, color.Bold)
75+
76+
fmt.Println(strings.Repeat("=", 50))
77+
titleColor.Println("TLV 数据解析结果")
78+
fmt.Println(strings.Repeat("=", 50))
79+
80+
// 递归显示TLV结构
81+
displayTLVStructure(tlvList, 0)
82+
83+
return nil
84+
}
85+
86+
// displayTLVStructure 递归显示TLV结构
87+
func displayTLVStructure(tlvList tlv.TLVList, level int) {
88+
indent := strings.Repeat(" ", level)
89+
tagColor := color.New(color.FgYellow, color.Bold)
90+
valueColor := color.New(color.FgGreen)
91+
constructedColor := color.New(color.FgMagenta, color.Bold)
92+
93+
for _, item := range tlvList {
94+
// 显示标签
95+
tagColor.Printf("%s标签: %s", indent, item.Tag)
96+
97+
// 显示长度
98+
fmt.Printf(", 长度: %d", item.Length)
99+
100+
// 如果是构造型标签,递归显示其内容
101+
if item.IsConstructed() {
102+
constructedColor.Println(" [构造型]")
103+
104+
// 解析嵌套TLV
105+
nestedList, err := tlv.Parse(item.Value)
106+
if err != nil {
107+
fmt.Printf("%s 解析嵌套TLV失败: %v\n", indent, err)
108+
continue
109+
}
110+
111+
// 递归显示嵌套TLV
112+
displayTLVStructure(nestedList, level+1)
113+
} else {
114+
// 显示值
115+
fmt.Print(", 值: ")
116+
117+
// 根据数据类型显示值
118+
switch dataType {
119+
case "utf8", "utf-8":
120+
data, err := tlv.GetTagValueAsString(hexData, item.Tag.String(), "utf-8")
121+
if err != nil {
122+
valueColor.Printf("%s\n", item.Value)
123+
} else {
124+
valueColor.Printf("%s\n", data)
125+
}
126+
case "ascii":
127+
data, err := tlv.GetTagValueAsString(hexData, item.Tag.String(), "ascii")
128+
if err != nil {
129+
valueColor.Printf("%s\n", item.Value)
130+
} else {
131+
valueColor.Printf("%s\n", data)
132+
}
133+
case "numeric":
134+
data, err := tlv.GetTagValueAsString(hexData, item.Tag.String(), "numeric")
135+
if err != nil {
136+
valueColor.Printf("%s\n", item.Value)
137+
} else {
138+
valueColor.Printf("%s\n", data)
139+
}
140+
default:
141+
valueColor.Printf("%s\n", item.Value)
142+
}
143+
}
144+
}
145+
}
146+
147+
// displayTagValue 显示标签值
148+
func displayTagValue(tag string, tlvItem *tlv.TLV) {
149+
tagColor := color.New(color.FgYellow, color.Bold)
150+
valueColor := color.New(color.FgGreen)
151+
152+
// 显示标签
153+
tagColor.Printf("标签: %s", tag)
154+
155+
// 显示长度
156+
fmt.Printf(", 长度: %d", tlvItem.Length)
157+
158+
// 显示值
159+
fmt.Print(", 值: ")
160+
161+
// 根据数据类型显示值
162+
switch dataType {
163+
case "utf8", "utf-8":
164+
data, err := tlv.GetTagValueAsString(hexData, tag, "utf-8")
165+
if err != nil {
166+
valueColor.Printf("%s\n", tlvItem.Value)
167+
} else {
168+
valueColor.Printf("%s\n", data)
169+
}
170+
case "ascii":
171+
data, err := tlv.GetTagValueAsString(hexData, tag, "ascii")
172+
if err != nil {
173+
valueColor.Printf("%s\n", tlvItem.Value)
174+
} else {
175+
valueColor.Printf("%s\n", data)
176+
}
177+
case "numeric":
178+
data, err := tlv.GetTagValueAsString(hexData, tag, "numeric")
179+
if err != nil {
180+
valueColor.Printf("%s\n", tlvItem.Value)
181+
} else {
182+
valueColor.Printf("%s\n", data)
183+
}
184+
default:
185+
valueColor.Printf("%s\n", tlvItem.Value)
186+
}
187+
}
188+
189+
func init() {
190+
rootCmd.AddCommand(tlvCmd)
191+
192+
// 添加命令行标志
193+
tlvCmd.Flags().StringVar(&hexData, "hex", "", "要解析的十六进制TLV数据")
194+
tlvCmd.Flags().StringVar(&tagList, "tag", "", "要提取的标签列表,用逗号分隔")
195+
tlvCmd.Flags().StringVar(&dataType, "type", "", "数据类型 (utf8, ascii, numeric)")
196+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Makefile for TLV Tool
2+
3+
# Go parameters
4+
GOCMD=go
5+
GOBUILD=$(GOCMD) build
6+
GOCLEAN=$(GOCMD) clean
7+
GOTEST=$(GOCMD) test
8+
GOGET=$(GOCMD) get
9+
BINARY_NAME=tlvtool
10+
BINARY_UNIX=$(BINARY_NAME)_linux
11+
12+
all: build
13+
14+
build:
15+
$(GOBUILD) -o $(BINARY_NAME) -v
16+
17+
test:
18+
$(GOTEST) -v ./...
19+
20+
clean:
21+
$(GOCLEAN)
22+
rm -f $(BINARY_NAME)
23+
rm -f $(BINARY_UNIX)
24+
25+
run:
26+
$(GOBUILD) -o $(BINARY_NAME) -v
27+
./$(BINARY_NAME)
28+
29+
deps:
30+
$(GOGET) github.com/spf13/cobra
31+
$(GOGET) github.com/fatih/color
32+
33+
# Cross compilation
34+
build-linux:
35+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -o $(BINARY_UNIX) -v
36+
37+
build-windows:
38+
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GOBUILD) -o $(BINARY_NAME).exe -v
39+
40+
build-mac:
41+
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GOBUILD) -o $(BINARY_NAME)_mac -v
42+
43+
build-all: build-linux build-windows build-mac
44+
45+
.PHONY: all build test clean run deps build-linux build-windows build-mac build-all
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# TLV工具
2+
3+
TLV工具是一个用于解析TLV(Tag-Length-Value)数据结构的命令行工具。它可以解析十六进制格式的TLV数据,并提取指定标签的值。
4+
5+
## 功能特点
6+
7+
- 解析十六进制格式的TLV数据
8+
- 支持提取指定标签的值
9+
- 支持多种数据类型的解码(UTF-8、ASCII、数字)
10+
- 支持递归解析嵌套的TLV结构
11+
- 彩色输出,易于阅读
12+
13+
## 安装
14+
15+
### 从源代码构建
16+
17+
```bash
18+
# 克隆仓库
19+
git clone https://github.com/spensercai/nfc_apdu_runner.git
20+
cd nfc_apdu_runner/tools/ResponseDecoder/cmd/tlvtool
21+
22+
# 安装依赖
23+
make deps
24+
25+
# 构建
26+
make build
27+
```
28+
29+
### 跨平台构建
30+
31+
```bash
32+
# 构建所有平台版本
33+
make build-all
34+
35+
# 或者单独构建特定平台版本
36+
make build-linux
37+
make build-windows
38+
make build-mac
39+
```
40+
41+
## 使用方法
42+
43+
### 解析所有标签
44+
45+
```bash
46+
./tlvtool --hex 6F198407A0000000031010A50E500A4D617374657243617264
47+
```
48+
49+
### 解析指定标签
50+
51+
```bash
52+
./tlvtool --hex 6F198407A0000000031010A50E500A4D617374657243617264 --tag 84,50
53+
```
54+
55+
### 指定数据类型
56+
57+
```bash
58+
./tlvtool --hex 6F198407A0000000031010A50E500A4D617374657243617264 --tag 50 --type ascii
59+
```
60+
61+
## 命令行参数
62+
63+
- `--hex`: 要解析的十六进制TLV数据(必需)
64+
- `--tag`: 要提取的标签列表,用逗号分隔(可选)
65+
- `--type`: 数据类型(可选,支持utf8、ascii、numeric)
66+
67+
## 示例
68+
69+
### 解析EMV数据
70+
71+
```bash
72+
./tlvtool --hex 6F3A8407A0000000031010A52F500A4D6173746572436172649F38069F5C089F4D029F6E07BF0C089F5A0551031000009F0A0800010501000000
73+
```
74+
75+
### 提取应用标签和AID
76+
77+
```bash
78+
./tlvtool --hex 6F3A8407A0000000031010A52F500A4D6173746572436172649F38069F5C089F4D029F6E07BF0C089F5A0551031000009F0A0800010501000000 --tag 50,84 --type ascii
79+
```
80+
81+
## 许可证
82+
83+
GNU通用公共许可证第3版 (GPL-3.0)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module github.com/spensercai/nfc_apdu_runner/tools/ResponseDecoder/cmd/tlvtool
2+
3+
go 1.23.3
4+
5+
require (
6+
github.com/fatih/color v1.18.0
7+
github.com/spensercai/nfc_apdu_runner/tools/ResponseDecoder v0.0.0-20250312081615-6224734a1330
8+
github.com/spf13/cobra v1.9.1
9+
)
10+
11+
require (
12+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
13+
github.com/mattn/go-colorable v0.1.13 // indirect
14+
github.com/mattn/go-isatty v0.0.20 // indirect
15+
github.com/spf13/pflag v1.0.6 // indirect
16+
golang.org/x/sys v0.25.0 // indirect
17+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
2+
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
3+
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
4+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
5+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
7+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
8+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
9+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
10+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
11+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
12+
github.com/spensercai/nfc_apdu_runner/tools/ResponseDecoder v0.0.0-20250312081615-6224734a1330 h1:4fDAVh031G7FlvX3/lMQwWqhI2MtQ/Dv0oOdJHZVR0w=
13+
github.com/spensercai/nfc_apdu_runner/tools/ResponseDecoder v0.0.0-20250312081615-6224734a1330/go.mod h1:r8JrmoEg/q7zz97+G+odKfkrPN2gZ65/q5eNaIhUv4g=
14+
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
15+
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
16+
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
17+
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
18+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
19+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
20+
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
21+
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
22+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
23+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)