/// <summary> /// 验证URL /// </summary> /// <param name="sMsgSignature">签名串,对应URL参数的msg_signature</param> /// <param name="sTimeStamp">时间戳,对应URL参数的timestamp</param> /// <param name="sNonce">随机串,对应URL参数的nonce</param> /// <param name="sEchoStr">经过加密的消息体,对应URL参数的encrypt</param> /// <param name="sReplyEchoStr"></param> /// <returns></returns> public int VerifyURL(string sMsgSignature, string sTimeStamp, string sNonce, string sEchoStr, ref string sReplyEchoStr) { int ret = 0; if (m_sEncodingAESKey.Length != 43) { return((int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL); } ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEchoStr, sMsgSignature); sReplyEchoStr = ""; string cpid = ""; try { sReplyEchoStr = Cryptography.AES_decrypt(sEchoStr, m_sEncodingAESKey, ref cpid); //m_sCorpID); } catch (Exception) { sReplyEchoStr = ""; return((int)DingTalkCryptErrorCode.COMPUTE_SIGNATURE_ERROR); } if (cpid != m_sSuiteKey) { sReplyEchoStr = ""; return((int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR); } return(ret); }
//验证URL // @param sMsgSignature: 签名串,对应URL参数的msg_signature // @param sTimeStamp: 时间戳,对应URL参数的timestamp // @param sNonce: 随机串,对应URL参数的nonce // @param sEchoStr: 随机串,对应URL参数的echostr // @param sReplyEchoStr: 解密之后的echostr,当return返回0时有效 // @return:成功0,失败返回对应的错误码 public int VerifyURL(string sMsgSignature, string sTimeStamp, string sNonce, string sEchoStr, ref string sReplyEchoStr) { int ret = 0; if (m_sEncodingAESKey.Length != 43) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey); } ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEchoStr, sMsgSignature); if (0 != ret) { return(ret); } sReplyEchoStr = ""; string cpid = ""; try { sReplyEchoStr = Cryptography.AES_decrypt(sEchoStr, m_sEncodingAESKey, ref cpid); //m_sCorpID); } catch (Exception) { sReplyEchoStr = ""; return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error); } if (cpid != m_sCorpID) { sReplyEchoStr = ""; return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateCorpid_Error); } return(0); }
/// <summary> /// 密文解密 /// </summary> /// <param name="sMsgSignature">签名串</param> /// <param name="sTimeStamp">时间戳</param> /// <param name="sNonce">随机串</param> /// <param name="sPostData">密文</param> /// <param name="sMsg">解密后的原文,当return返回0时有效</param> /// <returns>成功0,失败返回对应的错误码</returns> public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg) { if (m_sEncodingAESKey.Length != AES_ENCODE_KEY_LENGTH) { return((int)DingTalkCryptErrorCode.AES_KEY_ILLEGAL); } string sEncryptMsg = sPostData; int ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature); string cpid = ""; try { sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid); } catch (FormatException) { sMsg = ""; return((int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR); } catch (Exception) { sMsg = ""; return((int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR); } if (cpid != m_sSuiteKey) { return((int)DingTalkCryptErrorCode.COMPUTE_DECRYPT_TEXT_SuiteKey_ERROR); } return(ret); }
/// <summary> /// 接收推送消息 /// </summary> /// <param name="xml">请求消息</param> /// <param name="configData">configData</param> /// <returns>处理结果</returns> public static PushResult ReceivePushMessage(string xml, ConfigData configData) { PushRequest pushRequest = new PushRequest { Xml = xml, EncodingAESKey = configData.EncodingAESKey, ComponentVerifyTicket = configData.component_verify_ticket_key, ValidityTime = DateTime.Now.AddDays(1) }; XElement doc = XElement.Parse(pushRequest.Xml); var encry = doc.Element("Encrypt").GetString(); string encodingAESKey = pushRequest.EncodingAESKey; string appid = string.Empty; var xmlContent = Cryptography.AES_decrypt(encry, encodingAESKey, ref appid); PushResult pushResult = TenpayUtil.ConvertToPushRequest(xmlContent); if (pushResult.InfoType == "component_verify_ticket") { // 写入缓存 //Redis.SetRedis(pushRequest.ComponentVerifyTicket, pushResult.ComponentVerifyTicket, pushRequest.ValidityTime); pushResult.IsSucceed = !string.IsNullOrEmpty(pushRequest.ComponentVerifyTicket); } else { pushResult.IsSucceed = false; pushResult.Message = $"暂不处理类型{pushResult.InfoType}"; } return(pushResult); }
/// <summary> /// 消息解密 /// </summary> /// <param name="post_xml">微信推送的加密事件或消息</param> /// <param name="decrypt_key">第三方平台的解密key</param> /// <param name="appid">公众号appid</param> /// <returns>解密后的xml字符串</returns> public static string MessageDecrypt(string post_xml, string decrypt_key, string appid) { XmlDocument xmldoc = new XmlDocument(); xmldoc.LoadXml(post_xml); XmlElement rootNode = xmldoc.DocumentElement; string sDecryptXml = Cryptography.AES_decrypt(rootNode.SelectSingleNode("Encrypt").InnerText, decrypt_key, ref appid); return(sDecryptXml); }
// 检验消息的真实性,并且获取解密后的明文 // @param sMsgSignature: 签名串,对应URL参数的msg_signature // @param sTimeStamp: 时间戳,对应URL参数的timestamp // @param sNonce: 随机串,对应URL参数的nonce // @param sPostData: 密文,对应POST请求的数据 // @param sMsg: 解密后的原文,当return返回0时有效 // @return: 成功0,失败返回对应的错误码 public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg) { if (m_sEncodingAESKey.Length != 43) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey); } XmlDocument doc = new XmlDocument(); XmlNode root; string sEncryptMsg; try { doc.LoadXml(sPostData); root = doc.FirstChild; sEncryptMsg = root["Encrypt"].InnerText; } catch (Exception) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ParseXml_Error); } //verify signature int ret = 0; ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature); if (ret != 0) { return(ret); } //decrypt string cpid = ""; try { sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid); } catch (FormatException) { sMsg = ""; return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecodeBase64_Error); } catch (Exception) { sMsg = ""; return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error); } if (cpid != m_sCorpID) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateCorpid_Error); } return(0); }
/// <summary> /// 开启微信回调模式 /// </summary> /// <returns></returns> public string OpenWeChatCallbackMode(U_WeChatCallbackParameter wcp) { //数据不为空,表示验证开启微信回调模式 //数据为空,表示微信数据正常回调 if (!string.IsNullOrEmpty(wcp.echostr)) { string corpid = ""; string echostr = Cryptography.AES_decrypt(wcp.echostr, ConfigSugar.GetAppString("WeChatCallbackEncodingAESKey"), ref corpid); return(echostr); } else { WeChatHandle wch = WeChatEventFactory.GetWeChatHandle(wcp, Request.InputStream); return(wch.ExecuteEventHandle()); } }
/// <summary> /// 返回验证内容 /// </summary> /// <param name="msg_signature"></param> /// <param name="timestamp"></param> /// <param name="nonce"></param> /// <param name="echostr"></param> /// <returns></returns> public string ReplyVerify(string echostr) { string rEchoStr = ""; int ret = 0; try { if (EncodingAESKey.Length != 43) { ret = (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey; } ret = VerifySignature(Token, _timestamp, _nonce, _signature, echostr); if (ret == 0) { rEchoStr = ""; string cpid = ""; try { rEchoStr = Cryptography.AES_decrypt(echostr, EncodingAESKey, ref cpid); //CorpID); } catch (Exception) { rEchoStr = ""; ret = (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error; } if (cpid != WeiXinID) { rEchoStr = ""; ret = (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateCorpid_Error; } } } catch { } if (ret != 0) { rEchoStr = "ERR: VerifyURL fail, ret: " + ret + " echostr:" + echostr; } return(rEchoStr); }
/// <summary> /// 检验消息的真实性,并且获取解密后的明文 /// </summary> /// <param name="sMsgSignature">签名串,对应URL参数的msg_signature</param> /// <param name="sTimeStamp">时间戳,对应URL参数的timestamp</param> /// <param name="sNonce">随机串,对应URL参数的nonce</param> /// <param name="sPostData">密文,对应POST请求的数据</param> /// <param name="sMsg">解密后的原文,当return返回0时有效</param> /// <returns> 成功0,失败返回对应的错误码</returns> public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sEncryptMsg, ref string sMsg) { if (m_sEncodingAESKey == null || m_sEncodingAESKey.Length != 43) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey); } XmlDocument doc = new XmlDocument(); XmlNode root; //检验签名 int ret = 0; ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature); if (ret != 0) { return(ret); } //解密 string cpid = ""; try { sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid); } catch (FormatException) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecodeBase64_Error); } catch (Exception) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_DecryptAES_Error); } if (cpid != m_sAppID) { return((int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ValidateAppid_Error); } return(0); }
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); } }