Сообщение об ошибке
cryptography.exceptions.InvalidSignature
Исключение выбрасывается без текста сообщения: трассировка стека заканчивается голым именем класса (воспроизведено на cryptography 50.0).
Python cryptography — raised by verify()
Что это означает
public_key.verify(signature, data, ...) установил, что подпись не проходит проверку для этих данных с этим ключом. Всё разобрано успешно, просто проверка не пройдена. Исключение намеренно не содержит подробностей, поэтому для диагностики приходится проверять каждую часть входных данных по отдельности: ключ, байты данных, кодирование подписи и хеш.
Почему это происходит
Подпись raw r‖s там, где ожидается DER
частоМетод verify() для ECDSA в библиотеке cryptography принимает ASN.1 DER. 64-байтовая подпись в формате raw из WebCrypto, JWS или режима «raw» другой библиотеки не распознаётся как некорректная: verify() выбрасывает то же голое InvalidSignature, что и при подделке, поэтому такую путаницу так легко пропустить.
Байты данных отличаются
частоРазница в кодировке str и bytes, перевод строки в конце, повторная сериализация JSON с другим порядком ключей или пробелами: подпись создаётся и проверяется по точным байтам, и «семантически идентичное» ещё не значит идентичное.
Двойное хеширование из-за неверного использования Prehashed
частоverify(sig, data, ec.ECDSA(hashes.SHA256())) сам хеширует data. Если передать уже вычисленный дайджест без utils.Prehashed, дайджест будет захеширован повторно — это одна из трёх самых частых причин загадочных сбоев проверки.
Не тот ключ или не тот хеш
иногдаОткрытый ключ после ротации или просто не тот, либо проверка с SHA-256 того, что подписано с SHA-384. Хеш — часть схемы подписи, а не свободный параметр.
Как исправить
- 1.
Преобразуйте подписи raw в DER
Если подпись занимает 64 байта (P-256), перед проверкой разделите её на r и s и закодируйте заново в DER.
python from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature r = int.from_bytes(raw_sig[:32], "big") s = int.from_bytes(raw_sig[32:], "big") der_sig = encode_dss_signature(r, s) public_key.verify(der_sig, message, ec.ECDSA(hashes.SHA256())) - 2.
Используйте Prehashed для заранее вычисленных дайджестов
Если у вас дайджест, а не само сообщение, укажите это явно, иначе библиотека захеширует ваш хеш.
python from cryptography.hazmat.primitives.asymmetric import utils public_key.verify( der_sig, digest_bytes, # already SHA-256(message) ec.ECDSA(utils.Prehashed(hashes.SHA256())), ) - 3.
Выясните, какие входные данные неверны
Вставьте ключ, сообщение и подпись в инструмент разбора ошибок ниже: он проверяет обычные гипотезы о несоответствии (не тот хеш, raw вместо DER, двойное хеширование, нормализация high-S, не та кривая) и называет ту, при которой ваша подпись проходит проверку.