Взлом коротких ключей RSA

Учитывая следующие ключи RSA, как определить значения p и q?

Public Key: (10142789312725007, 5)
Private Key: (10142789312725007, 8114231289041741)

person Donald Taylor    schedule 02.11.2010    source источник
comment
какие алгоритмы вы уже пробовали? Если это для класса теории чисел, в вашем тексте должна быть глава или две по криптоалгоритмам.   -  person Brian Driscoll    schedule 02.11.2010
comment
Это курс по информационной безопасности. Профессор не объяснил, как это сделать, но предлагает это за небольшую дополнительную плату. Я еще не пробовал какой-либо алгоритм, потому что не знаю, как к нему подойти.   -  person Donald Taylor    schedule 02.11.2010
comment
С данным секретным ключом существует быстрый метод факторинга n.   -  person starblue    schedule 02.11.2010
comment
ПРИМЕЧАНИЕ. Я не просил здесь решить проблему, а скорее пытался узнать, как выполнить необходимые вычисления.   -  person Donald Taylor    schedule 11.11.2013
comment
Я голосую за то, чтобы закрыть этот вопрос как не по теме, потому что он не о программировании. Подобные вопросы следует задавать на crypto.stackexchange.com. (Хотя, вероятно, не по теме в его нынешнем виде, из-за отсутствия предварительного исследования).   -  person Duncan Jones    schedule 23.09.2019
comment
@DuncanJones: Существовал ли crypto.stackexchange.com, когда этот вопрос был задан почти десять лет назад?   -  person Donald Taylor    schedule 24.09.2019
comment
@DonaldTaylor Мой комментарий предназначен для будущих читателей вопроса, которые могут увидеть его (надеюсь) закрытым и иметь представление о том, где задавать подобные вопросы в будущем.   -  person Duncan Jones    schedule 24.09.2019


Ответы (12)


Ваш учитель дал вам:

Открытый ключ: (10142789312725007, 5)

что значит

n = 10142789312725007
e = 5 

где n — модуль, а e — общедоступный показатель степени.

Кроме того, вам дается

Закрытый ключ: (10142789312725007, 8114231289041741)

означающий, что

 d = 8114231289041741

где d — показатель степени расшифровки, который должен оставаться в секрете.

Вы можете «сломать» RSA, зная, как разложить «n» на его простые множители «p» и «q»:

n = p * q

Вероятно, самый простой способ — проверить все нечетные числа, начинающиеся чуть ниже квадратного корня из n:

Floor[Sqrt[10142789312725007]] = 100711415

Вы получите первый множитель за 4 попытки:

10142789312725007 mod 100711415 = 100711367
10142789312725007 mod 100711413 = 100711373
10142789312725007 mod 100711411 = 100711387
10142789312725007 mod 100711409 = 0 <-- Winner since it evenly divides n

Итак, у нас есть

 p = 100711409

В настоящее время,

 q = n / p 
   = 10142789312725007 / 100711409
   = 100711423

Почему это важно? Это потому, что d — это специальное число, такое что

d = e^-1 mod phi(n)
  = e^-1 mod (p-1)*(q-1)

Мы можем проверить это

d * e = 40571156445208705 = 1 mod 10142789111302176

Это важно, потому что если у вас есть открытое текстовое сообщение m, то зашифрованный текст

c = m^e mod n

а вы его расшифровываете

m = c^d = (m^e)^d = (m^(e*d)) = (m^(e*e^-1)) = m^1 (mod n)

Например, я могу «зашифровать» сообщение 123456789, используя открытый ключ вашего учителя:

m = 123456789

Это даст мне следующий зашифрованный текст:

c = m^e mod n 
  = 123456789^5 mod 10142789312725007
  = 7487844069764171

(Обратите внимание, что на практике «e» должно быть намного больше, потому что для небольших значений «m» вы даже не превышаете n)

В любом случае, теперь у нас есть "c", и мы можем поменять его местами на "d".

m = c^d mod n
  = 7487844069764171^8114231289041741 mod 10142789312725007
  = 123456789

