Having X-Ray Eyes In Cybersecurity: Debugging with OpenSSL and ASN.1

The first thing we tell our students in the lab is to try and avoid using GUIs for their commands. While a GUI is unavoidable in the…

Having X-Ray Eyes In Cybersecurity: Debugging with OpenSSL and ASN.1

The first thing we tell our students in the lab is to try and avoid using GUIs for their commands. While a GUI is unavoidable in the analysis of network packets, most of our tools are command-line based.

And, so, one of the best skills that electronic and software engineers can have is the ability to debug and fault find, and it’s the same for cybersecurity analysts. In cybersecurity, it is often data at rest (on the disk), data over-the-air (on the network), or data in-process (in memory).

Often it is like finding a needle in a haystack, and the ability to move up and down levels of abstract is key, especially to break data down into its smallest elements … the bits and bytes. A good deal of the analysis, too, is the understanding of how the data is structured and which bits and bytes show what information.

X-Ray eyes

Cybersecurity is often about an alert trigger, and then an analysis of whether the alert is threat or not. If it is a threat, it then can involve digging deep into the data around the event. For this, you need X-ray eyes, and often need to call on Python, xxd, Wireshark, and so on. These tools allow for a deep inspection. One such tool is OpenSSL, and wherever there’s encrypted data around, it’s likely that OpenSSL can be used to break it open, and analyse the fields. In this case, we’ll learn a bit about the ANS.1 parse option in OpenSSL, and also a little about discrete logarthms (using the DSA — Digital Signature Algorithm). While DSA is now a legacy method, the learning of discrete logarithms is a good thing for understand the basics of cryptography.

DSA

The Digital Signature Algorithm (DSA) is a standard defined in Federal Information Processing Standard (as FIPS 186) for digital signatures, and is based on discrete logarithms. It was outlined by NIST is 1991, and proposed within the Digital Signature Standard (DSS). This was then standardized with FIPS 186 in 1994, and FIPS 186–4 in 2013. Within FIPS 186–5, it is defined that DSA should not be used for the generation of signatures, but can be used for signature verification.

Although DSA has a patent (Patent 5,231,668 by David W. Kravitz, who had previously worked for the NSA), NIST published the standard as a royality-free. The ECDSA method is an extension of DSA, but implemented with elliptic curve (EC) methods. As with most public key signing methods, we take a hash of a message, and then apply a private key to create a signature (r,s). This is done by creating a random value (k) to produce the signature. The signature is then verified using the associated public key. This then verifies the creator of the signature and that the message has not been changed.

Method

With a discrete logarithm method, we typically have a base generator (g) and a prime number (p). We can then perform operations such as:

and:

Initially, Bob creates two prime numbers (p and q) and generates a generator value of g. Next, he generates his secret key (x) and then computes his public key:

To create a signature for a message (M), he creates a random value (k) and then computes two values for the signature:

When Alice receives this signature, she takes Bob’s public key (p,q,g,Y) and the message can compute:

She then checks that vis equal to r. If so, the signature checks out. This works because:

Coding

