2017-01-17 5 views
0

Dies ist eine Fortsetzung meiner Frage gestern: Android Java AES EncryptionAndroid Java AES-Verschlüsselung Cipher Padding und Mode Error

ich derzeit AES-Verschlüsselung auf Android am Testen. In meiner vorherigen Frage bin ich in der Lage eine Zeichenfolge mit Cipher c = Cipher.getInstance("AES");

Ich wurde in den Antworten informiert, dass ich angeben soll den IV, Verschlüsselungsmodus und Polsterung zu verhindern, potenzielle Probleme in der Zukunft verschlüsseln und entschlüsseln, da keine Angabe bedeutet, dass die Das Programm verwendet den Standardwert des Systems. Also änderte ich meinen Code zu c = Cipher.getInstance("AES/CBC/PKCS5Padding");

Aber jetzt funktioniert mein Code nicht mehr, und es wird eine NullPointerException zurückgeben.

Mein Code:

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; 
    } 

Ausgang:

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) auf die letzte Zeile von decryptFIN128AES, das ist: return new String(decodedBytes, StandardCharsets.UTF_8);

Ich verstehe, dass die Nullpointer tritt auf, weil etwas schief falsch mit dem Entschlüsselungsprozess. Da muss es in den catch Fall gegangen sein und somit decodedBytes bleibt als NULL und verursacht somit den Fehler wenn ich decodedBytes zurückgeben will. Jetzt ist meine Frage: Warum passiert das und wie kann ich das beheben?

Ihre Hilfe wird sehr geschätzt.

+0

Mögliche Duplikate von [Was ist eine NullPointerException und wie behebe ich sie?] (Http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix -it) –

+3

** 1) Keine Ausnahme erfassen, ohne die Ursache zu protokollieren. 2) Noch mehr, fangen Sie nicht (ohne erneutes Auslösen) eine Ausnahme, die Sie nicht lösen können. ** Wenn Sie den richtigen Praktiken folgen, können Sie sehen, welche Ausnahme 'e' Ihnen zu sagen versuchte. Siehe: http://literatejava.com/exceptions/ten-practices-for-perfect-java-exception-handling/ –

Antwort

0

Vielen Dank an @Thomas W für Ihre Hilfe. Ich habe die catch zu throw und jetzt kann ich die tatsächliche Fehler sehen etwas mit BadPaddingException: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

Nach einigen googeln ich die Lösung der Mangel ist in meinem c.init von IV Argument gefunden zu tun hat. Zuvor verwendete ich "AES", in der Java standardmäßig "AES/ECB/PKCS5Padding" ist und das funktioniert ohne IV. (Quelle: Android: Encrypt a string with AES 256bit Encryption with iv and secret key)

Aber sobald ich zu "AES/CBC/PKCS5Padding" geändert habe, wird Java Probleme ohne eine erklärte IV haben. Daher wurde das Problem durch Ändern von c.init(Cipher.ENCRYPT_MODE, sks); und c.init(Cipher.DECRYPT_MODE, sks); zu c.init(Cipher.ENCRYPT_MODE, sks, new IvParameterSpec(new byte[16])); und c.init(Cipher.DECRYPT_MODE, sks, new IvParameterSpec(new byte[16])); behoben.

Jetzt kann mein Programm richtig verschlüsseln und entschlüsseln.

+2

Sie geben immer die gleiche IV an, nämlich ein Byte-Array von 0s. Das vereitelt den Zweck des IV. Die IV muss zufällig sein. Und Sie müssen es zusammen mit den verschlüsselten Daten übertragen, damit es für die Entschlüsselung verfügbar ist. – Codo