We need ways to distribute our public keys, private keys and digital certificates in a portable format. One of the most common forms is Distinguished Encoding Rules (DER) encoding of ASN.1. Overall it is truly binary representation of the encoded data. The other common format is PEM, and which converts the binary encoding into a text readable format. With PEM we can encode cryptographic infromation in a Base64 ASCII format and with plain-text headers and footers of "-----BEGIN RSA PRIVATE KEY-----" and "-----END RSA PRIVATE KEY-----", whereas with DER we have binary format. In this page, we will read in a DER encoded hex string and determine its contents [ASN.1 reader for PEM and DER].
Distinguished Encoding Rules (DER) format |
Theory
One of the great things about cryptography is the way we have managed to migrate our methods. This migration is often required when we introduce new methods (such as with ECC) or where methods are deprecated (such as for DES). We thus have ways to define new methods and which can be easily interpreted by applications. At the core of this is the DER format for defining our cryptography.
We need ways to distribute our public keys, private keys and digital certificates in a portable format. One of the most common forms is Distinguished Encoding Rules (DER) encoding of ASN.1 (Abstract Syntax Notation One). Overall it is a truly binary representation of the encoded data. The other common format is PEM, and which converts the binary encoding into a text readable format. With PEM we can encode cryptographic information in a Base64 ASCII format and with plain-text headers and footers of “ — — -BEGIN RSA PRIVATE KEY — — -” and “ — — -END RSA PRIVATE KEY — — -”, whereas with DER we have binary format.
This page will look at the DER format and has code to decode a hex string and into its contents. Overall ASN.1 is used to define abstract types and values. One of the most basic types is SEQUENCE and is an ordered collection of one or more types. In DER, SEQUENCE is identified with a tag of “30”, and followed by a byte value for the length of the object defined. The other common types are OBJECT IDENTIFIER (and which has a tag of “06”) and BIT STRING (and which has a tag of “03”).
The object identifier tag is used to define the cryptography methods used. An example identifier for ECC encryption is “1.2.840.10045.2.1”, and where 1 is OSI, 2 is member body, 840 is US (ANSI), and 10045 is “ansi-X9–62”, and “2” is key type [1]. Other common algorithms are: “1.2.840.113549.1.1.1” (X509 RSA), “1.2.840.10040.4.1” (X509 Digital Signature Standard -DSS), and “1.2.840.10046.2.1” (Diffie-Hellman — DH). The following is an example of the hex sequence for an object ID, and where we have the “06” tag, followed by an identifier for seven bytes (“07”), and then the Object ID of seven bytes (“2a8648ce3d0201”):
06 07 2a8648ce3d0201 # Object ID - 7 bytes long - 1.2.840.10045.2.1 (ECC)
We can also define the curve type in the object identifier, and where we have the form of iso(1), member-body(2), us(840), ansi-X9–62(10045), curves(3), prime(1). For example, 1.2.840.10045.3.1.7 defines ECDSA P-256. Other examples are SECP192R1 (“1.2.840.10045.3.1.1”), SECP224R1 (“1.3.132.0.33”), SECP256K1 (“1.3.132.0.10”), SECP256R1 (“1.2.840.10045.3.1.7”), SECP384R1 (“1.3.132.0.34”), SECP521R1 (“1.3.132.0.35”), and BRAINPOOLP256R1 (“1.3.36.3.3.2.8.1.1.7”). An example where we have an identifier (“06”), followed by the number of bytes identifier (“08”) and Object ID of eight bytes (“2a8648ce3d030107”):
06 08 2a8648ce3d030107 # Object ID - 8 bytes long - 1.2.840.10045.3.1.7 (ECDSA P256)For the “03” tag, we define a bitstream for keys. In the following, we have “03”, followed by the number of bytes (66 bytes) for the keys, and then the keys are defined after this (64 bytes):
03 42 # Bit stream - 0x42 (66 bytes long) 0004 # Identifies public key 2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # Identifies public key x co-ordinate c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e # Identifies public key y co-ordinate
An example hex string for a DER format for ECC public keys is:
3059301306072a8648ce3d020106082a8648ce3d030107034200042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513
We can then break down with:
30 59 # Sequence length 0x59 - 91 bytes long 30 13 # Sequence length 0x13 - 21 bytes long 06 07 2a8648ce3d0201 # Object ID - 7 bytes long - 1.2.840.10045.2.1 (ECC) 06 08 2a8648ce3d030107 # Object ID - 8 bytes long - 1.2.840.10045.3.1.7 (ECDSA P256) 03 42 # Bit stream - 0x42 (66 bytes long) 0004 # Identifies public key 2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # Identifies public key x co-ordinate c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e # Identifies public key y co-ordinate
If we need to convert a DER into a hex format, we can just use "xxd" and "tr":
% xxd -plain 512b-rsa-example-keypair.der | tr -d '\n' 3082013b0201000241009bfc6690798442bbab13fd2b7bf8de1512e5f193e3068a7bb8b1e19e26bb9501bfe730ed648502dd1569a834b006ec3f353c1e1b2b8ffa8f001bdf07c6ac5307020301000102401b4af77b31f7e56146d6d1866943ab400eb5732688239dd9760091d4853c6f1ec051ebe6905b417fe6aa316bac59539626f1aedabe55a47540225f2717a0d291022100c8c4277cd561adbf328e1ecbe894f49f5577e5a8c970d00f8104b709b21b53e9022100c6e665be10c86db71eee8e41bce867099d8dee461bd590b9ee0dc5f9c6c9c96f0221009bb0318706da36a89c85c5b00eeee43c6345151dad0904efe0f74d1201c25b71022046d1258c84a1381f290e3aec40fc6623504b8678c3d448514ae6f0843c3900550221008d036e290ed74e1f2770b52079fb316a14b7e6559a6540cfe0e646f8b28ef4630a
In OpenSSL, we can convert from DER to PEM with:
openssl x509 -inform der -in mycert.der -out mycert.pem
and:
openssl x509 -outform der -in mycert.pem -out mycert.der
An example of a public key is:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw51PMBm2psyIjHPU1efH Ulyh22zy3hEhlsNPH6/Cqg0HJorX1WbNKLfiU2aAt24jn4CC+y8PusrmMMCIca5x 0L4XZxm14QvKKImIOMOMblS1Te29n64HuuQ9owKLHuSMww4wiLiY/nAvjK/5/kKT HL6x7nK/Pq72eoQ/etFBkaX5nYGUD/+G+5BgAPx1mBgU5/y9+/+QZ9xbYU6zogOW Tfa6rDMSAbmJOtkk1ghnuaq4dSoHWbW+zpHMVtjtHgzDGhX9KjOmvSDQIGn4wevD p2yDLULUbsdO4ylacTkxyIc92ZHdZeP6Hh+KhNC04Z65zwXLEA3M4bucX+u6nszW xwIDAQAB -----END PUBLIC KEY-----
Code
The code used is:
# https://asecuritysite.com/encryption/sigs3 import sys,binascii from findit import findit from Crypto.Util.asn1 import DerObjectId,DerBitString, DerSequence, DerInteger der="305c300d06092a864886f70d0101010500034b003048024100a79850deede08e51270555ac9ea15623e22f902058fcdb87383cca46ca886ad6f95f6dcb7ed34198eb2ce07bc7459d1f4ebcce43c87147ebd263a67abaa8b3390203010001" if (len(sys.argv)>1): der=str(sys.argv[1]) print (f"\nDER string: {der}") # 30 59 # 30 13 # 06 07 2a8648ce3d0201 # 06 08 2a8648ce3d030107 # 03 42 # 0004 # 2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838 # c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e" pkx="" pky="" der_str=DerSequence() der_str.decode(binascii.unhexlify(der)) ctype="" res=der_str[:] print ("\n\n==Sequence==") for r in res: if (str(r).isnumeric()): print ("Integer (02): ",hex(r)) continue r=binascii.hexlify(r).decode() if (r[0:2]=="30"): print ("--->Sequence (30)") der_str=DerSequence() der_str.decode(binascii.unhexlify(r)) for st in (der_str[:]): if (str(st).isnumeric()): print ("--->Sequence (30)") continue r=binascii.hexlify(st).decode() if (r[0:2]=="06"): print (" --->Obj ID tag (06 - Object ID)") der_str=DerObjectId() der_str.decode(binascii.unhexlify(r)) print (" ",findit(der_str.value)) ctype = der_str.value elif (r[0:2]=="a0"): print ("--->Sequence (A0)") print (" --->Obj ID tag (06 - Object ID)") der_str=DerObjectId() der_str.decode(binascii.unhexlify(r[4:])) print (" ",findit(der_str.value)) elif (r[0:2]=="a1"): print ("--->Sequence (A1)") der_str=DerBitString() der_str.decode(binascii.unhexlify(r[4:])) bits =binascii.hexlify(der_str.value) print (" Bit value: ",binascii.hexlify(der_str.value)) elif (r[0:2]=="03"): print ("--->Obj ID tag (03)") if (r[6:8]=="30"): length = int(r[2:4],16) seq = r[6:] der_str=DerSequence() der_str.decode(binascii.unhexlify(seq)) for st in (der_str[:]): print (" --->Obj ID tag (02 - Integer)") print (" ",hex(st)) if (r[8:10]=="30"): seq = r[8:] der_str=DerSequence() der_str.decode(binascii.unhexlify(seq)) for st in (der_str[:]): print (" --->Obj ID tag (02 - Integer)") print (" ",hex(st)) else: der_str=DerBitString() der_str.decode(binascii.unhexlify(r)) bits =binascii.hexlify(der_str.value) print (" Bit value: ",binascii.hexlify(der_str.value)) pkx=bits[2:64+2].decode() pky=bits[64+2:128+2].decode() print (f" Public key: ({int(pkx,16)},{int(pky,16)}") # "wx" : "2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838", # "wy" : "00c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e" from Crypto.PublicKey import ECC from Crypto.PublicKey import RSA if (ctype=="1.2.840.10045.3.1.7"): print ("\nNow checking key if ECC - 256") key = ECC.generate(curve='P-256') f = binascii.unhexlify(der) rtn=ECC.import_key(f) print ("\n",rtn) rtn=rtn.export_key(format='PEM') print ("\n",rtn) if (ctype=="1.3.132.0.35"): print ("\nNow checking key if ECC - 521") key = ECC.generate(curve='P-521') f = binascii.unhexlify(der) rtn=ECC.import_key(f) print ("\n",rtn) rtn=rtn.export_key(format='PEM') print ("\n",rtn) if (ctype=="1.3.132.0.34"): print ("\nNow checking key if ECC - 384") key = ECC.generate(curve='NIST P-384') f = binascii.unhexlify(der) rtn=ECC.import_key(f) print ("\n",rtn) rtn=rtn.export_key(format='PEM') print ("\n",rtn) if (ctype=="1.2.840.113549.1.1.1"): print ("\nNow checking key if RSA") key = RSA.generate(1024) f = binascii.unhexlify(der) rtn=RSA.import_key(f) print ("\n",rtn) rtn=rtn.export_key(format='PEM') print ("\n",rtn.decode()) # "keyPem" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKSexBRK64+3c/kZ4KBKLrSkDJpkZ\n9whgacjE32xzKDjHeHlk6qwA5ZIfsUmKYPRgZ2az2WhQAVWNGpdOc0FRPg==\n-----END PUBLIC KEY-----"
A sample run for an RSA public key:
==Sequence== --->Sequence (30) --->Obj ID tag (06 - Object ID) ID algorithm: 1.2.840.113549.1.1.1 RSA Encryption --->Obj ID tag (03) R is 03818d0030818902818100a399caf6d93b62a6b6a5311efe93c4d647397ca05a98fa5cddb72d6816ab16fc85f940efe9cf2233975c8925c60f4cd356767cc8445686313a0caeae32930070ca90591a1b249c2fcef9280f5a11d8f1990579d86a05b2523f52c4a876da2d635ca27fbff195e6f7015f834928f033a20b2cd0216a852958b3e58d0f9bd542330203010001 --->Obj ID tag (02 - Integer) 0xa399caf6d93b62a6b6a5311efe93c4d647397ca05a98fa5cddb72d6816ab16fc85f940efe9cf2233975c8925c60f4cd356767cc8445686313a0caeae32930070ca90591a1b249c2fcef9280f5a11d8f1990579d86a05b2523f52c4a876da2d635ca27fbff195e6f7015f834928f033a20b2cd0216a852958b3e58d0f9bd54233 --->Obj ID tag (02 - Integer) 0x10001 Now checking key if RSA Public RSA key at 0x7F858855EE80 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjmcr22TtipralMR7+k8TWRzl8 oFqY+lzdty1oFqsW/IX5QO/pzyIzl1yJJcYPTNNWdnzIRFaGMToMrq4ykwBwypBZ GhsknC/O+SgPWhHY8ZkFedhqBbJSP1LEqHbaLWNcon+/8ZXm9wFfg0ko8DOiCyzQ IWqFKViz5Y0Pm9VCMwIDAQAB -----END PUBLIC KEY-----
This gives N (modulus) and e (public exponent). A sample run for an RSA private key is:
DER string: 3082013a020100024100a53c172810b45f94cb1edbd6a7eeffd5fa94b4c692d00bec0760bc53dff8b3034ed82f92debb553ae6fc0663ab90247e71af25a7643ad055cec78345b92c36c7020301000102403de24885efe3ae1c8b0a6ea97151d8ad6a610167919aabac6582fc65a96f7a937b40f06c5594f0fe1a74b957e731a021f9b214bfcb7fecfee328a9b041eb8d41022100da6a12118066136f8b1478dd78625bb80ed2ffa6b525a0cbc89058a37040faa7022100c1ab44c7fd1fcc554f4143072361f0bf064619b25fcc54064def8692da5006e102203bf114585d46a65adc6e97e5201ece512b30591d2565d845551bd857b27d02cd02201acc03dc581dca3c1397481af8be587d55f4e521553804784ad8559a84328681022100bd24bc374ab656a11b2d531ac4eaebb5dd013848c654268d453942a39248bc32 ==Sequence== Integer (02): 0x0 Integer (02): 0xa53c172810b45f94cb1edbd6a7eeffd5fa94b4c692d00bec0760bc53dff8b3034ed82f92debb553ae6fc0663ab90247e71af25a7643ad055cec78345b92c36c7 Integer (02): 0x10001 Integer (02): 0x3de24885efe3ae1c8b0a6ea97151d8ad6a610167919aabac6582fc65a96f7a937b40f06c5594f0fe1a74b957e731a021f9b214bfcb7fecfee328a9b041eb8d41 Integer (02): 0xda6a12118066136f8b1478dd78625bb80ed2ffa6b525a0cbc89058a37040faa7 Integer (02): 0xc1ab44c7fd1fcc554f4143072361f0bf064619b25fcc54064def8692da5006e1 Integer (02): 0x3bf114585d46a65adc6e97e5201ece512b30591d2565d845551bd857b27d02cd Integer (02): 0x1acc03dc581dca3c1397481af8be587d55f4e521553804784ad8559a84328681 Integer (02): 0xbd24bc374ab656a11b2d531ac4eaebb5dd013848c654268d453942a39248bc32
This gives version, N (modulus), e (public exponent), d (private exponent), p1 (prime 1), p2 (prime 2), ex1 (d mod (p-1)), ex2 ( d mod (q-1)), co (co-efficient)
References
[1] RFC 3279, Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile [here]
A list of object IDs:
Hashing: MD2 1.2.840.113549.2.2 MD5 1.2.840.113549.2.5 SHA-1 1.3.14.3.2.26 SHA-224 2.16.840.1.101.3.4.2.4 SHA-256 2.16.840.1.101.3.4.2.1 SHA-394 2.16.840.1.101.3.4.2.2 SHA-512 2.16.840.1.101.3.4.2.3 Public key: RSA Encryption 1.2.840.113549.1.1.1 DSA 1.2.840.10040.4.1 Diffie-Hellman (dhPublicNumber) 1.2.840.10046.2.1 ECC (ecPublicKey) 1.2.840.10045.2.1 md2WithRsaEncryption 1.2.840.113549.1.1.2 Signatures: md5WithRsaEncryption 1.2.840.113549.1.1.4 sha1WithRsaEncryption 1.2.840.113549.1.1.5 sha224WithRsaEncryption 1.2.840.113549.1.1.14 sha256WithRsaEncryption 1.2.840.113549.1.1.11 sha384WithRsaEncryption 1.2.840.113549.1.1.12 sha512WithRsaEncryption 1.2.840.113549.1.1.13 dsaWithSha1 1.2.840.10040.4.3 dsaWithSha224 2.16.840.1.101.3.4.3.1 dsaWithSha256 2.16.840.1.101.3.4.3.2 ecdsaWithSha1 1.2.840.10045.4.1 ecdsaWithSha224 1.2.840.10045.4.3.1 ecdsaWithSha256 1.2.840.10045.4.3.2 ecdsaWithSha384 1.2.840.10045.4.3.3 ecdsaWithSha512 1.2.840.10045.4.3.4 Password Base Encryption Algorithms: pbeWithMd2AndDesCbc 1.2.840.113549.1.5.1 pbeWithMd5AndDesCbc 1.2.840.113549.1.5.3 pbeWithSha1AndDesCbc 1.2.840.113549.1.5.10 pbeWithMd2AndRc2Cbc 1.2.840.113549.1.5.4 pbeWithMd5AndRc2Cbc 1.2.840.113549.1.5.6 pbeWithSha1AndRc2Cbc 1.2.840.113549.1.5.11 pbeWithSha1And40BitRc2Cbc 1.2.840.113549.1.12.1.6 pbeWithSha1And128BitRc2Cbc 1.2.840.113549.1.12.1.5 pbeWithSha1And40BitRc4 1.2.840.113549.1.12.1.2 pbeWithSha1And128BitRc4 1.2.840.113549.1.12.1.1 pbeWithSha1And3DesCbc 1.2.840.113549.1.12.1.3 Symmetric Encryption Algorithms: DES CBC 1.3.14.3.2.7 3DES CBC 1.2.840.113549.3.7 RC2 1.2.840.113549.3.2 ArcFour 1.2.840.113549.3.4 AES CBC 128 2.16.840.1.101.3.4.1.2 AES CBC 256 2.16.840.1.101.3.4.1.42 x.500 Distinguished Name Attributes: name 2.5.4.41 surname 2.5.4.4 given name 2.5.4.42 initials 2.5.4.43 generation qualifier 2.5.4.44 common name 2.5.4.3 locality name 2.5.4.7 state or province name 2.5.4.8 organization name 2.5.4.10 organizational unit name 2.5.4.11 title 2.5.4.12 dnQualifier 2.5.4.46 country name 2.5.4.6 email address 1.2.840.113549.1.9.1 domain component 0.9.2342.19200300.100.1.25 street address 2.5.4.9 postal code 2.5.4.17 mail 0.9.2342.19200300.100.1.3 serial number 2.5.4.5 ECC names: secp192r1 1.2.840.10045.3.1.1 secp224r1 1.3.132.0.33 secp256r1 1.2.840.10045.3.1.7 secp384r1 1.3.132.0.34 secp521r1 1.3.132.0.35 brainpoolP160r1 1.3.36.3.3.2.8.1.1.1 brainpoolP192r1 1.3.36.3.3.2.8.1.1.3 brainpoolP224r1 1.3.36.3.3.2.8.1.1.5 brainpoolP256r1 1.3.36.3.3.2.8.1.1.7 brainpoolP320r1 1.3.36.3.3.2.8.1.1.9 brainpoolP384r1 1.3.36.3.3.2.8.1.1.11 brainpoolP512r1 1.3.36.3.3.2.8.1.1.13