How to fix Invalid AES key length?

后端 未结 4 724
我在风中等你
我在风中等你 2020-12-12 22:39

I am working on a text encryption and decryption project (following Struts 2)

Whenever I enter the password and the plain text I get a Invalid AES K

4条回答
  •  春和景丽
    2020-12-12 22:50

    Things to know in general:

    1. Key != Password
      • SecretKeySpec expects a key, not a password. See below
    2. It might be due to a policy restriction that prevents using 32 byte keys. See other answer on that

    In your case

    The problem is number 1: you are passing the password instead of the key.

    AES only supports key sizes of 16, 24 or 32 bytes. You either need to provide exactly that amount or you derive the key from what you type in.

    There are different ways to derive the key from a passphrase. Java provides a PBKDF2 implementation for such a purpose.

    I used erickson's answer to paint a complete picture (only encryption, since the decryption is similar, but includes splitting the ciphertext):

    SecureRandom random = new SecureRandom();
    byte[] salt = new byte[16];
    random.nextBytes(salt);
    
    KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 256); // AES-256
    SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    byte[] key = f.generateSecret(spec).getEncoded();
    SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
    
    byte[] ivBytes = new byte[16];
    random.nextBytes(ivBytes);
    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    
    Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
    c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
    byte[] encValue = c.doFinal(valueToEnc.getBytes());
    
    byte[] finalCiphertext = new byte[encValue.length+2*16];
    System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
    System.arraycopy(salt, 0, finalCiphertext, 16, 16);
    System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);
    
    return finalCiphertext;
    

    Other things to keep in mind:

    • Always use a fully qualified Cipher name. AES is not appropriate in such a case, because different JVMs/JCE providers may use different defaults for mode of operation and padding. Use AES/CBC/PKCS5Padding. Don't use ECB mode, because it is not semantically secure.
    • If you don't use ECB mode then you need to send the IV along with the ciphertext. This is usually done by prefixing the IV to the ciphertext byte array. The IV is automatically created for you and you can get it through cipherInstance.getIV().
    • Whenever you send something, you need to be sure that it wasn't altered along the way. It is hard to implement a encryption with MAC correctly. I recommend you to use an authenticated mode like CCM or GCM.

提交回复
热议问题