Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Cipher encrypt/decrypt

I'm using cipher to encrypt and decrypt messages:

public String encrypt(String string) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
  cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
  byte[] stringBytes = string.getBytes("UTF-8");
  byte[] encryptedBytes = cipher.doFinal(stringBytes);
  return android.util.Base64.encodeToString(encryptedBytes, android.util.Base64.DEFAULT);
}

public String decrypt(String string) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
  cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
  byte[] stringBytes = android.util.Base64.decode(string.getBytes(), android.util.Base64.DEFAULT);
  byte[] decryptedBytes = cipher.doFinal(stringBytes);
  return new String(decryptedBytes,"UTF-8");
}

For some reason although I'm using Base64 to encode and decode the string, I still get this error:

javax.crypto.IllegalBlockSizeException: last block incomplete in decryption

What am I doing wrong?

Edit:

This is my JSONObject - I'm trying to decrypt the "m":

{"m":"Cu7FR2be0E6ZP2BrZaLU2ZWQSfycNg0-fPibphTIZno\r\n"}

The weird thing is that the error only appears in Android. My server is written in Java and I'm using Apache Base64 encoder and it works great.

like image 999
Asaf Nevo Avatar asked Feb 19 '23 02:02

Asaf Nevo


2 Answers

Your code seems OK to me, you can try to add "UTF-8" before decoding.

byte[] stringBytes = android.util.Base64.decode(string.getBytes("UTF-8"), android.util.Base64.DEFAULT);

EDIT

This is an example Security Utility class which do encryption/decryption that uses BouncyCastle and password-based AES encryption.

public class SecurityUtils {

public static final String KEY_DERIVATION_ALGORITHM = "PBKDF2WithHmacSHA1";

private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

private static final String DELIMITER = "]";

private static final int KEY_LENGTH = 256;

private static final int ITERATION_COUNT = 1000;

private static final int SALT_LENGTH = 8;

private static SecureRandom random = new SecureRandom();

static {
    Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
}


public static String encrypt(Context context, String plaintext)
        throws Exception {
    byte[] salt = generateSalt();
    return encrypt(plaintext, getKey(salt, getPassword(context)), salt);
}

private static String encrypt(String plaintext, SecretKey key, byte[] salt)
        throws Exception {
    try {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");

        byte[] iv = generateIv(cipher.getBlockSize());
        IvParameterSpec ivParams = new IvParameterSpec(iv);

        cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);
        byte[] cipherText = cipher.doFinal(plaintext.getBytes("UTF-8"));

        if (salt != null) {
            return String.format("%s%s%s%s%s",
                    new String(Base64.encode(salt)), DELIMITER, new String(
                            Base64.encode(iv)), DELIMITER, new String(
                            Base64.encode(cipherText)));
        }

        return String.format("%s%s%s", new String(Base64.encode(iv)),
                DELIMITER, new String(Base64.encode(cipherText)));
    } catch (Throwable e) {
        throw new Exception("Error while encryption", e);
    }
}

public static String decrypt(Context context, String ciphertext)
        throws Exception {
    return decrypt(ciphertext, getPassword(context));
}

private static String decrypt(String ciphertext, String password)
        throws Exception {
    String[] fields = ciphertext.split(DELIMITER);
    if (fields.length != 3) {
        throw new IllegalArgumentException("Invalid encypted text format");
    }
    try {
        byte[] salt = Base64.decode(fields[0]);
        byte[] iv = Base64.decode(fields[1]);
        byte[] cipherBytes = Base64.decode(fields[2]);

        SecretKey key = getKey(salt, password);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, "BC");
        IvParameterSpec ivParams = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, key, ivParams);
        byte[] plaintext = cipher.doFinal(cipherBytes);
        String plainrStr = new String(plaintext, "UTF-8");

        return plainrStr;
    } catch (Throwable e) {
        throw new Exception("Error while decryption", e);
    }
}

private static String getPassword(Context context) {

    return "My secret password";
}

private static SecretKey getKey(byte[] salt, String password)
        throws Exception {
    try {
        KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt,
                ITERATION_COUNT, KEY_LENGTH);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(
                KEY_DERIVATION_ALGORITHM, "BC");
        byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
        return new SecretKeySpec(keyBytes, "AES");
    } catch (Throwable e) {
        throw new Exception("Error while generating key", e);
    }
}

private static byte[] generateIv(int length) {
    byte[] b = new byte[length];
    random.nextBytes(b);

    return b;
}

private static byte[] generateSalt() {
    byte[] b = new byte[SALT_LENGTH];
    random.nextBytes(b);

    return b;
}

}

like image 165
iTech Avatar answered Mar 05 '23 22:03

iTech


You need to convert Base-64 first.

CODEED = encrypt(Base64.encode(MYSTRING, Base64.DEFAULT));

MYSTRING = Base64.decode(decrypt(CODEED), Base64.DEFAULT);

here is a link http://androidcodemonkey.blogspot.com/2010/03/how-to-base64-encode-decode-android.html

like image 32
Mert Avatar answered Mar 05 '23 22:03

Mert