Кодирование алгоритма RSA Java

Итак, я пытаюсь создать алгоритм RSA с нуля.

На данный момент я успешно создал возможность выбора двух простых чисел (в моем текущем примере это 11 и 13). Затем я вычисляю N, выполняя p x q. Получается 143.

Затем я перехожу к моему методу public BigInteger findZ(), который вычисляет ϕ, который равен (p-1)(q-1).

Используя этот вновь вычисленный ϕ, я хочу найти число или, скорее, создать переменную e, которая следует за 1‹(e)‹ϕ, или простым gcd(e,ϕ) = 1. Таким образом, я изначально установил temp равным моей константе ONE (что равно единице) + 1, чтобы удовлетворить диапазон. Однако после непрерывных попыток отладки цикл так и не находит значение, имеющее GCD, равное единице, для представления которого я создал константу, поскольку мне необходимо использовать BigInteger. Есть причина для этого?

Вот мой код.

import java.math.BigInteger;

public class RSA 
{
//Intialize the variables.

private BigInteger p;
private BigInteger q;
private BigInteger n;
private BigInteger z;

final private BigInteger ONE = BigInteger.valueOf(1);


public BigInteger getP()
{
    return p;
}

public BigInteger getQ()
{
    return q;
}

//Computes N, which is just p*q.
public BigInteger findN()
{

    n = p.multiply(q);


    return p.multiply(q);
}


public BigInteger findZ()
{
    long pMinusOne = p.intValue() - 1;
    long qMinusOne = q.intValue() - 1;


    z = BigInteger.valueOf(pMinusOne * qMinusOne);

    return z;
}


public BigInteger getE()
{
     int temp = ONE.intValue() + 1;

     BigInteger GCD = BigInteger.valueOf(temp);

     while (GCD.gcd(z).compareTo(ONE) != 0)
     {
         temp++;
     }



    e = BigInteger.valueOf(temp);

    return e;
}

}

Любая помощь приветствуется.

Спасибо!


person Granzo    schedule 28.09.2018    source источник
comment
Что меняется в этом коде while (GCD.gcd(z).compareTo(ONE) != 0) { temp++; } Единственное, что меняется, это temp, которая является локальной переменной, поэтому цикл никогда не закончится, поскольку он не меняется   -  person Scary Wombat    schedule 28.09.2018
comment
Что ж, temp изменяется в цикле, так что даже если она объявляется локально, она должна меняться. Что-то вроде индексации в цикле for, верно?   -  person Granzo    schedule 28.09.2018
comment
Нет, while (GCD.gcd(z).compareTo(ONE) != 0) не использует temp, поэтому его изменение не имеет значения.   -  person Scary Wombat    schedule 28.09.2018
comment
@ScaryWombat Даже после удаления temp изменение GDC на значение BigInteger.valueOf(2); затем зацикливание и выполнение GCD.add(ONE); пока сравнение не станет истинным, цикл будет продолжаться вечно. Так что в любом случае разницы все равно нет.   -  person Granzo    schedule 28.09.2018
comment
Я также пытался запустить переменную GCD с z-1, однако это приводит к немедленному завершению цикла, поэтому мое e всегда будет на единицу меньше, чем z, что, я считаю, не работает.   -  person Granzo    schedule 28.09.2018
comment
Страшный Вомбар пытается сказать, что вы сравниваете GCD.gcd(z) с ONE, и если это сравнение не равно нулю, вы меняете значение temp. Но изменение значения temp никак не влияет ни на одно из сравниваемых значений, поэтому цикл продолжается вечно.   -  person 1615903    schedule 28.09.2018


Ответы (1)


Поскольку вы просили о какой-либо помощи, я отвечу на ваш вопрос и дам другие советы.

Как получить e

Один из советов — использовать equals() вместо compareTo(), когда вы просто проверяете равенство. Иногда это может уменьшить объем выполняемой работы, а также его легче читать.

Самая большая ошибка в вашем коде заключается в том, что temp используется для установки исходного значения GCD, но это не связывает temp с НОД. Они остаются отключенными. Если вы измените temp позже, GCD не узнает об этом и не изменит. Вам нужно добавить один в GCD напрямую. Вот пример кода:

BigInteger e = BigInteger.valueOf(3);
while (! phi.gcd(e).equals(BigInteger.ONE)) {
    e = e.add(BigInteger.ONE);
}

