完全去除__MOBILE__,由std支持
大石头 编写于 2018-12-22 15:23:32
X
using System;
using System.IO;
using System.Security.Cryptography;

namespace NewLife.Security
{
    /// <summary>RSA算法</summary>
    /// <remarks>
    /// RSA加密或签名小数据块时,密文长度128,速度也很快。
    /// </remarks>
    public static class RSAHelper
    {
        #region 加密解密
        /// <summary>产生非对称密钥对</summary>
        /// <remarks>
        /// RSAParameters的各个字段采用大端字节序,转为BigInteger的之前一定要倒序。
        /// RSA加密后密文最小长度就是密钥长度,所以1024密钥最小密文长度是128字节。
        /// </remarks>
        /// <param name="keySize">密钥长度,默认1024位强密钥</param>
        /// <returns></returns>
        public static String[] GenerateKey(Int32 keySize = 2048)
        {
            var rsa = new RSACryptoServiceProvider(keySize);

            var ss = new String[2];
            ss[0] = rsa.ToXmlString(true);
            ss[1] = rsa.ToXmlString(false);

            return ss;
        }

        /// <summary>RSA加密</summary>
        /// <param name="buf"></param>
        /// <param name="pubKey"></param>
        /// <param name="fOAEP">如果为 true,则使用 OAEP 填充(仅可用于运行 Windows XP 及更高版本的计算机)执行直接 System.Security.Cryptography.RSA加密;否则,如果为 false,则使用 PKCS#1 v1.5 填充。</param>
        /// <returns></returns>
        public static Byte[] Encrypt(Byte[] buf, String pubKey, Boolean fOAEP = true)
        {
            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(pubKey);

            return rsa.Encrypt(buf, fOAEP);
        }

        /// <summary>RSA解密</summary>
        /// <param name="buf"></param>
        /// <param name="priKey"></param>
        /// <param name="fOAEP">如果为 true,则使用 OAEP 填充(仅可用于运行 Microsoft Windows XP 及更高版本的计算机)执行直接 System.Security.Cryptography.RSA解密;否则,如果为 false 则使用 PKCS#1 v1.5 填充。</param>
        /// <returns></returns>
        public static Byte[] Decrypt(Byte[] buf, String priKey, Boolean fOAEP = true)
        {
            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(priKey);

            return rsa.Decrypt(buf, fOAEP);
        }
        #endregion

        #region 复合加解密
        /// <summary>配合DES加密</summary>
        /// <param name="buf"></param>
        /// <param name="pubKey"></param>
        /// <returns></returns>
        public static Byte[] EncryptWithDES(Byte[] buf, String pubKey) { return Encrypt<DESCryptoServiceProvider>(buf, pubKey); }

        /// <summary>配合DES解密</summary>
        /// <param name="buf"></param>
        /// <param name="priKey"></param>
        /// <returns></returns>
        public static Byte[] DecryptWithDES(Byte[] buf, String priKey) { return Decrypt<DESCryptoServiceProvider>(buf, priKey); }

        /// <summary>配合对称算法加密</summary>
        /// <typeparam name="TSymmetricAlgorithm"></typeparam>
        /// <param name="buf"></param>
        /// <param name="pubKey"></param>
        /// <returns></returns>
        public static Byte[] Encrypt<TSymmetricAlgorithm>(Byte[] buf, String pubKey) where TSymmetricAlgorithm : SymmetricAlgorithm, new()
        {
            // 随机产生对称加密密钥
            var sa = new TSymmetricAlgorithm();
            sa.GenerateIV();
            sa.GenerateKey();

            // 对称加密
            buf = sa.Encrypt(buf);

            var ms = new MemoryStream();
            ms.WriteWithLength(sa.Key)
                .WriteWithLength(sa.IV);
            var keys = ms.ToArray();

            // 非对称加密前面的随机密钥
            keys = Encrypt(keys, pubKey);

            // 组合起来
            ms = new MemoryStream();
            ms.WriteWithLength(keys)
                .WriteWithLength(buf);

            return ms.ToArray();
        }

        /// <summary>配合对称算法解密</summary>
        /// <typeparam name="TSymmetricAlgorithm"></typeparam>
        /// <param name="buf"></param>
        /// <param name="priKey"></param>
        /// <returns></returns>
        public static Byte[] Decrypt<TSymmetricAlgorithm>(Byte[] buf, String priKey) where TSymmetricAlgorithm : SymmetricAlgorithm, new()
        {
            var ms = new MemoryStream(buf);

            // 读取已加密的对称密钥
            var keys = ms.ReadWithLength();
            // 读取已加密的数据
            buf = ms.ReadWithLength();

            // 非对称解密密钥
            keys = Decrypt(keys, priKey);

            ms = new MemoryStream(keys);

            var sa = new TSymmetricAlgorithm
            {
                Key = ms.ReadWithLength(),
                IV = ms.ReadWithLength()
            };

            // 对称解密
            return sa.Descrypt(buf);
        }
        #endregion

        #region 数字签名
        /// <summary>签名</summary>
        /// <param name="buf"></param>
        /// <param name="priKey"></param>
        /// <returns></returns>
        public static Byte[] Sign(Byte[] buf, String priKey)
        {
            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(priKey);

            return rsa.SignData(buf, MD5.Create());
        }

        /// <summary>验证</summary>
        /// <param name="buf"></param>
        /// <param name="pukKey"></param>
        /// <param name="rgbSignature"></param>
        /// <returns></returns>
        public static Boolean Verify(Byte[] buf, String pukKey, Byte[] rgbSignature)
        {
            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(pukKey);

            return rsa.VerifyData(buf, MD5.Create(), rgbSignature);
        }
        #endregion

        #region 辅助
        private static RNGCryptoServiceProvider _rng;
        /// <summary>使用随机数设置</summary>
        /// <param name="buf"></param>
        /// <returns></returns>
        public static Byte[] SetRandom(this Byte[] buf)
        {
            if (_rng == null) _rng = new RNGCryptoServiceProvider();

            _rng.GetBytes(buf);

            return buf;
        }

        static Stream WriteWithLength(this Stream stream, Byte[] buf)
        {
            var bts = BitConverter.GetBytes(buf.Length);
            stream.Write(bts);
            stream.Write(buf);

            return stream;
        }

        static Byte[] ReadWithLength(this Stream stream)
        {
            var bts = new Byte[4];
            stream.Read(bts, 0, bts.Length);

            var len = BitConverter.ToInt32(bts, 0);
            bts = new Byte[len];

            stream.Read(bts, 0, bts.Length);

            return bts;
        }

        static Stream Write(this Stream stream, params Byte[][] bufs)
        {
            //stream.Write(buf, 0, buf.Length);
            foreach (var buf in bufs)
            {
                stream.Write(buf, 0, buf.Length);
            }

            return stream;
        }
        #endregion
    }
}