關於加密,此處沒有更加通俗易懂的解釋。與同是對於字節類型數據處理的編碼和摘要對比:git
加密是可逆的,但只知道加密算法並不能解密,還須要知道加密密鑰。github
接下來,將針對幾個常見的加密算法:DES
、3DES
、AES
、RSA
的 Java 實現及其相關進行介紹,因爲以前實現過 DES
和 AES
算法,所以具體算法說明,後續有空會寫到。算法
在代碼實現的過程當中,密鑰便是 key 。使用對稱加密算法時,加密和解密是同一個密鑰。使用非對稱加密算法時,加密和解密密鑰不相同,區分爲公鑰(public key)和私鑰(private key)。編碼
見過把 base64
當作對稱加密, md5
當作非對稱加密,所以下面劃重點:加密
加密模式主要體如今對稱加密算法中。以前提到過,對稱加密算法效率優,適合加密長數據。實際加密過程當中,是將長數據劃分紅固定長度的若干塊短數據進行加密操做。爲防止暴力破解得出明文,所以衍生了四種加密模式。spa
英譯 Electronic Code Book ,簡稱 ECB
模式,最簡單的加密模式。code
上述步驟存在一個嚴重的問題,若是有重複的明文塊,那麼加密出來的密文也重複。對象
英譯 Cipher Block Chaining ,簡稱 CBC
,基於 ECB
模式的改進版。 此處引入一個概念:初始化向量 Initialization Vector 簡稱 IV
。ip
英譯 Cipher Feedback Mode ,簡稱 CFB
。md5
英譯 Output Feedback Mode , 簡稱 OFB
,與 CFB
模式有些細小的區別。
CFB
與 OFB
的區別在於中間密文和密文塊的用法 。
CFB
使用前一塊的密文進行加密。OFB
使用前一塊的中間密文進行加密。分塊加密的過程當中,遇到不夠整分的塊。如,將 16 字節做爲一個明文塊。當加密 17 字節時,不夠分紅兩塊。此時須要對第二塊明文進行填充。填充後的兩個明文塊各 16 字節共 32 字節後再進行加密操做。
後 15 字節的填充內容,須要取決於具體的填充模式。見後續 Java 代碼實現中介紹。
Java 對加密部分作了比較完整的封裝—— Cipher
類。
如下列舉幾個主要方法:
getInstance
獲取 Cipher
對象,主要接收轉換類型參數對象。轉換類型參數分爲 算法 和 算法/模式/填充 。init
初始化加密參數。包括指定加解密模式、密鑰和初始化向量-IV
。doFinal
結束加密和解密操做,有多個重載方法,主要接收須要加密或解密的數據。關於填充,以前簡要介紹過。在 Java 代碼中常見的填充模式是 PKCS5Padding
。還有一種模式 NoPadding
因爲對明文長度有要求,不建議使用。其餘填充模式未深刻了解,暫不誤導。
PKCS5Padding
指,須要填充多少字節,就填充多少個字節的數字。如 DES
算法要求每一個明文塊 8 字節,那麼,加密 1 字節數據,須要填充 7 個字節,此時填充 7 個 7 。加密 7 字節數據,須要填充 1 個 1 。加密 8 字節數據時,爲方便校驗解密後的明文正確性,須要擴展成 16 字節數據,此時第二個明文塊填充 8 個 8 。
DES 全稱 Data Encryption Standard ,數據加密標準算法。固定密鑰 8 字節,64 位。每一個明文塊長度 8 字節。
getInstance
接收參數:DES/ECB/PKCS5Padding ,其中 ECB
表示加密模式,能夠用上述的其餘三個模式替換以及更多 JDK 支持的模式。PKCS5Padding
表示一種填充模式。
在使用 CBC
、 CFB
、 OFB
時,須要在 init
方法中指定 IV 。
private static final String KEY_ALGORITHM = "DES";
private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
public static final byte[] encrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
// 加密模式
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, KEY_ALGORITHM));
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static final byte[] decrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
// 解密模式
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, KEY_ALGORITHM));
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
複製代碼
3DES
即便用 3 次 DES
算法。因爲每一個 DES
算法處理須要 8 字節密鑰,所以 3DES
算法須要 24 字節密鑰。
須要注意,3DES
算法名稱使用 DESede
或 TripleDES
。e 表示作 DES
加密操做,d 表示作 DES
解密操做。前者表示用 DES 連續作加密 、解密、加密操做,後者表示連續作三次加密操做。每次使用的密鑰,分別是 24 字節密鑰中不一樣的三段(前、中、後各8字節)。
若使用
DESede
算法時 24 字節密鑰中的前兩段同樣,該算法等同於DES
算法使用第三段的 8 字節密鑰。
填充相關同 DES
算法同樣。
private static final String KEY_ALGORITHM = "DESede";
private static final String DEFAULT_CIPHER_ALGORITHM = "DESede/CBC/PKCS5Padding";
// 初始化向量
private static final String IV = "12345678";
public static final byte[] encrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, KEY_ALGORITHM),new IvParameterSpec(IV.getBytes()));
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static final byte[] decrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, KEY_ALGORITHM));
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
複製代碼
AES 全稱 Advanced Encryption Standard ,高級加密標準算法,用於替代 DES
。
DES
只支持 8 字節密鑰,AES
能夠支持 16 字節、24 字節和 32 字節密鑰。明文塊長度也能夠劃分紅 16 字節 、24 字節和 32 字節進行填充。
private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
public static final byte[] encrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, KEY_ALGORITHM));
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static final byte[] decrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, KEY_ALGORITHM));
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
複製代碼
以上三種對稱加密算法的 Java 代碼實現基本一致。
RSA是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一塊兒提出的非對稱加密算法,所以使用他們 3 人姓氏首字母命名。
示例代碼中的公鑰和私鑰是隨機生成的密鑰對,密鑰對模長建議是 1024 或 2048,對應密文長度是 128 字節和 256 字節。模長能夠大於 2048 , 越長越難破解,可是效率越低。 實際應用中,建議將密鑰對模長設置爲 2048 並以文件的形式存儲在終端。
private static PrivateKey privateKey;
private static PublicKey publicKey;
private static final String DEFAULT_CIPHER_ALGORITHM = "RSA";
static {
KeyPairGenerator keyGener = null;
try {
keyGener = KeyPairGenerator.getInstance(DEFAULT_CIPHER_ALGORITHM);
keyGener.initialize(1024);
KeyPair keyPair = keyGener.generateKeyPair();
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
public static final byte[] encrypt(byte[] data) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
public static final byte[] decrypt(byte[] data) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return null;
}
複製代碼
以爲有用?那打賞一個唄。我要打賞
此處是廣告:Flueky的技術小站