In experimenting with openssl on the Linux command line with elliptic curve secp256k1 I encountered a strange situation where on converting a DER private key file to PEM format using openssl pkey the Base64 in the PEM file does not match the original DER file.
The DER private key file priv.der is generated with :
ubuntu3@ubuntu3:~/OpenSSL Test$ openssl ecparam -name secp256k1 -genkey -noout -outform DER -out priv.der (recreate present example with : ubuntu3@ubuntu3:~/OpenSSL Test$ echo "3074020101042090f4a50b8dd639597c01b56bb97eb0a5063ec56326da72c7acbd303354df393ba00706052b8104000aa14403420004cb452cb3662eb70920eb8532040f807853928a5d13c4331e822334a60aa04ea115e7ce0c8648416e6bc22ef33f55d75057442b2a66c5c95ef652df9e6a306c57" | xxd -r -ps > priv.der ) which looks like the following under asn1parse :
ubuntu3@ubuntu3:~/OpenSSL Test$ openssl asn1parse -inform DER -in priv.der 0:d=0 hl=2 l= 116 cons: SEQUENCE 2:d=1 hl=2 l= 1 prim: INTEGER :01 5:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:90F4A50B8DD639597C01B56BB97EB0A5063EC56326DA72C7ACBD303354DF393B 39:d=1 hl=2 l= 7 cons: cont [ 0 ] 41:d=2 hl=2 l= 5 prim: OBJECT :secp256k1 48:d=1 hl=2 l= 68 cons: cont [ 1 ] 50:d=2 hl=2 l= 66 prim: BIT STRING The conversion of the DER file to a PEM file using openssl pkey :
ubuntu3@ubuntu3:~/OpenSSL Test$ openssl pkey -inform DER -in priv.der > priv.pem ubuntu3@ubuntu3:~/OpenSSL Test$ cat priv.pem -----BEGIN PRIVATE KEY----- MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgkPSlC43WOVl8AbVruX6w pQY+xWMm2nLHrL0wM1TfOTuhRANCAATLRSyzZi63CSDrhTIED4B4U5KKXRPEMx6C IzSmCqBOoRXnzgyGSEFua8Iu8z9V11BXRCsqZsXJXvZS355qMGxX -----END PRIVATE KEY----- Decoding the Base64 text in the PEM file :
ubuntu3@ubuntu3:~/OpenSSL Test$ echo "MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgkPSlC43WOVl8AbVruX6wpQY+xWMm2nLHrL0wM1TfOTuhRANCAATLRSyzZi63CSDrhTIED4B4U5KKXRPEMx6CIzSmCqBOoRXnzgyGSEFua8Iu8z9V11BXRCsqZsXJXvZS355qMGxX" | base64 --decode > priv2.der Comparing priv2.der with priv.der : ubuntu3@ubuntu3:~/OpenSSL Test$ ll priv.der priv2.der -rw-r--r-- 1 ubuntu3 ubuntu3 135 Jan 29 17:00 priv2.der -rw-r--r-- 1 ubuntu3 ubuntu3 118 Jan 29 16:42 priv.der => file sizes are different and ASN.1 structure is different :
ubuntu3@ubuntu3:~/OpenSSL Test$ openssl asn1parse -inform DER -in priv2.der 0:d=0 hl=3 l= 132 cons: SEQUENCE 3:d=1 hl=2 l= 1 prim: INTEGER :00 6:d=1 hl=2 l= 16 cons: SEQUENCE 8:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey 17:d=2 hl=2 l= 5 prim: OBJECT :secp256k1 24:d=1 hl=2 l= 109 prim: OCTET STRING [HEX DUMP]:306B020101042090F4A50B8DD639597C01B56BB97EB0A5063EC56326DA72C7ACBD303354DF393BA14403420004CB452CB3662EB70920EB8532040F807853928A5D13C4331E822334A60AA04EA115E7CE0C8648416E6BC22EF33F55D75057442B2A66C5C95EF652DF9E6A306C57 The ASN.1 data for priv2.der contains 2 OID's, whereas the original priv.der only contains only 1 OID.
So why did the openssl pkey command not just Base64 encode the priv.der file passed in and place that between the
-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- lines in the priv.pem file ?
Why did it encode to Base64 a different DER structure than priv.der?
The byte by byte breakdowns of priv.der and priv2.der are shown below :
Breakdown of bytes of DER file priv.der --------------------------------------- 30 sequence type 74 length = 116 bytes 02 integer type 01 01 04 octet string type 20 length = 32 bytes 90f4a50b8dd639597c01b56bb97eb0a5063ec56326da72c7acbd303354df393b private key a0 07 length = 7 bytes 06 OID type 05 length = 5 bytes 2b8104000a OID for secp256k1 = 1.3.132.0.10 a1 44 length = 68 bytes 03 bit string type 42 length = 66 bytes 00 no of unused bits added to right (to make a multiple of 8 bits) 04 pubkey prefix cb452cb3662eb70920eb8532040f807853928a5d13c4331e822334a60aa04ea1 pubkey x 15e7ce0c8648416e6bc22ef33f55d75057442b2a66c5c95ef652df9e6a306c57 pubkey y Breakdown of bytes of DER file priv2.der ---------------------------------------- 30 sequence type 81 84 length = 132 bytes 02 integer type 01 00 30 sequence type 10 length = 16 bytes (sum of 2 OID lengths below) 06 OID type 07 length = 7 bytes 2a8648ce3d0201 object identifier = 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) 06 OID type 05 length = 5 bytes 2b8104000a object identifier = 1.3.132.0.10 secp256k1 (SECG (Certicom) named elliptic curve) 04 octet string type 6d length = 109 bytes 30 sequence type 6b length = 107 bytes 02 integer type 01 01 04 octet string type 20 length = 32 bytes 90f4a50b8dd639597c01b56bb97eb0a5063ec56326da72c7acbd303354df393b private key a1 44 length = 68 bytes 03 bit string type 42 length = 66 bytes 00 no of unused bits added to right (to make a multiple of 8 bits) 04 pubkey_prefix cb452cb3662eb70920eb8532040f807853928a5d13c4331e822334a60aa04ea1 pubkey_x 15e7ce0c8648416e6bc22ef33f55d75057442b2a66c5c95ef652df9e6a306c57 pubkey_y