2015-10-06 5 views
5

Ich muss einige Daten entschlüsseln, die ich vom Server erhalte, und der Programmierer, der die API erstellt hat, hat mich an diese Encrypter Klasse verwiesen, um zu sehen, was er zum Verschlüsseln benutzt hat.Wie entschlüsselt man in Java (Android) Text, der mit Crypt in Laravel verschlüsselt wurde?

Jetzt basierend auf dieser Klasse, fand ich, dass der verwendete Algorithmus AES128 CBC ist, und dass die Zeichenfolge, die ich erhalte, Base64-codiert ist und andere Daten enthält, nicht nur den Chiffretext.

nämlich, dass, wenn ich die folgende Zeichenfolge angezeigt:

eyJpdiI6InJsSzRlU3pDZTBBUVNwMzdXMjVcL0tBPT0iLCJ2YWx1ZSI6Ik5JOENsSVVWaWk2RGNhNlwvWjJNeG94UzVkclwvMGJOREQreWUyS1UzclRMND0iLCJtYWMiOiJhZTZkYjNkNGM2ZTliNmU0ZTc0MTRiNDBmMzFlZTJhNTczZWIxMjk4N2YwMjlhODA1NTIyMDEzODljNDY2OTk2In0 

nach Base64-Decodierung ich:

{"iv":"rlK4eSzCe0AQSp37W25\/KA==","value":"NI8ClIUVii6Dca6\/Z2MxoxS5dr\/0bNDD+ye2KU3rTL4=","mac":"ae6db3d4c6e9b6e4e7414b40f31ee2a573eb12987f029a80552201389c466996"} 

Basierend auf line 99 von Encrypter Klasse (iv = base64_decode($payload['iv']);), habe ich auf die andere Base64 dekodieren ausgeführt iv und die value, und bekam eine iv der Länge 16. Jene, die ich als Parameter an die folgende Funktion übergeben:

public static String decrypt(String iv, String encryptedData) throws Exception { 
    byte[] keyValue = "zy2dEd1pKG5i3WuWbvOBolFQR84AYbvN".getBytes(); 
    Key key = new SecretKeySpec(keyValue, "AES");   
    Cipher c = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
    c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv.getBytes())); 
    byte[] decordedValue = Base64.decode(encryptedData.getBytes(), Base64.DEFAULT); 
    byte[] decValue = c.doFinal(decordedValue); 
    return new String(decValue); 
} 

Aber ich bin immer folgende Fehlermeldung:

10-06 19:13:33.601 12895-12895/? W/System.err: java.security.InvalidAlgorithmParameterException: expected IV length of 16 
10-06 19:13:33.601 12895-12895/? W/System.err:  at com.android.org.conscrypt.OpenSSLCipher.engineInitInternal(OpenSSLCipher.java:281) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at com.android.org.conscrypt.OpenSSLCipher.engineInit(OpenSSLCipher.java:323) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at javax.crypto.Cipher.init(Cipher.java:751) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at javax.crypto.Cipher.init(Cipher.java:701) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at com.example.kushtrim.testproject.MainActivity.decrypt(MainActivity.java:62) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at com.example.kushtrim.testproject.MainActivity.onCreate(MainActivity.java:45) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at android.app.Activity.performCreate(Activity.java:5990) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at android.app.ActivityThread.access$800(ActivityThread.java:151) 
10-06 19:13:33.601 12895-12895/? W/System.err:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at android.os.Handler.dispatchMessage(Handler.java:102) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at android.os.Looper.loop(Looper.java:135) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at android.app.ActivityThread.main(ActivityThread.java:5254) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at java.lang.reflect.Method.invoke(Native Method) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at java.lang.reflect.Method.invoke(Method.java:372) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
10-06 19:13:33.602 12895-12895/? W/System.err:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

Hinweis: Der String iv hat eine Länge von 16, aber iv.getBytes() gibt einen Array mit einer Länge von 26

Könnte jemand Punkt mich dorthin, wo ich falsch gelaufen bin, und wie repariere ich es. Dank/

EDIT
Nach dem Kommentar, ich habe einige Änderungen, die den obigen Fehler behoben:
Bevor ich base64-Decodierung iv, war die Bytes in String konvertieren, dann diese Zeichenfolge an die Entschlüsselungs-Methode übergeben , die dafür die getBytes() aufgerufen hat. Irgendwie hat dies dazu geführt, dass das Byte-Array eine Länge von 26 hat.
Das Senden des Byte-Arrays, das ich nach der base64-Decodierung erhalten habe, an das Entschlüsselungsverfahren, behob das Problem.
Nun wird das Verfahren ist wie folgt:

public static String decrypt(byte[] iv, String encryptedData) throws Exception { 
    byte[] keyValue = "zy2dEd1pKG5i3WuWbvOBolFQR84AYbvN".getBytes(); 
    Key key = new SecretKeySpec(keyValue, "AES"); 
    Cipher c = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
    c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); 
    byte[] decordedValue = Base64.decode(encryptedData.getBytes(), Base64.DEFAULT); 
    byte[] decValue = c.doFinal(decordedValue); 
    return new String(decValue); 
} 

