2017-01-17 82 views
0

这是我的问题的延续昨天: Android Java AES EncryptionAndroid的Java的AES加密密码填充和模式错误

我目前在Android测试AES加密。在我之前的问题中,我能够使用密码对字符串进行加密和解密c = Cipher.getInstance("AES");

我在回复中得到通知,我应该指定IV,加密模式和填充以防止未来出现任何潜在问题,因为没有说明意味着程序将使用系统的默认值。所以我改变了我的代码c = Cipher.getInstance("AES/CBC/PKCS5Padding");

但现在我的代码不再起作用,它会返回一个NullPointerException。

我的代码:

byte[] a = encryptFIN128AES("pls"); 
String b = decryptFIN128AES(a); 
Log.e("AES_Test", "b = " + b); 

/** 
    * Encrypts a string with AES (128 bit key) 
    * @param fin 
    * @return the AES encrypted string 
    */ 
    private byte[] encryptFIN128AES(String fin) { 

     SecretKeySpec sks = null; 

     try { 
      sks = new SecretKeySpec(generateKey(PASSPHRASE, SALT.getBytes(StandardCharsets.UTF_8)).getEncoded(), "AES"); 
     } catch (Exception e) { 
      Log.e("encryptFIN128AES", "AES key generation error"); 
     } 

     // Encode the original data with AES 
     byte[] encodedBytes = null; 
     try { 
      Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      c.init(Cipher.ENCRYPT_MODE, sks); 
      encodedBytes = c.doFinal(fin.getBytes(StandardCharsets.UTF_8)); 
     } catch (Exception e) { 
      Log.e("encryptFIN128AES", "AES encryption error"); 
     } 

     return encodedBytes; 

    } 


    /** 
    * Decrypts a string with AES (128 bit key) 
    * @param encodedBytes 
    * @return the decrypted String 
    */ 
    private String decryptFIN128AES(byte[] encodedBytes) { 

     SecretKeySpec sks = null; 

     try { 
      sks = new SecretKeySpec(generateKey(PASSPHRASE, SALT.getBytes(StandardCharsets.UTF_8)).getEncoded(), "AES"); 
     } catch (Exception e) { 
      Log.e("decryptFIN128AES", "AES key generation error"); 
     } 

     // Decode the encoded data with AES 
     byte[] decodedBytes = null; 
     try { 
      Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      c.init(Cipher.DECRYPT_MODE, sks); 
      decodedBytes = c.doFinal(encodedBytes); 
     } catch (Exception e) { 
      Log.e("decryptFIN128AES", "AES decryption error"); 
     } 

     //return Base64.encodeToString(decodedBytes, Base64.DEFAULT); 
     return new String(decodedBytes, StandardCharsets.UTF_8); 
    } 


/** 
    * Build private key from a passpharase/PIN (incl. key derivation (Uses PBKDF2)) 
    * @param passphraseOrPin 
    * @param salt 
    * @return The generated SecretKey (Used for AES-encryption, key size specified in outputKeyLength) 
    */ 
    public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) 
      throws NoSuchAlgorithmException, InvalidKeySpecException { 
     // Number of PBKDF2 hardening rounds to use. Larger values increase 
     // computation time. You should select a value that causes computation 
     // to take >100ms. 
     final int iterations = 1000; 

     // Generate a 256-bit key 
     final int outputKeyLength = 128; 

     SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
     KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength); 
     SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); 
     return secretKey; 
    } 

输出:

E/decryptFIN128AES: AES decryption error 
E/AndroidRuntime: FATAL EXCEPTION: Thread-176 
        Process: testapp.ttyi.nfcapp, PID: 2920 
        java.lang.NullPointerException: Attempt to get length of null array 
         at java.lang.String.<init>(String.java:371) 
         at testapp.ttyi.nfcapp.DisplayQRActivity.decryptFIN128AES(DisplayQRActivity.java:254) 
         at testapp.ttyi.nfcapp.DisplayQRActivity.access$100(DisplayQRActivity.java:29) 
         at testapp.ttyi.nfcapp.DisplayQRActivity$1.run(DisplayQRActivity.java:77) 
         at java.lang.Thread.run(Thread.java:818) 

testapp.ttyi.nfcapp.DisplayQRActivity.decryptFIN128AES(DisplayQRActivity.java:254)点至decryptFIN128AES最后一行,也就是: return new String(decodedBytes, StandardCharsets.UTF_8);

我明白发生NullPointerException异常,因为出事解密过程错误。由于它必须已经进入catch的情况,因此decodedBytes保持为NULL,因此导致错误,当我想返回decodedBytes时。所以现在我的问题是:为什么会发生这种情况,我该如何解决这个问题?

非常感谢您的帮助。

+0

可能重复[什么是NullPointerException,以及如何解决它?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-doi-i-fix -it) –

+3

** 1)不要在没有记录原因的情况下捕捉异常。 2)更重要的是,不要捕捉(不重新抛出)一个你无法解决的异常。**如果你遵循正确的做法,你将能够看到什么异常'e'试图告诉你。请参阅:http://literatejava.com/exceptions/ten-practices-for-perfect-java-exception-handling/ –

回答

0

非常感谢@Thomas W的帮助。我改变了对catchthrow现在我可以看到实际的错误有事情做与BadPaddingException: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

一些谷歌上搜索我找到了解决办法是在我c.init缺乏IV论证后。以前我使用的是"AES",其中Java默认为"AES/ECB/PKCS5Padding",并且没有IV就可以正常工作。 (来源:Android: Encrypt a string with AES 256bit Encryption with iv and secret key

但是,一旦我改变为"AES/CBC/PKCS5Padding" Java将有没有声明IV的问题。因此通过将c.init(Cipher.ENCRYPT_MODE, sks);c.init(Cipher.DECRYPT_MODE, sks);更改为 c.init(Cipher.ENCRYPT_MODE, sks, new IvParameterSpec(new byte[16]));c.init(Cipher.DECRYPT_MODE, sks, new IvParameterSpec(new byte[16]));修复了此问题。

现在我的程序可以正确加密和解​​密。

+2

您始终指定相同的IV,即0的字节数组。这完全破坏了IV的目的。 IV需要是随机的。而且您需要将它与加密数据一起传输,以便解密。 – Codo