zoukankan      html  css  js  c++  java
  • 常见加密算法简析

    1、对称加密算法(AES、DES、3DES)

    对称加密算法是指加密和解密采用相同的密钥,是可逆的(即可解密)。

    AES加密算法是密码学中的高级加密标准,采用的是对称分组密码体制,密钥长度的最少支持为128。AES加密算法是美国联邦政府采用的区块加密标准,这个标准用来替代原先的DES,已经被多方分析且广为全世界使用。

    AES数学原理详解:https://www.cnblogs.com/block2016/p/5596676.html

    优点:加密速度快

    缺点:密钥的传递和保存是一个问题,参与加密和解密的双方使用的密钥是一样的,这样密钥就很容易泄露。

    2、非对称加密算法(RSA、DSA、ECC)

    非对称加密算法是指加密和解密采用不同的密钥(公钥和私钥),因此非对称加密也叫公钥加密,是可逆的(即可解密)。公钥密码体制根据其所依据的难题一般分为三类:大素数分解问题类、离散对数问题类、椭圆曲线类。

    RSA加密算法是基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解极其困难,因此可以将乘积公开作为加密密钥。虽然RSA的安全性一直未能得到理论上的证明,但它经历了各种攻击至今未被完全攻破。 

    优点:加密和解密的密钥不一致,公钥是可以公开的,只需保证私钥不被泄露即可,这样就密钥的传递变的简单很多,从而降低了被破解的几率。

    缺点:加密速度慢

    RSA加密算法既可以用来做数据加密,也可以用来数字签名。

    --数据加密过程:发送者用公钥加密,接收者用私钥解密(只有拥有私钥的接收者才能解读加密的内容)

    --数字签名过程:甲方用私钥加密,乙方用公钥解密(乙方解密成功说明就是甲方加的密,甲方就不可以抵赖)

    详细数学原理见 【来龙去脉系列】RSA算法原理

    ECC加密算法是基于椭圆曲线上离散对数计算问题(ECDLP)的ECC算法。ECC算法的数学理论非常深奥和复杂,在工程应用中比较难于实现,但它的单位安全强度相对较高。

    用国际上公认的对于ECC算法最有效的攻击方法--Pollard rho方法去破译和攻击ECC算法,它的破译或求解难度基本上是指数级的。正是由于RSA算法ECC算法这一明显不同,使得ECC算法的单位安全强度高于RSA算法,也就是说,要达到同样的安全强度,ECC算法所需的密钥长度远比RSA算法低。有研究表示160位的椭圆密钥与1024位的RSA密钥安全性相同。在私钥的加密解密速度上,ECC算法比RSA、DSA速度更快。存储空间占用更小。

    扩展阅读:

    ECDH and ECDSA   

    How to encrypt data using Elliptic Curve Algorithm in C#

    ECC Examples for C#

    3、线性散列算法算法(MD5、SHA1、HMAC)

    MD5全称是Message-Digest Algorithm 5(信息摘要算法5),单向的算法不可逆(被MD5加密的数据不能被解密)。MD5加密后的数据长度要比加密数据小的多,且长度固定,且加密后的串是唯一的。

    适用场景:常用在不可还原的密码存储、信息完整性校验等。

    信息完整性校验:典型的应用是对一段信息产生信息摘要,以防止被篡改。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

    SHA-1 与 MD5 的比较

    SHA-1摘要比MD5摘要长32 位,所以SHA-1对强行攻击有更大的强度,比MD5更安全。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。

    在相同的硬件上,SHA-1 的运行速度比 MD5 慢。

    4、混合加密

    由于以上加密算法都有各自的缺点(RSA加密速度慢、AES密钥存储问题、MD5加密不可逆),因此实际应用时常将几种加密算法混合使用。

    例如:RSA+AES:

    采用RSA加密AES的密钥,采用AES对数据进行加密,这样集成了两种加密算法的优点,既保证了数据加密的速度,又实现了安全方便的密钥管理。

    那么,采用多少位的密钥合适呢?一般来讲密钥长度越长,安全性越高,但是加密速度越慢。所以密钥长度也要合理的选择,一般RSA建议采用1024位的数字,AES建议采用128位即可。

    5、Base64

    严格意义讲,Base64并不能算是一种加密算法,而是一种编码格式,是网络上最常见的用于传输8bid字节代码的编码方式之一。

    Base64编码可用于在HTTP环境下传递较长的标识信息,Base编码不仅不仅比较简单,同时也据有不可读性(编码的数据不会被肉眼直接看到)。

    C#实现:

    using System;
    using System.Text;
    using System.Security.Cryptography;
    using System.IO;
    
    namespace EnDeCode1
    {
        /// <summary>
        /// 加密解密工具类
        /// 作者博客:https://www.cnblogs.com/tuyile006/
        /// </summary>
        public class EncodeHelper
        {
            #region MD5
            /// <summary>
            /// MD5哈希加密
            /// </summary>
            /// <param name="scr">原始string数据</param>
            /// <returns>加密后的数据</returns>
            public static string MD5(string scr)
            {
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] palindata = Encoding.Default.GetBytes(scr);//将要加密的字符串转换为字节数组
                byte[] encryptdata = md5.ComputeHash(palindata);//将字符串加密后也转换为字符数组
                return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为加密字符串
            }
            #endregion
    
            #region SHA1
            /// <summary>
            /// SHA1哈希加密
            /// </summary>
            /// <param name="scr">原始string数据</param>
            /// <returns>加密后的数据</returns>
            public static string SHA1(string scr)
            {
                SHA1 sha1 = new SHA1CryptoServiceProvider();
                byte[] palindata = Encoding.Default.GetBytes(scr);//将要加密的字符串转换为字节数组
                byte[] encryptdata = sha1.ComputeHash(palindata);//将字符串加密后也转换为字符数组
                return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为加密字符串
            }
            #endregion
    
            #region RSA
            /// <summary>
            /// RSA加密
            /// </summary>
            /// <param name="scr">原始string数据</param>
            /// <returns></returns>
            public static string RSA(string scr)
            {
                CspParameters csp = new CspParameters(); //密钥容器知识参见https://docs.microsoft.com/zh-cn/dotnet/standard/security/how-to-store-asymmetric-keys-in-a-key-container
                                                         //在Web中配置参见https://docs.microsoft.com/zh-cn/previous-versions/aspnet/yxw286t2%28v%3dvs.100%29
                csp.KeyContainerName = "tuyile006.cnblogs.com";//密匙容器的名称,保持加密解密一致才能解密成功
                using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp))
                {
                    byte[] plaindata = Encoding.Default.GetBytes(scr);//将要加密的字符串转换为字节数组
                    byte[] encryptdata = rsa.Encrypt(plaindata, false);//将加密后的字节数据转换为新的加密字节数组
                    return Convert.ToBase64String(encryptdata);//将加密后的字节数组转换为字符串
                }
            }
            /// <summary>
            /// RSA解密
            /// </summary>
            /// <param name="scr">密文</param>
            /// <returns></returns>
            public static string RSADecrypt(string scr)
            {
                try
                {
                    CspParameters csp = new CspParameters();
                    csp.KeyContainerName = "tuyile006.cnblogs.com";//密匙容器的名称,保持加密解密一致才能解密成功
                    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp))
                    {
                        byte[] bytes = Convert.FromBase64String(scr); //加密时用了Base64,则解密时对应的也要用Base64解码
                        byte[] DecryptBytes =  rsa.Decrypt(bytes, false);
                        return Encoding.Default.GetString(DecryptBytes);
                    }
                }
                catch (Exception)
                {
                    return string.Empty;
                }
            }
    
            /// <summary>
            /// 返回RSA公匙
            /// </summary>
            /// <returns></returns>
            public static string GetRSAPublicKey()
            {
                CspParameters csp = new CspParameters();
                csp.KeyContainerName = "tuyile006.cnblogs.com";//密匙容器的名称,保持加密解密一致才能解密成功
                using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp))
                {
                    return rsa.ToXmlString(false);
                }
            }
    
            #endregion
    
            #region DES
            const string DesIV_64 = "xiaoy><@";//定义默认加密密钥 8个字节 
            /// <summary>
            /// 按指定键值进行DES加密
            /// </summary>
            /// <param name="strContent">要加密字符</param>
            /// <param name="strKey">自定义键值 ASCII编码  必须大于或等于8个字符</param>
            /// <returns></returns>
            public static string DES(string strContent, string strKey)
            {
                if (string.IsNullOrEmpty(strContent)) return string.Empty;
                if (strKey.Length > 8) strKey = strKey.Substring(0, 8);
                
                DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
                byte[] byKey = Encoding.ASCII.GetBytes(strKey);
                byte[] byIV = Encoding.ASCII.GetBytes(DesIV_64);
                
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(cst))
                        {
                            sw.Write(strContent);
                            sw.Flush();
                            cst.FlushFinalBlock();
                            sw.Flush();
                            return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
                        }
                    }
                }
            }
    
            /// <summary>
            /// 按指定键值进行DES解密
            /// </summary>
            /// <param name="strContent">要解密字符</param>
            /// <param name="strKey">加密时使用的键值 ASCII编码 必须大于或等于8个字符</param>
            /// <returns></returns>
            public static string DESDecrypt(string strContent, string strKey)
            {
                if (string.IsNullOrEmpty(strContent)) return string.Empty;
                if (strKey.Length > 8) strKey = strKey.Substring(0, 8); 
                byte[] byKey = Encoding.ASCII.GetBytes(strKey);
                byte[] byIV = Encoding.ASCII.GetBytes(DesIV_64);
    
                byte[] byEnc;
                try
                {
                    byEnc = Convert.FromBase64String(strContent);
                    using (DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider())
                    {
                        using (MemoryStream ms = new MemoryStream(byEnc))
                        {
                            using (CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read))
                            {
                                StreamReader sr = new StreamReader(cst);
                                return sr.ReadToEnd();
                            }
                        }
                    }
                }
                catch
                {
                    return string.Empty;
                }
                
            }
            #endregion
    
            #region AES
            const string AesIV_128 = "xiaoy设计.";//定义默认加密密钥 16个字节 Unicode编码为8个英文或汉字
            /// <summary>
            /// 按指定键值进行AES加密
            /// </summary>
            /// <param name="plainText">要解密字符</param>
            /// <param name="strKey">加密时使用的键值 Unicode编码 必须大于或等于8个英文或汉字</param>
            /// <returns></returns>
            public static string AES(string strContent, string strKey)
            {
                if (string.IsNullOrEmpty(strContent)) return string.Empty;
                if (strKey.Length > 8) strKey = strKey.Substring(0, 8);
    
                using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
                {
                    aesAlg.Key = Encoding.Unicode.GetBytes(strKey);
                    aesAlg.IV = Encoding.Unicode.GetBytes(AesIV_128);
                    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                    using (MemoryStream msEncrypt = new MemoryStream())
                    {
                        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                            {
                                swEncrypt.Write(strContent);
                            }
                            return Convert.ToBase64String(msEncrypt.ToArray()); //返回Base64密文方便传输
                        }
                    }
                }
            }
            /// <summary>
            /// 按指定键值进行AES解密
            /// </summary>
            /// <param name="strContent">要解密字符</param>
            /// <param name="strKey">加密时使用的键值 Unicode编码 必须大于或等于8个英文或汉字</param>
            /// <returns></returns>
            public static string AESDecrypt(string strContent, string strKey)
            {
                if (string.IsNullOrEmpty(strContent)) return string.Empty;
                if (strKey.Length > 8) strKey = strKey.Substring(0, 8);
                //与加密时Base64对应
                byte[] byEnc;
                try
                {
                    byEnc = Convert.FromBase64String(strContent);
                    //解密
                    using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
                    {
                        aesAlg.Key = Encoding.Unicode.GetBytes(strKey);
                        aesAlg.IV = Encoding.Unicode.GetBytes(AesIV_128);
    
                        // Create a decryptor to perform the stream transform.
                        ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    
                        // Create the streams used for decryption.
                        using (MemoryStream msDecrypt = new MemoryStream(byEnc))
                        {
                            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                            {
                                using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                                {
                                    return srDecrypt.ReadToEnd();
                                }
                            }
                        }
                    }
                }
                catch
                {
                    return string.Empty;
                }
            }
            #endregion
    
            #region ECC
    
            /// <summary>
            /// 利用ecc生成key
            /// 假设从A-->B进行信息发送
            /// </summary>
            /// <param name="AKeyName">A的公钥名称 自身</param>
            /// <param name="BKey">B的公钥</param>
            /// <returns> 生成A端用于交互信息的密钥,可以用于AES加密的密钥</returns>
            public static string ECC_EncodeKey(string AKeyName,string BKey)
            {
                byte[] BKeybyte = Convert.FromBase64String(BKey);
                using (ECDiffieHellmanCng AClient = new ECDiffieHellmanCng(CngKey.Open(AKeyName)))
                //using (ECDiffieHellmanCng AClient = new ECDiffieHellmanCng())
                {
                    AClient.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                    AClient.HashAlgorithm = CngAlgorithm.Sha256;
                    
                    byte[] MsgKey = AClient.DeriveKeyMaterial(CngKey.Import(BKeybyte, CngKeyBlobFormat.EccPublicBlob));
                    return Convert.ToBase64String(MsgKey);
                }
            }
    
            /// <summary>
            /// 获取自身的公钥
            /// </summary>
            /// <returns>Base64编码的字符串,接收端需要Base64解码再使用</returns>
            public static string ECC_GetMyPublicKey(string keyName)
            {
                if (!CngKey.Exists(keyName))
                {
                    using (ECDiffieHellmanCng MyECC = new ECDiffieHellmanCng(CngKey.Create(CngAlgorithm.ECDiffieHellmanP256, keyName)))
                    {
                        MyECC.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                        MyECC.HashAlgorithm = CngAlgorithm.Sha256;
                        byte[] Keybyte = MyECC.PublicKey.ToByteArray();
                        return Convert.ToBase64String(Keybyte);
    
                    }
                }
                else
                {
                    using (ECDiffieHellmanCng MyECC = new ECDiffieHellmanCng(CngKey.Open(keyName)))
                    {
                        byte[] Keybyte = MyECC.PublicKey.ToByteArray();
                        return Convert.ToBase64String(Keybyte);
                    }
                }
            }
            #endregion
        }
    }

    这些算法已经在.net框架里面封装好了,只需要引用System.Security.Cryptography库,使用起来还是非常方便的。

    使用示例:(下载Demo)

    算法调用很简单:

     txtEncode.Text = EncodeHelper.MD5(txtMsg.Text);
     txtEncode.Text = EncodeHelper.RSA(txtMsg.Text);
    txtMsg.Text = "解密后的文本:" + EncodeHelper.RSADecrypt(txtEncode.Text);
    txtEncode.Text = EncodeHelper.AES(txtMsg.Text, "密钥可以是汉字哦");
    txtMsg.Text = "解密后的文本:" + EncodeHelper.AESDecrypt(txtEncode.Text, "密钥可以是汉字哦");

    稍微复杂一点的是ECC+AES混合加密,用ECC加密AES的密钥,而用AES加密要传送的信息,接收端用ECC公钥解密得到AES密钥,然后解密信息。

    该过程可以参考MSDN上的例子https://docs.microsoft.com/ru-ru/dotnet/api/system.security.cryptography.ecdiffiehellmancng

    string bkey, akey,akeyname="akey",bkeyname="bkey";
    
            private void btn_Ecc_Click(object sender, EventArgs e)
            {
                akey = EncodeHelper.ECC_GetMyPublicKey(akeyname); //A先获取自身的publickey
                bkey = EncodeHelper.ECC_GetMyPublicKey(bkeyname); //B先获取自身的publickey
                string  AClientAESKey = EncodeHelper.ECC_EncodeKey(akeyname, bkey);  //用bkey生成用于AES算法的key
                txtEncode.Text = EncodeHelper.AES(txtMsg.Text, AClientAESKey);
            }
    
            private void btn_eccrec_Click(object sender, EventArgs e)
            {
                string BClientAESKey = EncodeHelper.ECC_EncodeKey(bkeyname, akey);  //用akey生成用于AES算法的key
                txtMsg.Text ="解密后的文本:"+ EncodeHelper.AESDecrypt(txtEncode.Text, BClientAESKey);
            }
  • 相关阅读:
    codeforces 439C 模拟
    codeforces 435B
    【WebVR】AFrame中的A-sky无法利用src指定路径显示全景图
    【UE4】添加头文件之后VS中UCLASS()报错问题解决办法
    【UE4】蓝图之间的通讯
    git中报unable to auto-detect email address 错误的解决办法
    2017ACM省赛总结与生涯回顾
    hihocoder#1121 : 二分图一•二分图判定
    hihocoder#1039 : 字符消除
    2048low版
  • 原文地址:https://www.cnblogs.com/tuyile006/p/10873975.html
Copyright © 2011-2022 走看看