C#加密与java 互通

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

在我们对接其他公司接口的时候,时常会出现对方使用的开发语言和我方使用的开发语言不同的情况,因为每个语言之间都会有些许差别,在进行加密签名中就会出现签名一直对接不上的问题,下面我就来和各位分享一下我所遇到的问题以及解决方案。


对方接口签名要求

  1. 报文发送方自行产生随机密钥,然后再使用接收方公钥对随机秘钥进行RSA 非对称加密,生成 encrypted。
  2. 按照报文规范生成报文原文,然后对报文原文(JSON 格式字符串)使用 对称密钥字节数组进行 AES256 算法加密,再进行 Base64 编码,生成msg
  3. 再对报文原文进行签名,得到签名结果(十六进制字符串),签名算法采用"SHA1withRSA",生成 signature

可以看到上面这一堆文字,看似字很少,实则却使用到了很多种加密方式

可以梳理出会用到的加密有:RSA加密,AES256加密,Base64加密,SHA1加密

我方对接思路

1.RSA 加密

由于对方时使用的java,java密钥的key格式和我们C#这边RSA加密使用的key格式不一样,需要进行格式处理也就是下面的"RSAPrivateKeyJava2DotNet"方法。

csharp 复制代码
  public class RSAUtils
  {
      /// <summary>
      /// 生成私钥
      /// </summary>
      /// <returns></returns>
      public static string CreatePrivateKey()
      {
          string str = Guid.NewGuid().ToString("N");
          Byte[] bytes = Encoding.GetEncoding("utf-8").GetBytes(str);
          byte[] aesKey = new byte[16];
          for (int i = 0; i < 16; i++)
          {
              aesKey[i] = bytes[i];
          }
          return Convert.ToBase64String(aesKey);
      }
   
      /// <summary>
      /// 生成密钥
      /// <param name="privateKey">私钥</param>
      /// <param name="publicKey">公钥</param>
      /// <param name="keySize">密钥长度:512,1024,2048,4096,8192</param>
      /// </summary>
      public static void Generator(out string privateKey, out string publicKey, int keySize = 1024)
      {
          RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);
          privateKey = rsa.ToXmlString(true); //将RSA算法的私钥导出到字符串PrivateKey中 参数为true表示导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
          publicKey = rsa.ToXmlString(false); //将RSA算法的公钥导出到字符串PublicKey中 参数为false表示不导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
      }
      /// <summary>
      /// RSA加密 将公钥导入到RSA对象中,准备加密
      /// </summary>
      /// <param name="publicKey">公钥</param>
      /// <param name="encryptstring">待加密的字符串</param>
      public static string RsaEncrypt(string publicKey, string encryptstring)
      {
          using (var rsaProvider = new RSACryptoServiceProvider())
          {
              string key = RSAPublicKeyJava2DotNet(publicKey);
              var inputBytes = Encoding.UTF8.GetBytes(encryptstring);//有含义的字符串转化为字节流
              rsaProvider.FromXmlString(key);//载入公钥
              int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
              var buffer = new byte[bufferSize];
              using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
              {
                  while (true)
                  { //分段加密
                      int readSize = inputStream.Read(buffer, 0, bufferSize);
                      if (readSize <= 0)
                      {
                          break;
                      }
                      var temp = new byte[readSize];
                      Array.Copy(buffer, 0, temp, 0, readSize);
                      var encryptedBytes = rsaProvider.Encrypt(temp, false);
                      outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
                  }
                  return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
              }
          }
      }

      /// <summary>
      /// Java转.net格式
      /// </summary>
      /// <param name="JavaPublicKey">Java格式公钥</param>
      /// <returns></returns>
      public static string RSAPublicKeyJava2DotNet(string JavaPublicKey)
      {
          RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(JavaPublicKey));
          return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
             Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
             Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
      }

      /// <summary>
      /// .NET格式转Java格式
      /// </summary>
      /// <param name="cPublicKey">c#的.net格式公钥</param>
      /// <returns></returns>
      public static string RSAPublicKeyDotNet2Java(string cPublicKey)
      {
          XmlDocument doc = new XmlDocument(); doc.LoadXml(cPublicKey);
          BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
          BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
          RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
          SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
          byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
          return Convert.ToBase64String(serializedPublicBytes);
      }
      /// <summary>
      /// .java格式密钥转c#使用的.net格式密钥
      /// </summary>
      /// <param name="JavaPrivateKey">.java密钥</param>
      /// <returns></returns>
      public static string RSAPrivateKeyJava2DotNet(string JavaPrivateKey)
      {
          RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(JavaPrivateKey));
          return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
              Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
      }

      /// <summary>
      /// c#使用的.net格式密钥转换成.Java格式密钥
      /// </summary>
      /// <param name="cPrivateKey">.net格式密钥</param>
      /// <returns></returns>
      public static string RSAPrivateKeyDotNet2Java(string cPrivateKey)
      {
          XmlDocument doc = new XmlDocument();
          doc.LoadXml(cPrivateKey);
          BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
          BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
          BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
          BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
          BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
          BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
          BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
          BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));

          RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);

          PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
          byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
          return Convert.ToBase64String(serializedPrivateBytes);
      }



      /// <summary>  
      /// RSA解密 载入私钥,解密数据  
      /// </summary>  
      /// <param name="privateKey">私钥</param>  
      /// <param name="decryptstring">待解密的字符串</param>  
      public static string RsaDecrypt(string privateKey, string decryptstring)
      {
          using (var rsaProvider = new RSACryptoServiceProvider())
          {
              string key = RSAPrivateKeyJava2DotNet(privateKey);
              rsaProvider.FromXmlString(key); //载入私钥  
              var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流  
              //var outputStream = new MemoryStream(encryptedBytes);
              var bufferSize = rsaProvider.KeySize / 8;
              var buffer = new byte[bufferSize];
              using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
              {
                  while (true)
                  {
                      int readSize = inputStream.Read(buffer, 0, bufferSize);
                      if (readSize <= 0)
                      {
                          break;
                      }
                      var temp = new byte[readSize];
                      Array.Copy(buffer, 0, temp, 0, readSize);
                      var decryptedBytes = rsaProvider.Decrypt(temp, false);
                      outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
                  }
                  return Encoding.UTF8.GetString(outputStream.ToArray()); //转化为字符串  
              }
          }
      }

      /// <summary>
      /// RSA私钥加密
      /// </summary>
      /// <param name="privateKey">私钥</param>
      /// <param name="encryptstring">待加密的字符串</param>
      public static string RsaPrivateEncrypt(string privateKey, string encryptstring)
      {
          var rsaProvider = new RSACryptoServiceProvider();
          rsaProvider.FromXmlString(privateKey);//载入私钥
          var inputBytes = Convert.FromBase64String(encryptstring);//有含义的字符串转化为字节流
          int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
          var buffer = new byte[bufferSize];
          using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
          {
              while (true)
              {
                  //分段加密
                  int readSize = inputStream.Read(buffer, 0, bufferSize);
                  if (readSize <= 0)
                  {
                      break;
                  }
                  var temp = new byte[readSize];
                  Array.Copy(buffer, 0, temp, 0, readSize);
                  var encryptedBytes = RsaPrivateEncrypt(privateKey, temp);
                  outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
              }
              return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
          }
      }

      /// <summary>  
      /// RSA公钥解密
      /// </summary>  
      /// <param name="publicKey">公钥</param>  
      /// <param name="decryptstring">待解密的字符串</param>  
      public static string RsaPublicDecrypt(string publicKey, string decryptstring)
      {
          var rsaProvider = new RSACryptoServiceProvider();
          rsaProvider.FromXmlString(publicKey); //载入私钥  
          var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流  
          var bufferSize = rsaProvider.KeySize / 8;
          var buffer = new byte[bufferSize];
          using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
          {
              while (true)
              {
                  int readSize = inputStream.Read(buffer, 0, bufferSize);
                  if (readSize <= 0)
                  {
                      break;
                  }
                  var temp = new byte[readSize];
                  Array.Copy(buffer, 0, temp, 0, readSize);
                  var decryptedBytes = decryptByPublicKey(publicKey, temp);
                  outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
              }
              return Convert.ToBase64String(outputStream.ToArray());
          }
      }
      /// <summary>
      /// SHA1 加密,返回大写字符串
      /// </summary>
      /// <param name="content">需要加密字符串</param>
      /// <returns>返回40位UTF8 大写</returns>
      public static string SHA1(string content)
      {
          return SHA1(content, Encoding.UTF8);
      }
      /// <summary>
      /// SHA1 加密,返回大写字符串
      /// </summary>
      /// <param name="content">需要加密字符串</param>
      /// <param name="encode">指定加密编码</param>
      /// <returns>返回40位大写字符串</returns>
      private static string SHA1(string content, Encoding encode)
      {
          try
          {
              SHA1 sha1 = new SHA1CryptoServiceProvider();
              byte[] bytes_in = encode.GetBytes(content);
              byte[] bytes_out = sha1.ComputeHash(bytes_in);
              sha1.Dispose();
              string result = BitConverter.ToString(bytes_out);
              result = result.Replace("-", "");
              return result;
          }
          catch (Exception ex)
          {
              throw new Exception("SHA1加密出错:" + ex.Message);
          }
      }
      /// <summary>
      /// 私钥加密
      /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
      /// </summary>
      /// <param name="privateKey">密钥</param>
      /// <param name="data">要加密的数据</param>
      /// <returns></returns>
      public static byte[] RsaPrivateEncrypt(string privateKey, byte[] data)
      {
          string xmlPrivateKey = privateKey;
          //加载私钥  
          RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
          privateRsa.FromXmlString(xmlPrivateKey);
          //转换密钥  
          AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
          //IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       
          IBufferedCipher c = CipherUtilities.GetCipher("RSA");
          c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 
          byte[] DataToEncrypt = data;
          byte[] outBytes = c.DoFinal(DataToEncrypt);//加密  
          return outBytes;
      }

      /// <summary>
      /// 用公钥解密
      /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
      /// </summary>
      /// <param name="data"></param>
      /// <param name="key"></param>
      /// <returns></returns>
      public static byte[] decryptByPublicKey(string publicKey, byte[] data)
      {
          string xmlPublicKey = publicKey;

          RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
          publicRsa.FromXmlString(xmlPublicKey);

          AsymmetricKeyParameter keyPair = DotNetUtilities.GetRsaPublicKey(publicRsa);
          //转换密钥  
          // AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(publicRsa);
          //IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       
          IBufferedCipher c = CipherUtilities.GetCipher("RSA");
          c.Init(false, keyPair); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 
          byte[] DataToEncrypt = data;
          byte[] outBytes = c.DoFinal(DataToEncrypt);//解密  
          return outBytes;
      }


  }

