//将企业号回复用户的消息加密打包 // @param sReplyMsg: 企业号待回复用户的消息,xml格式的字符串 // @param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp // @param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce // @param sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串, // 当return返回0时有效 // return:成功0,失败返回对应的错误码 public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg) { if (m_sEncodingAESKey.Length != 43) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey); } string raw = ""; try { raw = Cryptography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sAppID); } catch (Exception) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_EncryptAES_Error); } string MsgSigature = ""; int ret = 0; ret = GenarateSinature(m_sToken, sTimeStamp, sNonce, raw, ref MsgSigature); if (0 != ret) { return(ret); } sEncryptMsg = ""; string EncryptLabelHead = "<Encrypt><![CDATA["; string EncryptLabelTail = "]]></Encrypt>"; string MsgSigLabelHead = "<MsgSignature><![CDATA["; string MsgSigLabelTail = "]]></MsgSignature>"; string TimeStampLabelHead = "<TimeStamp><![CDATA["; string TimeStampLabelTail = "]]></TimeStamp>"; string NonceLabelHead = "<Nonce><![CDATA["; string NonceLabelTail = "]]></Nonce>"; sEncryptMsg = sEncryptMsg + "<xml>" + EncryptLabelHead + raw + EncryptLabelTail; sEncryptMsg = sEncryptMsg + MsgSigLabelHead + MsgSigature + MsgSigLabelTail; sEncryptMsg = sEncryptMsg + TimeStampLabelHead + sTimeStamp + TimeStampLabelTail; sEncryptMsg = sEncryptMsg + NonceLabelHead + sNonce + NonceLabelTail; sEncryptMsg += "</xml>"; return(0); }
/// <summary> /// 将消息加密,返回加密后字符串 /// </summary> /// <param name="sReplyMsg">传递的消息体明文</param> /// <param name="sTimeStamp">时间戳</param> /// <param name="sNonce">随机字符串</param> /// <param name="sEncryptMsg">加密后的消息信息</param> /// <returns>成功0,失败返回对应的错误码</returns> public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg, ref string signature) { if (string.IsNullOrEmpty(sReplyMsg)) { return((int)DingTalkCryptErrorCode.ENCRYPTION_PLAINTEXT_ILLEGAL); } if (string.IsNullOrEmpty(sTimeStamp)) { return((int)DingTalkCryptErrorCode.ENCRYPTION_TIMESTAMP_ILLEGAL); } if (string.IsNullOrEmpty(sNonce)) { return((int)DingTalkCryptErrorCode.ENCRYPTION_NONCE_ILLEGAL); } if (m_sEncodingAESKey.Length != AES_ENCODE_KEY_LENGTH) { return((int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL); } string raw = ""; try { raw = Cryptography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sSuiteKey); } catch (Exception) { return((int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL); } string msgSigature = ""; int ret = GenerateSignature(m_sToken, sTimeStamp, sNonce, raw, ref msgSigature); sEncryptMsg = raw; signature = msgSigature; return(ret); }
public async Task InvokeAsync(HttpContext context) { var request = context.Request; if (request.Path.Value.Contains(_options.Value.LazyWechatListener)) { bool validation = Validate(out string signature, out string timestamp, out string nonce, out string echostr); var info = "signature:{0},timestamp:{1},nonce:{2},echostr:{3} received from wechat at {4}"; _logger.LogInformation(info, signature, timestamp, nonce, echostr, DateTime.Now); var weChatMessager = new WeChatMessager { signature = signature, timestamp = timestamp, nonce = nonce, echostr = echostr, validation = validation, type = _options.Value.Type, method = context.Request.Method }; #region 以stream的方式获取微信post到监听程序的数据:数据类型为XML var inputContent = ""; using (StreamReader stream = new StreamReader(request.Body, Encoding.UTF8)) { inputContent = await stream.ReadToEndAsync(); } #endregion info = "inputXml:'{0}' received from wechat at {1}"; _logger.LogInformation(info, inputContent, DateTime.Now); var encrypted = false; if (!string.IsNullOrEmpty(inputContent)) { dynamic messageBody = new ExpandoObject(); messageBody = ParseMessage(inputContent, out MessageFormat format); weChatMessager.format = format; if (UtilRepository.IsPropertyExist(messageBody, "Encrypt")) { string decryptedMessage = Cryptography.AES_decrypt(messageBody.Encrypt, _options.Value.EncodingAESKey); messageBody = ParseMessage(decryptedMessage, out _); encrypted = true; } weChatMessager.messageBody = messageBody; if (UtilRepository.IsPropertyExist(messageBody, "FromUserName")) { _onMessageReceived?.Invoke(weChatMessager); } var json = JsonConvert.SerializeObject(weChatMessager); _ = _messageQueue.Push(json); info = "json format of message:'{0}' has been pushed into queue at {1}"; _logger.LogInformation(info, json, DateTime.Now); } var message = weChatMessager.message; if (encrypted && message.ToLower() != "success") { var encryptMessage = Cryptography.AES_encrypt(weChatMessager.message, _options.Value.EncodingAESKey, _options.Value.AppID); var signatureResponse = generateSignature(timestamp, nonce, encryptMessage); message = string.Format(MessageTemplateFactory.CreateInstance(weChatMessager.format == MessageFormat.Xml ? MessageType.Encrypt : MessageType.EncryptJson), encryptMessage, signatureResponse, timestamp, nonce); } info = "sent message:'{0}' has been logged at {1}"; _logger.LogInformation(info, message, DateTime.Now); await context.Response.WriteAsync(message); } else { await _next(context); } bool Validate(out string signature, out string timestamp, out string nonce, out string echostr) { #region 微信在向监听程序发送数据的时候会同时发送signature,timestamp,nonce以及echostr供用户判断该请求是否来自微信端 signature = string.IsNullOrEmpty(request.Query["signature"]) ? "" : request.Query["signature"].ToString(); timestamp = string.IsNullOrEmpty(request.Query["timestamp"]) ? "" : request.Query["timestamp"].ToString(); nonce = string.IsNullOrEmpty(request.Query["nonce"]) ? "" : request.Query["nonce"].ToString(); echostr = string.IsNullOrEmpty(request.Query["echostr"]) ? "" : request.Query["echostr"].ToString(); #endregion List <string> lstSort = new List <string> { _options.Value.Token, timestamp, nonce }; lstSort.Sort(); var sha1 = string.Join(string.Empty, lstSort).SHA1(); var validation = (sha1.ToUpper() == signature.ToUpper()); return(validation); } string generateSignature(string timestamp, string nonce, string encryptMessage) { ArrayList AL = new ArrayList(); AL.Add(_options.Value.Token); AL.Add(timestamp); AL.Add(nonce); AL.Add(encryptMessage); AL.Sort(new DictionarySort()); string raw = ""; for (int i = 0; i < AL.Count; ++i) { raw += AL[i]; } SHA1 sha; ASCIIEncoding enc; string hash = ""; sha = new SHA1CryptoServiceProvider(); enc = new ASCIIEncoding(); byte[] dataToHash = enc.GetBytes(raw); byte[] dataHashed = sha.ComputeHash(dataToHash); hash = BitConverter.ToString(dataHashed).Replace("-", ""); hash = hash.ToLower(); return(hash); } dynamic ParseMessage(string inputContent, out MessageFormat format) { inputContent = inputContent.Trim().Replace("\n", ""); dynamic messageBody = new ExpandoObject(); if (inputContent.StartsWith("<") && inputContent.EndsWith(">")) { messageBody = UtilRepository.ParseAPIResult(JsonConvert.SerializeObject(inputContent.FromXml())); format = MessageFormat.Xml; } else if (inputContent.StartsWith("{") && inputContent.EndsWith("}")) { messageBody = UtilRepository.ParseAPIResult(inputContent); format = MessageFormat.Json; } else { throw new ArgumentException(nameof(inputContent)); } return(messageBody); } }