Найдите число, взаимно простое с модулем

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

Вот как работает RSA:

  • Во-первых, вы генерируете значение n, произведение двух простых чисел, выбранных случайным образом:

    n = p * q
    
    • Затем вам понадобится ваш открытый ключ, который называется e. Это может быть любое число, взаимно простое с φ(n):

      mcd(φ(n), e) = 1

    • Согласно функции Эйлера, φ(n) = (p-1)(q-1)

    • Вам по-прежнему нужен закрытый ключ, известный как d, который является инверсией e on modulo **φ(n).

    • So d * e = 1 (mod φ(n))

    • n и e — ваши общедоступные значения, а d — ваш закрытый ключ. Никто не должен знать p или q, так как с этими значениями можно было бы получить φ(n) и использовать его для вычисления d.
  • Чтобы зашифровать сообщение, мы используем M = m^e (mod n), где m — исходное сообщение, а M — зашифрованное. Таким образом, каждый может отправить вам зашифрованное сообщение, которое вы сможете прочитать, используя ваши общедоступные значения.
  • Чтобы расшифровать сообщение, вы используете d, так как это значение, обратное e, поэтому M^d = (m^e)^d = m (mod n). Сообщение можно расшифровать, но только с помощью d.

Зная это, чтобы зашифровать сообщение, нам просто нужно получить два случайных простых числа, вычислить n, e, d, и создать наши методы шифрования и дешифрования.


Теоретически это кажется довольно простым, теперь давайте превратим это в java-код:

Сначала я выбираю два случайных простых числа, чем больше число, тем сильнее шифрование. Так что я выберу p = 1644623 и q = 1644751. Согласно этой странице, это простые числа.

BigInteger p = new BigInteger("1644623");
BigInteger q = new BigInteger("1644751");

Затем в моем методе инициализации я инициализирую n, e и d:

BigInteger p = new BigInteger("1644623");
BigInteger q = new BigInteger("1644751");

BigInteger n;
BigInteger e;
BigInteger d;

void init() {
    n = p.multiply(q);

    BigInteger pn = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));

    e = n.subtract(pn);
    while (!mcd(pn, e).equals(BigInteger.ONE)) {
        e = e.add(BigInteger.ONE);
        System.out.println(e);
    }

    d = e.modPow(new BigInteger("-1"), pn);
}

Я использовал BigInteger вместо long, так как используемые значения очень велики.

Теоретически все работает. Практически pn = 2704992034500, так что проверить, если mcd(pn, e) = 1, и если не добавить 1 к e, и попробовать еще раз, это не вариант. Эта программа работает уже 30 минут, в среднем 150 000 номеров в секунду. e = 548151505 и до сих пор не найден mcd(pn, e) = 1.


Есть ли способ найти e за разумное время?



person Juanco    schedule 03.02.2016    source источник
comment
Разве это не то, что делает расширенный алгоритм Евклида? en.wikipedia.org/wiki/Extended_Euclidean_algorithm   -  person Thilo    schedule 03.02.2016
comment
Нет такой вещи, как mcd. Возможно, вы сделали опечатку, потому что это gcd или алгоритм Евклида.   -  person Artjom B.    schedule 03.02.2016
comment
Это для получения закрытого ключа (d) из открытого (e), что является следующим шагом и может быть выполнено просто d (mod n) = e^-1. Что я пытаюсь сделать, так это сгенерировать e, открытый ключ.   -  person Juanco    schedule 03.02.2016
comment
@ArtjomB это абсолютно то же самое, только в моей стране это известно как mcd (maximo comun divisor), что является испанским переводом gcd (наибольший общий делитель).   -  person Juanco    schedule 03.02.2016
comment
Как ответил пользователь448810, вам не нужно находить e, вы просто устанавливаете его в какое-то общее значение. Если вы действительно заинтересованы в поиске уникального e, то этот вопрос, вероятно, лучше подходит для математики или Криптография. Пожалуйста, проверьте, не задавался ли уже подобный вопрос. Причина, по которой простые числа Ферма выбираются как e, заключается в том, что количество установленных битов должно быть низким для быстрого шифрования и быстрой проверки подписи.   -  person Artjom B.    schedule 03.02.2016
comment
@ Тило Нет, это не так.   -  person Artjom B.    schedule 03.02.2016
comment
@Juanco: Можете ли вы показать нам реализацию mcd?   -  person Mark Dickinson    schedule 03.02.2016


Ответы (1)


Любое простое число будет взаимно простым с модулем по определению, поэтому вам не нужно искать его, просто выберите простое число. Поскольку ключ шифрования общедоступен, в большинстве реализаций RSA используется то, что упрощает вычисление модульного возведения в степень: 3 и 65537 = 2 ** 16 + 1 являются простыми, и оба обычно используются для ключа шифрования.

person user448810    schedule 03.02.2016
comment
Обычно используются следующие варианты: числа Ферма. Кроме того, 3 — очень плохой выбор, если используется учебник RSA. - person Artjom B.; 03.02.2016
comment
@ArtjomB.: Но в этом случае проблема не в использовании 3. Проблема в учебнике RSA. - person user2357112 supports Monica; 03.02.2016
comment
Любое простое число будет взаимно простым с модулем по определению. Это неправда: маленькое простое число легко может быть делителем phi(n). В примере, который дал ОП, phi(n) делится на 3, поэтому, например, использование e = 3 не вариант. Если вы собираетесь всегда использовать 3, вам нужно приложить дополнительные усилия, чтобы убедиться, что ни одно из выбранных вами простых чисел не конгруэнтно 1 по модулю 3. Точно так же, если вы заранее решите, что хотите использовать e = 65537. - person Mark Dickinson; 03.02.2016
comment
@MarkDickinson: Другими словами, для экспонентов важна взаимная простота с phi(n), не взаимная простота с n. - person President James K. Polk; 04.02.2016
comment
@JamesKPolk: А, хорошая мысль; мое слишком быстрое чтение не заметило взаимного простого числа с битом модуля. Поэтому я беру свои слова обратно: утверждение, которое я цитировал, истинно верно (при условии, что вы не выбираете сами p или q), но не очень полезно. - person Mark Dickinson; 04.02.2016