调用方法

csharp 复制代码
  string pkey= RSAUtils.CreatePrivateKey();
   encrypt.data.encrypted = RSAUtils.RsaEncrypt(publicKey, pkey);

其中publicKey 是对方公司(JAVA)给我们的公钥,

这里我们生成的KEY是:Q2THHWOD1H4L81DO

加密出来的值是:rZdVr8ksB4EyJ0L6GGjcgHR+XYKwRnxxs+94Hyd/Y52SgqaROFva3DLACjYrzyAHetmGrMpPLKf4TRq0V8F5eDrjZRhOQelA5ogSWRoLwzpN4KZirBc1HCHyrfaEvHDtoJeNabZzKFTDHvNZ94NRQfpHXqABlS7TzOXJKLK1Z/BiQjGuyOGL3xohwhyZ+vgjqNFjpTYU7gqobno5kBK6zoG8B2wilsDP+4hkF7IAn6dAlw8scBMpuULZF6ceBCEakkgWrBYn4E5DiC5c1tz2x3yViBNO+2XV0YdZIrBVkWKZGCWBYVkq53ovyPavuMMyK16HF7CnKlE3RdMc2WvT6g==

这一步我们加密后对方公司的java是能解密出正确明文的。

2.AES256加密

这里问题就来了

下面是错误方法:

