Насколько безопасен мой класс расшифровки пароля? - PullRequest
4 голосов
/ 06 июня 2011

Я полный новичок в любом виде расшифровки.Я написал класс, который, я думаю, должен быть вполне безопасным.Можете ли вы дать мне конструктивную критику, как я мог бы улучшить алгоритм.

package main;

import java.util.Random;

public class Main {

   public static void main(String[] args) {
      //we will be playing around with this string
      new Main("1234567890abc");
   }

   private Random rnd;
   private byte[] randoms;

   /**
    * Starts up RNG
    * Prints out a test
    */
   public Main(String password) {
      //random long generated from the password
      long randomLong = randomNumber(password);
      //Random class using randomLong as seed
      rnd = new Random(randomLong);
      randoms = new byte[password.length()];
      //Array of random bytes generated with rnd
      rnd.nextBytes(randoms);

      System.out.println(randomNumber(password));

      String cryped = encrypt(password);
      String decryped = decrypt(cryped);

      System.out.println(cryped);
      System.out.println(decryped);
   }

   /**
    * Encrypts the password.
    */
   private String encrypt(String password) {
      char[] chars = password.toCharArray();      
      for (int i = 0; i < chars.length; i++) {
         chars[i] = (char) (chars[i] + randoms[i]);
      }
      return String.valueOf(chars);
   }

   /**
    * Decrypts an allready encryped password.
    */
   private String decrypt(String crypted) {
      char[] chars = crypted.toCharArray();
      for (int i = 0; i < chars.length; i++) {
         chars[i] = (char) (chars[i] - randoms[i]);
      }
      return String.valueOf(chars);
   }

   /**
    * Finds a random number BASED ON PASSWORD
    */
   private long randomNumber(String password)
   {
      char[] chars = password.toCharArray();
      long number = 0;
      for (char c : chars) {
         number += c;
      }
      number *= chars.length;
      return number;
   }
}

Класс написан на Java, но должен быть доступен для чтения любому.

Ответы [ 2 ]

10 голосов
/ 06 июня 2011
  1. Не изобретайте свою собственную криптографию в реальной жизни (это упражнение?) Даже эксперты делают ошибки. Используйте то, что было публично изучено.
  2. Генератор случайных чисел Java не является криптографически безопасным. С достаточно длинным текстом для шифрования появятся шаблоны, которые могут допускать утечку различной информации, включая раскрытие пароля (но см. Пункт три) и открытого текста.
  3. Вы используете пароль для заполнения генератора случайных чисел. Это стандартная (и хорошая) идея, но вы делаете это, используя алгоритм, который инвариантен к перестановке! т. е. ваше шифрование рассматривает "sinecure" и "незащищенный" или другие пароли, которые являются анаграммами, как эквивалентные (и, вероятно, другие тоже). Для надежного пароля длиной до 16 букв и кодовых точек, не превышающих 255, максимально достижимое начальное число составляет 255 * 16 * 16 = 65280; но возможностей еще меньше, так как есть семена ниже этого, которые недоступны. На моей клавиатуре брутфорсинг показывает только 9734 различных начальных числа для паролей, состоящих исключительно из символов, доступных для записи на клавиатуре, за исключением новой строки (я считаю 95) длиной до 16 символов; это меньше, чем 1 бит энтропии на букву.
  4. CodeInChaos имеет несколько дополнительных замечаний в своем ответе: вы используете потоковый шифр (еще сложнее разобраться!). Вы также шифруете пароль, который предполагает, что вы, возможно, ищете хеш, а не функцию шифрования (или это только пример?).
  5. Кстати, если вы пытаетесь хранить пароли; не - даже не зашифрован! Посмотрите на фиаско sony для почему; вас могут взломать, вы можете потерять базу паролей, а ваши ключи шифрования могут быть известны злоумышленнику. Вместо этого используйте стандартное, наилучшее хеширование пароля (и, если возможно, предпочитайте стандартный ранее существующий компонент). Такая система должна по крайней мере использовать безопасный хеш, такой как sha1 или лучше; пароли должны быть индивидуально посолены (соль может храниться в незашифрованном виде), а процесс должен быть дорогостоящим в вычислительном отношении, чтобы сделать грубую силу непривлекательной. Подробнее см. http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html.
9 голосов
/ 06 июня 2011

Ужасно сломан несколькими способами.

  1. Ваш ключ 64-битный, на сегодня немного маловат. Но пока это меньше всего твоих забот.
  2. Я вижу не криптографический PRNG. Вам нужно использовать крипто-PRNG.
  3. Вы повторно используете ключ в потоковом шифре. Потоковые шифры печально известны тем, что их трудно правильно использовать. В этом режиме работы он в основном ведет себя как одноразовая панель, генерируемая PRNG. После повторного использования ключа в таком режиме ваша криптография нарушается.
    Предположим, что злоумышленник знает encrypt(p1) и encrypt(p2). Затем он может вычислить encrypt(p1)-encrypt(p2), что идентично p1-p2.
  4. Ваш эффективный размер ключа намного меньше 64-битного. Сумма символов в строке <2 ^ 16 * длина. И для большинства персонажей это даже <128. Таким образом, ваш ключ обычно будет числом <1000'000. Это просто для грубой силы. </li>
  5. Каждый элемент в randoms является байтом, т. Е. 8 бит. Символ 16 бит. Таким образом, вы не добавляете модуль 256. Таким образом, вы теряете информацию о зашифрованном пароле.

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

А вам действительно нужно расшифровать пароль (т.е. это хранилище паролей), или достаточно хэширования пароля?

Мое предложение состоит в том, чтобы поместить ваш мастер-пароль в функцию-ключ-деривация (PKDF2 является распространенным выбором). Затем используйте ключ, который возвращает эта функция, чтобы зашифровать остаток вашего файла данных с помощью AES.

...