Question

First of all I wanna say thank you...

I wrote a program which one is doing encryption and decryption with Enum. Enum has AES,BlowFish,DESede. My program will support these 3 encryption algorithm.

Then I wanted to Generate a SecretKey with SecretKeyFactory.But I think,I made a mistake to generate a key. (Obviously I loose myself in code.I have no idea about what can I do...)

My Code is below. This program's purpose is;

  • Users will write encryption and decryption method parameters. (Text,Encryption Algorithm)
  • Algorithm type will choose in Enum type. (Enum has 3 algorithm format)
  • According to the entered Encryption Type,program will encrypt entered text.

I know my code is really terrible. It has lots of unnecessary declaration and logical mistakes.

Code is working fine sometimes,sometimes will crash.

EDIT = Question is my code doesnt work always. Sometimes gives error. Error is = javax.crypto.BadPaddingException: Given final block not properly padded

Thank you for answering.

import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class SymetricAlgorithms {

    private static enum algorithms { //Enum declaration 3 encryption types here

        AES, BlowFish, DESede;

    }

    private static String data = "HOWCANISOLVETHIS"; //this will be encrypt and decrypt

    public static void main(String[] args) throws Throwable {

        SecretKey kgen = GenerateKey(); // Create a key.
        String encrypText = encrypt(kgen, data, algorithms.AES); //encrypt method calling here.
        String decrypText = dencypt(kgen, encrypText, algorithms.AES);//decrypt method calling here.
        System.out.println("plaintext = " + data + " key = " + kgen
                + "\nEncryptedText = " + encrypText
                + "\nDecryptedText = " + decrypText);

    }

    public static String dencypt(SecretKey inKey, String text, algorithms eValue)throws Throwable {//decryption
        try {
            byte[] text2 = text.getBytes(); //convert from parameters TEXT to Bytes
            Cipher cipher = Cipher.getInstance("AES"); //Cipher initialize and choose encryption method (AES)
            cipher.init(Cipher.DECRYPT_MODE, inKey); //cipher process
            byte plainTextByte[] = new byte[20]; //Creating byte array
            plainTextByte =cipher.doFinal(text2);//using byte array to assign ciphers result
            System.out.println(plainTextByte);
            return new String(plainTextByte);
        } catch (Exception e) {
            System.err.println("Data Cant Decrypted !");
            e.printStackTrace();
        }
        return null;


    }

    public static String encrypt(SecretKey inKey, String text, algorithms eValue)
            throws Throwable {
        try {
            Cipher cipher = null; //cipher declaration
            switch (eValue) {//Enum. 3 types here and control structure for Users choosing encryption type is acceptable
            case AES:cipher = Cipher.getInstance("AES");
                break;
            case BlowFish:Cipher cipher2 = Cipher.getInstance("BlowFish");
            cipher = cipher2;
                break;
            case DESede:Cipher cipher3 = Cipher.getInstance("DESede");
            cipher=cipher3;
                break;
            default:
                System.out.println("Unexpectable value input.");
                break;

            }
            System.out.println(inKey);
            //Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, inKey);
            byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));//cipher result is assign to byte array
            System.out.println(ciphertext);
            return new String(ciphertext);
        } catch (Exception e) {
            System.err.println("Unexpectable algorithm type !");
            e.printStackTrace();
        }
        return null;

    }

    public static SecretKey GenerateKey() throws Throwable {//Generate a key for using crypt
            //could sb explain these? =D I loose myself. I combined codes from finding internet...Failed...    
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
            byte bytes[] = new byte[20];
            prng.nextBytes(bytes);
            String passwordTemp = prng.toString();
            String saltTemp = passwordTemp;
            char[] password = passwordTemp.toCharArray();
            byte[] salt = saltTemp.getBytes();
            KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
            return secret;
        } catch (Exception e) {
            System.err.println("Key cant be generated !");
            e.printStackTrace();
        }
        return null;

    }

}
Was it helpful?

Solution

The theme of the problem is misunderstanding of the relationship between Strings and bytes. At the end of the encrypt method, what do you think these two lines do:

byte[] ciphertext = cipher.doFinal(...
return new String(ciphertext);

The last line takes the encrypted bytes, which could be almost anything, and attempts to interpret those bytes as encoding some characters of a string. Using what encoding? String constructor with no character encoding argument uses system default encoding, which depends on JVM/OS/Locale. Lets say it is UTF-8. Are you guaranteed that there will actually be some character for the encrypted bytes? Answer: NO. Will you get the same bytes back, when you take the resulting string and call .getBytes("UTF-8"). Answer: No, there are mutliple byte sequences encoding the same characters, thus new String(bytes, "UTF-8").getBytes("UTF-8") is not guaranteed to return the bytes you started with.

In summary, don't attempt to interpret arbitrary bytes as a string. Make your encrypt method return byte[], and your decryp method take an array of bytes to decode-- then it will work.

It is not necessary to make your program work, but if you must represent the encrypted bytes as a string, consider base64 encoding, or hexadecimal encoding -- these encodings uniquely map every possible byte (or sequence of bytes) to a string.

UPDATE: here is a more concise generateKey() method. It allows you to pass the password in as an argument.

public static SecretKey generateKey(String password) {
    try {
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        byte saltBytes[] = new byte[20];
        secureRandom.nextBytes(saltBytes);

        KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65536, 128);
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        SecretKey secretKey = factory.generateSecret(spec);

        return new SecretKeySpec(secretKey.getEncoded(), "AES");
    } catch (Exception e) {
        throw new IllegalStateException("Key cant be generated !");
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top