csharp 复制代码
        /// <summary>
 
        /// AES加密
 
        /// </summary>
 
        /// <param name="encryptStr">明文</param>
 
        /// <param name="key">密钥</param>
 
        /// <returns></returns>
 
        public static string Encrypt(string encryptStr,string key)
 
        {
 
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
 
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(encryptStr);
 
 
            RijndaelManaged rDel = new RijndaelManaged();
 
            rDel.Key = keyArray;
 
            rDel.Mode = CipherMode.ECB;
 
            rDel.Padding = PaddingMode.PKCS7;
 
 
            ICryptoTransform cTransform = rDel.CreateEncryptor();
 
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
 
 
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
 
        }
                /// <summary>
 
        /// AES解密
 
        /// </summary>
 
        /// <param name="decryptStr">密文</param>
 
        /// <param name="key">密钥</param>
 
        /// <returns></returns>
 
        public static string Decrypt(string decryptStr,string key)
 
        {
 
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
 
            byte[] toEncryptArray = Convert.FromBase64String(decryptStr);
 
 
            RijndaelManaged rDel = new RijndaelManaged();
 
            rDel.Key = keyArray;
 
            rDel.Mode = CipherMode.ECB;
 
            rDel.Padding = PaddingMode.PKCS7;
 
 
            ICryptoTransform cTransform = rDel.CreateDecryptor();
 
            byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
 
 
            return UTF8Encoding.UTF8.GetString(resultArray);
 
        }

