Kala J
Kala J

Reputation: 2070

Encrypting and decrypting a string

I tried following one of the examples on SO for encrypting and decrypting a string.

Here's what I have so far:

public static String encrypt(String value) {
        byte[] encrypted = null;
        String encrypted_string = null;
        try {

            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = new byte[cipher.getBlockSize()];

            IvParameterSpec ivParams = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);
            encrypted  = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:" + encrypted.length);

            //Encrypted byte array
            System.out.println("encrypted byte array:" + encrypted);

            //Encrypted string
            encrypted_string = new String(encrypted);
            System.out.println("encrypted string: " + encrypted_string);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return encrypted_string;
    }

    public static String decrypt(String encrypted_string) {
        byte[] original = null;
        Cipher cipher = null;
        String decrypted_string = null;
        try {
            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key key = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
            byte[] ivByte = new byte[cipher.getBlockSize()];
            //This class specifies an initialization vector (IV). Examples which use
            //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.
            IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
            original= cipher.doFinal(encrypted_string.getBytes());

            //Converts byte array to String
            decrypted_string = new String(original);
            System.out.println("Text Decrypted : " + decrypted_string);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return decrypted_string;
    }

I want to be able to encrypt a string and then return an encrypted string. Then take that encrypted string and pass it to my decrypt method that also returns the original decrypted string.

I followed an example using Byte[] arrays but I don't want to use Byte arrays, I want to use just strings.

The problem with the above is I get an error on this line:

original= cipher.doFinal(encrypted_string.getBytes());

which says, "Wrong final block length: IllegalBlockSizeException". Which makes me think I can't just simply convert my string to a byte array and pass that to doFinal() method. But what can I do to fix this problem in the format I want above?

Upvotes: 1

Views: 3615

Answers (1)

divanov
divanov

Reputation: 6339

When you convert random byte array, which is typical signature into a string, all non-printable characters will be replaced with substitute character. Substitute character depends on encoding used. For ASCII this is ? (3F hexadecimal) and for UTF-8 this is � (EFBFBD hexadecimal).

public String(byte[] bytes) uses default encoding for conversion, which is probably UTF-8 for your application. Then String.getBytes() converts string data back to default encoding you get a lot of EFBFBD for each non-printable character of original data, making it longer. AES in its turn is block cipher and it operates on 16 byte blocks. Thus, all cipher texts have length proportional to 16. That is why you get invalid block size, when feeds corrupted data to the AES decryption.

One of the possibilities to convert binary data to string representation is Base64 encoding. On Android it can be done with Base64 class:

String encryptedString = Base64.encodeToString(encrypted, Base64.DEFAULT);
byte[] encrypted2 = Base64.decode(encryptedString, Base64.DEFAULT);

Upvotes: 2

Related Questions