Очевидно, что вы не можете вычислить "7487844069764171^8114231289041741" напрямую, потому что оно состоит из 128 808 202 574 088 302 цифр, поэтому вы должны использовать модуль возведение в степень трюк.

В «реальном мире» n явно намного больше. Если вы хотите увидеть реальный пример того, как HTTPS использует RSA под прикрытием с 617-значным n и e из 65537, см. мою запись в блоге "Первые несколько миллисекунд соединения HTTPS".

person Jeff Moser    schedule 02.11.2010
comment
Это все еще решение грубой силы, которое не будет работать для больших чисел. - person President James K. Polk; 03.11.2010
comment
Да, для более крупных вам понадобится что-то вроде сита числового поля. Я просто пытался дать что-то практичное для этой конкретной проблемы, которую вы могли бы сделать с помощью calc.exe :) - person Jeff Moser; 03.11.2010
comment
IIRC есть сокращение от факторинга до определения секретного показателя степени в исходном документе CACM RSA. Таким образом, при знании секретного показателя факторизация должна быть возможной намного быстрее, чем с помощью стандартных алгоритмов факторизации, применяемых к n. - person starblue; 03.11.2010
comment
@starblue: см. мой ответ для одного из таких алгоритмов. - person President James K. Polk; 03.11.2010
comment
Привет. Я только что прочитал, как вы находите множители, используя: Floor[Sqrt[10142789312725007]] = 100711415 Мне просто интересно, а что, если один из множителей равен 5? Тогда ваше решение не сработает, не так ли? Я знаю, что мелких факторов следует избегать, но я предполагаю, что они могут появиться. - person Janman; 05.12.2012
comment
Это сработает, но займет больше времени. Обратите внимание, что я начинаю с Floor[Sqrt[x]] и каждый раз считаю в обратном порядке на 2. Это в конечном итоге достигнет 5 - person Jeff Moser; 11.12.2012
comment
@JeffMoser, как вы выяснили, сколько цифр будет в числе? - person temporary_user_name; 02.05.2016
comment
@Aerovistae Я использовал WolframAlpha. - person Jeff Moser; 02.05.2016
comment
Важное примечание для людей, программирующих это. Убедитесь, что результатом Floor[Sqrt[n]] является тип данных int. Многие языки требуют явного приведения! Если оставить его как число с плавающей запятой, выполнение программы может занять в сотни раз больше времени. - person James L.; 15.07.2017

Вот относительно простой способ взглянуть на это (и тот, который выполним вручную). Если бы вы должны были полностью разложить число на множители, то самый высокий фактор, который вам нужно было бы учитывать, - это sqrt (N):

sqrt(10142789312725007) = 100711415.9999997567

Первое простое число ниже этого — 100711409, всего на 6 меньше, чем sqrt(N).

10142789312725007 / 100711409 = 100711423 

следовательно, это два множителя N. Ваш профессор сделал это довольно просто — хитрость в том, чтобы признать, что никто не выберет маленький p или q, поэтому начните проверку снизу (как в скрипте Python кто-то написал) это плохая идея. Если это будет практично вручную, большие p и q должны лежать около sqrt(N).

person ine    schedule 02.11.2010
comment
Вы правы, начиная с максимума выглядит как лучший подход. Я не думал об этом. - person Juri Robl; 02.11.2010

Существуют различные быстрые алгоритмы для решения задачи факторизации n при заданных n, e и d. Вы можете найти хорошее описание одного из таких алгоритмов в Handbook of Applied Cryptography, Глава 8, раздел 8.2.2. Вы можете найти эти главы онлайн для бесплатной загрузки здесь. Алгоритм, по сути, представляет собой тщательную разработку ответа Хенно Брандсма на этот самый вопрос.

ОБНОВЛЕНИЕ 25 сентября 2019 г.:

В комментарии ниже пользователь Imperishable Night предлагает альтернативный метод, который должен быть, по крайней мере, концептуально более простым для понимания.

