Подписание и проверка ключа RSA в Java (Android) - PullRequest
0 голосов
/ 27 января 2019

У меня небольшая проблема с пониманием концепции подписи и проверки RSA.Проблема заключается в том, что я могу создать пару ключей (открытый и закрытый ключ), что прекрасно.

        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        random = SecureRandom.getInstance("SHA1PRNG");
        keyGen.initialize(2048, random);
        KeyPair pair = keyGen.generateKeyPair();
        myPrivateKey = pair.getPrivate();
        myPublicKey = pair.getPublic();

Подписывание и проверка выполняются следующим образом:

        //Singing with private key
        Signature s = Signature.getInstance("SHA1withRSA");
        s.initSign(javaPrivateKey);

        //Verifying with public key
        Signature s = Signature.getInstance("SHA1withRSA");
        s.initVerify(javaPublicKey);

Когда я печатаю myPrivateKey иmyPublicKey, я вижу, что модуль (n) и открытый показатель (e) одинаковы для открытого и закрытого ключа.

Я преобразовал открытый и закрытый ключи в base64 и hex, и я получаю различные значения, что совершенно нормально,Однако я не могу подписать сообщение с base64 или hex.Я могу подписать его только тем, что получаю из этого:

         myPrivateKey = pair.getPrivate();  

Я знаю, что проверку необходимо проводить с открытым ключом, который виден всем.Когда получатель проверяет сообщение, использует ли получатель только модуль и показатель степени?Какая часть открытого ключа должна быть отправлена ​​отправителем?Модуль и показатель степени или Base64 или шестнадцатеричное значение ключа?

1 Ответ

0 голосов
/ 27 января 2019

Да, приемник использует только модуль и показатель степени;нет других компонентов, которые необходимы математически для проверки подписи для RSA.

Математические операции выполняются с использованием больших чисел (обычно BigInteger значения, когда RSA реализуется в программном обеспечении).Для выполнения любого вида расчета реализация должна восстановить эти числа.То, как эти числа передаются, не имеет значения для алгоритма.

Обычно открытые ключи RSA кодируются с использованием чего-то на основе PKCS # 1, который определяет формат открытого ключа с использованием ASN.1 (который определяет структуру) иBER / DER (который определяет кодировку этой структуры).Конечно, разные протоколы могут использовать разные кодировки открытых ключей.Например, PGP использует совершенно другой «формат пакета» для кодирования ключей.


Java, однако, возвращает структуру SubjectPublicKeyInfo, которая определена в спецификациях X.509 (сертификат и CRL);кроме того, модуль и экспонента также содержит идентификатор алгоритма, который показывает, что он является открытым ключом RSA.Таким образом, эта структура также может быть использована для распределения других видов значений ключей.Его можно получить, вызвав getEncoded() в экземпляре RSAPublicKey - при условии, что этот экземпляр совместим с предоставленным Oracle - они обычно таковыми и являются.Разумеется, реализации Android должны быть совместимы с этой структурой.Обратите внимание, что структура SubjectPublicKeyInfo содержит структуру открытого ключа PKCS # 1 , внутри нее .

Для обратного обращения вам нужно KeyFactory.getInstance("RSA") и получить ключ, используя X509EncodedKeySpec, инициализированный с заданныммассив байтов.


Если вам нужны текстовые строки вместо двоичных, то вы можете преобразовать байты, возвращенные getEncoded(), в основание 64 и шестнадцатеричные числа.Разумеется, в этом случае вам необходимо изменить кодирование (т. Е. Декодировать) результат до того, как вы сможете декодировать сами байты.

Также можно кодировать модуль и открытый показатель степени самостоятельно.Вы можете получить их, используя RSAPublicKey.getModulus() и RSAPublicKey.getPublicExponent().Чтобы вернуть их обратно в RSAPublicKey, вы можете использовать KeyFactory.getInstance("RSA") и RSAPublicKeySpec.Таким образом, вы можете, например, просто создать строку "(<modulus>, <exp>)" и использовать ее для распространения ключа.Как правило, вы хотели бы придерживаться предварительно определенных стандартов.


В этом ответе не рассматривается тот факт, что для проверки с открытым ключом сначала необходимо установить доверие в открытом доступе.ключ.Если вы не можете доверять открытому ключу, вы не знаете, кто создал открытый ключ.В этом случае вы также не можете доверять результату вашей операции проверки;подпись, возможно, была создана с парой ключей противника.Однако углубляться в инфраструктуры открытого ключа (PKI / PKIX) для этого ответа слишком сложно.

Аналогично: SHA-1 больше не считается безопасным, особенно для генерации / проверки подписи.Вы хотели бы использовать по крайней мере SHA256withRSA или - немного более продвинутую и несколько более безопасную - схему RSA, которая использует PSS.2048 бит слишком мал для комфорта;рекомендуется использовать 4096-битный ключ, если ваша схема это позволяет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...