javax.crypto.BadPaddingException: блок пэда иногда поврежден - PullRequest
1 голос
/ 18 апреля 2019

У меня есть следующий код для шифрования

public static String encrypt(String value, char[] secret) {
        try {
            final byte[] bytes = value != null ? value.getBytes(StandardCharsets.UTF_8) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(secret));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().getDeviceUniqueIdentifier().getBytes(StandardCharsets.UTF_8), 20));
            return new String(Base64.encodeBase64(pbeCipher.doFinal(bytes)), StandardCharsets.UTF_8);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;

    }

и следующий код для дешифрования.

public static String decrypt(String value, char[] secret) {
        try {
            final byte[] bytes = value != null ? Base64.decodeBase64(value.getBytes(StandardCharsets.UTF_8)) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(secret));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().getDeviceUniqueIdentifier().getBytes(StandardCharsets.UTF_8), 20));
            return new String(pbeCipher.doFinal(bytes), StandardCharsets.UTF_8);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;

    }

Однако иногда возникает исключение на

pbeCipher.doFinal(bytes)

в методе дешифрования.

Исключение составляет javax.crypto.BadPaddingException: pad block corrupted

Это странно, поскольку иногда я получаю это исключение с теми же значениями.

Есть идеи?Спасибо.

Ответы [ 2 ]

2 голосов
/ 19 апреля 2019

Наиболее вероятная причина - просто неверный пароль. Если указан неправильный пароль, то выводится неправильный ключ. Затем зашифрованный текст будет расшифрован до открытого текста. Это будет замечено только в том случае, если возникнет исключение заполнения: распадание случайных байтов может завершиться неудачей.

Вы могли бы, например, сначала проверьте правильность производного ключа, выполнив HMAC над известными данными, используя производный ключ. Кроме того, было бы неплохо использовать какое-либо аутентифицированное шифрование, чтобы , если ключ или данные были неверными или поврежденными, дешифрование действительно завершилось неудачей. Если вам не повезло, тогда - в этот раз - данные будут расшифрованы, удастся завершить загрузку, и вы получите чистый текстовый мусор.

Конечно, вам лучше перейти на PBKDF2 для получения ключа и обновить AES, например, до. AES-GCM вместо DES. В настоящее время ваше шифрование совершенно небезопасно, даже если вы используете надежный пароль.

1 голос
/ 19 апреля 2019

Ваша проблема:

IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().getDeviceUniqueIdentifier().getBytes(StandardCharsets.UTF_8)

Я запускал следующий код несколько раз, и исключений не было, и расшифрованные данные были равны «Привет!»:

public static void main(String[] args)
    {
        new CryptographyError();
    }

    private CryptographyError()
    {
        char[] secret = "MySecret".toCharArray();
        String mesasge = "Hello there!";
        EncryptedData encryptedData = encrypt(mesasge, secret);
        System.out.println("ENCRYPTED " + encryptedData.encryptedString);
        String decrypted = decrypt(encryptedData, secret);
        System.out.println("DECRYPTED " + decrypted);
    }

    private static final SecureRandom RANDOM = new SecureRandom();

    public static EncryptedData encrypt(String value, char[] secret) {
        try {
            final byte[] bytes = value != null ? value.getBytes(StandardCharsets.UTF_8) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(secret));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            byte[] salt = new byte[8];
            RANDOM.nextBytes(salt);
            pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(salt, 20));
            return new EncryptedData(salt, new String(Base64.getEncoder().encode(pbeCipher.doFinal(bytes)), StandardCharsets.UTF_8));

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(value);
        }
        return null;

    }

    public static String decrypt(EncryptedData encryptedData, char[] secret) {
        try {
            String value = encryptedData.encryptedString;
            byte[] salt = encryptedData.salt;
            final byte[] bytes = value != null ? Base64.getDecoder().decode(value.getBytes(StandardCharsets.UTF_8)) : new byte[0];
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey key = keyFactory.generateSecret(new PBEKeySpec(secret));
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(salt, 20));
            return new String(pbeCipher.doFinal(bytes), StandardCharsets.UTF_8);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    private static class EncryptedData
    {
        private final byte[] salt;
        private final String encryptedString;

        private EncryptedData(byte[] salt, String encryptedString)
        {
            this.salt = salt;
            this.encryptedString = encryptedString;
        }
    }

Единственное основное различие между моим кодом и вашим кодом -

IsoGame.$().crossPlatformManager.getCrossPlatformUtilsInstance().getDeviceUniqueIdentifier().getBytes(StandardCharsets.UTF_8)

, что означает, что при шифровании и дешифровании не должно возвращаться одно и то же значение.Также, если вы хотите проверить это, вы можете просто изменить соль между ними и заметить, что исключение выдается снова.

Также Мартен Бодьюс дал вам несколько хороших замечаний о том, как улучшить ваш код.

...