[转]常用加密解密方法
[转]常用加密解密方法
1. 概述
加密方法分为3类:
- 摘要算法
- 对称算法
- 非对称算法
2.摘要算法
通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密。数据摘要算法也被称为哈希(Hash)算法或散列算法。
应用范围:密码加密、数据完整性校验、数字签名等
这里介绍常用的两种摘要算法,MD5与SHA1。
提示:当前MD5已经被破解,推荐使用SHA1
2.1 MD5
哈希函数将任意长度的二进制字符串映射为固定长度的小型二进制字符串。 加密哈希函数有这样一个属性:在计算上不大可能找到散列为相同的值的两个不同的输入;也就是说,两组数据的哈希值仅在对应的数据也匹配时才会匹配。
MD5 算法的哈希值大小为 128 位,即16个字节。
using System.Security.Cryptography;
using System.Text;
public static string EncryptByMD5(string input)
{
var md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(input));
// 3C-B9-5C-FB-E1-03-5B-CE-8C-44-8F-CA-F8-0F-E7-D9
var result = BitConverter.ToString(data);
// 3cb95cfbe1035bce8c448fcaf80fe7d9
return result.Replace("-", "").ToLower();
}
input:hello,world
Md5:3cb95cfbe1035bce8c448fcaf80fe7d9
2.2 SHA1
SHA1 算法的哈希值大小为 160 位,即20个字节
using System.Security.Cryptography;
using System.Text;
public static string EncryptBySHA1(string input)
{
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] bytes = Encoding.Unicode.GetBytes(input);
byte[] result = sha.ComputeHash(bytes);
var strBuilder = BitConverter.ToString(result);
return strBuilder.Replace("-", "").ToLower();
}
input:hello,world
SHA1:b4033d87336844e048522be3647a2aae62a879c2
3.对称算法
对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。
优点:算法公开、计算量小、加密速度快、加密效率高。
常用的对称加密算法有:DES、IDEA、RC2、RC4、SKIPJACK、RC5、AES算法等
应用场景:数据传输、大数据量加密、敏感数据加密等等
提示: DES已经被破解,推荐使用3DES或AES
3.1 DES
最早、最著名的保密密钥或对称密钥加密算法DES(Data Encryption Standard)是由IBM公司在70年代发展起来的,并经政府的加密标准筛选后,于1976年11月被美国政府采用,DES随后被美国国家标准局和美国国家标准协会(American National Standard Institute,ANSI)承认。
DES使用56位密钥对64位的数据块进行加密,并对64位的数据块进行16轮编码。与每轮编码时,一个48位的"每轮"密钥值由56位的完整密钥得出来。DES用软件进行解码需用很长时间,而用硬件解码速度非常快。幸运的是,当时大多数黑客并没有足够的设备制造出这种硬件设备。在1977年,人们估计要耗资两千万美元才能建成一个专门计算机用于DES的解密,而且需要12个小时的破解才能得到结果。当时DES被认为是一种十分强大的加密方法。
随着计算机硬件的速度越来越快,制造一台这样特殊的机器的花费已经降到了十万美元左右,而用它来保护十亿美元的银行,那显然是不够保险了。另一方面,如果只用它来保护一台普通服务器,那么DES确实是一种好的办法,因为黑客绝不会仅仅为入侵一个服务器而花那么多的钱破解DES密文。
但是,这个算法,现在已经能够轻易破解。不过对于日常的非机密文件同样可以继续使用。
/// <summary>
/// DES 加密
/// </summary>
/// <param name="input">明文</param>
/// <param name="secret">秘钥,64位</param>
/// <returns></returns>
public static string EncryptByDES(string input, string secret)
{
byte[] data = Encoding.UTF8.GetBytes(input);
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = ASCIIEncoding.ASCII.GetBytes(secret);
des.IV = ASCIIEncoding.ASCII.GetBytes(secret);
ICryptoTransform desencrypt = des.CreateEncryptor();
byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);
return BitConverter.ToString(result);
}
}
/// <summary>
/// DES 解密
/// </summary>
/// <param name="input">密文</param>
/// <param name="secret">秘钥,64位</param>
/// <returns></returns>
public static string DecryptByDES(string input, string secret)
{
string[] sInput = input.Split("-".ToCharArray());
byte[] data = new byte[sInput.Length];
for (int i = 0; i < sInput.Length; i++)
{
data[i] = byte.Parse(sInput[i], System.Globalization.NumberStyles.HexNumber);
}
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = ASCIIEncoding.ASCII.GetBytes(secret);
des.IV = ASCIIEncoding.ASCII.GetBytes(secret);
ICryptoTransform desencrypt = des.CreateDecryptor();
byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);
return Encoding.UTF8.GetString(result);
}
input:hello,world, secret=12345678
EncryptByDES:F1-DC-AD-BC-F3-54-20-92-27-A8-7A-0A-17-2C-61-E8
DecryptByDES:hello,world
3.2 AES
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为“体(state)”,其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte)。(Rijndael加密法因支持更大的区块,其矩阵行数可视情况增加)加密时,各轮AES加密循环(除最后一轮外)均包含4个步骤:
AddRoundKey
—矩阵中的每一个字节都与该次回合密钥(round key)做XOR运算,每个子密钥由密钥生成方案产生。SubBytes
—通过一个非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。ShiftRows
—将矩阵中的每个横列进行循环式移位。MixColumns
—为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每内联的四个字节。最后一个加密循环中省略MixColumns
步骤,而以另一个AddRoundKey
取代。
参考加密动画演示
秘钥生成:
/// <summary>
/// 默认秘钥
/// </summary>
private static byte[] _aesKetByte = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
private static string _aesKeyStr = Encoding.UTF8.GetString(_aesKetByte);
/// <summary>
/// 随机生成密钥
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static byte[] GetIv(int n)
{
char[] arrChar = new char[]{ 'a','b','d','c','e','f','g','h','i','j','k','l','m','n','p','r','q','s','t','u','v','w','z','y','x',
'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','Q','P','R','T','S','V','U','W','X','Y','Z'
};
StringBuilder num = new StringBuilder();
Random rnd = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < n; i++)
{
num.Append(arrChar[rnd.Next(0, arrChar.Length)].ToString());
}
_aesKetByte = Encoding.UTF8.GetBytes(num.ToString());
return _aesKetByte;
}
加密:
/// <summary>
/// AES加密
/// </summary>
/// <param name="input">被加密的明文</param>
/// <param name="secret">密钥</param>
/// <param name="Vector">向量</param>
/// <returns>密文</returns>
public static string EncryptByAES(string input, string secret)
{
byte[] plainBytes = Encoding.UTF8.GetBytes(input);
string Vector = _aesKeyStr;
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(secret.PadRight(bKey.Length)), bKey, bKey.Length);
byte[] bVector = new byte[16];
Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
byte[] Cryptograph = null; // 加密后的密文
Rijndael Aes = Rijndael.Create();
try
{
// 开辟一块内存流
using (MemoryStream Memory = new MemoryStream())
{
// 把内存流对象包装成加密流对象
using CryptoStream Encryptor = new CryptoStream(Memory,
Aes.CreateEncryptor(bKey, bVector),
CryptoStreamMode.Write);
// 明文数据写入加密流
Encryptor.Write(plainBytes, 0, plainBytes.Length); Encryptor.FlushFinalBlock();
Cryptograph = Memory.ToArray();
}
}
catch
{
Cryptograph = null;
}
return Convert.ToBase64String(Cryptograph);
}
解密:
/// <summary>
/// AES 解密
/// </summary>
/// <param name="input">密文</param>
/// <param name="secret">秘钥</param>
/// <returns></returns>
public static string DecryptByAES(string input, string secret)
{
byte[] encryptedBytes = Convert.FromBase64String(input);
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(secret.PadRight(bKey.Length)), bKey, bKey.Length);
byte[] bVector = new byte[16];
string Vector = _aesKeyStr;
Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
byte[] original = null; // 解密后的明文
Rijndael Aes = Rijndael.Create();
try
{
// 开辟一块内存流,存储密文
using (MemoryStream Memory = new MemoryStream(encryptedBytes))
{
// 把内存流对象包装成加密流对象
using CryptoStream Decryptor = new CryptoStream(Memory,
Aes.CreateDecryptor(bKey, bVector),
CryptoStreamMode.Read);
// 明文存储区
using (MemoryStream originalMemory = new MemoryStream())
{
byte[] Buffer = new byte[1024];
int readBytes = 0;
while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
{
originalMemory.Write(Buffer, 0, readBytes);
}
original = originalMemory.ToArray();
}
}
}
catch
{
original = null;
}
return Encoding.UTF8.GetString(original);
}
4.非对称算法
非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
基本过程:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。另一方面,甲方可以使用乙方的公钥对机密信息进行签名后再发送给乙方;乙方再用自己的私匙对数据进行验签。非对称加密算法的保密性比较好,它消除了最终用户交换密钥的需要。
优点:非对称加密体系不要求通信双方事先传递密钥或有任何约定就能完成保密通信,并且密钥管理方便,可实现防止假冒和抵赖,因此,更适合网络通信中的保密通信要求
主要算法:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。
4.1 RSA
RSA(Rivest-Shamir-Adleman)算法是基于大数不可能被质因数分解假设的公钥体系。简单地说就是找两个很大的质数。一个对外公开的为"公钥"(Public key) ,另一个不告诉任何人,称为"私钥"(Private key)。这两个密钥是互补的,也就是说用公钥加密的密文可以用私钥解密,反过来也一样。
参考