Jetzt habe ich ein anderes seltsam Problem:
Der Text, den ich auf dem ersten Platz verschlüsselt war KushtrimPacaj, aber der entschlüsselten Text ist s:13:"KushtrimPacaj";. Woher kommt dieser andere Teil? 13 repräsentiert vielleicht die Länge von KushtrimPacaj?

bearbeiten
Hier ist der Arbeitscode, falls es jemand braucht:
https://gist.github.com/KushtrimPacaj/43a383ab419fc222f80e

+0

Bitte geben Sie ein vollständiges Beispiel. Wenn 'iv' eine Zeichenkette ist, was ist ihr Wert? Hast du vergessen es zu dekodieren? Ich sehe keinen Grund, dass die Länge 26 wäre. Denken Sie daran, dass Sie binäre/nicht druckbare Daten nicht als String übergeben können. Sie müssten ein Byte-Array verwenden. –

+0

@ ArtjomB. Danke für den Kommentar, du hast mir eine Idee gegeben, die zu dem Längenproblem geführt hat. Obwohl ich jetzt ein anderes komisches habe (siehe die bearbeitete Frage). Irgendeine Idee, wie man es repariert? –

Antwort

2

Sie im padAndMcrypt() function sehen können, dass die gegebene $ Wert serialize() function PHP serialisiert verwendet. Sie können re-implement die unserialize() Funktion in Java oder Sie können das Byte-Array selbst teilen, wenn Sie immer Zeichenfolgen in PHP verschlüsseln.

int firstQuoteIndex = 0; 
while(decValue[firstQuoteIndex] != (byte)'"') firstQuoteIndex++; 
return new String(Arrays.copyOfRange(decValue, firstQuoteIndex + 1, decValue.length-2)); 

Voll Code:

public static String decrypt(byte[] keyValue, String ivValue, String encryptedData) throws Exception { 
    Key key = new SecretKeySpec(keyValue, "AES"); 
    byte[] iv = Base64.decode(ivValue.getBytes("UTF-8"), Base64.DEFAULT); 
    byte[] decodedValue = Base64.decode(encryptedData.getBytes("UTF-8"), Base64.DEFAULT); 

    Cipher c = Cipher.getInstance("AES/CBC/PKCS7Padding"); // or PKCS5Padding 
    c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); 
    byte[] decValue = c.doFinal(decodedValue); 

    int firstQuoteIndex = 0; 
    while(decValue[firstQuoteIndex] != (byte)'"') firstQuoteIndex++; 
    return new String(Arrays.copyOfRange(decValue, firstQuoteIndex + 1, decValue.length-2)); 
} 

die MAC-Überprüfung ist immer eine gute Idee, weil es einige Angriffe wie der Polsterung Orakel Angriff verhindert. Es ist auch ein sehr guter Weg, um allgemeine Veränderungen von Chiffretexten zu erkennen.

Voll Code mit MAC-Überprüfung:

public static String decrypt(byte[] keyValue, String ivValue, String encryptedData, String macValue) throws Exception { 
    Key key = new SecretKeySpec(keyValue, "AES"); 
    byte[] iv = Base64.decode(ivValue.getBytes("UTF-8"), Base64.DEFAULT); 
    byte[] decodedValue = Base64.decode(encryptedData.getBytes("UTF-8"), Base64.DEFAULT); 

    SecretKeySpec macKey = new SecretKeySpec(keyValue, "HmacSHA256"); 
    Mac hmacSha256 = Mac.getInstance("HmacSHA256"); 
    hmacSha256.init(macKey); 
    hmacSha256.update(ivValue.getBytes("UTF-8")); 
    byte[] calcMac = hmacSha256.doFinal(encryptedData.getBytes("UTF-8")); 
    byte[] mac = Hex.decodeHex(macValue.toCharArray()); 
    if (!secureEquals(calcMac, mac)) 
     return null; // or throw exception 

    Cipher c = Cipher.getInstance("AES/CBC/PKCS7Padding"); // or PKCS5Padding 
    c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); 
    byte[] decValue = c.doFinal(decodedValue); 

    int firstQuoteIndex = 0; 
    while(decValue[firstQuoteIndex] != (byte)'"') firstQuoteIndex++; 
    return new String(Arrays.copyOfRange(decValue, firstQuoteIndex + 1, decValue.length-2)); 
} 

/* Constant-time compare to prevent timing attacks on invalid authentication tags. */ 
public static boolean secureEquals(final byte[] known, final byte[] user) { 
    int knownLen = known.length; 
    int userLen = user.length; 

    int result = knownLen^userLen; 
    for (int i = 0; i < knownLen; i++) { 
     result |= known[i]^user[i % userLen]; 
    } 
    return result == 0; 
} 
+0

Danke Mann. Ich wusste, wie man die Saite spaltete, wagte es aber nicht, weil ich nicht wusste, warum es passierte und ob es immer dem gleichen Muster folgen würde. Sie könnten auch die Antwort bearbeiten und den zweiten Parameter in copyOfRange: "firstQuoteIndex + 1" angeben, da der Startindex inklusive ist. Stackoverflow lässt mich nicht bearbeiten, dass es weniger als 6 Zeichen hat. –

+0

Ich habe MAC-Verifizierung hinzugefügt. Können Sie überprüfen, ob es wie erwartet funktioniert? –

+0

'// TODO: Zeitkonstanten vergleichen 'Würden Sie lieber ein Github-Projekt dafür machen? –

Verwandte Themen