1. DES算法簡介
1.1.1 DES加密的算法
首先要生成一套加密密鑰,從用戶處取得一個64位(bit)長的密碼口令,然后通過等分、移位、選取和迭代形成一套16個加密密鑰,分別供每一輪運算中使用。
DES對64位(bit)的明文分組M進行操作,M經過一個初始置換IP,置換成m0。將m0明文分成左半部分和右半部分m0 = (L0,R0),各32位長。然后進行16輪完全相同的運算(迭代),這些運算被稱為函數f,在每一輪運算過程中數據與相應的密鑰結合。
在每一輪中,密鑰位移位,然后再從密鑰的56位中選出48位。通過一個擴展置換將數據的右半部分擴展成48位,并通過一個異或操作替代成新的48位數據,再將其壓縮置換成32位。這四步運算構成了函數f。然后,通過另一個異或運算,函數f的輸出與左半部分結合,其結果成為新的右半部分,原來的右半部分成為新的左半部分。將該操作重復16次。
經過16輪迭代后,左,右半部分合在一起經過一個末置換(數據整理),這樣就完成了加密過程。
參考播客:http://blog.chinaunix.net/uid-29106641-id-4032988.html

1.1.2 DES算法的安全性和發展
DES的安全性首先取決于密鑰的長度。密鑰越長,破譯者利用窮舉法搜索密鑰的難度就越大。目前,根據當今計算機的處理速度和能力,56位長度的密鑰已經能夠被破解,而128位的密鑰則被認為是安全的,但隨著時間的推移,這個數字也遲早會被突破。
另外,對DES算法進行某種變型和改進也是提高DES算法安全性的途徑。
例如后來演變出的3-DES算法使用了3個獨立密鑰進行三重DES加密,這就比DES大大提高了安全性。如果56位DES用窮舉搜索來破譯需要2∧56次運算,而3-DES 則需要2∧112次。
DES還有DESX、CRYPT、GDES、RDES等變型。這些變型和改進的目的都是為了加大破譯難度以及提高密碼運算的效率。
2. DES算法使用
~~~
31. package com;
32. public class DESTest {
33. public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException,
34. NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException,
35. UnsupportedEncodingException {
36.
37. String str = "這是原文";
38. String psw = "12345678";
39. String encrypte = encrypte(str, psw);
40. System.out.println("加密后:"+encrypte);
41. String decrypte = decrypte(encrypte, psw);
42. System.out.println("解密后:"+decrypte);
43.
44. }
45.
46. public static String encrypte(String original,String psw) throws NoSuchAlgorithmException,
47. NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
48. /**
49. * 創建加密對象,參數為加密算法
50. */
51. Cipher cipher = Cipher.getInstance("DES");
52. /**
* 調用自己的方法生成密鑰
54. */
55. Key key = getKey(psw);
56. /**
57. * 初始化加密器
58. * 參數1:加密模式
59. * 參數2:密鑰
60. */
61. cipher.init(Cipher.ENCRYPT_MODE, key);
62. /**
63. * 執行加密,解密后得到的字節數組
64. */
65. byte[] doFinal = cipher.doFinal(original.getBytes());
66. /**
67. * 將自己數組用Base64編碼,轉換為字符串
68. */
69. String encode = Base64.encode(doFinal);
70.
71. return encode;
72. }
73. /**
74. * 從指定字符串生成密鑰,密鑰所需的字節數組長度為8位
75. * 不足8位時后面補0,超出8位只取前8位
76. * @param psw
77. * @return
78. */
79. private static SecretKeySpec getKey(String psw) {
80. byte[] buffer = new byte[8];
81. byte[] bytes = psw.getBytes();
82. for(int i=0;i<buffer.length&&i<bytes.length;i++){
83. buffer[i]=bytes[i];
84. }
85.
86. return new SecretKeySpec(buffer, "DES");
87. }
88.
89. public static String decrypte(String original,String psw) throws NoSuchAlgorithmException,
90. NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
91. BadPaddingException,
92. UnsupportedEncodingException{
93. /**
94. * 獲取加密器(同時也是解密器)
95. */
96. Cipher cipher = Cipher.getInstance("DES");
/**
98. * 獲取密鑰
99. */
100. Key key = getKey(psw);
101. /**
102. * 初始化密碼器,設置為解密模式
103. */
104. cipher.init(Cipher.DECRYPT_MODE, key);
105. /**
106. * 解密。注意,這里需要將傳入的原文使用Base64編碼轉換為byte,因為加密后的密文是用Base64編碼的
107. */
108. byte[] doFinal = cipher.doFinal(Base64.decode(original));
109. /**
110. * 將解密后的字節數組轉換為字符串
111. */
112. return new String(doFinal);
113. }
114.
115. }
116.
~~~
3. Base64原理
加密后的結果是字節數組,這些被加密后的字節在碼表(例如 UTF-8 碼表)上找不到對應字符,會出現
亂碼,當亂碼字符串再次轉換為字節數組時,長度會變化,導致解密失敗,所以轉換后的數據是不安全的。
使用 Base64 對字節數組進行編碼,任何字節都能映射成對應的 Base64 字符,之后能恢復到字節數組,
利于加密后數據的保存于傳輸,所以轉換是安全的。同樣,字節數組轉換成 16 進制字符串也是安全的。

1、當字符串字符個數為3的倍數時;比如字符串“ABC”,其在計算機內存中的
十六進制表示為$41、$42、$43,十進制表示為“65”“66”“67”;二進制表示
為01000001 01000010 01000011 將這三個二進制數依次取6bit
,010000/01 0100/0010 01/000011 就轉換成了: 010000
010100 001001 000011, 將這四個二進制數轉換成十六制數為:
$10,$14,$9,$3,十進制數位為16,20,9,3。對照上面的碼表,分別查
找出對應的字符為Q,U,J,D。也是就說字符串“ABC”經過BASE64編碼后得
出“QUJD”。這是最簡單的情況,即ASCII碼字符數剛好可以被3整除。接
著繼續討論余數為2、為1的情況。
2、當余數為2時,比如字符串“ce”,其在內存中十六進制表示為$63,$65;十
進制表示表示99,101;二進制表示為 01100011 01100101 依次取6bit
011000/11 0110/0101 這時,第3個字符不足6位,在后面補零,也就
是0101變成010100。轉換結果為 011000 110110 010100 這3個二進
制數轉換成十六制數為$18,$36,$14;十進制數位為24,54,20。對照碼表
得出結果“Y2U”。編碼后的字符個數不足4位,用“=”填充,最后編碼得出“Y2U=”。
3、當余數為1時,比如字符串“{”,其在內存中的十六進制表示為$7B,十進制為
123,二進制位表示為 01111011 依次取6bit 011110/11 補0后為
011110/110000 轉換結果為011110和110000 這兩個二進制數轉換成
十六進制數為$1E,$30,十進制數為30,48。對照碼表得出結果為“ew”,補上
“=”,最后編碼得出“ew= =”。解碼也很簡單,是編碼的逆過程,即將每
個字符對照碼表換算成6bit的二進制數,然后重組起來,按8位進行截取,得出原碼。