3

I need help on encryption/decryption on Android application.

I explain the situation. I'm actually wrote an application that used content generated and encrypted by an iPhone application.

And for securisation, the user provide his own passphrase to correctly encrypt/decrypt data between different platform...

But, I encount a problem with the encryption/decryption of this passphrase on Android.

I have two functions:

public byte[] crypt(String pStringToCrypt) throws Exception{

    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, this.passphrase.getBytes().length);
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(pStringToCrypt.getBytes());
    return encrypted;

}

for the crypting of String, and this function:

public String decrypt(byte[] pCryptedStringtoDecrypt) throws Exception{
    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, this.passphrase.getBytes().length);
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    byte[] encrypted = pCryptedStringtoDecrypt;
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] original = cipher.doFinal(encrypted);
    String originalString = new String(original);
    return originalString;
}

for the decrypting of String.

When I use the crypt method to encrypt data, I haven't error and the string was encrypted:

encrypted = [26, 119, -108, -24, 81, -128, 18, 35, -96, 10, -38, 69, 111, 40, 109, 107]

If I try to transform this byte into a string, I obtain this string:

encryptedString = "w��Q�#�\n�Eo(mk"

I think the crypting phase was good. Now when I try to decrypt this encrypted String, the application crashed:

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711)
    at javax.crypto.Cipher.doFinal(Cipher.java:1090)
    at org.vincentsaluzzo.lightrpc.common.security.AES256.decrypt(AES256.java:61)
    at com.vincentsaluzzo.LoginBox.model.SettingsManager.getUserPassphrase(SettingsManager.java:67)
    at com.vincentsaluzzo.LoginBox.mainActivity.onCreate(mainActivity.java:26)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638)
    at android.app.ActivityThread.access$1500(ActivityThread.java:117)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:3647)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)

And I don't understand why this error appear...

Do you have some solutions ? or some explanation for me ?

Vincent Saluzzo
  • 1,377
  • 1
  • 11
  • 13
  • You should post the used passphrase, otherwise it is difficult to retrace your code and the encrypted result. BTW: Never ever use a passphrase as a key! Use a key derivation function for generating a key from a password. – Robert Mar 23 '12 at 15:27
  • @Robert _A key derivation function for generating a key from a password_ : Do you have some example ? – Vincent Saluzzo Mar 23 '12 at 15:32
  • PBKDF2: http://stackoverflow.com/questions/8091519/pbkdf2-function-in-android – Robert Mar 23 '12 at 15:44
  • @Robert Ok, but I do the same code in Objective-C (With Apple functions, of course) but the result are good... So, even if use a Passphrase for Key are bad, it could be work, no ? – Vincent Saluzzo Mar 23 '12 at 19:30
  • 1
    Most of the time it is the (character)encoding part that goes wrong somewhere, not the actual encryption/decryption. That's just for the implementation. Security wise there could still be many issues, such as using ECB mode encryption, forgetting to add integrity/authentication, forgetting to create a random IV, using a password directly as a key... – Maarten Bodewes Mar 25 '12 at 09:03

2 Answers2

2

Ok, with the help of all yours comments, I solved my problem.

I explain. I have transformed my two methods to be the more simplest possible:

public byte[] crypt(byte[] toCrypt) throws Exception {
    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, ((this.passphrase.getBytes().length < 16) ? this.passphrase.getBytes().length : 16));
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(toCrypt);
    return encrypted;
}

and

public byte[] decryptt(byte[] toDecrypt) throws Exception {
    byte[] key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    System.arraycopy(this.passphrase.getBytes(), 0, key, 0, ((this.passphrase.getBytes().length < 16) ? this.passphrase.getBytes().length : 16));
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] original = cipher.doFinal(toDecrypt);
    return original;
}

Shortly, I remove all conversion into string in this methods. And I have inspect my methods in my other project in Objective-C. I found the problem: Encoding String !

Sometime, if I encrypt/decrypt, I get the same bytes array, but sometime, the array was different, because I stock this encrypted byte array into a String in the SharedPreference. It could be possible, of Course, but I just put the byte into a new String(bytes) and the basic encoding are the UTF-8, so that's the problem.

I resolv this with base 64 encoding. I use the Base64 Class found here: http://sourceforge.net/projects/iharder/files/base64/2.3/

and before save the encrypted bytes array into SharedPreferences, I encode them into a Base64 encoding, and same for the decryption process.

TryPyPy
  • 6,214
  • 5
  • 35
  • 63
Vincent Saluzzo
  • 1,377
  • 1
  • 11
  • 13
0

Generally, using getBytes() to convert a String to bytes in cryptography is not a good thing. You are at the mercy of the default character encoding on your machine. Much better to specify an encoding for both encryption and decryption, getBytes("UTF-8")

You do not show the calling code, are you sure you are passing the byte array (encrypted) to the decryption function and not the String of the byte array, your "w��Q�#�\n�Eo(mk"?

ECB mode is insecure and leaks data. You need to use CBC mode or CTR mode for security.

rossum
  • 15,344
  • 1
  • 24
  • 38