这种方式加密在网上的在线解密工具都解密不了,只有我们C#写的解密方法能解密,估计是因为填充类型或者其他什么地方有问题。在这里我也困惑了很久

下面是正确方法:

csharp 复制代码
public class AESUtils
{
    /// <summary>
    /// AES256加密
    /// </summary>
    /// <param name="content">明文</param>
    /// <param name="passphase">密钥</param>
    /// <returns></returns>
    public static string Encrypt(string content, string passphase)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(content);
        byte[] key, iv, salt = new byte[8];

        using (var rng = new RNGCryptoServiceProvider())
        {
            rng.GetBytes(salt); 
        }

        using (var md5 = new MD5CryptoServiceProvider())
        {
            var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
            var bs1 = md5.ComputeHash(preHash);
            var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
            var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());

            key = bs1.Concat(bs2).ToArray();
            iv = bs3;
        }

        using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
        using (var encryptor = aes.CreateEncryptor())
        {
            var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
            var concated = Encoding.UTF8.GetBytes("Salted__").Concat(salt).Concat(encryptedBytes);
            return Convert.ToBase64String(concated.ToArray());
        }

    }
    /// <summary>
    /// AES256解密
    /// </summary>
    /// <param name="content">密文</param>
    /// <param name="passphase">密钥</param>
    /// <returns></returns>
    public static string Decrypt(string content, string passphase)
    {
        // openssl aes-256-cbc -k 123456789 -md md5 -e -base64
        //
        byte[] bytes = Convert.FromBase64String(content);
        byte[] key, iv, salt = new byte[8], encryptedBytes = new byte[bytes.Length - 8 - 8];

        //提取 salt
        Array.ConstrainedCopy
        (
            sourceArray: bytes,
            sourceIndex: 8, //剔除开头的 "Salted__"
            destinationArray: salt,
            destinationIndex: 0,
            length: salt.Length
        );
        //提取 encryptedBytes
        Array.ConstrainedCopy
        (
            sourceArray: bytes,
            sourceIndex: 8 + 8, //并剔除开头的 salt
            destinationArray: encryptedBytes,
            destinationIndex: 0,
            length: encryptedBytes.Length
        );

        using (var md5 = new MD5CryptoServiceProvider())
        {
            var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
            var bs1 = md5.ComputeHash(preHash);
            var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
            var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());

            key = bs1.Concat(bs2).ToArray();
            iv = bs3;
        }

        using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
        using (var decryptor = aes.CreateDecryptor())
        {
            byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
            return Encoding.UTF8.GetString(decryptedBytes);
        }

    }


    /// <summary>
    /// 加密 (新的思路)
    /// </summary>
    /// <param name="content">明文</param>
    /// <param name="passphase">密码(固定32位)</param>
    /// <returns>密文(base64)</returns>
    static string CryptoJsEncrypt_New(string content, string passphase )
    {
        byte[] bytes = Encoding.UTF8.GetBytes(content);
        byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
        byte[] iv = new byte[16];

        using (var rng = new RNGCryptoServiceProvider())
            rng.GetBytes(iv); // 产生16个字节的随机iv

        using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
        using (var encryptor = aes.CreateEncryptor())
        {
            var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
            var concated = iv.Concat(encryptedBytes);
            return "aes256:" + Convert.ToBase64String(concated.ToArray());
        }
    }
    /// <summary>
    /// 解密 (新的思路)
    /// </summary>
    /// <param name="content">密文(base64)</param>
    /// <param name="passphase">密码(固定32位)</param>
    /// <returns>明文</returns>
    static string CryptoJsDecrypt_New(string content, string passphase )
    {
        byte[] bytes = Convert.FromBase64String(content.Substring(7)); //剔除开头的 "aes256:"
        byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
        byte[] iv = new byte[16];
        byte[] encryptedBytes = new byte[bytes.Length - 16];

        //提取 iv
        Array.ConstrainedCopy
        (
            sourceArray: bytes,
            sourceIndex: 0,
            destinationArray: iv,
            destinationIndex: 0,
            length: iv.Length
        );
        //提取 加密结果
        Array.ConstrainedCopy
        (
            sourceArray: bytes,
            sourceIndex: 16, //并剔除开头的 iv
            destinationArray: encryptedBytes,
            destinationIndex: 0,
            length: encryptedBytes.Length
        );

        using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
        using (var decryptor = aes.CreateDecryptor())
        {
            byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
            return Encoding.UTF8.GetString(decryptedBytes);
        }
    }
}

调用方法

