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:] } }