Как сгенерировать закрытый ключ RSA из строки * pem в Java

Я хочу сгенерировать закрытый ключ из строки (файла .pem) в Java.

private static final String test = "-----BEGIN RSA PRIVATE KEY-----\n" +
         "MIIEpAIBAAKCAQEAvcCH8WsT1xyrZqq684VPJzOF3hN5DNbowZ96Ie//PN0BtRW2\n" +
// and so on
         "-----END RSA PRIVATE KEY-----";

try {
    String privKeyPEM = test.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
    privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");

    byte [] encoded = Base64.decode(privKeyPEM);

    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey privKey = kf.generatePrivate(keySpec);
}
catch (Exception e) {
    e.printStackTrace();
}

Последняя строка (функция generatePrivate) выбрасывает это исключение:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source)
    at java.security.KeyFactory.generatePrivate(Unknown Source)
    at Test.main(Test.java:52)
Caused by: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
    at sun.security.pkcs.PKCS8Key.decode(Unknown Source)
    at sun.security.pkcs.PKCS8Key.decode(Unknown Source)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(Unknown Source)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(Unknown Source)
    at sun.security.rsa.RSAKeyFactory.generatePrivate(Unknown Source)
    ... 3 more

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

Я приложил снимок экрана с байтами, напечатанными в виде строки (один раз жестко закодированный с \ n и один раз жестко закодированный без \ n) и один раз из файла.

Изображение большего размера

Вывод

Странно то, что вывод из файла отличается от вывода из строк.

Если я попытаюсь закодировать файл .der с помощью Base64, результат будет отличаться от строки в файле .pem. Почему это так?


person Niklas    schedule 21.08.2013    source источник
comment
Вы вообще нашли ответ?   -  person Sankar    schedule 22.02.2016
comment
@SankarP не совсем.   -  person Niklas    schedule 23.02.2016
comment
Ладно. Я нашел решение. Ключи, начинающиеся с ----- BEGIN RSA PRIVATE KEY, представляют собой файлы в кодировке pkcs1. Эта кодировка pkcs1 не поддерживается Java, если вы не используете внешнюю библиотеку, такую ​​как BouncyCastle. Вчера я столкнулся с той же проблемой и примерно через 8 часов нашел решение. Если вы закодируете закрытый ключ с помощью pkcs8, он будет начинаться как --- BEGIN PRIVATE KEY --- который будет обрабатываться стандартным java. HTH.   -  person Sankar    schedule 23.02.2016
comment
Дупите stackoverflow.com / questions / 3243018 /   -  person dave_thompson_085    schedule 16.09.2016


Ответы (1)


Вы говорите, что последняя строка генерирует исключение, т.е.

PrivateKey privKey = kf.generatePrivate(keySpec);

Вышеупомянутая строка работает при правильной установке спецификаций клавиш, т.е.

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);

Итак, актуальная проблема связана с массивом закодированных байтов. Вы сделали System.out после byte [] encoded = Base64.decode(privKeyPEM); и посмотрите, что будет на выходе.

Я понимаю, что если сообщение находится в формате MIME, то после определенных символов оно добавляет комбинацию возврата каретки и новой строки, чтобы строки не были слишком длинными для системы электронной почты или того места, где вы ее используете.

Последний тест String содержит символы '\ n' в исходном тексте, который вы используете. Вы удалили другой текст в строке ниже,

String privKeyPEM = test.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
    privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");

Но посмотрите на строку,

"MIIEpAIBAAKCAQEAvcCH8WsT1xyrZqq684VPJzOF3hN5DNbowZ96Ie//PN0BtRW2\n" +
// and so on
         "-----END RSA PRIVATE KEY-----";

в нем может остаться еще несколько символов '\ n', что может привести к появлению некоторых нежелательных символов при генерации ключей. Попробуйте еще System.out и посмотрите, на что похож закодированный массив байтов, а также перед этим проверьте String privKeyPEM и посмотрите, не осталось ли в нем лишних символов.

Надеюсь на это.

person H-Patel    schedule 22.08.2013
comment
Я загрузил вывод encoded. pastebin.com/YUsNdhgW. Я также изменил тест на чистую строку без \n, и это тоже не сработало. - person Niklas; 22.08.2013
comment
Я также загрузил снимок экрана с выводом в виде строки. - person Niklas; 22.08.2013
comment
Декодирование Base64 игнорирует перенос строки и обычно все пробелы. - person dave_thompson_085; 16.09.2016