csharp 复制代码
AESUtils.Encrypt(datastr, pkey);

加密前明文字符串:
{"storeId":"1788431406828474370","merchantId":"1788027169854296065","tradeNo":"123456","phone":"13366237305","tradeAmount":"5.0","notifyUrl":"http://wx.wjy99.com/onlinemtorder/yunxin/orderMsg","callbackUrl":"http://wx.wjy99.com/onlinemtorder/yunxin/orderMsg","remark":"测试请求"}

加密后密文:
U2FsdGVkX1+FSSnYrXRRcvfDoSeLLPcaA2LEN0/ix7Z41jXIYRdCdIm3DMob+xwvVdMnFwv4iq7LhFxAZcetRHbS3hxhbjObhNvkQrvd79+AnZdEMoM/BGTx66U/c8xtdMheqxrRWoXoIIpfRf++UQCGZBuU5upwMjTmuU3vJKQX/2r5qUHkjH05qkR+ioLb6bvi1FKI6vp3Bs4sKPEKtq+5M26aBdOfo5RmmrSJ023GkvC4DGxlyVn7ac97bBj3X/8h2yfpT1E6zW6FwZIBK+aVPlPFVeKVeXBZwdX5tgpgB+4e6duHPAjArQ1XYRfx2ugNn38IDxwtap7ocBi3GnPB8U4iTXPCz+/7uFutDzIQi0hRVEMpVRqaaaw2Ri2fFV84QYgotJC+qXkKRwyx9g==

这种加密方式,网上的解密都能解开了。


完整的加密帮助类

