银商TMS平台秘钥自动下载并形成文件工具

时间:2022-07-22
本文章向大家介绍银商TMS平台秘钥自动下载并形成文件工具,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
package main

import (
	"flag"
	"fmt"
	"github.com/larspensjo/config"
	//"hex"
	"bytes"
	//"github.com/djimenez/iconv-go"
	"encoding/base64"
	"encoding/csv"
	"encoding/hex"
	"encoding/json"
	"io"
	"log"
	"os"
	"strconv"
	"testgo/desutil"
	"testgo/httputil"
)

func bytesToHexStr(data []byte, lenth int) string {
	buf := data[0:lenth]
	hexStr := fmt.Sprintf("%x", buf)
	//fmt.Println(hexStr)
	return hexStr

}

// bytes to hex string
func bytesToHexString(b []byte) string {
	var buf bytes.Buffer
	for _, v := range b {
		t := strconv.FormatInt(int64(v), 16)
		if len(t) > 1 {
			buf.WriteString(t)
		} else {
			buf.WriteString("0" + t)
		}
	}
	return buf.String()
}

// hex string to bytes
func hexStringToBytes(s string) []byte {
	bs := make([]byte, 0)
	for i := 0; i < len(s); i = i + 2 {
		b, _ := strconv.ParseInt(s[i:i+2], 16, 16)
		bs = append(bs, byte(b))
	}
	return bs
}

func memcpy(dst, src []byte, size int) {
	for i := 0; i < size; i++ {
		dst[i] = src[i]
	}
	return
}
func base64Encoding(enc *base64.Encoding, data []byte) string {
	// 编码
	encStr := enc.EncodeToString(data)
	return encStr
}

var (
	conFile = flag.String("configfile", "/tmsconf.ini", "config file")
)

//全局变量
var records [][]string
var outkey2 [][]string
var srecv []string
var MID string = "xxx"
var FID string = "xxx"

//var SN string = "xxxxxx3"
//var SN string = "xxxxxxxx"
var SN string = "xxxxxxxx"
var random string = "51xxxxxxxx030"

//var tmskey1 string = "xxxxxxxD4A4C1E"
var tmskey1 string = "xxxxxx"
var tmskey2 string = ""
var mainkey string = ""
var url_keyactive_test string = "xxxxxx/TMSWebService/nostandard/10003"
var url_keyactive string = "https://xxxxx/TMSWebService/nostandard/10003"
var url_keydownload string = "https://xxxxxxx/TMSWebService/standard/10004"
var url_updatecheck string = "https://xxxx/TMSWebService/standard/10001"

//url_keydownload := "http://xxxx/TMSWebService/nostandard/10004"
//url_updatecheck := "http://58.247xxxx/TMSWebService/nostandard/10001"

//bufsend = make([]byte, 21, 128)
//bufrand = make([]byte, 16)
func dataXor(src, dest []byte, size int) {
	for i := 0; i < size; i++ {
		src[i] = ((dest[i] & 0xff) ^ (src[i] & 0xff))
	}
	return
}

func calcAuthInfo(random, fid, mid, sn, tmskey1 string) string {

	auinfo := fid + mid + sn
	auinfolen := len(auinfo)
	auinfoloop := auinfolen / 8
	if (auinfolen % 8) > 0 {
		auinfoloop++
	}
	aubuf := make([]byte, auinfoloop*8)
	memcpy(aubuf, []byte(auinfo), auinfolen)
	authkey, _ := desutil.Des3Encrypt([]byte(random), hexStringToBytes(tmskey1))

	auinfoI := make([]byte, 8)
	auinfoD := make([]byte, 8)
	for i := 0; i < auinfoloop; i++ {
		memcpy(auinfoD, aubuf[i*8:], 8)
		dataXor(auinfoI, auinfoD, 8)
		auinfoI, _ = desutil.Des3Encrypt(auinfoI, authkey)
	}
	authinfo := base64Encoding(base64.StdEncoding, auinfoI)
	fmt.Println(authinfo)
	return authinfo
}

func tmsHttpPost(url string, sn string, tmskey1 string, transcode string, body string) (string, error) {
	headers := make(map[string]string)
	headers["VER"] = "01"
	headers["Encoding"] = "UTF8"
	headers["content-type"] = "application/json"
	headers["FID"] = FID
	headers["MID"] = MID
	headers["SN"] = sn
	headers["Random"] = random
	headers["TransCode"] = transcode
	headers["AuthInfo"] = calcAuthInfo(random, FID, MID, sn, tmskey1)
	strout, err := httputil.HttpPost(url, headers, body)
	if err != nil {
		//log.Fatal(err)
		return "", err
	}
	//log.Printf(strout)
	return strout, nil
}

