微信公众号消息加解密

科技资讯 投稿 6400 0 评论

微信公众号消息加解密

服务器配置中将消息加解密模式指定为安全模式

官方提供了5种开发语言的示例代码,参照官方给的C++示例代码,本文给出go语言的解密实现:

func handlerEncrypt(body []byte, timestamp, nonce, msg_sig string (random, rawXMLMsg []byte, err error {
	request := &WeChatEncryptRequest{}
	err = xml.Unmarshal(body, request
	if err != nil {
		log.Errorf("unmarshal wechat encrypt request error: %s"
		errors.Wrap(err, "unmarshal wechat encrypt request error"
		return
	}

	// verify msg from wechat signature
	if calcSignature(token, timestamp, nonce, request.Encrypt != msg_sig {
		log.Errorf("encrypt msg got from wechat verify signature failed"
		errors.New("encrypt msg got from wechat verify signature failed"
		return
	}

	// decode cipher text from base64
	cipherText, err := base64.StdEncoding.DecodeString(request.Encrypt
	if err != nil {
		log.Errorf("decode wechat encrypt request error: %s", err.Error(
		errors.Wrap(err, "decode wechat encrypt request error"
		return
	}
	// aes decrypt
	plainText, err := aesDecrypt(cipherText, key
	if err != nil {
		log.Errorf("decrypt wechat encrypt request error: %s", err.Error(
		errors.Wrap(err, "decrypt wechat encrypt request error"
		return
	}

	// get raw wechat encrypt request length
	rawXMLMsgLen := int(ntohl(plainText[16:20]
	if rawXMLMsgLen < 0 {
		log.Errorf("incorrect msg length: %d", rawXMLMsgLen
		errors.Wrapf(err, "incorrect msg length: %d", rawXMLMsgLen
		return
	}

	// verify appid
	appIDOffset := 20 + rawXMLMsgLen
	if len(plainText <= appIDOffset {
		log.Errorf("msg length too large: %d", rawXMLMsgLen
		errors.Wrapf(err, "msg length too large: %d", rawXMLMsgLen
		return
	}
	// verify appid
	if appID != string(plainText[appIDOffset:] {
		log.Errorf("Received an attack disguised as a WeChat server."
		errors.New("Received an attack disguised as a WeChat server."
		return
	}

	// get random which from wechat
	random = plainText[:16:20]

	// raw wechat msg
	rawXMLMsg = plainText[20:appIDOffset:appIDOffset]
	return
}

func calcSignature(args ...string string {
	sort.Strings(args
	h := sha1.New(
	for _, arg := range args {
		io.WriteString(h, arg
	}

	return hex.EncodeToString(h.Sum(nil
}

func aesDecrypt(cipherText []byte, key []byte ([]byte, error {
	block, err := aes.NewCipher(key
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize(
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]
	plainText := make([]byte, len(cipherText
	blockMode.CryptBlocks(plainText, cipherText
	plainText = pkcs7UnPadding(plainText
	return plainText, nil
}

func pkcs7UnPadding(data []byte []byte {
	length := len(data
	unpadding := int(data[length-1]
	return data[:(length - unpadding]
}

func ntohl(orderBytes []byte (n uint32 {
	return uint32(orderBytes[0]<<24 |
		uint32(orderBytes[1]<<16 |
		uint32(orderBytes[2]<<8 |
		uint32(orderBytes[3]
}

完整的代码示例在这里。


Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意


编程笔记 » 微信公众号消息加解密

赞同 (34) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