Nano Hash - криптовалюты, майнинг, программирование

javax.crypto.BadPaddingException: блок пэдов иногда повреждается

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

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

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

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


  • Не пытайтесь удовлетворить нуль, используя new byte[0] в любом направлении. m бросьте NullPointerException. Это ошибка программирования. Вы не можете его декодировать, так зачем кодировать? 18.04.2019
  • Привет @ user207421. Ага, ты прав) 19.04.2019
  • Кажется, есть только две проблемы: одна - предложенная Маартеном причина, другая - как вы получаете соль. Вы уверены, что вывод IsoGame... всегда одинаков? 19.04.2019
  • @kelalaka Вывод IsoGame... всегда должен быть одинаковым. Это идентификатор пакета моего приложения на iOS и идентификатор устройства на Android. Я не думаю, что это может измениться сразу после повторного открытия моего приложения. Тем не менее, я испытываю эту проблему на обеих платформах. Итак, я не думаю, что проблема исходит от IsoGame.... 19.04.2019
  • Так что же на самом деле иногда? = 1/5 1/10 и т. д.? 19.04.2019
  • @келалака. Не знаю, правда. Но я думаю, что-то вроде 1/500 или около того. Поскольку я получил это от производственных пользователей и был рад вчера столкнуться с этой проблемой и на своей стороне (в первый раз). 19.04.2019
  • Вы обязательно должны изменить шифрование. ДЕС? По крайней мере, используйте AES-GCM. 19.04.2019
  • Согласен @kelalaka. Но проблема в том, что приложение находится в разработке уже около 5 месяцев, и у него 50 тысяч активных пользователей в месяц, и они сохранили данные в настройках своих телефонов. Так что, если я поменяю шифрование, то они потеряют свои данные) P.S., но если другого выхода нет, то сделаю это обходным путем) :) 19.04.2019
  • Кроме того, чтобы убедиться, что пользователь ввел правильный пароль, вы можете зашифровать известный открытый текст и сохранить его во внутренней памяти. Перед шифрованием/дешифрованием вы можете проверить пароль. Примечание: этот метод может обеспечить атаку по известному открытому тексту. Кроме того, есть очень быстрые DES взломщики 19.04.2019
  • Привет @GagBaghdasaryan, ты нашел решение своего вопроса? 10.06.2020

Ответы:


1

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

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

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

19.04.2019
  • Привет. Вы имеете в виду, что секрет char[] неверен? Если да, то это константа) P.S., я использую это для Preferences. 19.04.2019
  • Я не вижу, что идет не так, поскольку я вижу код, но не контекст кода, ввод или вывод. Однако, если у вас есть наглость по-прежнему использовать DES и возвращать открытый текст вместо зашифрованного текста при любом исключении во время шифрования, то, я думаю, все потеряно. Черт возьми, вы могли пытаться расшифровать открытый текст все это время. Ой, подождите, если вы расшифруете открытый текст и заполнение будет правильным, тогда ваш метод завершится ошибкой с мусором в результате. Ха :) Если вам нужен более точный ответ, укажите неверные значения теста. 19.04.2019
  • Меня иногда раздражает. Если бы не было кодировки base64, это было бы причиной. Думаю, Мартен прав. 19.04.2019
  • Хммм.... @MaartenBodewes Например, входное значение для encrypt() равно 703, а результат dGwO/zHe/Pg= . Затем я получаю исключение в decrypt() для значения dGwO/zHe/Pg=. P.S. Исключение не выдается каждый раз для значения 703. Не могу воспроизвести, почему он брошен. 19.04.2019

  • 2

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

    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)
    

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

    Также Maarten Bodewes дал вам несколько полезных заметок о том, как улучшить ваш код.

    19.04.2019
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..