2014-04-04 56 views
0
static void encrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { 
    // Here you read the cleartext. 
    FileInputStream fis = new FileInputStream("data/cleartext"); 
    // This stream write the encrypted text. This stream will be wrapped by another stream. 
    FileOutputStream fos = new FileOutputStream("data/encrypted"); 

    // Length is 16 byte 
    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES"); 
    // Create cipher 
    Cipher cipher = Cipher.getInstance("AES"); 
    cipher.init(Cipher.ENCRYPT_MODE, sks); 
    // Wrap the output stream 
    CipherOutputStream cos = new CipherOutputStream(fos, cipher); 
    // Write bytes 
    int b; 
    byte[] d = new byte[8]; 
    while((b = fis.read(d)) != -1) { 
     cos.write(d, 0, b); 
    } 
    // Flush and close streams. 
    cos.flush(); 
    cos.close(); 
    fis.close(); 
} 

static void decrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { 
    FileInputStream fis = new FileInputStream("data/encrypted"); 

    FileOutputStream fos = new FileOutputStream("data/decrypted"); 
    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES"); 
    Cipher cipher = Cipher.getInstance("AES"); 
    cipher.init(Cipher.DECRYPT_MODE, sks); 
    CipherInputStream cis = new CipherInputStream(fis, cipher); 
    int b; 
    byte[] d = new byte[8]; 
    while((b = cis.read(d)) != -1) { 
     fos.write(d, 0, b); 
    } 
    fos.flush(); 
    fos.close(); 
    cis.close(); 
} 

我使用這些功能的加密/解密文件,但在某些設備上,我得到不正確的數據。加密/解密文件和不正確的數據

例如,我的正確的數據是:

一個

解密後:

一個

൰Ẓ㫩

൰Ẓ㫩

我用postDelayed()函數,但是這並不重要!

decrypt(); 
new Handler().postDelayed(new Runnable() { 

    @Override 
    public void run() { 
    // TODO Auto-generated method stub 

      getContentsFile(); 
      } 
     }, 7000); 

文件大小爲80千字節!

它在模擬器上有問題! 它在三星gt-s7562上有問題,但在銀河s4上一切正常!

+1

你加密一個設備上在另一個解密? –

+0

我在Galaxy S4上加密文件,然後在主機上上傳文件,然後在每臺設備上下載。 –

回答

0

我看到至少有兩個潛在的平臺兼容性問題與您的代碼:

  1. ,一定不要調用getBytes()沒有聲明字符集:

    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES"); 
    

    應該是:(EG)

    SecretKeySpec sks = new SecretKeySpec(
        "MyDifficultPassw".getBytes("UTF-8"), "AES"); 
    
  2. Al方式指定完整的轉換,例如「AES/CBC/PKCS5Padding」:

    Cipher cipher = Cipher.getInstance("AES"); 
    

    應該(例如)

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    

僅這一點就可能是你的問題的原因。不同的平臺具有不同的默認字符集,這意味着您將獲得不同的字符串作爲密鑰。

較不常見的是,當您選擇"AES"時,不同的加密提供程序具有不同的默認值。有些會執行ECB模式加密,有些會執行CBC模式加密。宣佈你想要的東西總是最安全的。


附註:你真的不應該從字符串的原始字節創建一個鍵。改爲使用密碼派生方法,例如PBKDF2。

+0

請不要推薦「US-ASCII」或實際上不是「UTF-8」。 –

+0

@OlegEstekhin小心解釋爲什麼?只要符合選擇並理解輸入字符的範圍,我不確定是否看到問題。 –

+1

「UTF-8」可以是相同的一致選擇,它有一個較少的問題,因爲不需要關心字符的範圍。 –

0

我使用這兩種方法進行加密/解密,它們在任何設備上對我都很完美。它的做法與你的做法略有不同,所以試着比較兩種方法,看看可能會出現什麼問題。

對於加密

獲取iv載體和message加密:

public String getEncrypt(final byte[] iv, final String message) throws GeneralSecurityException, NullPointerException { 
    if (key.isEmpty()) 
    throw new NullPointerException(); 

    final byte[] rawData = key.getBytes(Charset.forName("US-ASCII")); 
    if (rawData.length != 16) { 
    // If this is not 16 in length, there's a problem with the key size, nothing to do here 
    throw new IllegalArgumentException("You've provided an invalid key size"); 
    } 

    final SecretKeySpec seckeySpec = new SecretKeySpec(rawData, "AES"); 
    final Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

    ciph.init(Cipher.ENCRYPT_MODE, seckeySpec, new IvParameterSpec(iv)); 

    byte[] encryptedBA = ciph.doFinal(message.getBytes(Charset.forName("US-ASCII"))); 
    try { 
    final String encryptedText = new String(Base64.encode(encryptedBA, Base64.DEFAULT), "UTF-8"); 
    return encryptedText.toString(); 
    } 
    catch (final UnsupportedEncodingException e1) { } 
    return ""; 
} 

對於解密:

public String getDecrypt(final byte[] encrypted) throws GeneralSecurityException, NullPointerException { 
    if (key.isEmpty()) 
    throw new NullPointerException(); 

    final byte[] rawData = key.getBytes(Charset.forName("US-ASCII")); 
    if (rawData.length != 16) { 
    // If this is not 16 in length, there's a problem with the key size, nothing to do here 
    throw new IllegalArgumentException("Invalid key size."); 
    } 

    final SecretKeySpec seckeySpec = new SecretKeySpec(rawData, "AES"); 

    final Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    ciph.init(Cipher.DECRYPT_MODE, seckeySpec, new IvParameterSpec(new byte[16])); 
    final byte[] decryptedmess = ciph.doFinal(encrypted); 

    return new String(decryptedmess, Charset.forName("US-ASCII")); 
} 
+0

我已經使用這些函數在http://stackoverflow.com/questions/10782187/how-to-encrypt-file-from-sd-card-using-aes-in-android –

+0

嘗試將其添加到我已經張貼這些工作順利。 – nKn

+0

直接使用String字節作爲密碼是不好的。 – Robert