Он отмечает, что обычно e мало. На самом деле e почти всегда равно 65537. В случае, когда e мало, вы можете построить квадратное уравнение с неизвестным простым числом p и, таким образом, легко решить его, используя, например, квадратичная формула. Чтобы продолжить, давайте установим x=p и найдем x, просто придерживаясь соглашения. Мы знаем, что ed = 1 mod phi(n) или, что то же самое, ed - 1 = k * (p-1)*(q-1). Теперь установив x=p и, следовательно, n/x=q, умножив обе части на x и переставив члены, мы имеем
k*x2 + (d*e - k*n - k - 1)*x + k *n = 0.
Теперь у нас есть уравнение формы ax2 + bx + c = 0, и мы можем найти x, используя квадратичную формулу. Таким образом, мы можем попробовать значения k в небольшом диапазоне около e, и должно быть только одно целочисленное решение квадратного уравнения, решение для правильного k.

Примечания:

  1. Все должно быть целым числом, поэтому дискриминант должен быть полным квадратом, иначе мы можем отбросить k и попробовать следующее. Кроме того, числитель должен делиться на 2*k.
  2. Иногда вместо фи-функции Эйлера используется лямбда-функция Кармайкла. Это немного усложняет ситуацию, потому что теперь мы также должны угадать g = gcd(p-1, q-1). g всегда четно, часто равно 2, а в остальном почти всегда немного кратно 2.

ОБНОВЛЕНИЕ 26 сентября 2019 г.:

Найти k на самом деле очень просто, когда e мало. Взяв уравнение ed - 1 = k * (p-1)*(q-1) и разделив обе его части на n, довольно легко увидеть, что floor((ed-1)/n) + 1 == k. Теперь, используя уравнения 31 и 32 из M.J. Винера "Криптоанализ коротких показателей секретности RSA" можно напрямую восстановить p и q.

person President James K. Polk    schedule 03.11.2010
comment
Думаю, есть концептуально более простое решение, когда e мало, что обычно и бывает в реальных приложениях RSA. В этих случаях ed-1 является небольшим кратным (p-1)(q-1), которое должно быть очень близко к n, поэтому вы можете перебрать все разумные значения (p-1)(q-1), из которых и n=pq вы можете решить простую квадратичную систему уравнений, чтобы найти p и q . - person Imperishable Night; 18.02.2018
comment
@ImperishableNight: я наконец-то добрался до вашего комментария и должен с вами согласиться, ваш метод концептуально проще. Я отредактирую свой ответ, включив в него и ваш метод. - person President James K. Polk; 25.09.2019

Wolframalpha говорит мне, что коэффициенты равны 100711409 и 100711423.

Я только что написал наивный Python-скрипт для брутфорса. Как отметил amdfan, лучше начинать сверху:

p = 10142789312725007
for i in xrange(int(p**0.5+2), 3, -2):
    if p%i == 0:
        print i
        print p/i
        break

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

person Juri Robl    schedule 02.11.2010
comment
Просто предоставление ответа не поможет ОП ... Вольфрамальфа определенно не будет доступен ему / ей на тесте. - person Brian Driscoll; 02.11.2010
comment
Ну, это, безусловно, дает мне ответ! Если никто больше не объяснит, как это сделать вручную, поставлю зеленую галочку. - person Donald Taylor; 02.11.2010
comment
Я думал, ему просто нужны продукты. Его комментарий был после того, как я опубликовал ответ. - person Juri Robl; 02.11.2010
comment
StackOverflow не является гигантским сайтом-калькулятором. Цель сайта — помочь людям понять, как что-то делать. Это не место, где вы просите людей кодировать или вычислять для вас. - person Philippe Carriere; 02.11.2010
comment
@Juri, тег домашнего задания должен был предупредить вас о том, что просто предоставление факторов независимо от того, что запрашивает ОП, не является лучшей практикой. - person Brian Driscoll; 02.11.2010
comment
Все вопросы должны быть оценены, чтобы понять, как лучше всего на них ответить — обратите внимание, что комментарий Сайленса не отличает домашнее задание от остальных. Если плакат должен предоставить больше информации (то есть этот вопрос скудный, как бы вы его ни нарезали), вы должны спросить. Отметка о домашнем задании ни о чем не говорит. Например, если бы я задал этот вопрос (а я определенно больше не делаю домашнюю работу), я бы хотел объяснения, а не двух факторов. - person ; 08.11.2010
comment
ПРИМЕЧАНИЕ. Я не просил здесь решить проблему, а пытался узнать, как выполнить необходимые вычисления. - person Donald Taylor; 11.11.2013
comment
Предоставление факторов и кода очень полезно для пользователей в будущем, таких как я. У меня нет опыта в криптографии и я в CTF. - person Ali Pardhan; 17.09.2020

