2017-04-16 49 views
0

在我的Android應用程序中,我想加密一行文本並解密它。密碼「PBEWithMD5AndDES」「穩定」?

我沒有javax.crypto的經驗,但我找到了這個答案Encrypt Password in Configuration Files?並實現了類似的東西。

代碼:

public String encrypt(String property) throws GeneralSecurityException, UnsupportedEncodingException { 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); 
    SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); 
    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); 
    pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, ITERATIONS)); 
    return Base64.encodeToString(pbeCipher.doFinal(property.getBytes("UTF-8")), Base64.DEFAULT); 
} 

public String decrypt(String property) throws GeneralSecurityException, IOException { 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); 
    SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD)); 
    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); 
    pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, ITERATIONS)); 
    return new String(pbeCipher.doFinal(Base64.decode(property, Base64.DEFAULT)), "UTF-8"); 
} 

我測試了它,它工作正常。但有一件事困擾我,這些方法可能會拋出GeneralSecurityException,UnsupportedEncodingExceptionIOException

問:可以在那裏當文字被成功加密但經過某些情況下(新的Android版本,或用新的VM類似的東西)decrypt方法將拋出GeneralSecurityExceptionIOException和應用程序將無法解密的情況下,文本?

+0

當然,一些/你的Android廠商可能會在未來的某個時候卸下PBEWithMD5AndDES。可以考慮使用DES,現在不應該使用MD5。不幸的是,這個答案並不是真正的答案,因爲我不認爲Google要求每個供應商保留PBEWithMD5AndDES。 –

+0

任何人都可以肯定某些供應商將來會做什麼? –

+0

@ArtjomB。 aha,我明白了,據我所知,使用Cipher並不「安全」,因爲每種算法都可以在將來被刪除? –

回答

2

至於例外:這些不應該突然投入正確的輸入。 NoSuchAlgorithmException - 當算法不再受支持時,應拋出GeneralSecurityException的子類。

任何API - 或在這種情況下,加密服務 - 可以撤回。但這適用於任何功能,所以在這種情況下,您的解決方案空間將是空的。在這種情況下,至少該算法是明確的,所以你可以隨時從開源或類似的東西重新導入代碼。當然,這樣一箇舊的算法可能會被撤銷,只是因爲它不應該被使用了,但是一般來說Java和Android都是爲了向後兼容而不是去掉棄用的函數。


是,該算法是穩定但我猜你需要從字穩定刪除「B」有一個更好的瞭解。

DES不再用於任何安全敏感材料。只有3鍵DES EDE 可以使用仍然可以提供接近安全的任何東西。

在PBE算法中使用的PBKDF1也是如此。

您需要在GCM模式下使用另一種密碼,例如PBKDF2等更現代的密碼哈希,或者更好的方式,如Argon2。

您的SALT常數 - 我認爲它是一個來自全大寫字母名稱的常數 - 應該在飛行中生成。使用恆定的鹽會破壞目的。


但基本上你需要在利用它之前瞭解一些密碼學。 Othwerwise你需要諮詢某人,因爲複製/粘貼安全不存在。

+0

明白了。我之前沒有使用密碼術,但想要添加一些基本的加密功能來過濾大多數可以從應用程序中提取SharedPreferences的「黑客」,但無法加密比Base64更難的東西。 –

+0

好吧,DES稍微好一點,然後只有64(根本沒有密鑰),但請嘗試閱讀PKCS#5,然後找到實現PBKDF2和AES的方法。 Base64是*編碼方案*不是加密方案。 –

0

它可以很容易解密,因爲它會使用DES(CBC)操作模式。 DES只有一個有效的密鑰大小爲56位。因此,無論(PBKDF1)密鑰派生如何,密鑰和強制都可能被強制。

MD5雖然被認爲是自行破解,但在PBKDF1中使用時不會出現問題 - 只要密碼中包含足夠的熵。

如果可能,您應該使用PBKDF2和AES升級到基於密碼的加密(PBE)。請注意,PBE通常使用CBC模式加密,因此它不適用於傳輸協議。

它是一個完整的任務,你只需要導入並使用它......

package com.example.siman.friend_pro; 

import java.io.IOException; 
import java.io.UnsupportedEncodingException; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import java.security.spec.AlgorithmParameterSpec; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.KeySpec; 

import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.PBEParameterSpec; 

import static javax.crypto.Cipher.DECRYPT_MODE; 
import static javax.crypto.Cipher.ENCRYPT_MODE; 
import static javax.crypto.Cipher.getInstance; 

public class Encryptor4j 
{ 
    private static byte[] salt = { 
      (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, 
      (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 
    }; 
    private static Cipher ecipher; 
    private static Cipher dcipher; 
    private static String Property = "youkey"; 
    private static int iterationCount = 19; 

    public static String encrypt(String Text) 
    { 
     String returnvalue=null; 
     try { 
      returnvalue = Encryptor4j.form1(Text); 
     } 
     catch (NoSuchAlgorithmException | InvalidKeySpecException | 
       NoSuchPaddingException | InvalidKeyException | 
       InvalidAlgorithmParameterException | IllegalBlockSizeException | 
       BadPaddingException | IOException e) { 
      e.printStackTrace(); 
     } 
     return returnvalue; 
    } 
    public static String decrypt(String Text) 
    { 
     String returnvalue=null; 
     try { 
      returnvalue = Encryptor4j.form2(Text); 
     } 
     catch (NoSuchAlgorithmException | InvalidKeySpecException | 
       NoSuchPaddingException | InvalidKeyException | 
       InvalidAlgorithmParameterException | IllegalBlockSizeException | 
       BadPaddingException | IOException e) { 
      e.printStackTrace(); 
     } 
     return returnvalue; 
    } 


    private static String form1(String Text) 
      throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException 
    { 
     //Key generation for enc and desc 
     KeySpec keySpec = new PBEKeySpec(Property.toCharArray(), salt, iterationCount); 
     SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec); 
     // Prepare the parameter to the ciphers 
     AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount); 

     //Enc process 
     ecipher = getInstance(key.getAlgorithm()); 
     ecipher.init(ENCRYPT_MODE, key, paramSpec); 
     String charSet = "UTF-8"; 
     byte[] in = Text.getBytes(charSet); 
     byte[] out = ecipher.doFinal(in); 
     String encStr = new String(android.util.Base64.encode(out,0)); 
     //String encStr = new String(Base64.getEncoder().encode(out)); 
     return encStr; 
    } 

    private static String form2(String Text) 
      throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, IOException 
    { 
     //Key generation for enc and desc 
     KeySpec keySpec = new PBEKeySpec(Property.toCharArray(), salt, iterationCount); 
     SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec); 
     // Prepare the parameter to the ciphers 
     AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount); 
     //Decryption process; same key will be used for decr 
     dcipher = getInstance(key.getAlgorithm()); 
     dcipher.init(DECRYPT_MODE, key, paramSpec); 
     //byte[] enc = Base64.getDecoder().decode(encryptedText); 
     byte[] enc = android.util.Base64.decode(Text.getBytes(),0); 
     byte[] utf8 = dcipher.doFinal(enc); 
     String charSet = "UTF-8"; 
     String plainStr = new String(utf8, charSet); 
     return plainStr; 
    } 
}