0

I want to encrypt and decrypt a string, but I am getting a strange output. I don't know why it isn't working.

My encryption class, using a Singleton pattern:

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import android.util.Base64;

public class CryptExample {

    private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA1";
    private static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static final String UTF_8_CHARSET = "UTF-8";
    private static final int BASE_64_ENCODING = Base64.DEFAULT;

    private static final String STR_PASSWORD = "bM4uOGs600okBDsF";
    private static final String STR_SALT = "iMYGYBFpl2ghOy1k0wMb";
    private static final int ITERATION_COUNT = 4;
    private static final int KEY_SIZE = 128;

    private static CryptExample mCrypt;

    private char[] mPasswordArray;
    private byte[] mSalt;
    private SecretKeySpec mSecretKeySpec;
    private Cipher mCipher;

    public static CryptExample getInstance() {
        if (mCrypt == null) {
            mCrypt = new CryptExample();
        }

        return mCrypt;
    }

    private CryptExample() {

        try {

            mPasswordArray = STR_PASSWORD.toCharArray();
            mSalt = STR_SALT.getBytes(UTF_8_CHARSET);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        try {
            init();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidParameterSpecException e) {
            e.printStackTrace();
        }

    }

    private void init() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidParameterSpecException {

        SecretKeyFactory factory = SecretKeyFactory.getInstance(SECRET_KEY_ALGORITHM);
        PBEKeySpec spec = new PBEKeySpec(mPasswordArray, mSalt, ITERATION_COUNT, KEY_SIZE);

        SecretKey secretKey = factory.generateSecret(spec);
        mSecretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");

        mCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);

    }

    public String encrypt(String szContent) throws NoSuchAlgorithmException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {

        mCipher.init(Cipher.ENCRYPT_MODE, mSecretKeySpec);

        byte[] encryptedContentBytes = mCipher.doFinal(szContent.getBytes(UTF_8_CHARSET));

        return Base64.encodeToString(encryptedContentBytes, BASE_64_ENCODING);
    }

    public String decrypt(String szEncryptedContent) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidParameterSpecException {

        byte[] encryptedContentBytes = Base64.decode(szEncryptedContent, BASE_64_ENCODING);

        mCipher.init(Cipher.DECRYPT_MODE, mSecretKeySpec);

        byte[] decryptedContentBytes = mCipher.doFinal(encryptedContentBytes);

        return new String(decryptedContentBytes, UTF_8_CHARSET);
    }

}

Ecryption/decription test:

@Override
protected void onCreate(Bundle savedInstance) {
   super.onCreate(savedInstance);
   // Other code

   String text = "This is an awesome text that should be encrypted ! This is me, John and Elvira! Welcome home!";

    CryptExample crypto = CryptExample.getInstance();

    try {
        String szEncryptedText = crypto.encrypt(text);

        Log.D(TAG, "Text before: " + text);
        Log.D(TAG, "Text encrypted: " + szEncryptedText);

        String szDecryptedText = crypto.decrypt(szEncryptedText);

        Log.D(TAG, "Text decrypted: " + szDecryptedText);

    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidParameterSpecException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
}

And the output:

Text before: This is an awesome text that should be encrypted ! This is me, John and Elvira! Welcome home!
Text encrypted: iYtkSbJXeZERPrdqLO40BHo8RMsmVKt7+6jNK9yTW8bPWBIB6IpnBcEk9eZp37p8fcHCOz7uJhcchrY0rgVATqwZHd8F1Xb8IWtdmZxpkB1jsANtrkA4zwJh6/IMLeDz
Text decrypted: ;?)?{eM??%t???me text that should be encrypted ! This is me, John and Elvira! Welcome home!

P.S: What do you think about my encryption class? Is it good enough? What about the key size or iteration count? Is it okay to use 128 len with 4 iteration? And the password combined with salt?

1
  • You can use multi-catch or GeneralSecurityException for exception handling, simply providing the exception as cause for an IllegalStateException. The ones you do need to handle during decryption are IllegalBlockSizeException and BadPaddingException as those indicate wrong I/O instead of mistakes in code/runtime. I always replace e.printStackTrace() with throw new IllegalStateException("Exception not handled yet", e); (with a comment indicating a TODO) to not mess up my control flow. Commented Nov 29, 2014 at 15:12

1 Answer 1

1

Java / Android provide a random IV if you don't specify one yourself in the init method.

You can generate one using new SecureRandom and IvParameterSpec, then you can communicate the IV by prefixing it to the ciphertext, and using it during decryption.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.