First, we need to generate the DSA parameters (g, q and p). This typically generates a PEM file (and which has a header and footer of with “ — DSA Parameters — “. Next we can parse this for its values in an ASN.1 form [here]:

$ openssl dsaparam -out dsaparam.pem 1024
$ cat dsaparam.pem | openssl asn1parse
0:d=0 hl=4 l= 294 cons: SEQUENCE
4:d=1 hl=3 l= 129 prim: INTEGER :F32D65E67DAEEA3BFD27F8E111EC8839AF1DF699ED1EB77F56AE8712F8DDB7047177DC08FC352F1F3AFD491C0FCB6558FFFA884C59BF131C8F2B83B52BDE7398D3DE305D75A8673DA256555C7212633356C0F54D50A595FDBE8DA1DB02A19F93C111B96E89F290D1B0693FA74B77074F20C485258644D2E9E5673A0B86559931
136:d=1 hl=2 l= 29 prim: INTEGER :A9E0490B4326857C1B6ACE962D30125BFE3BC2954D354F7FFEF11BA5
167:d=1 hl=3 l= 128 prim: INTEGER :6F54C58630BD46CAA0ECF31FD9471389E4F2056C1D1EE9A4A088180804BC327138EC4A26989884971ECEB4F159935D72DE654B3AFF329D61588AAC29CB8F2D7DEDC05A5912CC089E8F8E043019EAC944D2D1CBA1225AD17827BAA7AC1F11FCC82D9B9D632D4716A4D758EED8D84DCA7C4C07DE49AE861DA4A9025C6987EFA790

-----BEGIN DSA PARAMETERS-----
MIIBJgKBgQDzLWXmfa7qO/0n+OER7Ig5rx32me0et39WrocS+N23BHF33Aj8NS8f
Ov1JHA/LZVj/+ohMWb8THI8rg7Ur3nOY094wXXWoZz2iVlVcchJjM1bA9U1QpZX9
vo2h2wKhn5PBEbluifKQ0bBpP6dLdwdPIMSFJYZE0unlZzoLhlWZMQIdAKngSQtD
JoV8G2rOli0wElv+O8KVTTVPf/7xG6UCgYBvVMWGML1GyqDs8x/ZRxOJ5PIFbB0e
6aSgiBgIBLwycTjsSiaYmISXHs608VmTXXLeZUs6/zKdYViKrCnLjy197cBaWRLM
CJ6PjgQwGerJRNLRy6EiWtF4J7qnrB8R/Mgtm51jLUcWpNdY7tjYTcp8TAfeSa6G
HaSpAlxph++nkA==
-----END DSA PARAMETERS-----

In the case, we have p= F32D65E67DAEEA3BFD … 59931, q= A9E0490B4326857C1B6 … C2954D354F7FFEF11BA5, and q= 6F54C58630 … FA790. Thus g and p have 256 hex characters, and which is 1,024 bits, and q has 56 hex characters, and represents 224 bits (the size of the private key).

Next, we need to generate the DSA key (g, q, p, pub and priv) [here]:

$ openssl gendsa -out 1.pem dsaparam.pem
$ openssl dsa -in 1.pem -text | openssl asn1parse
0:d=0 hl=4 l= 458 cons: SEQUENCE
4:d=1 hl=2 l= 1 prim: INTEGER :00
7:d=1 hl=3 l= 129 prim: INTEGER :F32D65E67DAEEA3BFD27F8E111EC8839AF1DF699ED1EB77F56AE8712F8DDB7047177DC08FC352F1F3AFD491C0FCB6558FFFA884C59BF131C8F2B83B52BDE7398D3DE305D75A8673DA256555C7212633356C0F54D50A595FDBE8DA1DB02A19F93C111B96E89F290D1B0693FA74B77074F20C485258644D2E9E5673A0B86559931
139:d=1 hl=2 l= 29 prim: INTEGER :A9E0490B4326857C1B6ACE962D30125BFE3BC2954D354F7FFEF11BA5
170:d=1 hl=3 l= 128 prim: INTEGER :6F54C58630BD46CAA0ECF31FD9471389E4F2056C1D1EE9A4A088180804BC327138EC4A26989884971ECEB4F159935D72DE654B3AFF329D61588AAC29CB8F2D7DEDC05A5912CC089E8F8E043019EAC944D2D1CBA1225AD17827BAA7AC1F11FCC82D9B9D632D4716A4D758EED8D84DCA7C4C07DE49AE861DA4A9025C6987EFA790
301:d=1 hl=3 l= 128 prim: INTEGER :3B8B165B513C634ECF18EE25F9E9822EBCC093AD9CA7B178E6BB7505590558EA22D5D66A04ACC5290E80241250FB3DBAD9C417E6EF689561F7718B982035F94C5E8715604EB0866F068B17064006841D055C66DB5F0EBFD471DA542FD3A2B496B9D1B299F3A01EE845E1E7EEB8E6A219651EDBF903D9DBC0836FFCE3E5789C7B
432:d=1 hl=2 l= 28 prim: INTEGER :4131BA6870D09314D3E645D9B3C682FC5791917C4EF52C67D3B76A11

-----BEGIN PRIVATE KEY-----
MIIBWgIBADCCATMGByqGSM44BAEwggEmAoGBAPMtZeZ9ruo7/Sf44RHsiDmvHfaZ
7R63f1auhxL43bcEcXfcCPw1Lx86/UkcD8tlWP/6iExZvxMcjyuDtSvec5jT3jBd
dahnPaJWVVxyEmMzVsD1TVCllf2+jaHbAqGfk8ERuW6J8pDRsGk/p0t3B08gxIUl
hkTS6eVnOguGVZkxAh0AqeBJC0MmhXwbas6WLTASW/47wpVNNU9//vEbpQKBgG9U
xYYwvUbKoOzzH9lHE4nk8gVsHR7ppKCIGAgEvDJxOOxKJpiYhJcezrTxWZNdct5l
Szr/Mp1hWIqsKcuPLX3twFpZEswIno+OBDAZ6slE0tHLoSJa0XgnuqesHxH8yC2b
nWMtRxak11ju2NhNynxMB95JroYdpKkCXGmH76eQBB4CHEExumhw0JMU0+ZF2bPG
gvxXkZF8TvUsZ9O3ahE=
-----END PRIVATE KEY-----

As we can see, we have taken g, q and p from the parameters, and now generated a private key of x=4131BA6870D09314D3 … 4EF52C67D3B76A11, and a public key of Y=3B8B165B513C634ECF18EE25 … A542FD3A2B496B9D1B299F3A01EE845E1E7EEB8E6A219651EDBF903D9DBC0836FFCE3E5789C7B.

We can see that the private key (priv) has 28 bytes (224 bits), while the public key (pub=G^{priv} (modP)) and prime number P has 128 bytes (1,024 bits). Notice that the Q value is smaller that the other prime (P). In a signature, Bob will sign with priv, and then send his public key (pub,P,Q and G) to Alice. She can then check Bob’s signature with his public key.

Now let’s try to compute this with Python, and check that the parameters are used correctly. Let’s take the private key (x), the generator (g) and the prime number (p), and compute the public key (Y):

>>> g=0x6F54C58630BD46CAA0ECF31FD9471389E4F2056C1D1EE9A4A088180804BC327138EC4A26989884971ECEB4F159935D72DE654B3AFF329D61588AAC29CB8F2D7DEDC05A5912CC089E8F8E043019EAC944D2D1CBA1225AD17827BAA7AC1F11FCC82D9B9D632D4716A4D758EED8D84DCA7C4C07DE49AE861DA4A9025C6987EFA790
>>> x=0x4131BA6870D09314D3E645D9B3C682FC5791917C4EF52C67D3B76A11
>>> p=0xF32D65E67DAEEA3BFD27F8E111EC8839AF1DF699ED1EB77F56AE8712F8DDB7047177DC08FC352F1F3AFD491C0FCB6558FFFA884C59BF131C8F2B83B52BDE7398D3DE305D75A8673DA256555C7212633356C0F54D50A595FDBE8DA1DB02A19F93C111B96E89F290D1B0693FA74B77074F20C485258644D2E9E5673A0B86559931
>>> Y=pow(g,x,p)
>>> print (hex(Y))
0x3b8b165b513c634ecf18ee25f9e9822ebcc093ad9ca7b178e6bb7505590558ea22d5d66a04acc5290e80241250fb3dbad9c417e6ef689561f7718b982035f94c5e8715604eb0866f068b17064006841d055c66db5f0ebfd471da542fd3a2b496b9d1b299f3a01ee845e1e7eeb8e6a219651edbf903d9dbc0836ffce3e5789c7b

This matches:

301:d=1  hl=3 l= 128 prim: INTEGER           :3B8B165B513C634ECF18EE25F9E9822EBCC093AD9CA7B178E6BB7505590558EA22D5D66A04ACC5290E80241250FB3DBAD9C417E6EF689561F7718B982035F94C5E8715604EB0866F068B17064006841D055C66DB5F0EBFD471DA542FD3A2B496B9D1B299F3A01EE845E1E7EEB8E6A219651EDBF903D9DBC0836FFCE3E5789C7B

Conclusions

In cybersecurity, you never know what will be coming along next, and need to have a whole toolbox of tricks. OpenSSL is one of the most useful tools, and you can find out more about it here:

https://asecuritysite.com/openssl/