func tmsHttpsPost(url string, sn string, tmskey1 string, transcode string, body string) (string, error) {
	headers := make(map[string]string)
	headers["VER"] = "01"
	headers["Encoding"] = "UTF8"
	headers["content-type"] = "application/json"
	headers["FID"] = FID
	headers["MID"] = MID
	headers["SN"] = sn
	headers["Random"] = random
	headers["TransCode"] = transcode
	headers["AuthInfo"] = calcAuthInfo(random, FID, MID, sn, tmskey1)
	strout, err := httputil.HttpsPost(url, headers, body)
	if err != nil {
		//log.Fatal(err)
		return "", err
	}
	//log.Printf(strout)
	return strout, nil
}

func main() {

	fmt.Println("Hello Go")
	//bufsend = make([]byte, 21, 128)
	//bufrand = make([]byte, 16)
	//httputil.HttpDo()
	fmt.Println("DES test...")
	data := []byte("12345678")
	key := []byte("12345678")
	result, err := desutil.DesEncrypt(data, key)
	if err != nil {
		fmt.Println(err)
	}
	a := hex.EncodeToString(result)
	fmt.Println(a)
	out, _ := hex.DecodeString(a)
	result, err = desutil.DesDecrypt(out, key)
	if err != nil {
		fmt.Println(err)
	}
	a = hex.EncodeToString(result)
	fmt.Println(a)

	//加载读取csv格式的文件ww
	log.Printf("load outkey1.csv file...")
	rfile, _ := os.Open("outkey1.csv")
	reader := csv.NewReader(rfile)
	for {
		// Read返回的是一个数组,它已经帮我们分割了,
		record, err := reader.Read()
		// 如果读到文件的结尾,EOF的优先级居然比nil还高!
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Println("记录集错误:", err)
			break
		}
		records = append(records, record)
		for i := 0; i < len(record); i++ {
			//fmt.Print(record[i] + " ")
		}
		//fmt.Print("n")
	}

	fmt.Print(records)
	fmt.Print("n")
	for i := 0; i < len(records); i++ {
		//fmt.Print(records[i][1])
		//fmt.Print("n")
		//SN =
	}
	fmt.Print("n")

	//=============================================
	name := ""
	//获取当前路径
	file, _ := os.Getwd()
	cfg, err := config.ReadDefault(file + *conFile)

	//获取配置文件中的配置项
	url_keyactive, err := cfg.String("URL", "url_keyactive")
	fmt.Println(url_keyactive)
	fmt.Println("tms tool,downlad tmskey2 from tms... ")
	fmt.Println("Please press any key to continue: ")
	fmt.Scanln(&name)
	down := func(sn, key1 string) {
		fmt.Println("tms tool begin downlad... ")
		fmt.Println(sn)
		fmt.Println(key1)
		//http test
		srecv = make([]string, 8)
		var strout string
		strout, err = tmsHttpsPost(url_keyactive, sn, key1, "020", "")
		if err != nil {
			log.Fatal(err)
		}
		log.Printf(strout)
		var f interface{}
		err = json.Unmarshal([]byte(strout), &f)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(f)
		m := f.(map[string]interface{})
		if m["ReturnCode"] == "00" {
			log.Printf("ok,秘钥分量2下载成功!")

			if str, ok := m["MKey2"].(string); ok {
				tmskey2 = str
			} else {
				tmskey2 = ""
			}

			fmt.Println("终端号:" + SN)
			fmt.Println("秘钥分量2密文:" + tmskey2)
			out, _ := desutil.Des3Decrypt(hexStringToBytes(tmskey2), hexStringToBytes(tmskey1))
			tmskey2 = bytesToHexString(out)
			fmt.Println("秘钥分量2明文:" + tmskey2)

			srecv[0] = SN
			srecv[1] = tmskey2

		} else {
			log.Printf("秘钥分量2下载失败!")
		}

		//fmt.Println("over!press any key to continue: ")
		//fmt.Scanln(&name)

		strout, err = tmsHttpsPost(url_keydownload, SN, tmskey2, "030", "")
		if err != nil {
			log.Fatal(err)
		}
		log.Printf(strout)

		err = json.Unmarshal([]byte(strout), &f)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(f)
		m = f.(map[string]interface{})
		if m["ReturnCode"] == "00" {
			log.Printf("ok,主秘钥下载成功!")
			n := m["KEY1"].(map[string]interface{})
			fmt.Println(n)
			fmt.Println(n["Key"])
			if str, ok := n["Key"].(string); ok {
				mainkey = str
			} else {
				mainkey = ""
			}
			fmt.Println("终端号:" + SN)
			fmt.Println("主秘钥密文:" + mainkey)
			out, _ := desutil.Des3Decrypt(hexStringToBytes(mainkey), hexStringToBytes(tmskey2))
			mainkey = bytesToHexString(out)
			fmt.Println("主秘钥明文:" + mainkey)
			srecv[2] = mainkey
		} else {
			log.Printf("主秘钥下载失败!")
		}
		//fmt.Println("over!press any key to continue: ")
		//fmt.Scanln(&name)

		var poststr string
		//商户号,终端号,IP,端口,TPDU
		poststr =
			`{
        "APPCount":     1,
        "APP1": {
                "APPID":        "xxxx",
                "APPVer":       "0",
                "APPIndex":     "1",
                "APPState":     "1",
                "ParameterUp":  {
                        "04000001":     "1"
                },
                "Parameter":    ["01000001", "01000002", "01000005", "04000001", "04000002", "04000006", "04000007","04000029","04000030","deptcode"]
                }
        }`

		strout, err = tmsHttpsPost(url_updatecheck, SN, tmskey2, "010", poststr)
		if err != nil {
			log.Fatal(err)
		}
		log.Printf(strout)

		err = json.Unmarshal([]byte(strout), &f)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(f)
		m = f.(map[string]interface{})
		if m["ReturnCode"] == "00" {
			log.Printf("ok,参数下载成功!")
			n := m["APP2"].(map[string]interface{})
			fmt.Println(n)
			p := n["Parameter"].(map[string]interface{})
			fmt.Println(p)
			//商户号
			fmt.Println(p["01000001"])
			//终端号
			fmt.Println(p["01000005"])
			//TPDU
			fmt.Println(p["04000002"])

			fmt.Println(p["04000029"])

			fmt.Println(p["04000030"])

			srecv[3] = p["01000001"].(string)
			srecv[4] = p["01000005"].(string)
			srecv[5] = p["04000002"].(string)

			srecv[6] = p["04000029"].(string)
			srecv[7] = p["04000030"].(string)

		} else {
			log.Printf("err,参数下载失败!")
		}

		outkey2 = append(outkey2, srecv)

	}

	for i := 0; i < len(records); i++ {
		//fmt.Print(records[i][1])
		//fmt.Print("n")
		SN = records[i][0]
		tmskey1 = records[i][1]

		down(SN, tmskey1)
	}

	fmt.Print("downoad over!n")

	rfile, err = os.Create("outkey2.csv")
	if err != nil {
		panic(err)
	}
	defer rfile.Close()
	//f.WriteString("xEFxBBxBF")
	w := csv.NewWriter(rfile)
	w.WriteAll(outkey2) //WriteAll保存slice二维数据
	w.Flush()

	fmt.Println("over,save file outkey2.csv ok,press any key to continue ")
	fmt.Scanln(&name)

}
package httputil

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func HttpPost(url string, headers map[string]string, data string) (string, error) {

	client := &http.Client{}

	req, err := http.NewRequest("POST", url, strings.NewReader(data))
	if err != nil {
		// handle error
		log.Fatal(err)
		return "", err
	}

	for key := range headers {
		fmt.Println(key, ":", headers[key])
		req.Header.Set(key, headers[key])
	}

	resp, err := client.Do(req)

	defer resp.Body.Close()

	var body []byte
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
		log.Fatal(err)
		return "", err

	}

	//fmt.Println(string(body))
	//log.Printf(string(body))
	return string(body), nil
	//jsonStr := string(body)
	//fmt.Println("jsonStr", jsonStr)
}

