Недавно я столкнулся с той же проблемой, пытаясь поддержать генерацию подписи для приложения Android, которое ожидает эквивалент NONEwithRSA. В моем случае на самом деле это была ситуация, когда приложение использует хеш, но в нем явно отсутствует префикс кода ASN.1.
Оказывается, шифр Java RSA работает как по волшебству за кулисами и автоматически использует заполнение блока подписи типа PKCS#1 (так что каждая комбинация сообщения/ключа создает одну и ту же подпись).
Это вызвало у меня проблемы, потому что я изначально думал, что смогу просто зашифровать необработанный хеш, используя закрытый ключ в Python, и тогда он будет совместим с Java. Однако при шифровании с помощью закрытого ключа в PyCryptodome используется тип блока шифрования PKCS#1, который вызывает исключение неподдерживаемой версии v15 при проверке с помощью Java.
Самым простым решением, которое я нашел, было использование пакета rsa (https://pypi.org/project/rsa/) и получить прямой доступ к некоторым из его внутренних методов.
key = rsa.PrivateKey.load_pkcs1(
RSA.import_key(base64.b64decode(private_key)).export_key()
)
keylength = rsa.pkcs1.common.byte_size(key.n)
padded = rsa.pkcs1._pad_for_signing(message, keylength)
payload = rsa.pkcs1.transform.bytes2int(padded)
encrypted = key.blinded_encrypt(payload)
block = rsa.pkcs1.transform.int2bytes(encrypted, keylength)
signature = base64.b64encode(block).decode()
По сути, этот код возникает в методе sign_hash модуля rsa/pkcs1.py. Мы просто не добавляем код ASN.1.
Это решение, по общему признанию, хрупкое, но оно должно дать вам хорошую рабочую ссылку, чтобы сделать что-то более надежное.
Проверка
Эта процедура генерации подписи Python создает подпись, идентичную алгоритму Java NONEwithRSA, для того же ключа/ввода.
private_key = "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDhqFoTCc5FEgL3OiM4yEmN/rLkS+bSBigRLW+2N+TdbR/n1O48fUqUoPPa4sEETz7KRHI8EIl+FISyJCk07sks47ucbdfmy0d9omb/GmDnwiRwKe0vFtoTZnrO+sW+l45VEmOymfPYeo6E5pdi9jp7oVZufGiFGryp9DX6mzmpw6unjeZpSfqWaQfba4+EjxO8uiN2GKNlFFxyL6ohrKafGsS9rPaMZv9U4dGpY2ls1855kt8WG4RCHxv8Dh5e0Uj2R3VVnuM/ZvwrW/KLvAf6aUWOZxZhqLknBLUrN+Wh+1KcwZ3PsUoZWAWtY/IIisy/EWatNZYQ0nbk9vFYeEYvAgMBAAECggEBANCJuXxAopwYMh9xXd160ubji0UJk+1h/SMqv0NBUkMDNuoTUHscOpEyUUlmJoQqC9f2+y7hBX87zQmn+2DMj6PpbZb5t/20vIOxUsfMA+QJ+YyiYmwTDUPCgBnJjHc/Li0WSoZiWgQj9pOBWkP9Uzyvc+W1GQ5xEAtsAXpwexCTZB/4Ce6Kmlps4K7QyAJhZnefDNOdtvDzqDlYP0hCfolNK9Y7w0+eGYRBMw7eoxtPlWhAwW+/49/Kljf6YOGYPDY9fP+X+U06YNyuP4kbWLRSaW+uYfLzol2lN1U9y9O83FbvIYI/m4fJVq0xveTkpTj6nwAm6FHcumsoIXEEQykCgYEA937skZ01b6/ea04erQA4kCZZIdAVXrZBSuFHsK/XozBLwVxE3rIIiGAVP5F27GFYsQZzqavx70IIJ/jjYYTc2HRxkT+yU4eXJKTwZTsyuGgR9YAqQrTgfA38NIJ3fYMcwzLOd5gR32GRWJELZI+DT4h+y2PjNPckXfuDQXurMQUCgYEA6WlUgic4yuhnjsT6lZVHCS+RFcp4rgSMBufn24zVkFLS5ajiczth2qMKQquewawoHnGWPQrD1JC1uPtZVL1Xu8oySx13BFlY2Mr6uTJG2TIMY2sh1Nk85QAUXye2nfS1LcuZ3hr6De/B2OCtf+F23dHZ9domxMzhyVQ6hklU0KMCgYEA2+izW09Mw8iI4N+w8hdYKv1oBVtXIajfqyExChW0jRPEvDK4Hwgh/MsjFjCycqasn98TtpdJiUYq6RmFMIlVkh8lKeJnGUFJUw4bbFeFYcVW78TJyCvfq1rh1eZ3NdbiH69tNWaxusJ+2ytF7Dx4eJrXzvEaWV2fusJYhj7UheECgYEAimIHV273jd1B4HRKeLrbNcf8xaWX7NwHROTjItiZmYpxPPXm5Bi1yFFXePWVFxABbSM8xo4GUpVFGBn0+XeUd2LGdKBQesSaF1YoVfpH5Od2Ts8qbK4rGz3z1gKOk5GMhU0ruXHXBMI79GAonSPIPHT5O3iN+anax2lnlUwOu+8CgYEAj/I5LNVX+ocHvM/VaaDAXPPEvcv00Wl84PWDJnKe2kOz7ouKU2fqvmv1LUHBDiPaTL3vK5REKFA0NQSQ4SzbHX1BAdNuZAOMP3Fmtd5CigOJx4lr508rutyCDNBlGjvXLuV7IzjelT4C6o0QoHLPIKN7r57jxP+uOcbMgmuVNmI="
message = "PLWReC8yuVEViE6kpS9tV2ueldyruoCMBLthuPgKDnw="
Декодируйте сообщение из базы 64 в массив байтов на каждом языке. Предоставленный ранее метод подписи Python создаст следующую подпись:
signature_result = "WhM77ROa7Dl0HmO6QdMQjkQ336N2gfi4c2QuLKkIHtxWZQDm7xmLbzbcVxzN3A6hrSdZIS/v5HIpuLe5MovEno6t5QhTyONL4J0evYeO3Ou784qQZORXRlgoOCbkZu25Ty9hBy043HaeUprkOC5f7hcJjRmrel1+izD25NFEDreCnC3paPJqzMXQyUI6gioqdaxth3H0lRW9rAu4pgH/Hgt0/ljd0ch8FJPhfEUNKAV6wltp4h53D9gSlJVBCW2/VFDpzfTHkgkNK+egA2GTc/glWKQ0jm2tEVWniR9nia2bJfNJ/LWrr19ktejex+7g93569HX8w+jp6dAlSIMk9Q=="
Следующий код Java дает тот же результат:
Signature instance = Signature.getInstance("NONEwithRSA");
instance.initSign(privateKey);
instance.update(Base64.decode(data, Base64.NO_WRAP));
byte[] signature = instance.sign();
String b64Signature = Base64.encodeToString(signature, Base64.NO_WRAP);
person
dmartens
schedule
08.07.2021
NONEWithRSA
и отдайте предпочтение серии SHA. PyCryptodome хорош в этом вопросе, так как не пускает людей на ложный путь. - person kelalaka   schedule 03.01.2020_encrypt
), который использует параметры CRT для шифрования дополненного хэша. Я предполагаю, что Python нуждается в библиотеке Extreme Hazmat :| - person Maarten Bodewes   schedule 03.01.2020