Перейти к содержимому
ecdsa.com
Python cryptographyPython: пакет cryptography

Сообщение об ошибке

Invalid EC key. Point is not on the curve specified.

Воспроизведено на cryptography 50.0. EllipticCurvePublicKey.from_encoded_point() сообщает о той же ошибке короче: «Invalid EC key.». Другие стеки формулируют её по-своему: стек ошибок OpenSSL 1.1 выдаёт «point is not on curve», Node отклоняет JWK с сообщением «Invalid JWK EC key», — но математика за всеми этими сообщениями одна и та же.

Python cryptography — ValueError from EllipticCurvePublicNumbers.public_key()

Что это означает

Переданная пара (x, y) не удовлетворяет уравнению кривой y² = x³ + ax + b (mod p) для указанной кривой. Библиотеки проверяют это при импорте, потому что, если принимать точки вне кривой, становятся возможны атаки с недопустимой кривой (invalid-curve attacks), которые могут привести к утечке закрытых ключей, — так что отказ здесь — защитная проверка, а не педантизм. Проверка сводится к одному дешёвому вычислению уравнения кривой, и её выполняет любая серьёзная библиотека: точку вне кривой где-нибудь да отклонят, и лучше здесь, с явной ошибкой, чем дальше по цепочке обработки.

Почему это происходит

Как исправить

  1. 1.

    Соберите ключ из закодированной точки с правильной кривой

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

    python
    from cryptography.hazmat.primitives.asymmetric import ec
    
    point = b"\x04" + x_bytes + y_bytes          # uncompressed, 65 bytes for P-256
    key = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), point)
    # if that raises, test: ec.SECP256K1() — the other 256-bit suspect
  2. 2.

    Проверьте исходные данные

    Перед сборкой ключа убедитесь, что длина координат — 32 байта, а значения правдоподобны; отброшенные нули восстановите дополнением координаты нулями слева.

    python
    print(len(x_bytes), len(y_bytes))        # must be 32, 32 for P-256
    x_bytes = x_bytes.rjust(32, b"\x00")     # repair stripped leading zeros
    y_bytes = y_bytes.rjust(32, b"\x00")

Связанные ошибки

Открыть всю базу ошибок подписей