user5354385
user5354385

Reputation:

Java AES improve safety, how long does the keystring need to be

Encryption and Decryption in Java is still very difficult for me to understand. I have been using the following class and methods. I wonder how to improve the safety and how long does the keystring (schlüssel) need to be?

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class AES
{
public static SecretKeySpec makeKey(String schlüssel) throws NoSuchAlgorithmException, UnsupportedEncodingException
{
    byte[] key = (schlüssel).getBytes("UTF-8");
    MessageDigest sha = MessageDigest.getInstance("SHA");
    key = sha.digest(key);
    key = Arrays.copyOf(key, 16);
    return new SecretKeySpec(key, "AES");
}


public static String encryptString(String text, SecretKeySpec schlüssel) throws Exception
{
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, schlüssel);
    byte[] encrypted = cipher.doFinal(text.getBytes());

    BASE64Encoder myEncoder = new BASE64Encoder();
    return myEncoder.encode(encrypted);
}


public static String decryptString(String text, SecretKeySpec schlüssel) throws Exception
{    
    BASE64Decoder myDecoder2 = new BASE64Decoder();
    byte[] crypted2 = myDecoder2.decodeBuffer(text);

    Cipher cipher2 = Cipher.getInstance("AES");
    cipher2.init(Cipher.DECRYPT_MODE, schlüssel);
    byte[] cipherData2 = cipher2.doFinal(crypted2);
    return new String(cipherData2);
}
}

I have been reading about the topic. But I did not understand how to transfer the ideas into my code. Any help is appreciated, please be kind with an encryption beginner. Thank you.

Upvotes: 0

Views: 596

Answers (2)

user5354385
user5354385

Reputation:

Refering to Maarten Bodeswes code I try to bring his code into the form I am using.

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class AESplus 
{
public static SecretKeySpec makeKey(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException
{
password = String.format("%040x", new BigInteger(1,password.getBytes(Charset.forName("UTF-8"))));
    password = password.substring(password.length()-32, password.length());
    final byte[] symKeyData = DatatypeConverter.parseHexBinary(password);
    return new SecretKeySpec(symKeyData, "AES");
}


public static String encryptString(String text, SecretKeySpec key) throws NoSuchAlgorithmException, NoSuchPaddingException, 
                    InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
    final byte[] encodedMessage = text.getBytes(Charset.forName("UTF-8"));

    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    final int blockSize = cipher.getBlockSize();

    // generate random IV using block size
    final byte[] ivData = new byte[blockSize];
    final SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
    rnd.nextBytes(ivData);
    final IvParameterSpec iv = new IvParameterSpec(ivData);

    cipher.init(Cipher.ENCRYPT_MODE, key, iv);
    final byte[] encryptedMessage = cipher.doFinal(encodedMessage);

    // concatenate IV and encrypted message
    final byte[] ivAndEncryptedMessage = new byte[ivData.length + encryptedMessage.length];
    System.arraycopy(ivData, 0, ivAndEncryptedMessage, 0, blockSize);
    System.arraycopy(encryptedMessage, 0, ivAndEncryptedMessage, blockSize, encryptedMessage.length);
    return DatatypeConverter.printBase64Binary(ivAndEncryptedMessage);
}


public static String decrytString(String crypttext, SecretKeySpec key) throws NoSuchAlgorithmException, NoSuchPaddingException, 
                        InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException 
{    
    final byte[] ivAndEncryptedMessage = DatatypeConverter.parseBase64Binary(crypttext);

    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    final int blockSize = cipher.getBlockSize();

    // retrieve random IV from start of the received message
    final byte[] ivData = new byte[blockSize];
    System.arraycopy(ivAndEncryptedMessage, 0, ivData, 0, blockSize);
    final IvParameterSpec iv = new IvParameterSpec(ivData);

    // retrieve the encrypted message itself
    final byte[] encryptedMessage = new byte[ivAndEncryptedMessage.length - blockSize];
    System.arraycopy(ivAndEncryptedMessage, blockSize, encryptedMessage, 0, encryptedMessage.length);

    cipher.init(Cipher.DECRYPT_MODE, key, iv);
    final byte[] encodedMessage = cipher.doFinal(encryptedMessage);

    // concatenate IV and encrypted message
    final String message = new String(encodedMessage,Charset.forName("UTF-8"));

    return message;
}

}

Upvotes: 0

Maarten Bodewes
Maarten Bodewes

Reputation: 94038

There are a lot of things wrong in this class.

  • the class uses a cryptographic hash instead of a password hash - such as PBKDF2 - to derive a key from the password;
  • you are using ECB mode encryption (the default), you need to use at least CBC, together with an initialization vector (IV);
  • your class doesn't add any integrity protection, in other words the ciphertext is malleable;

It depends on the use case if you require the integrity protection. So I'll point you to this question for more information about password based encryption (PBE). Note that the answers may still deliver malleable ciphertext.

Furthermore the class contains the following Java mistakes:

  • it doesn't distinguish between runtime related exceptions (missing algorithms) and input related exceptions;
  • it uses the default platform encoding for your plaintext;
  • it is using a Sun internal class to perform the Base 64 encoding/decoding.

Note that people will probably point out to you that you are using 128 bit AES encryption. That's however quite strong and - certainly at this point in time - the least of your worries. Upgrading to 192 or 256 bit AES won't increase security significantly.

Upvotes: 3

Related Questions