Определение RSA говорит вам, что модуль n = pq. Вы знаете n, поэтому вам просто нужно найти два числа p и q, которые умножаются на n. Вы знаете, что p и q простые числа, так что это проблема факторизации простых чисел.

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

person Cameron Skinner    schedule 02.11.2010
comment
Не правда! Когда задан показатель степени расшифровки, как в данном случае, проблема проста. - person President James K. Polk; 03.11.2010
comment
Что ж, когда указан показатель расшифровки, у вас есть закрытый ключ, что несколько противоречит цели. Облегчает ли знание d факторизацию? Если да, то можете объяснить? - person Cameron Skinner; 03.11.2010

Вот реализация метода быстрого факторинга на Java из главы Handbook of Applied Cryptography 8 раздел 8.2.2 (спасибо GregS за его нахождение):

/**
 * Computes the factors of n given d and e.
 * Given are the public RSA key (n,d)
 * and the corresponding private RSA key (n,e).
 */
public class ComputeRsaFactors
{
    /**
     * Executes the program.
     *
     * @param args  The command line arguments.
     */
    public static void main(String[] args)
    {
        final BigInteger n = BigInteger.valueOf(10142789312725007L);
        final BigInteger d = BigInteger.valueOf(5);
        final BigInteger e = BigInteger.valueOf(8114231289041741L);

        final long t0 = System.currentTimeMillis();

        final BigInteger kTheta = d.multiply(e).subtract(BigInteger.ONE);
        final int exponentOfTwo = kTheta.getLowestSetBit();

        final Random random = new Random();
        BigInteger factor = BigInteger.ONE;
        do
        {
            final BigInteger a = nextA(n, random);

            for (int i = 1; i <= exponentOfTwo; i++)
            {
                final BigInteger exponent = kTheta.shiftRight(i);
                final BigInteger power = a.modPow(exponent, n);

                final BigInteger gcd = n.gcd(power.subtract(BigInteger.ONE));
                if (!factor.equals(BigInteger.ONE))
                {
                    break;
                }
            }
        }
        while (factor.equals(BigInteger.ONE));

        final long t1 = System.currentTimeMillis();

        System.out.printf("%s %s (%dms)\n", factor, n.divide(factor), t1 - t0);
    }


    private static BigInteger nextA(final BigInteger n, final Random random)
    {
        BigInteger r;
        do
        {
            r = new BigInteger(n.bitLength(), random);
        }
        while (r.signum() == 0 || r.compareTo(n) >= 0);
        return r;
    }
}

Типичный вывод

100711423 100711409 (3ms)
person starblue    schedule 03.11.2010

Эти две статьи могли бы оказаться полезными

Наткнулся на них, когда проводил базовые исследования цепных дробей.

person user498884    schedule 05.11.2010

Алгоритм для этого (и он будет работать для любого примера, а не только для этого маленького, который может быть легко разложен на любом компьютере):

ed - 1 кратно phi(n) = (p-1)(q-1), поэтому оно как минимум кратно 4.
ed - 1 можно вычислить как 40571156445208704, что равно 2^7 * 316962159728193, и мы называем s=7 и t = 316962159728193. (вообще: любое четное число есть степень удвоенного нечетного числа). Теперь выберите a в [2,n-1) наугад и вычислите (путем последовательного возведения в квадрат по модулю n) последовательность a^t (mod n), a^(2t) (mod n), a^(4t) (mod n).. до не более чем a^((2^7)*t) (mod n), где последним гарантированно будет 1, путем построения e и d.

