RSA я должен использовать X.509 или PKCS # 1 - PullRequest
0 голосов
/ 25 декабря 2018

Вариант использования: у меня есть сценарий использования, в котором клиент генерирует закрытый и открытый ключ, отправляет на сервер открытый ключ в кодировке 64.

На стороне сервера я зашифрую сообщение с использованием этого открытого ключа и отправлюзашифрованное сообщение клиенту, которое клиент расшифровывает, используя свой закрытый ключ. Согласованный алгоритм «RSA».

Проблема на стороне сервера. Я вижу, что некоторые ключи работают с использованием X509EncodedKeySpec в качестве ключа.spec

byte[] publicBytes = Base64.decodeBase64(base64EncodedPubKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);

Хотя некоторые ключи выдают исключение (Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence), используя X509EncodedKeySpec, но работают, используя RSAPublicKeySpec:

byte[] publicBytes = Base64.decodeBase64(base64EncodedPubKey);
org.bouncycastle.asn1.pkcs.RSAPublicKey.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.RSAPublicKey.getInstance(publicBytes);
BigInteger modulus = pkcs1PublicKey.getModulus();
BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);

Итак, я понял, что клиенти сервер должен договориться, использовать ли: PKCS #1 или X.509 для кодирования ключа. У меня вопрос, какой из них лучше для моего варианта использования? Какие-либо рекомендации, когда использовать какой формат?

1 Ответ

0 голосов
/ 30 декабря 2018

Здесь очень мало различий. Формат ключа, который Java называет X.509, более точно известный как структура ASN.1 SubjectPublicKeyInfo (или SPKI), определенный в X.509 или эквивалентно и более удобный в RFC5280 сек. 4.1 , это довольно простой способ обработки большого и гибкого набора алгоритмов: он состоит из подструктуры AlgorithmIdentifier, которая идентифицирует алгоритм и его параметры, если это применимо, затем непрозрачной строки BIT, которая содержитфактическая ключевая информация (закодированная) в формате, зависящем от (алгоритма, идентифицированного) AlgorithmIdentifier.

Для RSA зависимая от алгоритма часть представляет собой структуру ASN.1 RSAPublicKey, определенную в PKCS1 или более удобно RFC8017, приложение A.1.1 и его более ранние версиии дублируется в RFC3279 сек. 2.3.1 .Таким образом, для RSA формат X.509 (SPKI) содержит формат PKCS1, и поскольку RSA не имеет параметров (или, по крайней мере, связанных с ключом параметров), единственное реальное отличие состоит в том, что X.509Формат явно указывает, что ключом является RSA - который в вашем приложении вы уже знаете.

Вы уже обнаружили, что ванильная (Oracle-was-Sun-now-OpenJDK) Java-криптография, также известная как JCA Java Cryptographic Architecture,напрямую поддерживает только формат X.509 (SPKI), что является небольшим преимуществом.Однако, если вы используете BouncyCastle, гораздо проще конвертировать туда и обратно, чем код в вашем Q;вы просто используете класс org.bouncycastle.asn1.x509.SubjectPublicKeyInfo, чтобы добавить или отбросить AlgorithmIdentifier:

    // test data source
    KeyStore ks = KeyStore.getInstance("JKS"); ks.load (new FileInputStream (args[0]), args[1].toCharArray());
    byte[] spkienc = ks.getCertificate(args[2]).getPublicKey().getEncoded();
    System.out.println (DatatypeConverter.printHexBinary(spkienc));

    // extract PKCS1 part of original SPKI
    byte[] pkcs1enc = SubjectPublicKeyInfo.getInstance(spkienc).parsePublicKey().getEncoded();
    System.out.println (DatatypeConverter.printHexBinary(pkcs1enc));

    // rebuild SPKI from the PKCS1
    AlgorithmIdentifier algid = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
    byte[] spki2enc = new SubjectPublicKeyInfo (algid, pkcs1enc).getEncoded();
    System.out.println (DatatypeConverter.printHexBinary(spki2enc));

См. мой ответ на аналогичный golang x509.MarshalPKIXPublicKey против x509.MarshalPKCS1PublicKey () и особенно ссылкив:
Преобразование открытого ключа в формате SubjectPublicKeyInfo в формат RSAPublicKey java
Генерация ключей RSA в формате PKCS # 1 в Java
Проблема передачиОткрытый ключ RSA, javaME, надувной замок

Если у вас нет BouncyCastle, это немного сложнее;вам нужно написать частичный парсер или генератор ASN.1.Полная обработка ASN.1 довольно сложна, но для этого случая вам нужно только небольшое подмножество, которое не так уж плохо.(Да, это слабая похвала.) Я могу добавить это позже, если у меня будет больше времени.

Гораздо большая потенциальная проблема заключается в том, что ваш ключ не аутентифицирован. Сложная часть распространения открытого ключа, намного сложнее, чем мелкие детали формата, гарантирует, что только законный ключ распространяется.Если злоумышленник может заменить свой открытый ключ на правильный, то жертва шифрует предположительно секретные данные так, чтобы злоумышленник мог легко их прочитать, и весь ваш модный криптографический код совершенно бесполезен.

Вот почему наиболее актуальносистемы не распространяют открытые публичные ключи, но вместо этого сертификаты, которые позволяют проверять ключ, являются правильным ключом.Существует несколько схем сертификатов, но наиболее распространенной на сегодняшний день является X.509 и его интернет-профиль PKIX - фактически RFC, на которые я ссылался выше, 5280 и 3279, являются частью PKIX.SSL-now-TLS использует X.509.Подписание кода использует X.509.S / MIME электронная почта использует X.509.(PGP / GPG использует другой вид сертификатов, не X.509, но все еще сертификаты.) И (ванильное) Java напрямую поддерживает сертификаты X.509 так же хорошо или даже лучше, чем публичные клавиши «X.509» (SPKI).

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