• 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”方法。

      public class RSAUtils
      {
          /// 
          /// 生成私钥
          /// 
          /// 
          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);
          }
       
          /// 
          /// 生成密钥
          /// 私钥
          /// 公钥
          /// 密钥长度:512,1024,2048,4096,8192
          /// 
          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 表示仅包含公钥。
          }
          /// 
          /// RSA加密 将公钥导入到RSA对象中,准备加密
          /// 
          /// 公钥
          /// 待加密的字符串
          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());//转化为字节流方便传输
                  }
              }
          }
    
          /// 
          /// Java转.net格式
          /// 
          /// Java格式公钥
          /// 
          public static string RSAPublicKeyJava2DotNet(string JavaPublicKey)
          {
              RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(JavaPublicKey));
              return string.Format("{0}{1}",
                 Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                 Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
          }
    
          /// 
          /// .NET格式转Java格式
          /// 
          /// c#的.net格式公钥
          /// 
          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);
          }
          /// 
          /// .java格式密钥转c#使用的.net格式密钥
          /// 
          /// .java密钥
          /// 
          public static string RSAPrivateKeyJava2DotNet(string JavaPrivateKey)
          {
              RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(JavaPrivateKey));
              return string.Format("{0}{1}

    {2}

    {3}{4}{5}{6}{7}
    "
    , 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())); } /// /// c#使用的.net格式密钥转换成.Java格式密钥 /// /// .net格式密钥 /// 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); } /// /// RSA解密 载入私钥,解密数据 /// /// 私钥 /// 待解密的字符串 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()); //转化为字符串 } } } /// /// RSA私钥加密 /// /// 私钥 /// 待加密的字符串 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());//转化为字节流方便传输 } } /// /// RSA公钥解密 /// /// 公钥 /// 待解密的字符串 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()); } } /// /// SHA1 加密,返回大写字符串 /// /// 需要加密字符串 /// 返回40位UTF8 大写 public static string SHA1(string content) { return SHA1(content, Encoding.UTF8); } /// /// SHA1 加密,返回大写字符串 /// /// 需要加密字符串 /// 指定加密编码 /// 返回40位大写字符串 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); } } /// /// 私钥加密 /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。 /// /// 密钥 /// 要加密的数据 /// 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; } /// /// 用公钥解密 /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。 /// /// /// /// 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; } }

    调用方法

      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加密

    这里问题就来了

    下面是错误方法:

            /// 
     
            /// AES加密
     
            /// 
     
            /// 明文
     
            /// 密钥
     
            /// 
     
            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);
     
            }
                    /// 
     
            /// AES解密
     
            /// 
     
            /// 密文
     
            /// 密钥
     
            /// 
     
            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#写的解密方法能解密,估计是因为填充类型或者其他什么地方有问题。在这里我也困惑了很久

    下面是正确方法:

    public class AESUtils
    {
        /// 
        /// AES256加密
        /// 
        /// 明文
        /// 密钥
        /// 
        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());
            }
    
        }
        /// 
        /// AES256解密
        /// 
        /// 密文
        /// 密钥
        /// 
        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);
            }
    
        }
    
    
        /// 
        /// 加密 (新的思路)
        /// 
        /// 明文
        /// 密码(固定32位)
        /// 密文(base64)
        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());
            }
        }
        /// 
        /// 解密 (新的思路)
        /// 
        /// 密文(base64)
        /// 密码(固定32位)
        /// 明文
        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);
            }
        }
    }
    

    调用方法

    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==

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


    完整的加密帮助类

     using Org.BouncyCastle.Asn1.Pkcs;
    using Org.BouncyCastle.Asn1.X509;
    using Org.BouncyCastle.Crypto;
    using Org.BouncyCastle.Crypto.Parameters;
    using Org.BouncyCastle.Math;
    using Org.BouncyCastle.Pkcs;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.X509;
    using System;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml;
    
    namespace HKBSKD.Common
    {
        /// 
        /// RSA
        /// 
        public class RSAUtils
        {
            /// 
            /// 生成私钥
            /// 
            /// 
            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);
            }
         
            /// 
            /// 生成密钥
            /// 私钥
            /// 公钥
            /// 密钥长度:512,1024,2048,4096,8192
            /// 
            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 表示仅包含公钥。
            }
            /// 
            /// RSA加密 将公钥导入到RSA对象中,准备加密
            /// 
            /// 公钥
            /// 待加密的字符串
            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());//转化为字节流方便传输
                    }
                }
            }
    
            /// 
            /// Java转.net格式
            /// 
            /// Java格式公钥
            /// 
            public static string RSAPublicKeyJava2DotNet(string JavaPublicKey)
            {
                RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(JavaPublicKey));
                return string.Format("{0}{1}",
                   Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                   Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
            }
    
            /// 
            /// .NET格式转Java格式
            /// 
            /// c#的.net格式公钥
            /// 
            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);
            }
            /// 
            /// .java格式密钥转c#使用的.net格式密钥
            /// 
            /// .java密钥
            /// 
            public static string RSAPrivateKeyJava2DotNet(string JavaPrivateKey)
            {
                RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(JavaPrivateKey));
                return string.Format("{0}{1}

    {2}

    {3}{4}{5}{6}{7}
    "
    , 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())); } /// /// c#使用的.net格式密钥转换成.Java格式密钥 /// /// .net格式密钥 /// 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); } /// /// RSA解密 载入私钥,解密数据 /// /// 私钥 /// 待解密的字符串 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()); //转化为字符串 } } } /// /// RSA私钥加密 /// /// 私钥 /// 待加密的字符串 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());//转化为字节流方便传输 } } /// /// RSA公钥解密 /// /// 公钥 /// 待解密的字符串 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()); } } /// /// SHA1 加密,返回大写字符串 /// /// 需要加密字符串 /// 返回40位UTF8 大写 public static string SHA1(string content) { return SHA1(content, Encoding.UTF8); } /// /// SHA1 加密,返回大写字符串 /// /// 需要加密字符串 /// 指定加密编码 /// 返回40位大写字符串 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); } } /// /// 私钥加密 /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。 /// /// 密钥 /// 要加密的数据 /// 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; } /// /// 用公钥解密 /// 这个方法只能加密 私钥长度/8 -11 个字符,分段加密的代码要自己处理了。 /// /// /// /// 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; } } /// /// AES /// public class AESUtils { /// /// AES加密 /// /// 明文 /// 密钥 /// 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); } /// /// AES解密 /// /// 密文 /// 密钥 /// 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); } /// /// AES256加密 /// /// 明文 /// 密钥 /// public static string Encrypt256(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()); } } /// /// AES256解密 /// /// 密文 /// 密钥 /// public static string Decrypt256(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); } } /// /// 加密 (新的思路) /// /// 明文 /// 密码(固定32位) /// 密文(base64) 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()); } } /// /// 解密 (新的思路) /// /// 密文(base64) /// 密码(固定32位) /// 明文 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); } } } }
  • 相关阅读:
    MySQL查漏补缺
    回顾C++
    第二十二 查询、检索、搜索
    maven如何手动添加jar包到本地仓库
    C++Qt开发——事件处理函数
    项目讲解说明
    DC综合基本概念:set_dont_touch
    [Android]修改应用包名、名称、版本号、Icon以及环境判断和打包
    SPDK block device及其编程的简单介绍
    缺陷检测:PatchCore的代码解读
  • 原文地址:https://blog.csdn.net/qq_42455262/article/details/139318363