Initial bytes incorrect after Java AES/CBC decryption

前端 未结 10 1994
鱼传尺愫
鱼传尺愫 2020-11-22 12:47

What\'s wrong with the following example?

The problem is that the first part of the decrypted string is nonsense. However, the rest is fine, I get...

10条回答
  •  南笙
    南笙 (楼主)
    2020-11-22 13:03

    The IV that your using for decryption is incorrect. Replace this code

    //Decrypt cipher
    Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
    decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
    

    With this code

    //Decrypt cipher
    Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptCipher.getIV());
    decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
    

    And that should solve your problem.


    Below includes an example of a simple AES class in Java. I do not recommend using this class in production environments, as it may not account for all of the specific needs of your application.

    import java.nio.charset.StandardCharsets;
    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 java.util.Base64;
    
    public class AES 
    {
        public static byte[] encrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
        {       
            return AES.transform(Cipher.ENCRYPT_MODE, keyBytes, ivBytes, messageBytes);
        }
    
        public static byte[] decrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
        {       
            return AES.transform(Cipher.DECRYPT_MODE, keyBytes, ivBytes, messageBytes);
        }
    
        private static byte[] transform(final int mode, final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
        {
            final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
            final IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
            byte[] transformedBytes = null;
    
            try
            {
                final Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
    
                cipher.init(mode, keySpec, ivSpec);
    
                transformedBytes = cipher.doFinal(messageBytes);
            }        
            catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) 
            {
                e.printStackTrace();
            }
            return transformedBytes;
        }
    
        public static void main(final String[] args) throws InvalidKeyException, InvalidAlgorithmParameterException
        {
            //Retrieved from a protected local file.
            //Do not hard-code and do not version control.
            final String base64Key = "ABEiM0RVZneImaq7zN3u/w==";
    
            //Retrieved from a protected database.
            //Do not hard-code and do not version control.
            final String shadowEntry = "AAECAwQFBgcICQoLDA0ODw==:ZtrkahwcMzTu7e/WuJ3AZmF09DE=";
    
            //Extract the iv and the ciphertext from the shadow entry.
            final String[] shadowData = shadowEntry.split(":");        
            final String base64Iv = shadowData[0];
            final String base64Ciphertext = shadowData[1];
    
            //Convert to raw bytes.
            final byte[] keyBytes = Base64.getDecoder().decode(base64Key);
            final byte[] ivBytes = Base64.getDecoder().decode(base64Iv);
            final byte[] encryptedBytes = Base64.getDecoder().decode(base64Ciphertext);
    
            //Decrypt data and do something with it.
            final byte[] decryptedBytes = AES.decrypt(keyBytes, ivBytes, encryptedBytes);
    
            //Use non-blocking SecureRandom implementation for the new IV.
            final SecureRandom secureRandom = new SecureRandom();
    
            //Generate a new IV.
            secureRandom.nextBytes(ivBytes);
    
            //At this point instead of printing to the screen, 
            //one should replace the old shadow entry with the new one.
            System.out.println("Old Shadow Entry      = " + shadowEntry);
            System.out.println("Decrytped Shadow Data = " + new String(decryptedBytes, StandardCharsets.UTF_8));
            System.out.println("New Shadow Entry      = " + Base64.getEncoder().encodeToString(ivBytes) + ":" + Base64.getEncoder().encodeToString(AES.encrypt(keyBytes, ivBytes, decryptedBytes)));
        }
    }
    

    Note that AES has nothing to do with encoding, which is why I chose to handle it separately and without the need of any third party libraries.

提交回复
热议问题