作者 | 喵叔
責編 | 劉靜
出品 | CSDN(ID:CSDNnews)
加密解密在開發中經常用到,比如登錄密碼加密解密、消息傳輸加密解密等。但是很多人只會使用不理解其中的原理,這篇文章就帶領大家快速學習加密解密的原理和使用。
1.零、什么是加密解密
通俗的說加密解密就是將不想讓別人很容易看到的東西根據一定的規則進行處理,形成無規則的內容。拿到加密后內容的人通過一定規則將加密后的內容還原成原文。這里所說的原文在計算機中被稱為明文,加密后的內容被稱為密文。加密后的內容并不是完全不可破解的,只是提高了破解的難度,讓大多數人退縮。那么怎么判斷一個加解密安全呢?一般來說加密消息在發送方和接收方進行傳遞時必須滿足三個條件:
-
發送方可以確定所發送的消息只有預期接收方可以解密,但不保證其他非接收方獲得密文,只要保證非接收方獲得密文后無法解密即可;
-
接收方可以確定消息是誰發送的;
-
接收方可以確定消息在傳輸過程中沒有被篡改,也就是說可以驗證消息的完整性。
一般來說常用的加密方式有三種:
-
不可逆加密;
-
對稱可逆加密;
-
非堆成可逆加密。
下面我來講一講這三種常用的加密方式。
2.不可逆加密
常用的不可逆加密是 MD5 加密,MD5是Message-Digest Algorithm 5英文簡稱,MD5 的特點如下:
-
任意長度的輸入,經過 MD5 處理后都會輸出128位的信息,這個信息稱作數字指紋;
-
輸入不同的信息產生的數字指紋不一樣,數字指紋是全球唯一的;
-
無法根據數字指紋推導出加密前的信息。MD5 我們經常用在文檔防篡改、密碼加密、數字簽名、網盤秒傳。針對這四個方面我下面簡單講解一下:
-
文檔防篡改
在文檔發送前記錄文檔的 MD5 值,接收方收到文檔后計算文檔的 MD5 值,如果兩個 MD5 值不一樣就說明文檔在發送過程中被篡改過;
-
密碼加密
如果將密碼明文存儲在數據庫中,泄露后可以別人可以直接登錄,在用 MD5 將密碼加密后即使泄露了也無法通過密文直接登錄。但是這里需要注意,目前網上有很多破解 MD5 密文的網站,這些網站說白了就是利用撞庫實現的,這些網站收集了常用的密碼組合方式,比如生日、連續相同的數字或密碼等,因此我們在驗證密碼強度時應當將常見的簡單密碼列,針對所有密碼最好將密碼中加入隨機的信息內容然后再進行 MD5 加密,這就是所謂的加鹽;
-
數字簽名
某人寫了一個重要文件,這個文件經過認證機構利用 MD5 生成摘要信息進行認證,如果以后這個人不承認這個文件是他寫的,只需認證機構再次對文件生成摘要信息和以前的照耀信息進行對比即可知道該文件是所寫的;
-
網盤秒傳
網盤記錄文件第一次上傳的 MD5 值,以后當有人上傳具有相同 MD5 值的文件時只需要將存在于網盤中的這個文件的鏈接發送出去即可。
MD5 的實現很簡單代碼如下:
public class MD5
{
/// <summary>
///
/// </summary>
/// <param name="source">待加密字串</param>
/// <param name="length">加密結果長度</param>
/// <returns>加密后的字串</returns>
public string Encrypt(string source, int length = 32)
{
if (string.IsOrEmpty(source))
{
return string.Empty;
}
HashAlgorithm provider = CryptoConfig.CreateFromName("MD5") as HashAlgorithm;
byte bytes = Encoding.UTF8.GetBytes(source);
byte hashValue = provider.ComputeHash(bytes);
StringBuilder sb = new StringBuilder;
switch (length)
{
case 16:
for (int i = 4; i < 12; i++)
{
sb.Append(hashValue[i].ToString("x2"));
}
break;
case 32:
for (int i = 0; i < 16; i++)
{
sb.Append(hashValue[i].ToString("x2"));
}
break;
default:
for (int i = 0; i < hashValue.Length; i++)
{
sb.Append(hashValue[i].ToString("x2"));
}
break;
}
return sb.ToString;
}
/// <summary>
/// 獲取文件的MD5
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string AbstractFile(string fileName)
{
FileStream file = new FileStream(fileName, FileMode.Open);
System.Security.Cryptography.MD5 md5 = new MD5CryptoServiceProvider;
byte retVal = md5.ComputeHash(file);
file.Close;
StringBuilder sb = new StringBuilder;
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString;
}
}
3.對稱可逆加密
對稱可逆加密就是用密鑰將需要加密的內容進行加密,然后將加密后的內容發送給接收方,接收方街道內容后利用相同的密鑰進行解密后就拿到了明文。對稱可逆加密方式有一個嚴重的問題就是要保證密鑰的安全,一旦密鑰泄密第三方就可以利用這個密鑰對解密收到的密文,甚至可以利用密鑰偽造信息發送給接收方,接收方也就無法分辨出到底是誰發送的密文。
最常用的對稱可逆加密算法是 DES ,下面我們通過代碼看一下 DES 的實現:
public class DES
{
/// <summary>
/// 密鑰
/// </summary>
private byte key = ASCIIEncoding.ASCII.GetBytes("123456");
/// <summary>
/// 偏移量
/// </summary>
private byte iv = ASCIIEncoding.ASCII.GetBytes("123456".Insert(0, "w").Substring(0, 8));
/// <summary>
/// 加密
/// </summary>
/// <param name="text">需要加密的值</param>
/// <returns>加密后的結果</returns>
public string Encrypt(string text)
{
DESCryptoServiceProvider dsp = new DESCryptoServiceProvider;
using (MemoryStream memStream = new MemoryStream)
{
CryptoStream crypStream = new CryptoStream(memStream, dsp.CreateEncryptor(key, iv), CryptoStreamMode.Write);
StreamWriter sWriter = new StreamWriter(crypStream);
sWriter.Write(text);
sWriter.Flush;
crypStream.FlushFinalBlock;
memStream.Flush;
return Convert.ToBase64String(memStream.GetBuffer, 0, (int)memStream.Length);
}
}
/// <summary>
/// 解密
/// </summary>
/// <param name="encryptText"></param>
/// <returns>解密后的結果</returns>
public string Decrypt(string encryptText)
{
DESCryptoServiceProvider dsp = new DESCryptoServiceProvider;
byte buffer = Convert.FromBase64String(encryptText);
using (MemoryStream memStream = new MemoryStream)
{
CryptoStream crypStream = new CryptoStream(memStream, dsp.CreateDecryptor(key, iv), CryptoStreamMode.Write);
crypStream.Write(buffer, 0, buffer.Length);
crypStream.FlushFinalBlock;
return ASCIIEncoding.UTF8.GetString(memStream.ToArray);
}
}
}
4.非對稱可逆加密
非對稱加密比較麻煩,發送方和接收方都保存有兩個密鑰,其中一個密鑰是公鑰,公鑰是對外公開的,任何人都可以拿到,另一個是私鑰,每個人的私鑰不一樣。規則是由A公鑰加密的信息只能用A的私鑰解密,由A的私鑰加密的消息只能由A的公鑰解密。
非對稱可逆加密的模式由兩種:
-
加密模式
使用接收方的公鑰加密,然后使用接收方的私鑰解密,這樣可以保證只有特定的接收方能收到信息,但是無法確認發送方是誰。
-
認證模式
使用發送方的私鑰加密,然后使用發送方的公鑰解密,這樣可以保證特定發送方發送消息,但是無法確定消息是發給了誰。
從上述兩種模式的描述中我們可以看到他們存在問題,因此就出現了數字簽名,在上述認證模式中加入了散列算法(例如MD5),對明文進行處理后再把信息進行加密后發送出去,接收方收到信息解密后比較信息的散列值和原始消息的散列值就可以確定信息是否被篡改。
常用的非對稱可逆加密算法常用的是RSA,代碼實現如下:
public class Rsa
{
/// <summary>
/// 獲取加密/解密對
/// </summary>
/// <returns>Encrypt Decrypt</returns>
public static KeyValuePair<string, string> GetKeyPair
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider;
string publicKey = RSA.ToXmlString(false);
string privateKey = RSA.ToXmlString(true);
return new KeyValuePair<string, string>(publicKey, privateKey);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="content"></param>
/// <param name="encryptKey">加密key</param>
/// <returns></returns>
public static string Encrypt(string content, string encryptKey)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider;
rsa.FromXmlString(encryptKey);
UnicodeEncoding ByteConverter = new UnicodeEncoding;
byte DataToEncrypt = ByteConverter.GetBytes(content);
byte resultBytes = rsa.Encrypt(DataToEncrypt, false);
return Convert.ToBase64String(resultBytes);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="content"></param>
/// <param name="decryptKey">解密key</param>
/// <returns></returns>
public static string Decrypt(string content, string decryptKey)
{
byte dataToDecrypt = Convert.FromBase64String(content);
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider;
RSA.FromXmlString(decryptKey);
byte resultBytes = RSA.Decrypt(dataToDecrypt, false);
UnicodeEncoding ByteConverter = new UnicodeEncoding;
return ByteConverter.GetString(resultBytes);
}
/// <summary>
/// 產生一組新的密鑰
/// </summary>
/// <param name="content"></param>
/// <param name="encryptKey">加密key</param>
/// <param name="decryptKey">解密key</param>
/// <returns>加密后結果</returns>
private static string Encrypt(string content, out string publicKey, out string privateKey)
{
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider;
publicKey = rsaProvider.ToXmlString(false);
privateKey = rsaProvider.ToXmlString(true);
UnicodeEncoding ByteConverter = new UnicodeEncoding;
byte DataToEncrypt = ByteConverter.GetBytes(content);
byte resultBytes = rsaProvider.Encrypt(DataToEncrypt, false);
return Convert.ToBase64String(resultBytes);
}
}
5.總結
上述三種加密方式在開發中會經常用到,根據我在開發中的經驗我建議使用非對稱加密,這樣更安全。
作者簡介:朱鋼,筆名喵叔,CSDN博客專家,.NET高級開發工程師,7年一線開發經驗,參與過電子政務系統和AI客服系統的開發,以及互聯網招聘網站的架構設計,目前就職于北京恒創融慧科技發展有限公司,從事企業級安全監控系統的開發。
聲明:本文系作者獨立觀點,不代表CSDN立場。
【END】