Форматирование ключей RSA для OpenSSL в Java

Задний план

Генерация ключа RSA с OpenSSL в Linux с помощью команды

openssl genrsa -out mykey.pem 1024

создал следующее:

"-----BEGIN RSA PRIVATE KEY-----
 MIICXQIBAAKBgQChs9Fepy5FgeL0gNJ8GHcKRHsYnM2Kkw19zwydDQNyh2hrHWV2
 B11wpLFp8d0imcl2Wjb0oV/AxOhb3unQgNzs66LVuXJwS8icp3oIJZtExs6tkxzE
 s5mnU68wMeCYtJqHIZOmNblVWvpJMLNAwAVi3oLfnzDDbzjnDapm8M21nQIDAQAB
 AoGAZ11P1+acUHgvwMXcRtFIvvp5iYkqZouL00EYOghIjNx75gTbh7A7jbbpZeTi
 y6xsuMgAWy4QzGPSeG+tHMhS7+dYQNPuKSv5KtK3V7ubXz/I3ZN1etRVecA56QNw
 7HKv6b7srolt08kogGIwpbbfl/mhfJHnv4Jeqd5lNMnK4e0CQQDWFZo4h22OlSaH
 ZGd3i4rwLrA0Ux5bkdh7YH0uEeE/nGzpVs1DPhsN8UCyq9LAiKYLlXeeCvwurKwo
 OgKlUCkzAkEAwVy2KignoRInFTAaYH8PQRfD835q+oC0Iu21BF68ne06U6wu+wWk
 bWiYxTOOb+TGZfA1vA6OAvGVGoXs1bHF7wJBAItGiop0MKYuCl7Sxy1SrxUKir+/
 w2Q3QesiHs41+6Byl7hGLEuuv9MWPM0AU5/GRqAKoUNESkPjOi0BcG8z81kCQGGn
 OvCreugjzM0skAWv5bpQEExGyixdF5yURFlCpytzBYQAb3Gi9dmze4QMd6EW/wO4
 fsrM5vehnlXY0TVTJM0CQQCMPVhub8LSo7T/lCzypvb/cgxJfyITRKcM2asrXud5
 r27kbzsXqYum4huHqyFkb3pZammsYA/z89HchylfrD4U
 -----END RSA PRIVATE KEY-----"

Следующий код в Java 6,

