• caglararli@hotmail.com
  • 05386281520

Why does PEM Base64 created by `openssl pgen` not match the DER file passed in?

Çağlar Arlı      -    2 Views

Why does PEM Base64 created by `openssl pgen` not match the DER file passed in?

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 pgen 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