收藏
回答

微信同城配送数据加密,一直报签名问题,有哪位大侠指点一下?

//此处走JAVA服务,签名数据

  string HttpSignData(string action, string data)

        {

            var req = HttpWebRequest.Create("http://127.0.0.1:8080/myweb/hello-servlet?action=" + action);

            req.Method = "POST";

            req.ContentType = "appliction/json";

            var buf = Encoding.UTF8.GetBytes(data);

            using (var sw = req.GetRequestStream())

            {

                sw.Write(buf, 0, buf.Length);

            }

            var str = "";

            using (var stream = req.GetResponse().GetResponseStream())

            {

                using (var sr = new StreamReader(stream))

                {

                    str = sr.ReadToEnd();

                }

            }

            return str;

        }


        private void button1_Click(object sender, EventArgs e)

        {


            var strLog = new StringBuilder();


            //配置信息

            var config = new WxConfig();


            //当前页面路径

            var urlpath = "https://api.xjshw.com/wxa/getuserriskrank";// "http://localhost:28085/Default2";// Request.Url.AbsoluteUri;


            //额外数据

            var aad = urlpath + "|" + WxConfig.appid + "|" + config.timestamp + "|" + WxConfig.aes_sn;


            #region 日志

            strLog.Append("\r\n-----------数据:\r\n");

            strLog.Append("iv:" + config.iv + "\r\n");

            strLog.Append("nonce:" + config.nonce + "\r\n");

            strLog.Append("timestamp:" + config.timestamp + "\r\n");

            strLog.Append("appid:" + WxConfig.appid + "\r\n");

            strLog.Append("sn:" + WxConfig.aes_sn + "\r\n\r\n");

            strLog.Append("额外数据:" + aad + "\r\n\r\n");

            #endregion


            #region 请求数据包明文

            dynamic data = new ExpandoObject();

            data.wx_store_id = "4000000000000650042";

            data._n = config.nonce;

            data._appid = WxConfig.appid;

            data._timestamp = config.timestamp;

            #endregion



            //将请求的数据对象转成JSON字符串

            var plaintext = Newtonsoft.Json.JsonConvert.SerializeObject(data);


            strLog.Append("请求数据:" + plaintext + "\r\n\r\n");


            #region 加密数据-AES256_GCM

            //GCM模式输出的认证信息,使用base64编码


            //AES256_GCM 方式加密数据

            var aesResultBuff = AesGcmHelper.AesGcmEncrypt(plaintext, WxConfig.aes_key, config.iv, aad);// associatedData);


            #region java方式加密

            var sss = HttpSignData("encryption", Newtonsoft.Json.JsonConvert.SerializeObject(new { plaintext = plaintext, key = WxConfig.aes_key, iv = config.iv, aad = aad }));


            var jsonObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(sss);

            var a = jsonObj.Value<String>("data").ToString();

            var b = jsonObj.Value<String>("authtag").ToString();

            var c = jsonObj.Value<String>("iv").ToString();


            #endregion


            #region 测试解密数据

            var dataBuff = Convert.FromBase64String(a);// (aesResultBuff.EncryptedData);

            var authBuff = Convert.FromBase64String(b);// (aesResultBuff.AuthTag);

            var rawBuff = new byte[dataBuff.Length + authBuff.Length];

            Array.Copy(dataBuff, 0, rawBuff, 0, dataBuff.Length);

            Array.Copy(authBuff, 0, rawBuff, dataBuff.Length, authBuff.Length);

            // var rawBase64Str = Convert.ToBase64String(rawBuff);

            var decryptData = AesGcmHelper.AesGcmDecrypt(rawBuff, WxConfig.aes_key, config.iv, aad);// associatedData);

            #endregion


            strLog.Append("-----------加密:\r\n\r\n");// + Newtonsoft.Json.JsonConvert.SerializeObject(data) + "\r\n\r\n");

            strLog.Append("加密数据:" + a + "\r\n\r\n");

            strLog.Append("授权标签:" + b + "\r\n\r\n");


            #endregion


            #region  发送的数据包对象

            var reqData = new

            {

                iv = config.iv,//加密向量

                data = aesResultBuff.EncryptedData,//加密数据

                authtag = aesResultBuff.AuthTag//授权标签

            };

            #endregion


            //转JSON字符串

            var reqDataJsonStr = Newtonsoft.Json.JsonConvert.SerializeObject(reqData);


            strLog.Append("-----------发送的数据包:" + reqDataJsonStr + "\r\n\r\n");


            strLog.Append("-----------签名:\r\n\r\n");


            #region 数量签名

            //签名字段格式

            //开发者需先拼接待签名串,使用 urlpath\n appid\n timestamp\n postdata 格式,字段之间使用换行符\n做分隔符。


            //待签名数据

            var payload = urlpath + "\n" + WxConfig.appid + "\n" + config.timestamp + "\n" + reqDataJsonStr;


            strLog.Append("待签名数据:" + payload + "\r\n\r\n");


             //开始签名

            var payloadSigned = this.HttpSignData("sign", payload);


            strLog.Append("签名结果:" + payloadSigned + "\r\n\r\n");

            #endregion


            #region 封装网络请求对象


            var access_token = Senparc.Weixin.MP.CommonAPIs.AccessTokenContainer.TryGetToken(WxConfig.appid, WxConfig.appsecret, true);


            var url = "https://api.weixin.qq.com/cgi-bin/express/intracity/querystore?access_token=" + access_token;


            var req = WebRequest.CreateHttp(url);

            req.Method = "POST";

            req.ContentType = "application/json;charset=utf-8";

            req.Accept = "application/json";

            //req.Referer = urlpath;

            #endregion




            #region 设置请求头-添加签名信息

            req.Headers.Add("Wechatmp-Appid", WxConfig.appid);

            req.Headers.Add("Wechatmp-TimeStamp", config.timestamp.ToString());

            req.Headers.Add("Wechatmp-Signature", payloadSigned);


            strLog.Append("-----------请求头:\r\n\r\n");

            strLog.Append("Wechatmp-Appid:" + WxConfig.appid + "\r\n\r\n");

            strLog.Append("Wechatmp-TimeStamp:" + config.timestamp + "\r\n\r\n");

            strLog.Append("Wechatmp-Signature:" + payloadSigned + "\r\n\r\n");


            #endregion



            //待发送的缓存区

            var reqDataBytes = Encoding.UTF8.GetBytes(reqDataJsonStr);


            //发送数据

            using (var sr = req.GetRequestStream())

            {

                sr.Write(reqDataBytes, 0, reqDataBytes.Length);

            }


            var content = "";

            using (var stream = req.GetResponseAsync().Result.GetResponseStream())

            {

                using (var sr = new StreamReader(stream))

                {

                    content = sr.ReadToEnd();

                }

            }


            strLog.Append("-----------微信返回:\r\n\r\n");

            strLog.Append(content);


            textBox1.Text = strLog.ToString();

            // Label1.Text = strLog.ToString();


---------------------------------------------------aes加密解密


using System;

using System.Collections.Generic;

using System.Linq;

using System.Security.Cryptography;

using System.Text;

using System.Threading.Tasks;

using Org.BouncyCastle.Crypto.Engines;

using Org.BouncyCastle.Crypto.Modes;

using Org.BouncyCastle.Crypto.Parameters;

namespace Hidistro.Core

{

    /// <summary>

    /// 此加密算法和微信提供的加密算法结果一致

    /// </summary>

   public class AesGcmResult

    {

        /// <summary>

        /// 加密数据

        /// </summary>

        public string EncryptedData { get; set; }

        /// <summary>

        /// 授权标签

        /// </summary>

        public string AuthTag { get; set; }

    }


    public class AesGcmHelper

    {

        /// <summary>

        /// AES GCM加密

        /// </summary>

        /// <param name="plainText">加密数据</param>

        /// <param name="base64Key">加密KEY,BASE64编码</param>

        /// <param name="base64Iv">随机数,BASE64编码</param>

        /// <param name="associatedData">aad 额外数据</param>

        /// <returns></returns>

        public static /*byte[]*/ AesGcmResult AesGcmEncrypt(string plainText, string base64Key, string base64Iv, string aad = null)// byte[] associatedData = null)

        {

            byte[] realPlaintext = Encoding.UTF8.GetBytes(plainText);


            byte[] key = Convert.FromBase64String(base64Key);// Encoding.UTF8.GetBytes(aesKey);


            var realIv = Convert.FromBase64String(base64Iv);// "aFYXNjnWubVjvhqh");


            var cipher = new GcmBlockCipher(new AesEngine());// AesFastEngine());//


            byte[] associatedData = null;


            if (!string.IsNullOrWhiteSpace(aad))

            {

                associatedData = Encoding.UTF8.GetBytes(aad);

            }

            AeadParameters parameters = new AeadParameters(new KeyParameter(key), 128, realIv, associatedData);

            cipher.Init(true, parameters);

            byte[] ciphertext = new byte[cipher.GetOutputSize(plainText.Length)];

            int len = cipher.ProcessBytes(realPlaintext, 0, realPlaintext.Length, ciphertext, 0);

            //这个库加密完成会直接把tag放在密文最后面,因此,加解密不需要关注tag,跟其他库不太一致,需要注意下

            cipher.DoFinal(ciphertext, len);

            byte[] encryptedData = new byte[ciphertext.Length - 16];

            //取出授权标签数据部分

            byte[] authTag = new byte[16];

            Array.Copy(ciphertext, 0, encryptedData, 0, ciphertext.Length - 16);

            Array.Copy(ciphertext, ciphertext.Length - 16, authTag, 0, 16);


            //base64编码

            var encryptedDataStr = Convert.ToBase64String(encryptedData);

            var authtag = Convert.ToBase64String(authTag);

            return new AesGcmResult { EncryptedData = encryptedDataStr, AuthTag = authtag };


        }



        /// <summary>

        /// 解密数据

        /// </summary>

        /// <param name="data"></param>

        /// <param name="aesKey"></param>

        /// <param name="iv"></param>

        /// <param name="associatedData"></param>

        /// <returns></returns>

        public static String AesGcmDecrypt(/*string data,*/byte[] ciphertextbyte, string base64Key, string base64IV, string aad = null)// byte[] associatedData = null)

        {

            byte[] key = Convert.FromBase64String(base64Key);// Encoding.UTF8.GetBytes(aesKey);

            byte[] nonce = Convert.FromBase64String(base64IV);// new byte[12];

            byte[] associatedData = null;

            if (!string.IsNullOrWhiteSpace(aad))

            {

                associatedData = Encoding.UTF8.GetBytes(aad);

            }


            GcmBlockCipher cipher = new GcmBlockCipher(new AesEngine());

            AeadParameters parameters = new AeadParameters(new KeyParameter(key), 128, nonce, associatedData);

            cipher.Init(false, parameters);

            byte[] decryptedData = new byte[cipher.GetOutputSize(ciphertextbyte.Length)];

            int len = cipher.ProcessBytes(ciphertextbyte, 0, ciphertextbyte.Length, decryptedData, 0);

            cipher.DoFinal(decryptedData, len);

            //返回解密字符串

            return Encoding.UTF8.GetString(decryptedData);

        }

    }

}



以上是我做的整个过程,为何老是报无效签名,签名算法也是用微信提供的,私钥也是转成PCKS8格式,求教!!!

最后一次编辑于  01-07
回答关注问题邀请回答
收藏

2 个回答

登录 后发表内容