Подтвердить что ты не робот

Загружать закрытый ключ RSA с кодировкой PEM в Crypto ++

Часто пользователи имеют секретные ключи RSA, закодированные PEM. Crypto ++ требует, чтобы эти ключи были в формате DER для загрузки. Я просил людей вручную конвертировать свои файлы PEM в DER заранее, используя openssl следующим образом:

openssl pkcs8 -in in_file.pem -out out_file.der -topk8 -nocrypt -outform der

Это хорошо работает, но некоторые люди не понимают, как это сделать и не хотят. Поэтому я хотел бы автоматически конвертировать файлы PEM в файлы DER внутри программы.

Это так же просто, как разметка "----- BEGIN CERTIFICATE -----" и "----- КОНЕЦ СЕРТИФИКАТА -----" из PEM или требуется другое преобразование? Мне сказали, что между этими маркерами он просто кодирует B64 DER. Вот несколько примеров, которые демонстрируют проблему:

// load the private key
CryptoPP::RSA::PrivateKey PK;
CryptoPP::ByteQueue bytes;

try
{
    CryptoPP::FileSource File( rsa.c_str(), true, new CryptoPP::Base64Decoder() );
    File.TransferTo( bytes );
    bytes.MessageEnd();

    // This line Causes BERDecodeError when a PEM encoded file is used
    PK.Load( bytes );
}

catch ( CryptoPP::BERDecodeErr )
{
    // Convert PEM to DER and try to load the key again
}

Я бы хотел избежать системных вызовов в openssl и полностью выполнить преобразование в Crypto ++, чтобы пользователи могли предоставить либо формат, либо "просто работать". Спасибо за любой совет.

4b9b3361

Ответ 1

Да, это поток DER, закодированный с помощью Base64. Обратите внимание, что в дополнение к чередованию маркеров BEGIN и END в случае формата ключа RSA вам также необходимо снять любые флаги, которые могут быть вставлены между маркером BEGIN и закодированными данными. Только оставшаяся часть может быть успешно декодирована Base64. Похоже, что вы подаете полный файл сертификата в декодер и нуждаетесь в исправлении.

Ответ 2

Я знаю, что это старый вопрос, но другие могут найти это полезным. После того, как вы разделите маркеры, вы останетесь с "внутренним" материалом. В соответствии с http://www.cryptopp.com/wiki/Keys_and_Formats#BER_and_DER_Encoding вы можете использовать BERDecodePrivateKey для загрузки. Итак, чтобы загрузить ключ openssl, у которого были сняты маркеры, вы можете сделать что-то вроде

bool LoadKey(RandomNumberGenerator& rng, const std::string& file, 
    RSA::PrivateKey& key)
{
    ByteQueue q;
    FileSource KeyFile(file.c_str(), true, new Base64Decoder);
    KeyFile.TransferTo(q);
    key.BERDecodePrivateKey(q,false,0); // last 2 params unused
    return key.Validate(rng, 2);
}

Ответ 3

... Я хотел бы автоматически конвертировать файлы PEM в файлы DER внутри программы.

В июле 2014 года была предоставлена ​​PEM Pack для библиотеки Crypto ++. Пакет PEM представляет собой частичную реализацию шифрования сообщений, которая позволяет читать и записывать ключи и параметры, закодированные в PEM, включая зашифрованные закрытые ключи. Дополнительные файлы включают поддержку RSA, DSA, EC, ECDSA-ключей и параметров Diffie-Hellman.

Это дополнение к библиотеке, а не часть собственно библиотеки. Вы загружаете ZIP и добавляете в него пять исходных файлов. Затем вы создаете библиотеку (Crypto ++ автоматически их подбирает). ZIP содержит пять дополнительных исходных файлов, script для создания тестовых ключей с использованием OpenSSL, программы на С++ для проверки чтения и записи ключей и script для проверки ключей, написанных Crypto ++ с использованием OpenSSL.

Вот как вы его используете:

CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);

CryptoPP::PEM_Load(file, pk);

CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
    throw ...

Если ключи зашифрованы, то вот как вы его загрузите. PEM Pack повторно реализует OpenSSL EVP_BytesToKey, поэтому вывод ключа будет работать, и вы можете interop:

CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);

std::string pass = "<super secret password>";
CryptoPP::PEM_Load(file, pk, pass.data(), pass.size());

CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
    throw ...

Также существует PEM_Save, поэтому вы можете писать ключи непосредственно из Crypto ++. Например:

// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...; 
CryptoPP::FileSink file("<rsa-key-file.pem>", true);

CryptoPP::PEM_Save(file, pk);

И PEM_Save для зашифрованного ключа (или ключа, который вы собираетесь зашифровать):

// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...; 
CryptoPP::FileSink file("<rsa-key-file.pem>", true);

std::string pass = "<super secret password>";
CryptoPP::PEM_Save(file, pk, "AES-128-CBC", pass.data(), pass.size());

PEM_Load не нуждается в алгоритме, поскольку он закодирован в инкапсулированном заголовке. PEM_Save требуется алгоритм, поскольку алгоритм по умолчанию отсутствует.