ASN.1 and DER

One of the great things about cryptography is the way we have managed to migrate our methods. This migration is often required when we…

ASN.1 and DER

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.

DER format

This article 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

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

The code used is [here]:

# 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 [here]:

==Sequence== Length 21
Found: 301306072a8648ce3d020106082a8648ce3d030107
==Sequence==
String: 18
Obj ID tag (06)
ID algorithm: 1.2.840.10045.2.1
String: 20
Obj ID tag (06)
ID algorithm: 1.2.840.10045.3.1.7
Found: 034200042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e
Obj ID tag (03)
Bit value: b'042927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e'
Public key: (2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838,c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e

ASN1 parsing for RSA keys

For a 512-bit modulus, we generate a key pair with:

 % openssl genrsa 512
-----BEGIN PRIVATE KEY-----
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAl/izZfKyPP6HtLru
LaGNdl3rVjKS58rji3UPJ3ADg0UBEsJNC4PlJ7sXllgP+/WuK7u03oYR3Clpy1p4
1wV53wIDAQABAkAlnnPSNby3ao5vR6Kz+vzIo0EhSk2hQVEIcYa5zXmhIa8Rp/jA
VdQPqqZQzKQx9VH6a58IcaL7+c6UrUgMPO2ZAiEAyRqS4ZNKJ+WNJZLXEdahTR3S
Gq1Wj/u16KawXCkcLjUCIQDBdLB2dqd3tTyKzhLA2Lmb9yXwKTC3NCbmNPes5qQa
QwIhALUMOHneeV9ruOO/y+HiYXskwreDoC+mA8H89z8xP46VAiBql277dtlDPhsD
qBPxKfjrFLxUnX14FEYypZCqNdLJnQIgFvka51Q8+xTBf8/i3MUz70gCHWrlVZzI
MwBbV/dBppw=
-----END PRIVATE KEY-----

Next, we can parse of ASN.1:

openssl genrsa 512 | openssl asn1parse

The result is:

0:d=0  hl=4 l= 340 cons: SEQUENCE          
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=2 l= 13 cons: SEQUENCE
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
20:d=2 hl=2 l= 0 prim: NULL
22:d=1 hl=4 l= 318 prim: OCTET STRING [HEX DUMP]:3082013A020100024100E759C49A10BDC2B1C0FE4C15A49E92C4CD3761D01F49185A858EE2A4BC15FC2FABD4BE99664B77A959672DE49B14A7B335628CA956981F6ED6E03319514ED2970203010001024100AB74B1E9E4625E3A5267A4879DBB0FD6DEA81ECB998418926DCD19573135B1F151B2ADBB1D9C5042A1A2713D74C7B9B8432823642F0C2F049B2758EA04AEB8A1022100FA0BFF7EB78505882C2F223E0213FB0333F4742C0FE0FB664BE6AFB114B2088F022100ECDBD1ADEDFED7EC7AF4EC5A87BABD5D3D609C36CDD84302B91ABD5E1BC84979022014232F3A67514136CC48277BD2F304FE270B02E821873EF7E818F6014EE75FA502205AB50C25B9C120DBD572BA9928E5A0E3763FEB53299DAA7BFE7B790DF341CEB1022026139ADF506CD178AA636C0F1F3298ED096D2E157648D6E0C9F04765C1825610
-----BEGIN PRIVATE KEY-----
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEA51nEmhC9wrHA/kwV
pJ6SxM03YdAfSRhahY7ipLwV/C+r1L6ZZkt3qVlnLeSbFKezNWKMqVaYH27W4DMZ
UU7SlwIDAQABAkEAq3Sx6eRiXjpSZ6SHnbsP1t6oHsuZhBiSbc0ZVzE1sfFRsq27
HZxQQqGicT10x7m4QygjZC8MLwSbJ1jqBK64oQIhAPoL/363hQWILC8iPgIT+wMz
9HQsD+D7Zkvmr7EUsgiPAiEA7NvRre3+1+x69Oxah7q9XT1gnDbN2EMCuRq9XhvI
SXkCIBQjLzpnUUE2zEgne9LzBP4nCwLoIYc+9+gY9gFO51+lAiBatQwlucEg29Vy
upko5aDjdj/rUymdqnv+e3kN80HOsQIgJhOa31Bs0XiqY2wPHzKY7QltLhV2SNbg
yfBHZcGCVhA=
-----END PRIVATE KEY-----

If we now parse the hex dump [here], we get:

[U] SEQUENCE (30)
[U] INTEGER (02): 0
[U] INTEGER (02): 12116817039849248401319356999406059051625450402510019431412959920523532160118594003788061025023330473032269792790470895447632127444712140733276915755831959
[U] INTEGER (02): 65537
[U] INTEGER (02): 8979870967933808304500986762609705786615928804338185205055578731706180585271669652510628578660899693850546122114560606318184417835894425432418912100595873
[U] INTEGER (02): 113099410825127742267039210262960447814981236477626644536009838628702101047439
[U] INTEGER (02): 107134218926958436110103867647326371439969054167632533529786246420125486434681
[U] INTEGER (02): 9108422575568369374329507785951527283328058442237414435525885046344655527845
[U] INTEGER (02): 41028039529255273044103130601226746271577022468212480377963214865683651350193
[U] INTEGER (02): 17222527229870173145877956394241514093758116917613573354239518584480947394064

In this case we have N=121168170398 … 90470895447632127444712140733276915755831959, e=65537, and d=89798709679338 … 22114560606318184417835894425432418912100595873. Next, we have p=107134218926958436110 … 67632533529786246420125486434681 and q=107134218926958436110 … 167632533529786246420125486434681. If you multiply p times q, you get:

>>> 113099410825127742267039210262960447814981236477626644536009838628702101047439*107134218926958436110103867647326371439969054167632533529786246420125486434681
12116817039849248401319356999406059051625450402510019431412959920523532160118594003788061025023330473032269792790470895447632127444712140733276915755831959

and which is equal to the modulus (N).

ASN.1 parsing for ECC keys

We can generate a secp256k1 private key with (the -noout option does not generate the ECC parameters):

$ openssl ecparam -genkey -name secp256k1 -noout 
- - -BEGIN EC PRIVATE KEY - - -
MHQCAQEEIMriOv4jO/lKaW8k9OZ/HnF0Oa7M0KMqcXA9ZqJ+5EH7oAcGBSuBBAAK
oUQDQgAEGgs9FtbHu7fDFnx5q5F9FI6Kw6zY1CQHhGHUWwwgwzO+YVGuONuZtsSW
bLXHglwwp0loTKHxa1tN1BDTpbK+9g==
- - -END EC PRIVATE KEY - - -

We can then parse with [here]:

$ openssl ecparam - genkey - name secp128r1 -noout | openssl asn1parse
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]:F33E1F2BD67E9C463BAFB82E31468916D108E42B6EE435647FD03D76409666FA
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

In this case, we see that we only have one integer. This is the private key, and has a value of “F33E1F2BD67E9C463BA … B6EE435647FD03D76409666FA”. We can see there are 64 hex characters, and which is 32 bytes (256 bits).

For a 128-bit curve, we can use the secp128r1 curve [here]:

$ openssl ecparam - genkey - name secp128r1 -noout | openssl asn1parse - i
0:d=0 hl=2 l= 68 cons: SEQUENCE
2:d=1 hl=2 l= 1 prim: INTEGER :01
5:d=1 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:5DAA1F9DD7951208775572F395F7C608
23:d=1 hl=2 l= 7 cons: cont [ 0 ]
25:d=2 hl=2 l= 5 prim: OBJECT :secp128r1
32:d=1 hl=2 l= 36 cons: cont [ 1 ]
34:d=2 hl=2 l= 34 prim: BIT STRING

In this case, the private key is “5DAA1F9DD7951208775572F395F7C608”, and which has 32 hex characters. This gives 128 bits for the private key.

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.3Public 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.2Signatures:
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.4Password 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.3Symmetric 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.42x.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.5ECC 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