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 { ////// 加密解密工具类 /// 作者博客:https://www.cnblogs.com/tuyile006/ /// public class EncodeHelper { #region MD5 /// /// MD5哈希加密 /// /// 原始string数据 /// 加密后的数据 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 /// /// SHA1哈希加密 /// /// 原始string数据 /// 加密后的数据 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 /// /// RSA加密 /// /// 原始string数据 /// 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);//将加密后的字节数组转换为字符串 } } /// /// RSA解密 /// /// 密文 /// 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; } } /// /// 返回RSA公匙 /// /// 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个字节 /// /// 按指定键值进行DES加密 /// /// 要加密字符 /// 自定义键值 ASCII编码 必须大于或等于8个字符 /// 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); } } } } /// /// 按指定键值进行DES解密 /// /// 要解密字符 /// 加密时使用的键值 ASCII编码 必须大于或等于8个字符 /// 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个英文或汉字 /// /// 按指定键值进行AES加密 /// /// 要解密字符 /// 加密时使用的键值 Unicode编码 必须大于或等于8个英文或汉字 /// 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密文方便传输 } } } } /// /// 按指定键值进行AES解密 /// /// 要解密字符 /// 加密时使用的键值 Unicode编码 必须大于或等于8个英文或汉字 /// 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 /// /// 利用ecc生成key /// 假设从A-->B进行信息发送 /// /// A的公钥名称 自身 /// B的公钥 /// 生成A端用于交互信息的密钥,可以用于AES加密的密钥 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); } } /// /// 获取自身的公钥 /// /// Base64编码的字符串,接收端需要Base64解码再使用 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); }