func HttpsPost(url string, headers map[string]string, data string) (string, error) {

	//client := &http.Client{}
	// tr := &http.Transport{
	// 	TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	// }
	pool := x509.NewCertPool()
	caCertPath := "umstms.pem"

	caCrt, err := ioutil.ReadFile(caCertPath)
	if err != nil {
		fmt.Println("ReadFile err:", err)
		//return
	}

	pool.AppendCertsFromPEM(caCrt)
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			RootCAs:            pool,
			InsecureSkipVerify: true,
		},
	}
	client := &http.Client{Transport: tr}

	req, err := http.NewRequest("POST", url, strings.NewReader(data))
	if err != nil {
		// handle error
		log.Fatal(err)
		return "", err
	}

	for key := range headers {
		fmt.Println(key, ":", headers[key])
		req.Header.Set(key, headers[key])
	}

	resp, err := client.Do(req)

	defer resp.Body.Close()

	var body []byte
	body, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
		log.Fatal(err)
		return "", err

	}

	//fmt.Println(string(body))
	//log.Printf(string(body))
	return string(body), nil
	//jsonStr := string(body)
	//fmt.Println("jsonStr", jsonStr)
}
package desutil

import (
	"bytes"
	"crypto/des"
	"encoding/hex"
	"errors"
	"fmt"
)