csharp 复制代码
  /// <summary>
  /// RSA
  /// </summary>
  public class RSAUtils
  {
      /// <summary>
      /// 生成私钥
      /// </summary>
      /// <returns></returns>
      public static string CreatePrivateKey()
      {
          string str = Guid.NewGuid().ToString("N");
          Byte[] bytes = Encoding.GetEncoding("utf-8").GetBytes(str);
          byte[] aesKey = new byte[16];
          for (int i = 0; i < 16; i++)
          {
              aesKey[i] = bytes[i];
          }
          return Convert.ToBase64String(aesKey);
      }
   
      /// <summary>
      /// 生成密钥
      /// <param name="privateKey">私钥</param>
      /// <param name="publicKey">公钥</param>
      /// <param name="keySize">密钥长度:512,1024,2048,4096,8192</param>
      /// </summary>
      public static void Generator(out string privateKey, out string publicKey, int keySize = 1024)
      {
          RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);
          privateKey = rsa.ToXmlString(true); //将RSA算法的私钥导出到字符串PrivateKey中 参数为true表示导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
          publicKey = rsa.ToXmlString(false); //将RSA算法的公钥导出到字符串PublicKey中 参数为false表示不导出私钥 true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。
      }
      /// <summary>
      /// RSA加密 将公钥导入到RSA对象中,准备加密
      /// </summary>
      /// <param name="publicKey">公钥</param>
      /// <param name="encryptstring">待加密的字符串</param>
      public static string RsaEncrypt(string publicKey, string encryptstring)
      {
          using (var rsaProvider = new RSACryptoServiceProvider())
          {
              string key = RSAPublicKeyJava2DotNet(publicKey);
              var inputBytes = Encoding.UTF8.GetBytes(encryptstring);//有含义的字符串转化为字节流
              rsaProvider.FromXmlString(key);//载入公钥
              int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
              var buffer = new byte[bufferSize];
              using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
              {
                  while (true)
                  { //分段加密
                      int readSize = inputStream.Read(buffer, 0, bufferSize);
                      if (readSize <= 0)
                      {
                          break;
                      }
                      var temp = new byte[readSize];
                      Array.Copy(buffer, 0, temp, 0, readSize);
                      var encryptedBytes = rsaProvider.Encrypt(temp, false);
                      outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
                  }
                  return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
              }
          }
      }

      /// <summary>
      /// Java转.net格式
      /// </summary>
      /// <param name="JavaPublicKey">Java格式公钥</param>
      /// <returns></returns>
      public static string RSAPublicKeyJava2DotNet(string JavaPublicKey)
      {
          RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(JavaPublicKey));
          return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
             Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
             Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
      }

      /// <summary>
      /// .NET格式转Java格式
      /// </summary>
      /// <param name="cPublicKey">c#的.net格式公钥</param>
      /// <returns></returns>
      public static string RSAPublicKeyDotNet2Java(string cPublicKey)
      {
          XmlDocument doc = new XmlDocument(); doc.LoadXml(cPublicKey);
          BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
          BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
          RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
          SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
          byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
          return Convert.ToBase64String(serializedPublicBytes);
      }
      /// <summary>
      /// .java格式密钥转c#使用的.net格式密钥
      /// </summary>
      /// <param name="JavaPrivateKey">.java密钥</param>
      /// <returns></returns>
      public static string RSAPrivateKeyJava2DotNet(string JavaPrivateKey)
      {
          RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(JavaPrivateKey));
          return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
              Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
              Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
      }

      /// <summary>
      /// c#使用的.net格式密钥转换成.Java格式密钥
      /// </summary>
      /// <param name="cPrivateKey">.net格式密钥</param>
      /// <returns></returns>
      public static string RSAPrivateKeyDotNet2Java(string cPrivateKey)
      {
          XmlDocument doc = new XmlDocument();
          doc.LoadXml(cPrivateKey);
          BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
          BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
          BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
          BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
          BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
          BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
          BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
          BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));

          RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);

          PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
          byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
          return Convert.ToBase64String(serializedPrivateBytes);
      }



      /// <summary>  
      /// RSA解密 载入私钥,解密数据  
      /// </summary>  
      /// <param name="privateKey">私钥</param>  
      /// <param name="decryptstring">待解密的字符串</param>  
      public static string RsaDecrypt(string privateKey, string decryptstring)
      {
          using (var rsaProvider = new RSACryptoServiceProvider())
          {
              string key = RSAPrivateKeyJava2DotNet(privateKey);
              rsaProvider.FromXmlString(key); //载入私钥  
              var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流  
              //var outputStream = new MemoryStream(encryptedBytes);
              var bufferSize = rsaProvider.KeySize / 8;
              var buffer = new byte[bufferSize];
              using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
              {
                  while (true)
                  {
                      int readSize = inputStream.Read(buffer, 0, bufferSize);
                      if (readSize <= 0)
                      {
                          break;
                      }
                      var temp = new byte[readSize];
                      Array.Copy(buffer, 0, temp, 0, readSize);
                      var decryptedBytes = rsaProvider.Decrypt(temp, false);
                      outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
                  }
                  return Encoding.UTF8.GetString(outputStream.ToArray()); //转化为字符串  
              }
          }
      }

      /// <summary>
      /// RSA私钥加密
      /// </summary>
      /// <param name="privateKey">私钥</param>
      /// <param name="encryptstring">待加密的字符串</param>
      public static string RsaPrivateEncrypt(string privateKey, string encryptstring)
      {
          var rsaProvider = new RSACryptoServiceProvider();
          rsaProvider.FromXmlString(privateKey);//载入私钥
          var inputBytes = Convert.FromBase64String(encryptstring);//有含义的字符串转化为字节流
          int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
          var buffer = new byte[bufferSize];
          using (MemoryStream inputStream = new MemoryStream(inputBytes), outputStream = new MemoryStream())
          {
              while (true)
              {
                  //分段加密
                  int readSize = inputStream.Read(buffer, 0, bufferSize);
                  if (readSize <= 0)
                  {
                      break;
                  }
                  var temp = new byte[readSize];
                  Array.Copy(buffer, 0, temp, 0, readSize);
                  var encryptedBytes = RsaPrivateEncrypt(privateKey, temp);
                  outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
              }
              return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
          }
      }

      /// <summary>  
      /// RSA公钥解密
      /// </summary>  
      /// <param name="publicKey">公钥</param>  
      /// <param name="decryptstring">待解密的字符串</param>  
      public static string RsaPublicDecrypt(string publicKey, string decryptstring)
      {
          var rsaProvider = new RSACryptoServiceProvider();
          rsaProvider.FromXmlString(publicKey); //载入私钥  
          var encryptedBytes = Convert.FromBase64String(decryptstring); //将传入的字符串转化为字节流  
          var bufferSize = rsaProvider.KeySize / 8;
          var buffer = new byte[bufferSize];
          using (MemoryStream inputStream = new MemoryStream(encryptedBytes), outputStream = new MemoryStream())
          {
              while (true)
              {
                  int readSize = inputStream.Read(buffer, 0, bufferSize);
                  if (readSize <= 0)
                  {
                      break;
                  }
                  var temp = new byte[readSize];
                  Array.Copy(buffer, 0, temp, 0, readSize);
                  var decryptedBytes = decryptByPublicKey(publicKey, temp);
                  outputStream.Write(decryptedBytes, 0, decryptedBytes.Length);
              }
              return Convert.ToBase64String(outputStream.ToArray());
          }
      }
      /// <summary>
      /// SHA1 加密,返回大写字符串
      /// </summary>
      /// <param name="content">需要加密字符串</param>
      /// <returns>返回40位UTF8 大写</returns>
      public static string SHA1(string content)
      {
          return SHA1(content, Encoding.UTF8);
      }
      /// <summary>
      /// SHA1 加密,返回大写字符串
      /// </summary>
      /// <param name="content">需要加密字符串</param>
      /// <param name="encode">指定加密编码</param>
      /// <returns>返回40位大写字符串</returns>
      private static string SHA1(string content, Encoding encode)
      {
          try
          {
              SHA1 sha1 = new SHA1CryptoServiceProvider();
              byte[] bytes_in = encode.GetBytes(content);
              byte[] bytes_out = sha1.ComputeHash(bytes_in);
              sha1.Dispose();
              string result = BitConverter.ToString(bytes_out);
              result = result.Replace("-", "");
              return result;
          }
          catch (Exception ex)
          {
              throw new Exception("SHA1加密出错:" + ex.Message);
          }
      }
      /// <summary>
      /// 私钥加密
      /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
      /// </summary>
      /// <param name="privateKey">密钥</param>
      /// <param name="data">要加密的数据</param>
      /// <returns></returns>
      public static byte[] RsaPrivateEncrypt(string privateKey, byte[] data)
      {
          string xmlPrivateKey = privateKey;
          //加载私钥  
          RSACryptoServiceProvider privateRsa = new RSACryptoServiceProvider();
          privateRsa.FromXmlString(xmlPrivateKey);
          //转换密钥  
          AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetKeyPair(privateRsa);
          //IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       
          IBufferedCipher c = CipherUtilities.GetCipher("RSA");
          c.Init(true, keyPair.Private); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 
          byte[] DataToEncrypt = data;
          byte[] outBytes = c.DoFinal(DataToEncrypt);//加密  
          return outBytes;
      }

      /// <summary>
      /// 用公钥解密
      /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。
      /// </summary>
      /// <param name="data"></param>
      /// <param name="key"></param>
      /// <returns></returns>
      public static byte[] decryptByPublicKey(string publicKey, byte[] data)
      {
          string xmlPublicKey = publicKey;

          RSACryptoServiceProvider publicRsa = new RSACryptoServiceProvider();
          publicRsa.FromXmlString(xmlPublicKey);

          AsymmetricKeyParameter keyPair = DotNetUtilities.GetRsaPublicKey(publicRsa);
          //转换密钥  
          // AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(publicRsa);
          //IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");// 参数与Java中加密解密的参数一致       
          IBufferedCipher c = CipherUtilities.GetCipher("RSA");
          c.Init(false, keyPair); //第一个参数为true表示加密,为false表示解密;第二个参数表示密钥 
          byte[] DataToEncrypt = data;
          byte[] outBytes = c.DoFinal(DataToEncrypt);//解密  
          return outBytes;
      }


  }

  /// <summary>
  /// AES 
  /// </summary>
  public class AESUtils
  {
      /// <summary>
      /// AES256加密
      /// </summary>
      /// <param name="content">明文</param>
      /// <param name="passphase">密钥</param>
      /// <returns></returns>
      public static string Encrypt(string content, string passphase)
      {
          byte[] bytes = Encoding.UTF8.GetBytes(content);
          byte[] key, iv, salt = new byte[8];

          using (var rng = new RNGCryptoServiceProvider())
          {
              rng.GetBytes(salt); 
          }

          using (var md5 = new MD5CryptoServiceProvider())
          {
              var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
              var bs1 = md5.ComputeHash(preHash);
              var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
              var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());

              key = bs1.Concat(bs2).ToArray();
              iv = bs3;
          }

          using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
          using (var encryptor = aes.CreateEncryptor())
          {
              var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
              var concated = Encoding.UTF8.GetBytes("Salted__").Concat(salt).Concat(encryptedBytes);
              return Convert.ToBase64String(concated.ToArray());
          }

      }
      /// <summary>
      /// AES256解密
      /// </summary>
      /// <param name="content">密文</param>
      /// <param name="passphase">密钥</param>
      /// <returns></returns>
      public static string Decrypt(string content, string passphase)
      {
          // openssl aes-256-cbc -k 123456789 -md md5 -e -base64
          //
          byte[] bytes = Convert.FromBase64String(content);
          byte[] key, iv, salt = new byte[8], encryptedBytes = new byte[bytes.Length - 8 - 8];

          //提取 salt
          Array.ConstrainedCopy
          (
              sourceArray: bytes,
              sourceIndex: 8, //剔除开头的 "Salted__"
              destinationArray: salt,
              destinationIndex: 0,
              length: salt.Length
          );
          //提取 encryptedBytes
          Array.ConstrainedCopy
          (
              sourceArray: bytes,
              sourceIndex: 8 + 8, //并剔除开头的 salt
              destinationArray: encryptedBytes,
              destinationIndex: 0,
              length: encryptedBytes.Length
          );

          using (var md5 = new MD5CryptoServiceProvider())
          {
              var preHash = Encoding.UTF8.GetBytes(passphase).Concat(salt).ToArray();
              var bs1 = md5.ComputeHash(preHash);
              var bs2 = md5.ComputeHash(bs1.Concat(preHash).ToArray());
              var bs3 = md5.ComputeHash(bs2.Concat(preHash).ToArray());

              key = bs1.Concat(bs2).ToArray();
              iv = bs3;
          }

          using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
          using (var decryptor = aes.CreateDecryptor())
          {
              byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
              return Encoding.UTF8.GetString(decryptedBytes);
          }

      }


      /// <summary>
      /// 加密 (新的思路)
      /// </summary>
      /// <param name="content">明文</param>
      /// <param name="passphase">密码(固定32位)</param>
      /// <returns>密文(base64)</returns>
      static string CryptoJsEncrypt_New(string content, string passphase )
      {
          byte[] bytes = Encoding.UTF8.GetBytes(content);
          byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
          byte[] iv = new byte[16];

          using (var rng = new RNGCryptoServiceProvider())
              rng.GetBytes(iv); // 产生16个字节的随机iv

          using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
          using (var encryptor = aes.CreateEncryptor())
          {
              var encryptedBytes = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
              var concated = iv.Concat(encryptedBytes);
              return "aes256:" + Convert.ToBase64String(concated.ToArray());
          }
      }
      /// <summary>
      /// 解密 (新的思路)
      /// </summary>
      /// <param name="content">密文(base64)</param>
      /// <param name="passphase">密码(固定32位)</param>
      /// <returns>明文</returns>
      static string CryptoJsDecrypt_New(string content, string passphase )
      {
          byte[] bytes = Convert.FromBase64String(content.Substring(7)); //剔除开头的 "aes256:"
          byte[] key = Encoding.UTF8.GetBytes(passphase); //32位的key
          byte[] iv = new byte[16];
          byte[] encryptedBytes = new byte[bytes.Length - 16];

          //提取 iv
          Array.ConstrainedCopy
          (
              sourceArray: bytes,
              sourceIndex: 0,
              destinationArray: iv,
              destinationIndex: 0,
              length: iv.Length
          );
          //提取 加密结果
          Array.ConstrainedCopy
          (
              sourceArray: bytes,
              sourceIndex: 16, //并剔除开头的 iv
              destinationArray: encryptedBytes,
              destinationIndex: 0,
              length: encryptedBytes.Length
          );

          using (var aes = new AesCryptoServiceProvider() { Key = key, IV = iv })
          using (var decryptor = aes.CreateDecryptor())
          {
              byte[] decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
              return Encoding.UTF8.GetString(decryptedBytes);
          }
      }
  }
