0

I have some encrypted private keys and passphrases that I would like to load into .NET without OpenSSL, but I am having trouble finding the format and specification for them.

I can parse and decode the binary data from PEM, and originally I was thinking I would get PKCS#8, but that seems to not be the case.

The OpenSSL command to create them is such as openssl genrsa -des3 -out test.key 2048 resulting in a file like:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,7EF293A7B0C43A20

bwz7TPBN2Xr6AxW9y7PRkaQjXYOS3bireDgyD0lBfKMqQ9AV2oTNUcrI2MtaquBH
QaK+bZY0XBpviceXPrfl73cFrBLBZM7/QhyxINWvcuJiq/hyHFwkT/kEOPWg3g+B
6hIKnMiKcObrU2BVHzt9kuiAneRZob9KwohvIHKpD15y0b0Gm8djBTXBAMgDbyIR
vvQvOrWcyTGLhZs+xq07Bv+tpl9ben8RJcOLVb/xBiaoucvUA/jzyT4BcaZmeeNZ
+tSR8B4R0/AWvK5nTpHtDA/5VKWdrGy5HZPNqLOzKO9IMY6xbFrNnPs9/EwufZsi
USLQ/U5/4qdJ/uOMuOuzb0IHTbwMYfsi66Dv0tnCkp6Fmd0ZIGSQvXESQebCbSuJ
mSc3XgpbWK9C0WqHt5jwYs6Ta3TTwXw8aeDWAcyyHCfvcQRUoWWPEverqrZ6u9Ub
Q6+50qkrHqK0JLTclVj5ty1doWRmcu9tyKRpzQuULo9MPkJDYAxrzzbOzMEXrOVM
oKgK/lJSjFx2dHkyTA4Puuu8jyAj99tyhuVCr8G13voB3RdgglKuyAtIamaI8gPU
n13ysFtZv60oWbmP3obeRw3GJvuLkBUOkEGXxCaEmqHhSfA20bnXLPO5iGVHLoiI
Uiv0G+9+726A4GIGJBxVq0I1mt9IMXpqopiyuz22v4dKDJ5MHmtqyt3RalRfki6B
yJh51O46duyKedaWK94P9ZOpVdUcxsPMzJ9UmPW+L/r+N/tQlP54deK86Pq73LrS
9UIQ8A2QMylU0BvpXNLg5w08C3mAzKA4h+QBUL0RMe6JCk1wipKzDJ7oeNh0r/EN
JgMAi1Fxra1PjvPRNG7iYBSiyYoO75W8BIBPW0py6v72mzWQ8Dx9kcH+Xdr5vWfW
aagBTwv17zpfcLtuhmT6FVSg0A1iIQHM6TDjhRq+cJxH4ioaLZNHFxCXNhGa5c2g
E4KOtZPdnCubNinCdzZn0B5KNgKkCVSlm4o6bRrfdqrBLzBBlTTA3mkJgxQYbDzW
W6ET5LZTbJkozSi2nRehyLvLV/FUlIKneyRqQdLFksH82/3R+CW0jsGei+qB8XMY
9ssfQ7ccsvzfCHlss/g/v3uKCwOhTZ3yzo2IA16w4hftlw7IwT4jfOF73CRYILg+
C8Iw2+VMGZmEgDdwJt3TdSB95MDY/WJGwCR7fiat1oMP/uhGqhNyuswnZTq/gWMH
rDJfELbv8HAQfYuh2I3/HDmwjyUi8FkWPpbKhcOHQB8pk3zZTERk3NtV6iAYSG+V
rxEIj3yB3zjn5+9QFOEAU6edqigeM1UKdH5jUUc3hi+C4evzR1xbomDp3JQyw0PB
Jlj2tFMhDhj4thmltBKs1ZwUAd7ei7gvgvQq2vJB1zmwxHS/8g83lryOUHU9zQTF
8SObmYEEmUzy7I5CgvKcePQkRqeZD4x4nsf3Q09NvljrXaWGJjLH+Xjzg3h7fR5b
GvrX7EyyEdFwf3z1tcA/VcFnIQptLTDcjlpxou16WaM1F/OVQ/OGNJnG1xHbVwTv
cDNbpyoP5xERAYSp2YpFTVGJG43tcdDhLjZMN7WGHIb4Qc5Gm1JabxPtys2YnLhB
-----END RSA PRIVATE KEY-----

As far as I can tell, the base64 encoded data is not valid DER/ASN, tools I found just say the data is invalid, including openssl asn1parse -inform PEM.. I assume those two "headers" are the distinguishing feature, but what is the format? What are the common values?

RFC 1421 seems to call such headers "encapsulated header", I didn't find them otherwise.

Fire Lancer
  • 29,364
  • 31
  • 116
  • 182

1 Answers1

4

This is OpenSSL's 'traditional' or 'legacy' format private key file (or one of several, depending how you count). It is documented in the man page, on your system or on the web, for the related routines -- nominally man 3 PEM_{read,write}{,_bio}_{RSA,DSA,EC}PrivateKey although this page is duplicated or symlinked under numerous names -- in the 'PEM ENCRYPTION FORMAT' section. Briefly, the data is encrypted (with a chosen symmetric algorithm, in this example DES3 aka DESede aka triple-DES, with CBC and IV) using a key derived from the password (with salt equal to the IV or part of it, which is unusual, and only one iteration, which is weak). The password-based key derivation function used, EVP_BytesToKey, has its own man page.

This is not PKCS8. In addition to being encrypted differently than PKCS8-encrypted (formally, EncryptedPrivateKeyInfo) the clear data that you get after decrypting (or if you don't encrypt to start with, e.g. genrsa without -$cipher) is not PKCS8-clear PrivateKeyInfo. It is instead an algorithm-dependent data format; for RSA it is the format defined in PKCS1 appendix A.1.2, and for DSA and EC it has other formats not relevant here.

OpenSSL also supports PKCS8 privatekey files, both clear and encrypted, which have different PEM types: BEGIN/END PRIVATE KEY and BEGIN/END ENCRYPTED PRIVATE KEY but not BEGIN/END {RSA,DSA,EC} PRIVATE KEY. For the API see that same man page. You can convert at command line with

openssl pkcs8 -topk8 <tradfile >pk8file [-nocrypt | -v1 pbcipher | -v2 plaincipher]`
# since 1.0.0 in 2010 you can add -iter N
# or since 1.0.0 simply
openssl pkey <tradfile >pk8file [-$cipher]

PKCS8 is both more standard (and interchangeable) and more secure, thus recommended -- as that same man page says in the immediately preceding NOTES section.

The Java version of BouncyCastle supports OpenSSL PEM formats in bcpkix. I don't know for the dotnet version but it might be worth looking.

If not, or if you can't use it, you can convert the (decrypted) PKCS1 format to PKCS8 by adding a mostly-fixed header; in ASN.1 terms, PKCS8 is a wrapper that contains some metadata plus an OCTET STRING containing for RSA the PKCS1 encoding. I don't have a dotnet solution for this but you can probably adapt from Java using my list of links at Algid parse error, not a sequence and perhaps Converting a string private key to PrivateKey type .

Community
  • 1
  • 1
dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70