func main() {
	data := []byte("1234567812345678")
	key := []byte("12345678")
	result, err := DesEncrypt(data, key)
	if err != nil {
		fmt.Println(err)
	}
	a := hex.EncodeToString(result)
	fmt.Println(a)
	out, _ := hex.DecodeString(a)
	result, err = DesDecrypt(out, key)
	if err != nil {
		fmt.Println(err)
	}
	a = hex.EncodeToString(result)
	fmt.Println(a)

	data = []byte("1234567812345678")
	key = []byte("1234567812345678")

	result, err = Des3Encrypt(data, key)
	if err != nil {
		fmt.Println(err)
	}
	a = hex.EncodeToString(result)
	fmt.Println(a)

}

//DES算法,ECB模式
func DesEncrypt(data, key []byte) ([]byte, error) {
	//NewCipher创建一个新的加密块
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}

	bs := block.BlockSize()
	//data = Pkcs5Padding(data, bs)
	//if len(data)%bs != 0 {
	//	return nil, errors.New("need a multiple of the blocksize")
	//}

	out := make([]byte, len(data))
	dst := out
	for len(data) > 0 {
		//Encrypt加密第一个块,将其结果保存到dst
		block.Encrypt(dst, data[:bs])
		data = data[bs:]
		dst = dst[bs:]
	}
	return out, nil
}

func DesDecrypt(data, key []byte) ([]byte, error) {
	//NewCipher创建一个新的加密块
	block, err := des.NewCipher(key)
	if err != nil {
		return nil, err
	}

	bs := block.BlockSize()
	//data = Pkcs5Padding(data, bs)
	//if len(data)%bs != 0 {
	//  return nil, errors.New("need a multiple of the blocksize")
	//}

	out := make([]byte, len(data))
	dst := out
	for len(data) > 0 {
		//Encrypt加密第一个块,将其结果保存到dst
		block.Decrypt(dst, data[:bs])
		data = data[bs:]
		dst = dst[bs:]
	}
	return out, nil
}

//[golang ECB 3DES Encrypt]
//3DES双倍长算法
func Des3Encrypt(origData, key []byte) ([]byte, error) {

	if (len(key) != 16) || (len(origData)%8 != 0) {
		return nil, errors.New("error,lenth is not right!")
	}
	tkey := make([]byte, 16, 16)
	copy(tkey, key)
	k1 := tkey[:8]
	k2 := tkey[8:16]

	//bs := block.BlockSize()
	//origData = PKCS5Padding(origData, bs)

	buf1, err := DesEncrypt(origData, k1)
	if err != nil {
		return nil, err
	}
	buf2, err := DesDecrypt(buf1, k2)
	if err != nil {
		return nil, err
	}
	out, err := DesEncrypt(buf2, k1)
	if err != nil {
		return nil, err
	}
	return out, nil
}

//[golang ECB 3DES Decrypt]
//3DES双倍长算法
func Des3Decrypt(crypted, key []byte) ([]byte, error) {

	tkey := make([]byte, 16, 16)
	copy(tkey, key)
	k1 := tkey[:8]
	k2 := tkey[8:16]
	buf1, err := DesDecrypt(crypted, k1)
	if err != nil {
		return nil, err
	}
	buf2, err := DesEncrypt(buf1, k2)
	if err != nil {
		return nil, err
	}
	out, err := DesDecrypt(buf2, k1)
	if err != nil {
		return nil, err
	}
	//out = PKCS5Unpadding(out)
	return out, nil
}

func Pkcs5Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}