|
|
@@ -0,0 +1,306 @@
|
|
|
+package packet
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "crypto/aes"
|
|
|
+ "crypto/cipher"
|
|
|
+ "crypto/des"
|
|
|
+ "encoding/binary"
|
|
|
+ "encoding/hex"
|
|
|
+ "errors"
|
|
|
+)
|
|
|
+
|
|
|
+const AESKey = "F7A72DE7D6264530F01BA49BC73EB873"
|
|
|
+const macKey = "B0FB83E39A5EBFAABE471362A58393FF"
|
|
|
+const macIV = "D951DBE037C82325"
|
|
|
+
|
|
|
+// FIXME: - 为减少内存操作,这里的[]byte应该使用*[]byte
|
|
|
+
|
|
|
+func Encrypt(plaintext []byte, keyHex string, isPacket50 bool) ([]byte, error) {
|
|
|
+ key := []byte(keyHex)
|
|
|
+
|
|
|
+ // 构建密文结构体: 4 byte 明文长度+密文+8 byte MAC检验码
|
|
|
+ result := []byte{}
|
|
|
+ // 明文长度
|
|
|
+ plaintextLen := len(plaintext)
|
|
|
+ plaintextLenData := make([]byte, 4) // 如果写为 []byte{},PutUint32时会报溢出
|
|
|
+ binary.LittleEndian.PutUint32(plaintextLenData, uint32(plaintextLen))
|
|
|
+ result = append(result, plaintextLenData...)
|
|
|
+ // mac校验目标
|
|
|
+ macPlainText := result[:]
|
|
|
+ macPlainText = append(macPlainText, []byte{0, 0, 0, 0}...)
|
|
|
+
|
|
|
+ // 对内容进行加密
|
|
|
+ if isPacket50 {
|
|
|
+ // 5.0 报文
|
|
|
+ ciphertext, err := aesEncrypt(plaintext, key)
|
|
|
+ // ciphertext, err := aesEncrypt(plaintext, key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ result = append(result, ciphertext...)
|
|
|
+ } else {
|
|
|
+ // 4.0 报文
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // MAC检验码
|
|
|
+ // 注意:由于服务端的错误(遇到\0就停止),原本需要把长度+密文生成校验码,现改由长度4 byte进行校验即可
|
|
|
+ macKeyData, _ := hex.DecodeString(macKey)
|
|
|
+ macIVData, _ := hex.DecodeString(macIV)
|
|
|
+ macData, err := macAnsi(macPlainText, macKeyData, macIVData)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ result = append(result, macData...)
|
|
|
+
|
|
|
+ return result, nil
|
|
|
+}
|
|
|
+
|
|
|
+func Decrypt(ciphertext []byte, keyHex string, isPacket50 bool) ([]byte, error) {
|
|
|
+ key := []byte(keyHex)
|
|
|
+
|
|
|
+ // 对内容进行加密
|
|
|
+ if isPacket50 {
|
|
|
+ return aesDecrypt(ciphertext, key)
|
|
|
+ } else {
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func aesEncrypt(plaintext, key []byte) ([]byte, error) {
|
|
|
+ block, err := aes.NewCipher(key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, errors.New("错误的数据或密钥")
|
|
|
+ }
|
|
|
+ ecb := NewECBEncrypter(block)
|
|
|
+ content := plaintext[:]
|
|
|
+ content = PKCS5Padding(content, block.BlockSize())
|
|
|
+ crypted := make([]byte, len(content))
|
|
|
+ ecb.CryptBlocks(crypted, content)
|
|
|
+
|
|
|
+ return crypted, nil
|
|
|
+}
|
|
|
+
|
|
|
+func aesDecrypt(crypted, key []byte) ([]byte, error) {
|
|
|
+ var err error
|
|
|
+
|
|
|
+ defer func() {
|
|
|
+ if err := recover(); err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ block, err := aes.NewCipher(key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ blockMode := NewECBDecrypter(block)
|
|
|
+ origData := make([]byte, len(crypted))
|
|
|
+ blockMode.CryptBlocks(origData, crypted)
|
|
|
+ origData = PKCS5UnPadding(origData)
|
|
|
+
|
|
|
+ return origData, err
|
|
|
+}
|
|
|
+
|
|
|
+// Des加密
|
|
|
+func desEncrypt(plaintext []byte, key []byte) ([]byte, error) {
|
|
|
+ if len(plaintext) < 1 || len(key) < 1 {
|
|
|
+ return nil, errors.New("错误的数据或密钥")
|
|
|
+ }
|
|
|
+ block, err := des.NewCipher(key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ blockSize := block.BlockSize()
|
|
|
+ origData := PKCS5Padding(plaintext, blockSize)
|
|
|
+ out := make([]byte, len(origData))
|
|
|
+ dst := out
|
|
|
+
|
|
|
+ // for len(origData) > 0 {
|
|
|
+ // block.Encrypt(dst, origData[:blockSize])
|
|
|
+ // origData = origData[blockSize:]
|
|
|
+ // dst = dst[blockSize:]
|
|
|
+ // }
|
|
|
+
|
|
|
+ // return out, nil
|
|
|
+
|
|
|
+ block.Encrypt(dst, origData[:blockSize])
|
|
|
+ origData = origData[blockSize:]
|
|
|
+ dst = dst[blockSize:]
|
|
|
+
|
|
|
+ return out[0:8], nil
|
|
|
+}
|
|
|
+
|
|
|
+// Des解密
|
|
|
+func desDecrypt(plaintext []byte, key []byte) ([]byte, error) {
|
|
|
+ if len(plaintext) < 1 || len(key) < 1 {
|
|
|
+ return nil, errors.New("wrong data or key")
|
|
|
+ }
|
|
|
+ block, err := des.NewCipher(key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ blockSize := block.BlockSize()
|
|
|
+ origData := PKCS5Padding(plaintext, blockSize)
|
|
|
+ out := make([]byte, len(origData))
|
|
|
+ dst := out
|
|
|
+
|
|
|
+ // for len(origData) > 0 {
|
|
|
+ // block.Decrypt(dst, origData[:blockSize])
|
|
|
+ // origData = origData[blockSize:]
|
|
|
+ // dst = dst[blockSize:]
|
|
|
+ // }
|
|
|
+
|
|
|
+ // return out, nil
|
|
|
+
|
|
|
+ block.Decrypt(dst, origData[:blockSize])
|
|
|
+ origData = origData[blockSize:]
|
|
|
+ dst = dst[blockSize:]
|
|
|
+
|
|
|
+ return out[0:8], nil
|
|
|
+}
|
|
|
+
|
|
|
+func macAnsiX99(plainText []byte, key []byte, iv []byte) ([]byte, error) {
|
|
|
+ if len(plainText)%8 != 0 {
|
|
|
+ return nil, errors.New("目标数据长度必须为8的整数倍")
|
|
|
+ }
|
|
|
+ if len(key) != 8 {
|
|
|
+ return nil, errors.New("密钥位数不正确")
|
|
|
+ }
|
|
|
+ if len(iv) != 8 {
|
|
|
+ return nil, errors.New("向量位数不正确")
|
|
|
+ }
|
|
|
+
|
|
|
+ macData := iv[:]
|
|
|
+ xorData := make([]byte, 8)
|
|
|
+ for i := 0; i < len(plainText); i += 8 {
|
|
|
+ // 以8 byte为单位进行异或运算
|
|
|
+ for j := 0; j < 8; j++ {
|
|
|
+ xorData[j] = macData[j] ^ plainText[i+j]
|
|
|
+ }
|
|
|
+
|
|
|
+ // 异或结果的 8 byte 数据进行一次DES加密
|
|
|
+ desData, err := desEncrypt(xorData, key)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ macData = desData[:]
|
|
|
+ }
|
|
|
+
|
|
|
+ return macData, nil
|
|
|
+}
|
|
|
+
|
|
|
+func macAnsiX919(plainText []byte, key []byte, iv []byte) ([]byte, error) {
|
|
|
+ if len(plainText)%8 != 0 {
|
|
|
+ return nil, errors.New("目标数据长度必须为8的整数倍")
|
|
|
+ }
|
|
|
+ if len(key) != 16 {
|
|
|
+ return nil, errors.New("密钥位数不正确")
|
|
|
+ }
|
|
|
+ if len(iv) != 8 {
|
|
|
+ return nil, errors.New("向量位数不正确")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分解密钥
|
|
|
+ keyLeft := key[0:8]
|
|
|
+ keyRight := key[8:16]
|
|
|
+
|
|
|
+ // MAC(L)->R解密->L加密
|
|
|
+ dataLeft, err := macAnsiX99(plainText, keyLeft, iv)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ dataRight, err := desDecrypt(dataLeft, keyRight)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ return desEncrypt(dataRight, keyLeft)
|
|
|
+}
|
|
|
+
|
|
|
+func macAnsi(plainText []byte, key []byte, iv []byte) ([]byte, error) {
|
|
|
+ keyLen := len(key)
|
|
|
+ if keyLen == 8 {
|
|
|
+ return macAnsiX99(plainText, key, iv)
|
|
|
+ } else if keyLen == 16 {
|
|
|
+ return macAnsiX919(plainText, key, iv)
|
|
|
+ } else {
|
|
|
+ return nil, errors.New("密钥位数不正确")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ECB PKCS5Padding
|
|
|
+func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
|
|
+ padding := blockSize - len(ciphertext)%blockSize
|
|
|
+ padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
|
|
+ return append(ciphertext, padtext...)
|
|
|
+}
|
|
|
+
|
|
|
+// ECB PKCS5Unpadding
|
|
|
+func PKCS5UnPadding(origData []byte) []byte {
|
|
|
+ length := len(origData)
|
|
|
+ // 去掉最后一个字节 unpadding 次
|
|
|
+ unpadding := int(origData[length-1])
|
|
|
+ if unpadding > unpadding {
|
|
|
+ return []byte{}
|
|
|
+ }
|
|
|
+ return origData[:(length - unpadding)]
|
|
|
+}
|
|
|
+
|
|
|
+type ecb struct {
|
|
|
+ b cipher.Block
|
|
|
+ blockSize int
|
|
|
+}
|
|
|
+
|
|
|
+func newECB(b cipher.Block) *ecb {
|
|
|
+ return &ecb{
|
|
|
+ b: b,
|
|
|
+ blockSize: b.BlockSize(),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+type ecbEncrypter ecb
|
|
|
+
|
|
|
+// NewECBEncrypter returns a BlockMode which encrypts in electronic code book
|
|
|
+// mode, using the given Block.
|
|
|
+func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
|
|
|
+ return (*ecbEncrypter)(newECB(b))
|
|
|
+}
|
|
|
+func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
|
|
|
+func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
|
|
|
+ if len(src)%x.blockSize != 0 {
|
|
|
+ panic("crypto/cipher: input not full blocks")
|
|
|
+ }
|
|
|
+ if len(dst) < len(src) {
|
|
|
+ panic("crypto/cipher: output smaller than input")
|
|
|
+ }
|
|
|
+ for len(src) > 0 {
|
|
|
+ x.b.Encrypt(dst, src[:x.blockSize])
|
|
|
+ src = src[x.blockSize:]
|
|
|
+ dst = dst[x.blockSize:]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+type ecbDecrypter ecb
|
|
|
+
|
|
|
+// NewECBDecrypter returns a BlockMode which decrypts in electronic code book
|
|
|
+// mode, using the given Block.
|
|
|
+func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
|
|
|
+ return (*ecbDecrypter)(newECB(b))
|
|
|
+}
|
|
|
+func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
|
|
|
+func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
|
|
|
+ if len(src)%x.blockSize != 0 {
|
|
|
+ panic("crypto/cipher: input not full blocks")
|
|
|
+ }
|
|
|
+ if len(dst) < len(src) {
|
|
|
+ panic("crypto/cipher: output smaller than input")
|
|
|
+ }
|
|
|
+ for len(src) > 0 {
|
|
|
+ x.b.Decrypt(dst, src[:x.blockSize])
|
|
|
+ src = src[x.blockSize:]
|
|
|
+ dst = dst[x.blockSize:]
|
|
|
+ }
|
|
|
+}
|