KeyPairGenerator keyGen = null;
try {
  keyGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
  throw new RuntimeException(e);
}
KeyPair pair = keyGen.generateKeyPair();
privateKey = new Base64Encoder().encode(pair.getPrivate().getEncoded());
publicKey = new Base64Encoder().encode(pair.getPublic().getEncoded());`

вывести следующее:

"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIsJlqFOP+jPyYvrGwh+dff30a3p
 uHysMfHYi1MyNSFCsT/2QbOc/k9U/X28WRCMeFwEEnReLULXA9Ywox8GycI/ApMX+DjKBrrLDbpr
 ATLiu9+NMK4VSytKFI87P07HAni3RkiO4rFNEINVQ7t38ZmHavuXHjMkLEAK4dyLQO9NAgMBAAEC
 gYBN/jv0EmwBUgYSKflJI39TcT263B+0N/fwXXOSYNiy5rF9WstyUP/LSrbEAJLJmLKvk00y391t
 4CVz0ma+sdUdAPlS7Nmx9f3BThGOGcDmpjVo1y4e1afWtyu66ba/XDeuf7q5Y/h/pr20/gXl9Gz2
 yefQrzU9xXGKZhE/lxJ2IQJBAMELpeAal+Fa+u0InGrowVmV+lge8RZqKRfCDzPPna465E5Qcekb
 J0ShsarP5lnUfrNH5g8GLaDGQwYE/UoIpPkCQQC4YRfck5uMlI1K3F9YC3XvmFAJnf9YexoPfNSu
 dznOD4rxlwzW/5daPOR0jjlyIRDH/QuUoPIIEn1mt3dnz7X1AkBZciozgl7pPhySA7FmH96mwcUz
 W3LdrebIaVRd707iUctDNibxmXFCbaFCwf27laf3LdM9FuHBYtvfSCSMTyERAkEAlNAQsUAVmKZB
 T72D2o0Nd/7oAosaD7DzvLJU+idSaWUUEJ+IhnKuFu/0t7oe1WWopLEwypoIHsnFmsTTQ99ajQJA
 Scwh3P3RTN4F6Jz1SxRSe6L729xI8xkbco5EsMq5v5BZeoGynqdPUUZdAPcaO2k5UagaSejvzgna
 8xIqR7elVQ=="

"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItT
 MjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCu
 FUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB"

Вопросы

  1. Как мне надеть «броню» на закрытый и открытый ключи, созданные с помощью кода Java?

  2. Почему каждая строка ключей, сгенерированных с помощью кода Java, длиннее строк, выводимых OpenSSL?

  3. Есть ли разница? Один из инструментов, который использует другая команда, дает сбой при подписании сообщения с использованием закрытого ключа, сгенерированного упомянутым выше кодом Java. Тем не менее, этот инструмент отлично работает, используя закрытый ключ, сгенерированный OpenSSL.

  4. Есть ли способ экспортировать совместимый ключ с Java?


person MiKu    schedule 07.09.2010    source источник


Ответы (1)


Закрытый ключ OpenSSL имеет нестандартный формат, а код Java создает стандартный закрытый ключ в кодировке PKCS-#8.

OpenSSL может преобразовать стандартный формат ключа в нестандартную форму. Вы можете написать код Java, чтобы сделать то же самое, но для этого потребуются некоторые сторонние библиотеки, и хорошее знание ASN.1 также поможет.

Чтобы преобразовать ключ PKCS #8 в формат OpenSSL, используйте утилиту OpenSSL pkcs8.

openssl pkcs8 -nocrypt -inform der < pvt.der > pvt.pem

Чтобы преобразовать ключ RSA, хранящийся как SubjectPublicKeyInfo в кодировке DER, в формат PEM, используйте утилиту OpenSSL rsa.

openssl rsa -pubin -inform der < pub.der > pub.pem

Это предполагает, что закрытый ключ хранится в «двоичном» (DER) формате, а не в кодировке Base-64. Код Java для создания и хранения таких ключей будет выглядеть примерно так:

KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
KeyPair pair = gen.generateKeyPair();
FileOutputStream ospvt = new FileOutputStream("pvt.der");
try {
  ospvt.write(pair.getPrivate().getEncoded());
  ospvt.flush();
} finally {
  ospvt.close();
}
FileOutputStream ospub = new FileOutputStream("pub.der");
try {
  ospub.write(pair.getPublic().getEncoded());
  ospub.flush();
} finally {
  ospub.close();
}
person erickson    schedule 07.09.2010
comment
Спасибо за ответ. :) Инструмент, который использует другая команда, имеет ожидания закрытых ключей, задокументированные как PEM-encoded private key or a base64-encoded DER private key, которые я пытался использовать для 2-го варианта. - .getEncoded() возвращает - форму DER ASN.1 (download.oracle.com/javase/6/docs/api/java/security/spec/) - затем я дополнительно кодирую его в base64 И все равно id не работает. Есть ли способ, которым вы могли бы видеть? Есть ли способ создать закрытый ключ непосредственно в формате pem? Ограничения таковы, что я должен создать любую из форм, используя только код Java... - person MiKu; 08.09.2010
comment
@MiKu - PEM использует base-64. mykey.pem в вопросе, конечно же, ключ PEM. DER используется для обозначения двоичной формы. Но даже когда вы отличаете двоичный код от base-64, вам все равно нужно знать ожидаемую структуру ключа: PKCS #8 или родной OpenSSL. DER или PEM — это просто последний уровень кодирования. DER с кодировкой base64 действительно не имеет никакого смысла. Чем это будет отличаться от PEM? Вы пробовали мой код? - person erickson; 08.09.2010
comment
Я согласен с тем, что вы говорите, Эриксон. Что я хотел сделать, так это создать ключи с java-кодом, чтобы другой инструмент мог его хорошо интерпретировать. Структура PKCS#8 по умолчанию не была совместима с этим инструментом. Я разобрался с надувным замком. JDKKeyPairGenerator.RSA keyPairGen = new JDKKeyPairGenerator.RSA(); keyPairGen.initialize(RSA_KEY_STRENGTH); KeyPair keyPair = keyPairGen.generateKeyPair(); StringWriter stringWriter = new StringWriter(); PEMWriter pemFormatWriter = new PEMWriter(stringWriter); pemFormatWriter.writeObject(keyPair.getPrivate()); pemFormatWriter.close(); - person MiKu; 09.09.2010
comment
Кроме того, я действительно не знаю, соответствует ли DER с кодировкой base64 PEM или нет. Скорее всего, вы правы, утверждая, что они по сути одинаковы. Необходимо проверить (для моего личного подтверждения), создав .dem с помощью openssl и выполнив его кодировку BASE64, чтобы проверить, соответствует ли он .pem эквиваленту ключа. Из того, что вы предложили, кажется, что должно быть равным. :) Спасибо за помощь. ASN.1 было хорошо прочитано. :) - person MiKu; 09.09.2010