2015-10-06 20 views
5

Sunucumdan aldığım bazı verileri ve şifrelemek için ne kullandığını görmek için API'yi bu Encrypter sınıfına yönlendiren programcı şifresini çözmem gerekiyor.Laravel'de Crypt ile şifrelenmiş Java (Android) metninde nasıl şifre çözülür?

Artık bu sınıfa dayanarak, kullanılan algoritmanın AES128 CBC olduğunu ve aldığım dizenin Base64 kodlu olduğunu ve yalnızca şifreli metni değil başka verileri de içerdiğini buldum.

Yani aşağıdaki dize almak eğer: base64 kod çözülmesi sonrası

eyJpdiI6InJsSzRlU3pDZTBBUVNwMzdXMjVcL0tBPT0iLCJ2YWx1ZSI6Ik5JOENsSVVWaWk2RGNhNlwvWjJNeG94UzVkclwvMGJOREQreWUyS1UzclRMND0iLCJtYWMiOiJhZTZkYjNkNGM2ZTliNmU0ZTc0MTRiNDBmMzFlZTJhNTczZWIxMjk4N2YwMjlhODA1NTIyMDEzODljNDY2OTk2In0 

Elde:

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

Encrypter sınıf (iv = base64_decode($payload['iv']);) arasında line 99 dayanarak, başka bir base64 decode gerçekleştirilen iv ve value ve bir iv uzunluğu 16 var. Aşağıdaki işleve parametre olarak geçtim:

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

Ama şu hatayı alıyorum:

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) 

Not: Dize iv 16 uzunluğa sahiptir, ancak uzunluk 26.

Olabilir birisi noktası bir dizi iv.getBytes() döndürür Beni yanlış yere gittim ve nasıl düzeltebilirim? teşekkür/açıklama sonra

DÜZENLEME
, yaptığım yukarıdaki hata çözüldü bazı değişiklikler:
Sonra şifresini yöntemine bu dize geçen String bayt dönüştürülmesi, base64 çözme iv olmadan önce buna karşılık getBytes() denir. Her nasılsa bu bayt dizisi 26 uzunluğa sahiptir.
Base64 kod çözme çözme yöntemiyle sorunu çözdükten sonra elde edilen bayt dizisini I gönderme. aşağıdaki gibi
Şimdi yöntemdir:

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

Şimdi başka garip sorun var:
Ben ilk etapta şifreli metin KushtrimPacaj, ama deşifre metni s:13:"KushtrimPacaj"; olduğunu. Bu diğer kısım nereden geliyor? 13 belki de KushtrimPacaj uzunluğunu temsil eder?

Düzenleme
İşte durumda herkes buna ihtiyacı, çalışma kod:
https://gist.github.com/KushtrimPacaj/43a383ab419fc222f80e

+0

tam bir örnek verin. Eğer 'iv' bir String ise, değeri nedir? Çözmeyi unuttun mu? Uzunluğun 26 olması için bir neden göremiyorum. İkili/yazdırılamayan verileri bir Dize olarak aktaramayacağınızı unutmayın. Bayt dizisi kullanmanız gerekir. –

+0

@ArtjomB. Yorum için teşekkürler, bana uzunluk sorununa yol açan bir fikir verdin. Yine de başka bir tuhaflık var (düzenlenmiş soruya bakınız). Nasıl düzeltileceğine dair bir fikrin var mı? –

cevap

2

Sen verilen $ değeri PHP'nin serialize() function kullanılarak serileştirilebilen olduğunu, padAndMcrypt() function görebilirsiniz. Java'da re-implementunserialize() işlevini kullanabilirsiniz veya PHP'de dizeleri her zaman şifreliyorsanız, bayt dizisini kendiniz bölebilirsiniz.

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

Tam kod: böyle dolgu oracle saldırısı gibi bazı saldırıları önlediğinden MAC Doğrulama

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

, her zaman iyi bir fikirdir. Aynı zamanda şifrelerin genel modifikasyonlarını tespit etmek için de çok iyi bir yoldur. MAC doğrulama ile

Tam kodu:

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

Teşekkürler adamım. Dize nasıl ayrılacağını biliyordum ama cesaret edemedim, çünkü neden olduğunu bilmiyordum ve her zaman aynı modeli takip edip edemeyeceğini biliyordum. Ayrıca, cevabı düzenleyebilir ve başlangıç ​​parametresi kapsayıcı olduğundan, ikinci parametreyi copyOfRange: "firstQuoteIndex + 1" de yapabilirdiniz. Stackoverflow, 6 karakterden daha az bir düzenleme yapmama izin vermiyor. –

+0

MAC onayı ekledim. Beklendiği gibi çalışıp çalışmadığını kontrol edebilir misiniz? –

+0

'// TODO: zaman sabitini kullan“ Bunu bir Github projesi yapmak ister misin? –