行動裝置上的資料安全性是極為重要的。行動裝置一旦丟失或被盜,而裝置上的資料沒有進行某種加密,將帶來不可估量的損失。對於企業級應用,會使加密變得更複雜,比如由於工作模式的安排或分配任務,使得一個裝置可能有多個使用者使用。
有幾種方法試圖解決這個問題,其中之一是允許授權使用者訪問同一裝置上安全儲存的資料,而不需要儲存多份拷貝,這就是雙層加密方法。
Android實現了Java Cryptographic Extensions (JCE) ,並提供多種加密方法。加密可以在任何位元組陣列上進行,所以能實現雙層加密系統,其中密鑰用來加密敏感性資料後,用使用者的密碼再次加密,每個使用者都儲存密鑰的加密拷貝。當使用者希望訪問資料時,他們輸入自己的密碼,於是可以解密資料。
這種方法的好處是你只需要儲存主要資料的一份拷貝,這可以節省空間的。要訪問資料你需要使用裝置上沒有儲存的東西(使用者密碼)
Android使用下面的JCE方法產生256位元的AES key:
KeyGenerator kg = KeyGenerator.getInstance("AES");kg.init(256);SecretKey key = kg.generateKey();
有了key之後,可以使用JCE來加密任何位元組:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");cipher.init(Cipher.ENCRYPT_MODE, key);byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();byte[] encryptedData = cipher.doFinal(originalByteArray);
它使用了Android 加密實現方法的另兩個部分:
- CBC; 這是密文段連結方法,允許密碼編譯演算法能工作在特定大小的資料區段(如AES),來加密比演算法長的資料,它會把數據分成多個段,依次加密,然後使用某個段的加密結果去加密下一個段。
- PKCS7Padding; 前面提到過,AES只能工作在一定大小的資料區段,而CBC只能工作在段大小倍數的資料上。PKCS7Padding通過添加填充位元組來保證資料有合適的大小。
你需要儲存iv和encryptedData 來加密資料(如果你不知道iv包括什麼,請查詢初始化向量及在CBC中 如何使用它們)
要解密資料,你要使用同樣的代碼,並用Cipher.ENCRYPT_MODE替代 Cipher.DECRYPT_MODE,並提供在加密階段獲得的iv。
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));byte[] originalByteArray = cipher.doFinal(encryptedData);
現在已經實現第一級加密,接下來繼續第二級加密,這可以允許多個使用者訪問同一被AES 祕密金鑰加密的資料。
SecretKey JCE類包括一個獲得密鑰的位元組陣列的函數。位元組陣列可以使用下面的Password Based Encryption (PBE) 進行加密。
byte[] keyBytes = key.getEncoded();PBEKeySpec passwordKeySpec = new PBEKeySpec(password.toCharArray(), salt, 100, 256);SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithMD5AndDES");SecretKey passwordKey = kf.generateSecret(passwordKeySpec);Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");cipher.init(Cipher.ENCRYPT_MODE, passwordKey);byte[] encryptedKey = cipher.doFinal(keyBytes);
salt 是用密碼來建立的加密金鑰的位元組陣列。salt 值對每個使用者都是唯一地,你應當為每個使用者儲存其salt 值,因為你需要它來解密密鑰。另外兩個數(100和256)用來構建PBEKeySpec,前一個數是密碼編譯演算法迭代次數,後一個數是密碼產生的密鑰的位元長度。這裡密碼編譯演算法要用256位元的祕密金鑰加密100次。
再次使用同樣代碼,替換DECRYPT_MODE 來解密資料(這裡是AES 密鑰),並從解密資料中重建 SecretKey 對象。
PBEKeySpec passwordKeySpec = new PBEKeySpec(PASSWORD.toCharArray(), salt, 100, 256);SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithMD5AndDES");SecretKey passwordKey = kf.generateSecret(passwordKeySpec);Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");cipher.init(Cipher.DECRYPT_MODE, passwordKey);byte[] keyBytes = cipher.doFinal(encryptedKey);SecretKey key = new SecretKeySpec(keyBytes,"AES");
這就實現了第二級加密,這樣每個使用者都可以訪問共用的加密金鑰。
有了雙層加密系統,如果一個新使用者要使用這個裝置,或一個老使用者不能再使用這個裝置,只需要增加或刪除用他們密碼加密的共用密鑰版本即可。如果住資料集需要更新,只需要用共用祕密金鑰加密一次即可。
這樣可以減少資料存放區和複製,同時保證資料安全。