Ошибка в алгоритме проверки подписи в серверных скриптах на PHP
Ошибка в алгоритме проверки подписи в серверных скриптах примера на PHP
https://download.rutoken.ru/Rutoken_Web … TW_PHP.zip
Немного теории:
Пусть P = (x,y), тогда обратной к точек P является точка -P = (x, -y). Сумма P + (-P) = бесконченость.
Сумма точек P = (x1,y1) и Q = (x2,y2), где P != -Q, вычисляется по формулам:
x3 = L^2 - x1 - x2
y3 = L * (x1 - x3) - y1
L = (y2 - y1) / (x2 - x1), если P != Q
L = (3 * x1^2 + a) / (2 * y1), если P == Q
Переходим к коду
файл crypto\classes\Point.php
функция add
Разберём следующий код:
if (gmp_Utils::gmp_mod2(gmp_cmp($p1->x, $p2->x), $p1->curve->getPrime()) == 0) {
if (gmp_Utils::gmp_mod2(gmp_add($p1->y, $p2->y), $p1->curve->getPrime()) == 0) {
return self::$infinity;
} else {
return self::double($p1);
}
}
1.
Первая строка
if (gmp_Utils::gmp_mod2(gmp_cmp($p1->x, $p2->x), $p1->curve->getPrime()) == 0) {
1.1
Нам нужно проверить, что x1 == x2
gmp_cmp вернет 0, если x1 == x2. Положительное число, если x1 > x2, и отрицательное, если x1 < x2.
Результат сравнения (знаковое целое) передаётся в функцию gmp_Utils::gmp_mod2, там происходит деление.
Хотя этот код работает, но корректее будет использовать gmp_sub
1.2
Функция gmp_Utils::gmp_mod2 вернет строку с числом и далее она сравнивается с целочисленным нулем.
Да, в PHP делается приведение типов, но корректнее будет использовать gmp_cmp для сравнения.
2.
Следующая строка
if (gmp_Utils::gmp_mod2(gmp_add($p1->y, $p2->y), $p1->curve->getPrime()) == 0) {
Аналогично, для сравнения нужно использовать gmp_cmp
3.
Собственно, главная ошибка.
В коде проверется случай что y1 == -y2.
Но не проверяется случай y1 == y2 (то есть случай, когда P = Q)
Нужно добавить проверку
else if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_sub($p1->y, $p2->y), $p1->curve->getPrime()), '0') === 0)
Таким образом, код должен выглядеть так:
if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_sub($p1->x, $p2->x), $p1->curve->getPrime()), '0') === 0)
{
if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_add($p1->y, $p2->y), $p1->curve->getPrime()), '0') === 0)
{
return self::$infinity;
}
else if (gmp_cmp(gmp_Utils::gmp_mod2(gmp_sub($p1->y, $p2->y), $p1->curve->getPrime()), '0') === 0)
{
return self::double($p1);
}
}