相关推荐
程序leo源22 分钟前
C语言:操作符详解1
android·java·c语言·c++·青少年编程·c#
轮到我狗叫了1 小时前
栈的应用,力扣394.字符串解码力扣946.验证栈序列力扣429.N叉树的层序遍历力扣103.二叉树的锯齿形层序遍历
java·算法·leetcode
冰之杍2 小时前
Vscode进行Java开发环境搭建
java·ide·vscode
yngsqq3 小时前
c#注册机制作(根据机器码生成注册码和注册文件)
c#
今朝无言4 小时前
Tri Mode Ethernet MAC IP核详解
网络·网络协议·tcp/ip·fpga开发
雯0609~4 小时前
c#:winform调用bartender实现打印(学习整理笔记)
开发语言·c#
C++忠实粉丝4 小时前
计算机网络socket编程(5)_TCP网络编程实现echo_server
网络·c++·网络协议·tcp/ip·计算机网络·算法
跳动的梦想家h6 小时前
黑马点评 秒杀下单出现的问题:服务器异常---java.lang.NullPointerException: null(已解决)
java·开发语言·redis
苹果醋36 小时前
前端面试之九阴真经
java·运维·spring boot·mysql·nginx
疯狂吧小飞牛6 小时前
openssl颁发包含主题替代名的证书–SAN
运维·服务器·网络