Initial bytes incorrect after Java AES/CBC decryption

前端 未结 10 2042
鱼传尺愫
鱼传尺愫 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:19

    Optimized version of the accepted answer.

    • no 3rd party libs

    • includes IV into the encrypted message (can be public)

    • password can be of any length

    Code:

    import java.io.UnsupportedEncodingException;
    import java.security.SecureRandom;
    import java.util.Base64;
    
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class Encryptor {
        public static byte[] getRandomInitialVector() {
            try {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
                SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
                byte[] initVector = new byte[cipher.getBlockSize()];
                randomSecureRandom.nextBytes(initVector);
                return initVector;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return null;
        }
    
        public static byte[] passwordTo16BitKey(String password) {
            try {
                byte[] srcBytes = password.getBytes("UTF-8");
                byte[] dstBytes = new byte[16];
    
                if (srcBytes.length == 16) {
                    return srcBytes;
                }
    
                if (srcBytes.length < 16) {
                    for (int i = 0; i < dstBytes.length; i++) {
                        dstBytes[i] = (byte) ((srcBytes[i % srcBytes.length]) * (srcBytes[(i + 1) % srcBytes.length]));
                    }
                } else if (srcBytes.length > 16) {
                    for (int i = 0; i < srcBytes.length; i++) {
                        dstBytes[i % dstBytes.length] += srcBytes[i];
                    }
                }
    
                return dstBytes;
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
            }
    
            return null;
        }
    
        public static String encrypt(String key, String value) {
            return encrypt(passwordTo16BitKey(key), value);
        }
    
        public static String encrypt(byte[] key, String value) {
            try {
                byte[] initVector = Encryptor.getRandomInitialVector();
                IvParameterSpec iv = new IvParameterSpec(initVector);
                SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
                cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
    
                byte[] encrypted = cipher.doFinal(value.getBytes());
                return Base64.getEncoder().encodeToString(encrypted) + " " + Base64.getEncoder().encodeToString(initVector);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
    
            return null;
        }
    
        public static String decrypt(String key, String encrypted) {
            return decrypt(passwordTo16BitKey(key), encrypted);
        }
    
        public static String decrypt(byte[] key, String encrypted) {
            try {
                String[] encryptedParts = encrypted.split(" ");
                byte[] initVector = Base64.getDecoder().decode(encryptedParts[1]);
                if (initVector.length != 16) {
                    return null;
                }
    
                IvParameterSpec iv = new IvParameterSpec(initVector);
                SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
    
                byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedParts[0]));
    
                return new String(original);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
    
            return null;
        }
    }
    

    Usage:

    String key = "Password of any length.";
    String encrypted = Encryptor.encrypt(key, "Hello World");
    String decrypted = Encryptor.decrypt(key, encrypted);
    System.out.println(encrypted);
    System.out.println(decrypted);
    

    Example output:

    QngBg+Qc5+F8HQsksgfyXg== yDfYiIHTqOOjc0HRNdr1Ng==
    Hello World
    

提交回复
热议问题