概念git
加密領域主要有國際算法和國密算法兩種體系。國密算法是國家密碼局認定的國產密碼算法。國際算法是由美國安全局發佈的算法。因爲國密算法安全性高等一系列緣由。國內的銀行和支付機構都推薦使用國密算法。github
從上圖可知,對稱加密算法在算法體系裏佔了半壁江山。由於國際和國密算法的過程差別並不大。只是應用的數學公式和祕鑰位數不一樣。DES在裏面算是基礎,因此今天主要介紹一下DES的原理。算法
原理小程序
密碼安全
我們從加密的原理提及。舉個最簡單的加密:服務器
我有一段明文:520網絡
個人祕鑰是:221架構
個人加密算法是:加法socket
加密後的密文就是:741函數
若是這個密文被截獲了,接受者看到的信息是:741(氣死你),和原來明文520是徹底不一樣的,不能知道信息原有的意思。
從這個簡單的例子可知:加密是包含:明文、祕鑰、加密算法和密文四個要素的。加密算法可公開可不公開,常見的算法有:位移、循環位移、異或、置換、數學函數。
凱撒密碼
加密技術從古羅馬凱撒時候就在用:凱撒密碼
凱撒密碼是古羅馬時期凱撒大帝和他的將軍們通訊時使用的加密方式:
明文:由26個字母組成
祕鑰:1到25之間的任意數字
加密算法:循環位移
密文:舉例明文爲eat 祕鑰爲2,對照上面圖片的凱撒密碼盤能夠獲得密文是gcv。
我們來動手寫個凱撒密碼(代碼已經上傳github:
(https://github.com/xiexiaojing/yuna):
@Test
public void caesarCipher() {
String text = "love was growing in eyes"; //明文
int key = 3; //祕鑰
String cipher = encryptCaesarCipher(text, key); //密文
System.out.println(cipher);
}
//凱撒密碼加密算法
private String encryptCaesarCipher(String text, int key) {
char[] chars = text.toCharArray();
for(int i=0; i<chars.length; i++) {
if(chars[i] != ' ') {
chars[i] = (char)(chars[i]+key);
}
//若是超過了26個字母,則減去26
if(chars[i]>122) {
chars[i] = (char)(chars[i]-26);
}
}
return new String(chars);
}
運行獲得密文:oryh zdv jurzlqj lq hbhv
凱撒密碼連小朋友都能破解。一旦被人知道用的凱撒密碼,算法是已知的。要破解祕鑰拿個明文和密文試試就知道了。就是平時說的暴力破解法能夠很容易破解。對於這種全是英文字符的也可使用頻率分析法。頻率分析法能夠理解爲基於大數據的方法,由於26個字母中,e的使用頻率高。若是好比一篇文章,單詞足夠多的話,出現頻率最高的字母xxx就是e。xxx的char值e的char值就是祕鑰了。
DES
概述
DES全稱爲Data Encryption Standard,即數據加密標準,是一種分組加密算法。其分組長度爲64bit,密鑰長度爲64bit,其中8bit爲校驗位,因此實際長度爲56bit。
先介紹一下校驗位。舉個例子,我們的身份證號碼都是18位。這18位包含:
其中最後一位就是校驗位,原理是利用將前面部分利用某種算法計算獲得一個數。若是校驗位與算法獲得的不一致,則數據是有問題的。因此身份證自己是有不經過查庫就能夠簡單驗證有效性功能的。
回到DES算法。DES算法的祕鑰必須是64位,參與加密計算的是56位。這是原始祕鑰。這個原始祕鑰會用一個函數轉換成16個64位祕鑰。
加密過程
DES的加密過程:
明文64位->初始IP置換->16輪加密變換->逆初始IP置換->密文
DES算法的這個過程又被稱爲Feistel網絡。
簡單解釋下:
明文咱們本身想寫多長寫多長。可是加
密的時候每次以64bit做爲一個分組。最後將密文拼接起來。
而後執行一個IP置換(初始置換)操做。IP置換就是按位置換。舉例來講64bit就是64個0和1。把第40個位置上的數換成第50個位置上的數就是置換了。
置換好的64個bit會分紅兩個32bit。而後用相同的加密算法每次傳不一樣的轉換後祕鑰作16輪。
而後將兩組32bit拼接起來再進行一次IP置換(終結置換)變成密文
分組組合
剛纔介紹的加密過程是把明文的一塊怎麼加密成密文。DES密碼塊與密碼塊鏈接方式遵循對稱加密的方式。
對稱加密有兩種方式,一種是分組加密,一種是序列加密。
分組加密,也叫塊加密(block cyphers),一次加密明文中的一個塊。是將明文按必定的位長分組,明文組通過加密運算獲得密文組,密文組通過解密運算(加密運算的逆運算),還原成明文組。
序列加密,也叫流加密(stream cyphers),一次加密明文中的一個位。是指利用少許的密鑰經過某種複雜的運算(密碼算法)產生大量的僞隨機位流,用於對明文位流的加密。
分組加密算法中,分組密碼的設計基本遵循混淆原則和擴散原則。有ECB,CBC,CFB,OFB這4種算法模式。DES有ECB和CBC兩種實現。
ECB模式
ECB模式就是每組明文分別加密後拼接起來。
CBC模式
CBC即密碼分組連接(Cipher-block chaining)的簡稱。在CBC模式中,每一個明文塊先與前一個密文塊進行異或後,再進行加密。在這種方法中,每一個密文塊都依賴於它前面的全部明文塊。同時,爲了保證每條消息的惟一性,在第一個塊中須要使用初始化向量。在DES中,初始化向量就是祕鑰。
程序實現
咱們用程序來實現一下DES加密算法
@Test
public void desCiper() throws Exception{
String key = "12345678";
String text = "我知道我是任性很任性,傷透了你的心"; //明文
String cipher = encryptDesCipher(text, key); //密文
System.out.println(cipher);
text = decryptDesCipher(cipher, key); //明文
System.out.println(text);
}
//DES加密算法
private String encryptDesCipher(String text, String origKey) throws Exception{
Key key = new SecretKeySpec(origKey.getBytes(), "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
return Base64.encode(cipher.doFinal(text.getBytes()));
}
//DES加密算法
private String decryptDesCipher(String text, String origKey) throws Exception{
Key key = new SecretKeySpec(origKey.getBytes(), "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(Base64.decode(text)));
}
運行結果:
xo6mmVe8j1/d60cAAiFz1HAXxihi2FH5d0zMWILvEYISWR52lguy2TbMZQ4vuulCdO8WvxMRuXE=
我知道我是任性很任性,傷透了你的心
3DES
3DES即3重加密算法,是對每一個數據塊應用三次DES算法。這是爲了應對計算機計算能力加強,DES變的容易破解而產生的。
主要方法就是DES祕鑰64位,3DES祕鑰64*3=192位,分紅個三個祕鑰,進行2輪DES加密,1輪DES解密。最終獲得結果。
AES
AES全稱是高級加密標準(Advanced Encryption Standard)。是用來替代DES/3DES的。主要過程以下,這裏不過多介紹。
應用
咱們來回顧下https的SSL握手過程:
SSL握手的最後,雙方會用非對稱祕鑰協商出一個對稱祕鑰。用對稱祕鑰來加密傳輸的數據。之因此這樣作是由於非對稱加密安全性高可是效率低,對稱祕鑰正好相反。對稱祕鑰能夠被暴力破解,破解須要時間。若是破解出來時就過時了,再通訊就用另外的祕鑰就能保證信息安全。
咱們來模擬一下已經協商好的祕鑰以後http客戶端與服務器端的通訊。(代碼已經上傳github:(https://github.com/xiexiaojing/yuna):
@Test
public void client() throws Exception {
int i = 1;
while (i <= 2) {
Socket socket = new Socket("127.0.0.1", 520);
//向服務器端第一次發送字符串
OutputStream netOut = socket.getOutputStream();
InputStream io = socket.getInputStream();
String msg = i == 1 ? "客戶端:我知道我是任性太任性,傷透了你的心。我是追夢的人,追一輩子的緣分。":
"客戶端:我願意嫁給你,你卻不能答應我。";
System.out.println(msg);
netOut.write(encryptDesCipher(msg.getBytes(), "12345678"));
netOut.flush();
byte[] bytes = new byte[i==1?104:64];
io.read(bytes);
String response = new String(decryptDesCipher(bytes,"12345678"));
System.out.println(response);
netOut.close();
io.close();
socket.close();
i++;
}
}
@Test
public void server() throws Exception {
ServerSocket serverSocket = new ServerSocket(520);
int i = 1;
while (i <= 2) {
String msg = i == 1 ? "服務端:我知道你是任性太任性,傷透了個人心。同是追夢的人,難捨難分。" :
"服務端:你願意嫁給我,我卻不能向你承諾。";
Socket socket = serverSocket.accept();
InputStream io = socket.getInputStream();
byte[] bytes = new byte[i==1?112:64];
io.read(bytes);
System.out.println(new String(decryptDesCipher(bytes,"12345678")));
OutputStream os = socket.getOutputStream();
System.out.println(msg);
byte[] outBytes = encryptDesCipher(msg.getBytes(), "12345678");
os.write(outBytes);
os.flush();
os.close();
io.close();
i++;
}
}
//DES加密算法
private byte[] encryptDesCipher(byte[] text, String origKey) throws Exception {
Key key = new SecretKeySpec(origKey.getBytes(), "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(text);
}
//DES加密算法
private byte[] decryptDesCipher(byte[] text, String origKey) throws Exception {
Key key = new SecretKeySpec(origKey.getBytes(), "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(text);
}
運行結果
客戶端:我知道我是任性太任性,傷透了你的心。我是追夢的人,追一輩子的緣分。
服務端:我知道你是任性太任性,傷透了個人心。同是追夢的人,難捨難分。
客戶端:我願意嫁給你,你卻不能答應我。
服務端:你願意嫁給我,我卻不能向你承諾。
這個程序實現了簡單的客戶端和服務器端的DES加密方式通訊。稍加改造能夠實現一個信息加密的聊天小程序。
總結
本文使用概念、原理、應用的傳統型邏輯架構來對DES作系統梳理。裏面涉及到的一些基本知識限於篇幅省略了一些。
好比Base64編碼。它是加密時經常使用的編碼方式,咱們平時所看到的密鑰都是base64後的結果。能夠簡單理解爲對2的6次方進行64進制運算,可防止亂碼丟失字節。
再好比填充字節這部分也沒有介紹,有興趣能夠本身查閱下。
加解密不少人工做中或多或少都有涉及。我我的認爲只要涉及的地方至少要了解到原理和架構層面,才能避免遇到問題時【拿着錘子找釘子】找不到真正問題的窘境。而只有動手實踐才能避免當時瞭解了,事後又忘了須要再看一遍而產生重複工做的問題。