Просмотрите методы BigInteger

Получите представление о том, что вы можете легко сделать с BigInteger, используя свою любимую поисковую систему и выполнив поиск BigInteger 8 API. 8 соответствует версии Java, которую вы используете, так что это может измениться. API предназначен для списка методов.

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

Используйте встроенные константы BigInteger.

Не создавайте повторно следующие константы (которые отображаются на странице API выше):

  • BigInteger.ZERO
  • BigInteger.ONE
  • BigInteger.TEN

Никогда не конвертируйте BigInteger в long, если вы не уверены, что оно подойдет.

Вы конвертируете BigInteger в long, что является плохой идеей, так как есть много BigInteger, которые не помещаются в long, что дает неверные результаты. Для корректности (что важнее скорости) выполняйте арифметические действия напрямую с BigIntegers.

Вы также часто используете intValue(), когда получаете long. Используйте longValueExact(). Если на то пошло, используйте intValueExact(), когда вы получаете int.

Итак, для расчета ϕ:

BigInteger pMinusOne = p.subtract(BigInteger.ONE);
BigInteger qMinusOne = q.subtract(BigInteger.ONE);

BigInteger phi = pMinusOne.multiply(qMinusOne);

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

Что хранить

Вы также должны хранить только n и ed, но только если это закрытый ключ) Никогда не хранить < em>p, q или ϕ с RSA, потому что они позволяют легко определить закрытый ключ из открытого ключа.

В общем, не считайте getZZZ методами

Вы должны вычислить n и ed, но только если это закрытый ключ) в методах конструктора и сохранить только те в переменных экземпляра. Затем у вас может быть метод getN() и getE() для получения предварительно вычисленных переменных экземпляра. Например (и вам не обязательно использовать этот код, просто чтобы дать представление):

public class RSA {
    private final BigInteger n;
    private final BigInteger e;
    private final BigInteger d;

    public RSA(final BigInteger p, final BigInteger q) {
        this.n = p.multiply(q);

        // Calculate phi
        final BigInteger pMinusOne = p.subtract(BigInteger.ONE);
        final BigInteger qMinusOne = q.subtract(BigInteger.ONE);
        final BigInteger phi = pMinusOne.multiply(qMinusOne);

        // Calculate e
        BigInteger e = BigInteger.valueOf(3L);
        while (! phi.gcd(e).equals(BigInteger.ONE)) {
            e = e.add(BigInteger.ONE);
        }
        this.e = e;

        // Calculate d
        this.d = e.modInverse(phi);
    }

    public BigInteger getN() {
        return n;
    }

    public BigInteger getE() {
        return e;
    }

    public BigInteger getD() {
        return d;
    }
}
person Chai T. Rex    schedule 28.09.2018
comment
Феноменально объяснил! Большое спасибо! Это очень полезно. Я никогда не работал с BigInteger до вчерашнего дня, поэтому я не просматривал API так тщательно, как должен был. - person Granzo; 29.09.2018
comment
У меня только вопрос, какова стоимость 3L? - person Granzo; 29.09.2018
comment
@Granzo Поставить L после числа означает рассматривать число как long вместо стандартного int. Итак, значение 3L — это просто значение long 3. Здесь он не нужен, так как 3 (int) будет прекрасно преобразован в 3L (long), но я использую его по привычке везде, где ожидается long, потому что число может переполниться без L, если оно слишком велико для хранения в int и привычка позволяет избежать этой проблемы. - person Chai T. Rex; 29.09.2018
comment
Извините, последний вопрос. Когда я вызываю return d, кажется, что он возвращает неправильное значение. Например, я тестирую его со значениями p, равными 5, и q, равными 7. Однако после вычислений я получаю, что D = 5. Разве это не должно быть равно 29? - person Granzo; 01.10.2018
comment
Ну, и да, и нет, d = 29 также подойдет для расшифровки вещей, но фи равно 24, поэтому вы всегда должны уменьшать d по модулю фи, чтобы сократить последующие вычисления. Уменьшая 29 по модулю фи, мы получаем 29 ≡ 5 (мод 24), поэтому d = 5 также подходит для расшифровки, и требуется меньше времени для вычислений и (когда числа становятся больше) меньше места для хранения. - person Chai T. Rex; 01.10.2018