前段時間公司Android項目的網絡請求模塊進行了重構,從單純使用HttpClient切換到了使用Retrofit框架,在重構過程中重新梳理了一下數據加密解密的方式與過程,發現現在的加解密解決辦法簡單有效,在學習的過程中接觸了數據加密時需要用到的幾個類,算是我的知識盲區吧,現在拿出來和大家分享一下,順便記錄。
java為我們提供了完整的數據加解密,密鑰生成的類,我們只要確定我們的加密算法和需要加密的數據就可以調用方法進行加密,得到規范的加密后的數據,解密也同樣如此。
接下來蛋蛋介紹一下對稱加密和非對稱加密(記住,這和加密算法沒有關系),對稱加密是指加密和解密都使用同一個密鑰,比如說你的密鑰是1,我們用1進行加密,那么獲取我數據的人就要用1進行解密。加密算法是指我的數據和我的密鑰(1)進行了怎樣的操作,比如說我把我的數據拆成字節的形式,每個字節都加上1,那么解密的時候就要每個字節都減去1從而獲得正確的數據,這個方法就叫做加密算法,當然實際生產中加密算法復雜的多且多種多樣。非對稱加密是指加密的密鑰和解密的密鑰是不同的,分為公鑰和私鑰,私鑰只由一方保管,公鑰公布給需要與私鑰持有者進行數據交互的人,如果數據是由公鑰加密的那么必須要用私鑰進行解密,反之私鑰加密必須用公鑰解密。比較著名的非對稱加密算法是RSA,在實際生產中使用的也是這個加密算法。在項目中使用的是這兩種加密方式結合的方法,這點稍后介紹,我們先來看一下在java中怎樣通過調用系統的方法實現上述兩種加密方法。
首先是SecretKeySpec類,它負責根據一個字符數組構造一個密鑰,我們約定好的密鑰(也就是一個字符數組)不能直接作為加密Key來使用,必須要生成這樣一個對象。構造方法是SecretKeySpec(byte[] key, String algorithm),第一個參數是我的約定好的key,第二個參數是加密方法,這里我們使用DESede加密算法。
PRivate static final String Algorithm = "DESede"// 生成密鑰SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);// 加密Cipher c1 = Cipher.getInstance(Algorithm);c1.init(Cipher.ENCRYPT_MODE, deskey);從代碼我們可以看到,我們的加密類Cipher(之后會介紹到,這里只要知道我們使用它來加密數據即可)初始化需要SecertKeySpec的對象,那么SecertKeySpec的對象是什么呢?它是一種密鑰規范(底層可使用的密鑰材料),我們的密鑰材料(字符數組)不能直接使用,我們需要將它轉換為底層可使用的密鑰對象(材料),SecertKeySpec的對象對于Cipher來講就是透明的,可直接使用的。
接下來我們介紹一下Cipher類,這個類負責通過給定的密鑰和數據進行加解密從而得到我們需要的數據。我們先來關注一下Cipher的getInstance方法,getInstance方法傳入的是一個字符串,這個字符串是此類把怎樣把輸入的數據轉換為輸出數據的方法的名稱。說直白一點就是加密方法的名稱。init方法有兩個參數,第一個就是此對象加工數據的模式,第二個參數是我們剛剛生成的密鑰對象。介紹幾個MODE
public static final int <strong>DECRYPT_MODE   用于將 Cipher 初始化為解密模式的常量。</strong> | 
| 1 | public static final int <strong>WRAP_MODE      用于將 Cipher 初始化為密鑰包裝模式的常量。</strong> | 
| 1 | public static final int <strong>UNWRAP_MODE   用于將 Cipher 初始化為密鑰解包模式的常量。</strong> | 
| 1 | public static final int <strong>PUBLIC_KEY    用于表示要解包的密鑰為“公鑰”的常量。</strong> | 
| 1 | public static final int <strong>PRIVATE_KEY   用于表示要解包的密鑰為“私鑰”的常量。</strong> | 
| 1 | public static final int <strong>SECRET_KEY    用于表示要解包的密鑰為“秘密密鑰” | 
這樣我們加解密所需要的Cipher對象就初始化好了
return c1.doFinal(src);之后將我們的數據(src)傳入就可以等到我們需要的數據,無論是我們加密的數據還是我們解密的數據。這樣一個簡單的用來加密解密的Java類的調用就介紹完了。
使用非對稱加密方法加密數據時,我們還需使用X509EncodedKeySpec類,X509EncodedKeySpec類使用X.509標準作為密鑰規范管理的編碼格式。在使用公鑰時我們需要用編碼格式來表示公鑰。
// 實例化X509EncodedKeySpec對象X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);// 實例化KeyFactory對象,并指定DSA算法KeyFactory keyFactory = KeyFactory.getInstance("DSA");//或者"RSA"// 獲得PublicKey對象PublicKey publicKey = keyFactory.generatePublic(keySpec);
從代碼來看,我們的公鑰首先要轉換為X509格式,之后使用KeyFactory生成密鑰對象,這時我們可以指定使用的加密算法(和我們Cipher實例化時使用的加密算法保持一致)。這樣生成的密鑰對象就可以被Cipher使用了。
順便提一下,Cipher實例化出入的參數不僅僅是算法名稱還包括模式和填充。格式是“算法/模式/填充”(DES/OFB32/PKCS5Padding等)或單獨傳算法名稱
至此我們加密解密使用的Java類就介紹完了。
接下來說一下我在實際成產中用到的加密方式。在項目中與服務端進行數據交互時使用了對稱加密和非對稱加密結合的方式,首先在本地隨機生成一個24位的密鑰(字符數組)之后用此密鑰加密我要上傳的數據,然后用服務端提供的公鑰加密我的密鑰,之后將加密的數據和加密的密鑰都傳給服務端,服務端先使用私鑰解密得到我用來加密數據所使用的密鑰,再用這個密鑰解密數據,傳給我的數據也用這個密鑰進行加密。也就是說數據是使用對稱加密方法加密的,對稱加密的密鑰是使用非對稱加密的,這樣做的好處是讓數據更加安全,我每次用來加密數據的密鑰都是隨機稱成的,保證了每次密鑰都是不同的,這個密鑰具有時效性,被第三方獲破解后得到也不能使用。公鑰也可以隨時更換,當服務端發現私鑰已經不安全了,可以換一對key,將新的公鑰傳給我。
新聞熱點
疑難解答