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