Теперь мы ищем первую 1 в этой последовательности. Тот, что перед ним, будет либо +1, либо -1 (тривиальный корень из 1, mod n), и мы повторяем с другим a или некоторым числом x, которое не равно +1 или -1 mod n. В последнем случае gcd(x-1, n) является нетривиальным делителем n, а значит, p или q, и мы закончили. Можно показать, что случайное a сработает с вероятностью около 0,5, поэтому нам нужно несколько попыток, но в целом не очень много.

person Henno Brandsma    schedule 17.12.2010

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

person Yuval F    schedule 02.11.2010

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

Теперь, чтобы найти частную экспоненту, вы должны найти инверсию публичной экспоненты по модулю totient.

public_exponent * private_exponent = 1 mod totient

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

Я написал код:

// tinyrsa.c
//
// apt-get install libgmp-dev
// yum install gmp-devel
//
// gcc tinyrsa.c -o tinyrsa -lm -lgmp

#include<stdio.h>
#include<gmp.h>

int main()
{
  // declare some multi-precision integers
  mpz_t pub_exp, priv_exp, modulus, totient, fac_p, fac_q, next_prime;

  mpz_init_set_str(pub_exp,"5",10);
  mpz_init_set_str(modulus,"10142789312725007",10);

  mpz_init(priv_exp);
  mpz_init(totient);
  mpz_init(fac_p);
  mpz_init(fac_q);

  // now we factor the modulus (the hard part)
  mpz_init(next_prime);
  mpz_sqrt(next_prime,modulus);
  unsigned long removed=0;
  while(!removed)
  {
    mpz_nextprime(next_prime,next_prime);
    removed=mpz_remove(fac_p,modulus,next_prime);
  }

  mpz_remove(fac_q,modulus,fac_p);
  // we now have p and q

  // the totient is (p-1)*(q-1)  
  mpz_t psub, qsub;
  mpz_init(psub);
  mpz_init(qsub);

  mpz_sub_ui(psub,fac_p,1);
  mpz_sub_ui(qsub,fac_q,1);
  mpz_mul(totient,psub,qsub);

  // inverse of the public key, mod the totient..
  mpz_invert(priv_exp,pub_exp,totient);

  gmp_printf("private exponent:\n%Zd\n",priv_exp);

}

Алгоритм факторизации, который я использовал, глупый, но лаконичный, так что в этом есть доля соли. В этом конкретном примере код запускается почти мгновенно, но это во многом потому, что рассматриваемый инструктор предоставил пример, в котором используются два простых числа подряд, что на самом деле нереально для RSA.

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

person pierce    schedule 19.06.2012
comment
Ему дан частный показатель в его задаче. Факторизация n без использования дополнительной информации не будет работать для больших целых чисел в реальных системах RSA. - person President James K. Polk; 26.09.2019

Вам нужно факторизовать модуль, это первый параметр открытого ключа, 10142789312725007. Подойдет грубая сила (проверьте каждое нечетное число от 3 до sqrt(n), если это фактор), хотя существуют более сложные/быстрые алгоритмы.

Поскольку число слишком велико, чтобы вписаться в обычное целое число (даже 64-битное), вам может понадобиться числовая библиотека, которая поддерживает целые числа произвольной длины. Для C есть GMP и MPIR (более удобный для Windows). Для PHP есть Bignum. Python поставляется со встроенным — встроенный целочисленный тип данных уже имеет произвольную длину.

person Seva Alekseyev    schedule 02.11.2010

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

person Mick Press    schedule 31.05.2017
comment
не могли бы вы объяснить, как вы это делаете? - person Kevin Wallis; 31.05.2017
comment
Я буду, но не раньше, чем я взломаю номера вызовов RSA. В настоящее время я пытаюсь разобраться в c+, cuda и визуальных студиях. По натуре я программист на Паскале. Тем временем, если вам нужен 64-битный взлом, напишите мне по электронной почте с подробностями. - person Mick Press; 01.06.2017