When it comes to guarantee data confidentiality on the wire or on the disk we cannot be exempt to know how to use cryptography: this post provides a quick guide of both symmetric and asymmetric cryptography along with an overview of their bricks: RSA and DSA keys, Elliptic Curves keys, PGP Keys, Message Digest, HMAC, digital signature and encipherment. The aim is to provide the necessary terms and concepts to understand how to operate with cryptographic tools, providing examples with openssl.

Terms

Keys

It is a set of data used to feed cryptographic routines: they are called keys since same way as physical keys lock and unlock things, cryptographic keys lock and unlock cryptographic objects. There are two kind of keys:

  • symmetric – a single key
  • asymmetric – a pair of keys: one is private, the other is public

Symmetric (often called secret) keys and private keys must never and ever be disclosed since whoever has access to those keys can use (or abuse) them. We should make our best to avoid having our keys compromised: a compromised key is a key that got stolen or disclosed to unauthorized people.

A compromised key can be used to sign documents as if they were signed from the real owner of the key.

We must take all the measures necessary to avoid the key to be compromised, such as

  • limiting read access to the file containing the key
  • encrypting the key using a password-protected symmetric encryption function

Encryption should always be used, either if we are storing the key into a filesystem or we are transmitting the key to a peer.

There's only one kind of key that as its name suggests is public: the so-called public key of an asymmetric key pair.

Encryption

It is the scrambling of data so that it appears without an understandable meaning: scrambled data are said to be encrypted, whereas the original data are said to be plain-text (or unencrypted). There are two types of encryption: symmetric and asymmetric encryption, based on the type of keys used.

Basically there are two families of encryption algorithms:

  • block ciphers, such as DES, 3DES, Blowfish, IDEA, RC2, RC5, AES, ... : data gets encrypted by fixed size blocks (64, 128,...)
  • stream ciphers, such as RC4, SALSA, SOSEMANUK, PANAMA, ...: operate on each byte of data, so requiring fewer resources than block ciphers

Typically, stream ciphers are faster than block ciphers, although some of them are considered less secure than block ciphers. For example, RFC 7465 prohibits the use of RC4 in all versions of TLS. However, because they perform faster than block ciphers, stream ciphers are certainly interesting when it comes to stream data over the wire.

Block ciphers have several operating modes - provide a thorough explanation of them would be too theoretical for this post so I only list them providing a summary description:

  • Electronic Codebook Mode (ECB): data is handled in blocks of 64bits, one at a time, encrypting every block with the same key, padding the last chunk of data if it does not completely fit the last block. There's a risk with brute-force attacks and, in addition to that, an attacker can easily modify the order of the blocks, thus preventing the peer from being able to decrypt the message.
  • Cipher-Block Chaining (CBC): perform a xor of the data of the current block with the one of the previous one. Since there's not a preceding block, he first block uses an Initialization Vector (IV) for the xor block. The IV is randomly generated as new each time the encipher process is started, so to cope with replay-attacks. 
  • Cipher Feedback (CFB): use some optimizations to be a little bit more performing, making it more suitable than the others to encrypt data streams
  • Output Feedback mode (OFB): very similar to CFB, it does not propagate errors of transmission of bits, but it is more vulnerable to an attack that modifies the flow of the messages.
  • Counter (CTR): a mode specifically developed to be used with ATM and IPSec.
Malicious people may try to decrypt data by exploiting algorithms weakness and brute-force attacks: a brute-force attack consists in trying to force by continuous trials. However if strong keys, high-quality passwords and modern encryption methods are used, they should resist brute force attacks. Take in account that chances to violate encrypted contents increase as years go by, since computers become more and more powerful. For this reason it is wise to always keep current on cryptography standards in order to be able to find your weakness and fix them before breaches happen.

Message Digest

The solution to the integrity check problem

It is the outcome of deriving a bit array of a fixed size from the original data using a mathematical algorithm that cannot be reverted (it is called cryptographic hash). Examples of cryptographic hash functions are:

  • MD-4, MD-5, RIPEMD-160
  • SHA-1, SHA-256, SHA-512

Message digests are generated using a symmetric key and are suitable to implement the so called Message Authentication Code (MAC): this is the process of validating data integrity by verifying that the MAC code calculated at the receiving party does match the one provided by the sender: if it doesn't, it means that data has been tampered.

Hash-based Message Authentication Code

The solution to the authentication problem

Message digests let you verify that the message has not been tampered, but they do not guarantee that the received message does actually come from the entity that is supposed to be the author instead of from an impostor. This limitation is addressed by the Hash-based Message Authentication Code (HMAC) algorithm: it has been specifically designed to enable the parties to establish a trusted channel and to agree on the key and the MAC algorithm to use. This resolves the authentication problem: but there is still a missing thing: since both parties calculate the MAC using the shared key, you cannot say from a MAC which one of the parties did generate it. So HMAC are suitable for integrity check and authentication, but not for non-repudiation, since we cannot clearly identify who generated the MAC.

Signing

The solution to the non-repudiation problem

Asymmetric cryptography addresses the non-repudiation problem: when digitally signing  the sender encrypts the MAC using its own private key. Any receiver can easily verify that the message comes from us by decrypting it using the sender's public key, and then verify the integrity of the message validating the MAC. Conversely from HMAC, each party has its own private key, and so the signature can clearly identify who signed the message.

Symmetric Cryptography

Symmetric cryptography relies on symmetric keys, so only one secret key is used by both parties to perform cryptographic operations, such as encrypting, decrypting or Message Code Authentication.

Let's see it in action

We use openssl solely for providing examples, since it is really handy to explain concepts - when it comes to encrypt things in real life you'd better to use PGP. We'll have a deep dive on PGP on a future post.

Secret Key

It is a key that contains random data: we can easily generate one as follows: for example, to create 256 random bits:

openssl rand -out key.bin 32

we specified 32 since rand uses bytes: 256/8=32.

Encrypting contents

This is the most straightforward type of encryption: both parties use the same key to encrypt and decrypt. Despite this kind of encryption is easier to implement and offers better performance if compared with asymmetric encryption, it is cumbersome to keep secure since you have to deliver copies of the key in situations such as:

  • as time goes by, ideally you should generate a new key and provide it to all the parties to replace the old one
  • you should provide the key to any new party that get added
  • if one of the party withdraws or get compromised you should generate a new key and provide it to all the parties

Commonly used symmetric encryption algorithms include:

  • AES
  • Blowfish
  • Camellia
  • Idea
  • DES, 3DES
  • RC4, RC5, RC6
  • Twofish

In this example, we encrypt using AES-256 using cfb8 mode of operation: as we already saw, the mode of operation is the way to repeatedly apply a cipher’s single-block operation to securely transform amounts of data larger than a block.

cfb8 is only one of the modes of operation supported by the AES algorithm: as we already saw, other supported modes for example are cbc, cfb, ofb, and gcm.

So to  hide patterns in the encrypted data, we use an Initialization Vector (IV). It is needed to both encrypt and decrypt data, and the best practice is to use a new IV at each encryption operation: if you decrypt the file to modify it, and then you encrypt it back you should generate a new IV. In this particular use case, we need an hexadecimal IV:

IV=$(openssl rand -hex 16)

if you want to have a look at it:

echo ${IV}
e30a56e5dbce056834a513a3779d6a46

we are ready to encrypt files: as an example let's encrypt the contents of /etc/issue file into issue.dat

openssl enc -aes-256-cfb8 -in /etc/issue -pbkdf2 -iv ${IV} -out issue.dat

it asks for the password to be used for the encryption:

enter aes-256-cfb8 encryption password:
Verifying - enter aes-256-cfb8 encryption password:

The -pbkdf2 parameters tells openssl to generate and use a derived key: this is generated by repeatedly calling a pseudo-random function using a salt.

We can now try to decrypt what we have encrypted: the command is as follows:

openssl enc -d -aes-256-cfb8 -in issue.dat -out issue.txt -pbkdf2 -iv ${IV}

it asks for the password to be used for decrypting:

enter aes-256-cfb8 decryption password:

If we prefer not use a password, we can use generate a key file using "openssl rand ... " as we saw before and provide its path using the -key command option:

openssl rand -out key.bin 32
openssl enc -aes-256-cfb8 -in /etc/issue -k file:key.bin -pbkdf2 -iv ${IV} -out issue.dat

the command for decrypting the file is as follows:

openssl enc -d -aes-256-cfb8 -in issue.dat  -k file:key.bin -out issue.txt -pbkdf2 -iv ${IV}

Asymmetric Cryptograpy

Asymmetric cryptography relies on a pair of keys: a private key and a public key, mathematically related to the private one. It's very difficult to derive the private key by knowing only the related public key: this means that it should take hundreds if not thousands of years to compute it (considering the computational capabilities at when you generated the key).

But bear in mind that computational capabilities increase during the years, … that's why the recommended key size has changed during the years (at the time of writing this post, it is 2048-4096 bits for RSA or DSA keys if you want to stay safe).

As for the key size, asymmetric and symmetric keys behave very differently: an asymmetric key requires much more bits to provide the same strength of a symmetric key. For example a 80 bit symmetric key has more or less the same strength of a 1024 bit asymmetric key, or again, a 128 bit symmetric key has more or less the same strength of a 3072 bit asymmetric key.

For this reason, asymmetric cryptography is used only to encrypt and decrypt the random symmetric session key that is used to perform the encryption of the actual data.

This asymmetric cryptography is easier to keep secure if compared to symmetric cryptography: the key shared with the other parties is public data, so no special care is needed for both delivering and storing them. In addition to that, we should strive to protect only our key - the private one, conversely from symmetric encryption, where we have to strive to keep the key secure on all of the parties

The true pitfall of asymmetric cryptography is that you need a way ensure that the public key you received is actually the one that belongs to the entity you think it should - a need that has been addresses by using digital certificates.

Asymmetric key pairs can be used for the following purposes:

authentication
Authentication systems rely on authentication algorithms that validate the Private Key used by the connecting entity to authenticate against the related Public Key: if there's a match, then the identity of the caller is considered verified. Since the key used by the authenticator is public, it can even be published on an online repository and the authenticator can fetch it only when needed..
encrypt contents
Data are encrypted with an algorithm that uses the public key: the encrypted messages can be decrypted using the same algorithm, but only using the private key related to the public key used while encrypting (here I'm quite simplifying things, since only the session key is encrypted this way – more on this topic later on) .
So for example Foo user sends its public key to Bar user. Bar user can now encrypt a message using Foo user's public key and send the encrypted data to Foo user. Foo user can decrypt the message by using its own private key. Even here we didn't disclose anything valuable: Foo user gave Bar its public data. Even if Bar would disclose the foo public key there would be no consequences.
sign contents
After generating the MAC of the data that have to be signed, the MAC gets encrypted using the private key. The peer can verify the signature by decrypting it using the public key related to the key used to sign and validating the MAC.
Getting back to Foo and Bar users, Foo can digitally sign a message (usually in clear) using his private key. When Bar receives the message he can verify the signature using Foo's public key.
Signature can provide what is called non-repudiation, that is a proof that what is written, besides haven't been tampered, actually belongs to who digitally signed it.

Keys

Types

RSA

The RSA (Rivest–Shamir–Adleman, from the surnames of Ron Rivest, Adi Shamir and Leonard Adleman) is one of the oldest cryptographic systems (it has been published in 1977). It's security relies on the practical difficulty of factoring the product of two large prime numbers, the "factoring problem".

Let see how to generate and RSA key pair: for example let's generate a 2048 bit AES256 encrypted (-aes256 parameter) RSA key:

openssl genrsa -aes256 -out key.priv 2048

we can inspect the key as follows:

openssl rsa -in key.priv -noout -text

after typing the unlocking (decrypting) password, the output is as follows:

RSA Private-Key: (2048 bit, 2 primes)
modulus:
00:c9:99:01:39:5f:72:78:11:23:22:06:f3:77:e3:
1f:10:69:36:55:7a:c3:8c:d1:13:f3:d0:04:82:53:
0f:3e:f3:5f:32:5d:1f:eb:a1:07:d2:30:a1:ec:9b:
d8:14:57:29:f5:53:ba:be:5a:a6:55:d1:55:e6:2f:
72:37:fa:0f:00:bd:ac:9d:94:ca:ff:e2:89:89:be:
a9:f3:f0:ce:52:16:60:04:38:15:cf:12:ee:e9:d5:
72:ac:ff:e4:22:4d:0d:48:db:ef:f0:35:65:e5:08:
00:70:c3:d8:09:ae:61:23:53:2a:4b:3d:85:d2:f3:
8c:91:a3:77:96:54:7a:fc:b2:18:9c:5f:22:13:1a:
3c:d1:1c:2a:e7:02:bd:48:89:ee:ae:7f:95:e3:a8:
ab:95:77:8d:ea:5b:0e:ea:9c:b3:3f:45:47:d3:c0:
40:b8:41:e5:d2:7f:1b:d2:6a:44:4b:c1:1d:06:63:
63:91:6d:a1:53:43:76:f2:3f:ec:4b:17:32:fc:f8:
02:6b:76:28:0d:9c:f9:c1:64:a7:f1:46:6d:bb:fb:
31:f8:90:4b:0a:a8:51:f3:4c:15:1b:9a:eb:e1:60:
bb:fe:e6:e3:59:ba:6e:52:27:b3:c7:f8:85:63:ad:
05:b6:d7:c8:fb:ba:03:4c:6c:7a:98:f8:6f:81:fc:
3a:ed
publicExponent: 65537 (0x10001)
privateExponent:
62:c5:28:f9:60:0f:28:4e:55:25:3d:bc:99:77:58:
67:e4:f4:6e:ea:e7:d6:1d:35:a6:55:bb:6f:d2:9b:
fc:9e:a6:7c:79:6d:c3:37:31:2a:c5:13:00:66:d6:
76:18:c2:80:e4:d5:f0:9f:5f:31:5a:8f:b8:68:74:
90:82:5e:49:61:a4:a9:cc:15:ad:4a:e3:51:ee:6d:
3c:0c:36:39:b7:a6:b1:4a:7d:3c:e8:2c:cf:b9:f9:
26:53:75:05:6d:34:de:06:8b:c6:e7:92:95:a4:d6:
fa:68:a9:77:0c:cd:a0:ce:05:41:b9:d1:d0:29:ed:
2c:09:a7:f4:aa:4d:5b:72:53:c8:fa:0c:80:9e:bf:
f6:ef:fb:b5:fe:c9:ae:7a:0a:5a:05:fd:31:26:0e:
00:ab:c1:da:b8:7a:50:75:81:a7:83:8a:62:0b:2e:
58:54:0a:17:20:68:56:5c:5e:75:08:0e:0f:e2:59:
84:97:9f:cf:07:a9:67:ff:59:1b:02:4f:73:88:31:
db:db:2f:b2:40:b8:04:29:a9:ba:06:04:75:04:7d:
65:40:3a:ec:d3:2e:02:55:a3:82:ca:c6:99:e6:48:
14:a0:b5:6d:32:53:62:bf:ad:18:50:a4:14:ac:10:
84:f4:8c:23:5a:0f:4a:be:47:1b:a5:03:fd:ac:c8:
c1
prime1:
00:e5:1a:a9:bd:4f:2d:38:12:ab:05:a3:b4:49:a1:
29:1b:d2:50:fd:80:fa:9b:33:51:d9:54:8e:c4:bc:
13:d8:1c:c3:8b:6c:5b:86:e2:17:7f:d3:e1:4f:00:
8b:65:f6:0a:f6:6f:39:8f:7a:24:d9:fa:9f:8e:d4:
99:a6:72:6c:96:ab:33:de:f9:04:23:79:07:89:73:
6d:de:29:a8:6d:7f:d5:da:64:27:9c:83:ac:d7:10:
13:30:86:ae:f1:d3:16:e4:70:e0:98:07:b5:a1:00:
58:01:5b:cc:38:32:b7:f0:0f:3e:16:e3:40:b7:10:
b2:25:c8:6f:54:25:93:35:91
prime2:
00:e1:43:ae:61:b4:d6:d7:65:99:db:91:f2:54:01:
eb:87:51:1f:fc:bf:1b:6d:20:2c:86:a6:58:d3:a8:
72:e1:c6:a8:78:06:2d:14:92:4a:2c:c1:98:a5:5b:
28:44:97:5f:2c:9c:47:57:3a:8e:15:5a:f4:e4:30:
1b:cc:b8:57:5a:c2:8d:85:79:05:ca:45:81:7b:03:
55:32:0d:14:21:75:1e:c6:f4:55:4a:57:10:91:cc:
24:c7:55:7a:c6:75:4a:60:58:76:f7:4b:9c:4e:28:
fd:68:11:61:63:b8:51:b2:12:df:db:1f:e9:31:06:
08:c0:dc:f8:e3:97:e9:d1:9d
exponent1:
00:a1:00:a3:d8:8e:13:d1:1c:0d:63:e1:2f:89:ae:
e0:1c:d5:28:65:7e:86:9f:1a:e9:a2:39:72:3b:7f:
90:d2:87:24:44:8e:d9:a3:68:af:ea:fd:13:91:59:
68:9d:36:d3:6d:6b:ac:9f:cf:ce:a6:01:22:b0:55:
67:c5:39:14:66:ad:d9:be:10:71:80:1c:45:d7:aa:
6e:c3:79:b3:0b:80:92:e0:ef:11:87:44:61:ea:a1:
39:5b:18:cb:48:d6:77:78:02:7b:53:5b:d7:a0:55:
85:83:2e:e7:cd:76:97:1c:f5:19:45:2c:5f:06:47:
8d:6a:4f:f9:2c:c1:5b:3a:81
exponent2:
00:a5:9d:73:fc:c3:ce:dc:88:07:49:46:11:0a:b0:
6a:b0:8e:f5:5c:86:48:ac:bf:65:dd:0d:39:eb:4b:
42:43:3a:22:2c:34:26:3a:a4:9f:42:2e:87:82:b2:
f5:75:10:71:59:c4:00:33:62:8a:89:aa:d8:b7:57:
a3:68:ac:f3:14:78:4b:42:21:4b:1f:7e:60:86:c7:
59:80:b5:da:e2:0a:50:b9:67:73:b9:77:2f:68:71:
d5:6c:74:2d:12:f1:b2:e0:08:ca:56:60:51:a7:a9:
3d:3d:a0:e1:a0:46:28:52:2a:cc:48:37:3a:e3:df:
12:da:70:db:cf:c0:a5:98:85
coefficient:
34:3e:17:3f:44:77:3d:ef:6b:45:f1:78:f9:e0:cd:
39:db:e3:68:f9:37:62:fd:12:cb:b1:e5:82:ad:a9:
00:e0:62:d2:30:0a:33:60:da:0b:1a:f2:61:6b:41:
cc:59:23:7e:29:27:29:83:2a:3d:00:26:a0:26:90:
b6:fd:8c:dc:5d:ed:e3:11:8a:1f:52:d5:53:d0:e5:
bb:fc:69:c3:ad:b0:f1:da:88:86:2f:fc:00:8f:65:
fc:39:15:4c:67:69:5c:ca:f8:f5:b8:23:21:ae:4a:
5f:88:7b:de:87:1a:b7:c6:71:e1:72:2f:1c:94:9f:
bf:7c:9a:e0:9f:4b:f5:9f

now extract the public key from the private key:

openssl rsa -in key.priv -outform PEM -pubout -out key.pub

and give a close look to the public key too

cat key.pub
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwVxBMEe878hljd4ZLy9+
y+iHMpybKjFxo8oL7zXfwIv5lqUmY4pelCSnRoQENfPGtjgolYETYzGhpLTSBMU1
Hc3LcNdAs/RK/N7PxGjt3psyTS8obfp7FhDCc88H80WbpeA6iO6LOWRW8HUBOJ3E
Ccex5WKKiaSlNJ/KR3t6A6YtgVqcbKcmPlxpHFExc40Y1U+z2Cqq6WM8aGEL3YSO
TpJOobD4RXpJgfffigHFG6zeKYt1n+dQMC6dld6CRq5nrie8OH+IfFOFx3ZMptI6
PdhJ1VMKRT4CT5gRixCHw58pNC99gDP9tVURisY5DCpmn+5IE3xKxCY9GFDxLCl7
owIDAQAB
-----END PUBLIC KEY-----
DSA

The Digital Signature Algorithm (DSA) is a Federal Information Processing Standard (FIPS) for digital signatures based on the mathematical concept of modular exponentiation and the discrete logarithm problem. Despite it being patented, NIST has made it available worldwide royalty-free. Note that FIPS 186-5 discourages to use DSA to generate signatures, but permit its usage to verify already existent signatures

Let see how to generate and DSA key pair:let's generate a 2048 bit AES256 encrypted (-aes256 parameter) DSA key:

openssl dsaparam -genkey 2048 | openssl dsa -aes256 -out key.priv

you can give a close look to it as follows:

openssl dsa -in key.priv -noout -text

after typing the unlocking (decrypting) password, the output is as follows:

Private-Key: (2048 bit)
priv:
00:82:97:10:7e:8f:e5:0a:67:22:c5:ad:48:5e:b9:
ab:c0:f5:5f:88:81:95:2a:77:7f:17:83:71:db:e4:
e8:00:5e
pub: 
01:22:5f:2c:3c:68:59:f0:a2:de:2c:32:56:f4:dd:
d9:14:38:1c:2d:84:5d:50:d9:6a:7d:3c:01:dd:c4:
97:f9:b4:57:9d:b0:36:20:d7:d1:3f:2f:e0:45:fd:
06:5f:c6:a9:c1:6d:80:d4:34:e5:63:36:d4:25:59:
c8:82:be:2a:11:39:93:70:89:bc:ef:87:59:5f:c4:
14:58:7a:02:c2:2f:77:39:fe:cc:6a:57:ba:f4:10:
9d:b0:b2:62:3a:ef:86:6b:b2:c0:fb:1d:cf:d8:61:
fe:fc:4f:84:9b:fd:69:50:b4:91:32:4c:a8:68:8d:
ee:4f:20:42:c3:27:5f:cf:e8:2b:1f:e7:1b:05:30:
c1:17:a3:70:1f:5b:17:98:68:38:a5:8c:43:fc:0f:
ae:47:5e:22:3b:a0:88:bc:6d:aa:54:10:1f:9e:6b:
5e:1b:05:1a:91:0d:5e:c9:c8:de:76:5b:39:32:a5:
8e:63:64:8d:cc:5a:cd:d5:bd:e0:ca:28:f7:ec:ef:
ec:41:ac:b2:a2:5b:3e:01:dd:8f:c2:bd:ca:dd:c8:
84:bc:d2:18:cc:43:d2:93:16:56:07:d1:69:33:42:
74:e3:19:2b:a1:7a:f0:b2:03:80:a1:22:a7:a4:5b:
44:bc:08:fc:28:1c:13:0a:b4:a6:f1:a8:43:d4:4a:
05
P: 
00:c8:38:12:3f:15:dc:2e:9a:40:52:6a:71:25:a0:
3b:85:52:b3:18:54:81:09:d2:e3:3b:30:d6:03:08:
cc:86:5d:71:e2:d9:dd:60:3d:06:da:b5:27:4d:23:
dc:5c:30:3e:85:43:71:e5:01:13:17:86:9a:d3:a1:
73:c1:2c:d7:38:41:11:f5:d1:82:fa:a9:d1:4c:0f:
6e:30:ec:64:c5:d3:e7:8e:0d:e9:5f:d7:1d:6f:82:
b7:6f:bb:0f:04:95:7b:53:a4:2c:f3:9f:99:75:e1:
6a:57:29:b9:88:02:c2:f9:7f:d8:f6:7a:28:34:aa:
48:da:87:0f:87:fd:06:43:30:00:9d:a4:6b:70:6f:
91:7b:0a:87:52:ce:97:a3:05:fc:e4:40:1e:2a:e9:
e4:1b:fc:3e:b7:8c:8e:cf:eb:d1:0a:5f:6d:e0:03:
cb:d5:a5:84:29:da:68:c9:50:b6:d2:b7:6e:22:e9:
f1:5a:ef:d2:70:0c:f2:c9:49:a3:9d:06:9e:2a:5b:
c2:42:6f:d5:b8:02:c9:ad:08:47:07:db:40:21:79:
fc:15:e1:c2:3d:e6:cc:18:7b:22:58:9a:d2:64:27:
0b:e8:98:9b:f9:6f:47:3e:0b:52:4b:4c:7c:41:45:
fc:8b:16:fd:4f:fb:72:cc:4c:89:78:dd:6e:7c:d2:
23:69
Q: 
00:ea:61:ba:27:07:0c:3b:1e:cc:14:44:b7:8e:ba:
63:3e:51:e4:c3:21:53:b6:ab:1c:5c:88:5c:6e:6f:
df:81:b3
G: 
10:d5:07:e3:a2:0a:20:82:c4:25:e0:99:b7:df:ca:
86:c7:06:47:3c:be:4e:1a:fd:11:b6:fa:1b:b3:64:
e3:8d:5a:64:9c:e9:dc:8a:b6:b9:4d:b6:f0:43:9f:
99:71:2a:59:60:b2:1a:6b:8e:2d:d4:b1:be:e3:20:
7b:e7:d9:aa:2c:b7:13:58:59:19:e4:2c:09:bc:1b:
78:a6:8d:86:e0:7a:c7:51:04:93:7e:6d:cf:f9:33:
7f:64:12:c8:45:16:40:e2:17:70:f3:5a:1f:7f:f9:
ca:1d:61:74:03:26:36:6a:d2:07:12:49:1f:fb:d8:
36:c7:9d:38:e1:e9:85:12:40:00:fa:3a:c9:15:34:
a3:e5:cb:d2:f7:13:52:04:84:bb:bd:04:5c:d7:25:
d0:09:47:ed:10:81:51:58:bd:19:9e:70:5e:0d:0e:
47:bf:f8:7a:7b:c2:1e:6b:a8:82:a8:5a:e9:59:0d:
00:e3:cf:a9:9b:91:2c:0b:bc:f6:db:fa:e8:d1:c1:
1d:0e:b4:e7:70:09:76:fd:96:3e:57:ee:ff:90:f6:
ad:0c:41:c6:0a:37:7e:eb:0e:d1:20:4a:80:80:9b:
d9:2b:44:a1:cb:50:f8:a9:7b:49:7a:95:4f:9e:17:
55:d9:fc:e4:e3:43:69:f0:39:31:1e:ff:fa:9b:aa:
99

now extract the public key from the private key:

openssl dsa -in key.priv -outform PEM -pubout -out key.pub

and give a close look to the public key too – I cut it to keep it short

cat key.pub
-----BEGIN PUBLIC KEY-----
MIIDRzCCAjoGByqGSM44BAEwggItAoIBAQDZh2RzSgzh0raIrkga3cy6mlIZhHzV
brReEBYrSc8m3eqbhw3AR43zzusMsNyxBfrx7lrG0z1MLedeBFLnDOwqaPCwSJid
...
zqtizjniW8koGti62IKhNA0d31geMgEtioGTJBtO2oER/1dC2pxmXJshezni4NTy
xeDgMbxu58WYPvQtr/WA0eFkal+D4ODvL6Y7
-----END PUBLIC KEY-----
The strength of both RSA and DSA keys is provided by the key length (bitness): the more bit is the key, the more difficult it is to break. Take in account that chances to break contents protected by key increase as years go by, since computers become more and more powerful. For this reason it is wise to generate a new key after a few years, and keep current of security weaknesses that may arise..
You may be wondering when to use DSA or RSA keys: despite by the security perspective they can be considered equivalent when dealing with keys of equal length, DSA is faster than RSA for signature generation but is slower for validation and when encrypting, although it is faster when decrypting and.
Elliptic Curves (EC)

The Elliptic Curve Cryptography (ECC) is modern family of public-key cryptosystems based on the algebraic structures of the elliptic curves over finite fields and relies on the difficulty of the Elliptic Curve Discrete Logarithm Problem (ECDLP).

ECC provides a set of predefined curves, we can list the curves supported by the version of openssl we are using as follows:

openssl ecparam -list_curves

on my system the outcome is:

  secp384r1 : NIST/SECG curve over a 384 bit prime field
  secp521r1 : NIST/SECG curve over a 521 bit prime field
  prime256v1: X9.62/SECG curve over a 256 bit prime field
The strength of EC keys is provided by the curve used. Take in account that chances to break contents protected by key increase as years go by, since computers become more and more powerful. For this reason it is wise to generate a new key after a few years, and keep current of security weaknesses that may arise.

Generate an AES256 encrypted (-aes256 parameter) EC private key using secp384r1 curve:

openssl ecparam -name secp384r1 -genkey | openssl ec -out key.priv -aes256

note that we had to create a pipeline, issuing openssl command twice: the first creates the unencrypted key that is piped to the second one that encrypts it. You can give a close look to it as follows:

openssl ec -in key.priv -noout -text

after typing the unlocking (decrypting) password, the output is as follows:

Private-Key: (384 bit)
priv:
3c:11:2f:3a:89:2b:24:51:a5:d6:66:a2:d1:49:ba:
f7:82:e4:43:b2:01:29:68:95:de:08:8b:06:ed:bf:
29:16:9b:69:92:46:d5:3f:9a:c0:d4:ba:41:03:d4:
69:1a:41
pub:
04:70:3f:92:fa:be:8e:3f:eb:33:be:df:a2:84:09:
23:78:d2:23:73:01:3f:c0:31:70:e6:a9:e0:f4:ce:
a6:e6:90:a8:b5:85:9e:1c:3e:39:56:fe:65:d7:64:
e7:b1:df:f8:49:75:4b:4a:34:ac:e4:88:f3:08:aa:
40:2c:b7:61:27:d1:24:e3:85:5c:5a:45:18:2a:e4:
69:64:69:2a:b7:a1:52:37:69:02:f3:28:fc:3a:aa:
2c:72:67:43:9f:e4:7a
ASN1 OID: secp384r1
NIST CURVE: P-384

now extract the public key from the private key:

openssl ec -in key.priv -pubout -out key.pub

and have a close look to the public key too

cat key.pub 
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJlXtfu7gaWqSZ6IXPCqCeGDKGVZ4
Uy05bqvwAHpH4t2i4vXc7G6iyBcOntEf07gRRctC/T6yYpJzSibXwJZAPg==
-----END PUBLIC KEY-----
When using openssl command to “pretty print” the keys, did you notice how small the EC key is compared to RSA or DSA keys? This is one of the reasons the world is moving towards EC keys.

Encodings

To foster the support of keys from as many devices as possible, a few standards for encoding and formatting have been defined. There are two different ways to encode private keys (along with X.509 certificates, if necessary):

PEM

The Privacy-Enhanced Mail (PEM), is the most commonly used encoding - and the default used by OpenSSL: it is a Base64 ASCII encoded text file containing one or more items separated by plain-text headers and footers (e.g. -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----). Besides the private key, a PEM file can contain one or more X.509 certificates and are suitable to store a list of certificates to be used as truststore or to store a Certificate Signing Request (CSR)- but this will be the topic of another post). Usually PEM files are named with the following extensions: .crt, .pem, .cer, and .key.

DER

The Distinguished Encoding Rules (DER) is a binary encoding, less commonly used than PEM.

Formats

Besides encoding, there do exists several formats: the most commonly used for private keys are:

PKCS#1

This is the traditional and default format used by OpenSSL: it has the following header and footer:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,9AA41915E12E28466900B2BC60801ACA
iCuAcJLGrCiD0nYNIu8R+N82epcaZRat0uUqLBUIYpLAKO7xPqqYBBZZ4IMyRSdy
...
nYVRrEhvW0M44ddNxU/vL/7wx+qN17vCuYBLqj+ducrVGvavMSAWBFUwFO9WQNZI
-----END RSA PUBLIC KEY-----

The type of the key is specified after the BEGIN keyword, for example RSA, DSA, ECC.

PKCS#8

It is a format that provides a stronger encryption and is FIPS 140-2 compliant too:

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJmQE5X3J4ESMi
...
L3I3+g8AvaydlMr/4omJvqnz8M5SFmAEOBXPEu7p1XKs/+QiTQ1I2+/wNWXlCABw
-----END PRIVATE KEY-----

you can convert an existing private key to pkcs#8 as follows:

openssl pkcs8 -topk8 -outform PEM -nocrypt -in key.priv -out key.pkcs8

Generating Keys using PGP/GPG

OpenPGP is a suite that relies on asymmetric keys: it can generate both RSA, DSA or even ECC keys (note that only recent versions support ECC). For the sake of completeness, let's have a go with it too: let's generate an OpenPGP master key along with a sub-key with encryption capability as follows:

gpg --expert --full-gen-key
A PGP master key is a key that is solely used to sign the sub-keys (your own and the one of other's parties during key signing parties). Your reputation in the web of trust is tightly bound to this key, so you should do your best to keep it as secure as possible. The advice is to store them onto two different offline devices, such as pen-drives, stored in different locations. We'll go more on this in the post dedicated to PGP I'm going to write.

the above command starts an interactive tool that gathers the required information to generate the keys - Note that I cut some of the messages to keep it short and improve the overall readability:

gpg (GnuPG) 2.2.9; Copyright (C) 2018 Free Software Foundation, Inc.
…
gpg: directory '/home/vagrant/.gnupg' created
gpg: keybox '/home/vagrant/.gnupg/pubring.kbx' created
Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
Your selection? 

enter 1 so to generate both master key and subkey as RSA keys.

RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 

this is the key length (sometimes called bitness) of the master key: the longer a key is, the more time is required to brute-force it. Mind also that it also may require more time to gather enough entropy to generate it - this can be an issue on virtualized hosts with a poor support to entropy devices.

Enter 4096.

Requested keysize is 4096 bits
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want for the subkey? (2048) 

this time we set the key length of the sub-key: enter 4096 again

Requested keysize is 4096 bits
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
         ...
Key is valid for? (0) 

this is the desired lifetime of the keys: once reached the key expires and it is needed to generate them again. It's up to you to decide this value. However it is a best practice avoiding keys that lasts more than 10 years.

Enter 3650

Key expires at Thu May 16 17:43:25 2030 UTC
Is this correct? (y/N) 

here you can confirm or cancel before going on and actually generating the key: enter y

Now you should enter the metadata that are bundled along with the key: in the end you get the following output:

GnuPG needs to construct a user ID to identify your key.

Real name: Marco Antonio Carcano
Email address: marco@grimoire.carcano.ch
Comment: Marco's key
You selected this USER-ID:
    "Marco Antonio Carcano (Marco's key) <marco@grimoire.carcano.ch>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?

Enter O.

The tool now asks for a password to encrypt the keys:

┌─.....................................................┐
│ Please enter the passphrase to                       │
│ protect your new key                                 │
│                                                      │
│ Passphrase: ________________________________________ │
│                                                      │
│                                                      │
└─                                                     ┘

Wait until the generation of the keys completes: in the end it should look like as follows:

gpg: /home/macarcano/.gnupg/trustdb.gpg: trustdb created
gpg: key EAEF77DC65FCAACC marked as ultimately trusted
gpg: directory '/home/macarcano/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/macarcano/.gnupg/openpgp-revocs.d/96544ECF4FEE48C70C0032AEEAEF77DC65FCAACC.rev'
public and secret key created and signed.

pub   rsa4096 2021-05-15 [SC] [expires: 2031-05-13]
      96544ECF4FEE48C70C0032AEEAEF77DC65FCAACC
uid                      Marco Antonio Carcano (Marco's key) <marco@grimoire.carcano.ch>
sub   rsa4096 2021-05-15 [E] [expires: 2031-05-13]/code>
PGP calls a key a bundle that is made of the private key(s) along with the metadata, ... this makes it sounds a little bit more like a certificate rather than a key.

The next thing to do is to export the public key so to share it with other parties: we can do this as follows:

gpg --armor --export marco@grimoire.carcano.ch > marco@grimoire.carcano.ch.pub

We can export the private key too if you need it:

gpg --export-secret-keys --armor marco@grimoire.carcano.ch > marco@grimoire.carcano.ch.priv

It asks for the decrypting password:

┌─vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv┐
│ Please enter the passphrase to export the OpenPGP secret key:	     │
│ "Marco Antonio Carcano (Marco's key) <marco@grimoire.carcano.ch>"  │
│ 4096-bit RSA key, ID EAEF77DC65FCAACC,                             │
│ created 2021-05-15.                                                │
│                                                                    │
│                                                                    │
│ Passphrase: ______________________________________________________ │
│                                                                    │
│                                                     	             │
└─                                                                   ┘

let's have a look to the exported file - the output is of course cut:

cat marco@grimoire.carcano.ch.priv 
-----BEGIN PGP PRIVATE KEY BLOCK-----

lQPGBF7Cyq0BCADDWF4y9d6P4Tkdb70DGJHQQRpFqrcjq06qaY63qr51RL8iRZ2/
g7WyxaX8UEGf6QotuXf6JjBDQUE0QE1s/Mc/ROwTEabtuRAUw+6v/lladlHmKToG
...
16ExOA3X1oitVOMGgXTkP5u3VXS5ZBEO7nm8iWIkC4VN4W5E2OmuFE1reHPG2xEt
ekdSFRKc0s89JX1YBXjl
=pa0U
-----END PGP PRIVATE KEY BLOCK-----

As you can see the file starts with a heading "-----BEGIN PGP PRIVATE KEY BLOCK-----" and ends with a trailing "-----END PGP PRIVATE KEY BLOCK-----" marker.

You should backup the exported private keys and store them offline in a secure location. To reduce risks, the best practice is to remove the primary key from the keyring and use only the sub-key to operate with PGP: if needed, you can import it again in the keyring as follows - in this example you should first remove ~./gnupg directory to simulate an uninitliaized PGP environment:

gpg --import cat marco@grimoire.carcano.ch.priv 

As you can see the exported key is encrypted and asks you for the decryption password:

┌─ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd┐
│ Please enter the passphrase to import the OpenPGP secret key:	     │
│ "Marco Antonio Carcano (Marco's key) <marco@grimoire.carcano.ch>"  │
│ 4096-bit RSA key, ID EAEF77DC65FCAACC,                             │
│ created 2021-05-15.                                                │
│                                                                    │
│                                                                    │
│ Passphrase: ______________________________________________________ │
│                                                                    │
│                                                	             │
└─                                                                   ┘

an export the private key too if you need it:

gpg: directory '/home/macarcano/.gnupg' created
gpg: keybox '/home/macarcano/.gnupg/pubring.kbx' created
gpg: /home/macarcano/.gnupg/trustdb.gpg: trustdb created
gpg: key EAEF77DC65FCAACC: public key "Marco Antonio Carcano (Marco's key) <marco@grimoire.carcano.ch>" imported
gpg: key EAEF77DC65FCAACC/EAEF77DC65FCAACC: error sending to agent: No such file or directory
gpg: error building skey array: No such file or directory
gpg: error reading 'marco@grimoire.carcano.ch.priv': No such file or directory
gpg: import from 'marco@grimoire.carcano.ch.priv' failed: No such file or directory
gpg: Total number processed: 0
gpg: imported: 1
gpg: secret keys read: 1

The same command can be used also to import public keys of other users. Note that  it is not necessary to re-import your own public keys since they are derived from the private key.

If you want to read more on how to properly use GPG, you may find it useful reading A quick, easy yet comprehensive GPG tutorial.

Encrypting contents using public keys

Data is encrypted with the public key and decrypted by the private key. This encryption type relies on asymmetric key pairs:

  • public as the name suggests can be safely spread all over the world
  • private as the name suggests should never and ever be disclosed

Let’s say we want to encrypt a file called test.txt.

openssl rsautl -encrypt -inkey key.pub -pubin -in /etc/issue -out issue.dat

Let's try to decrypt the file using the private key (key.priv):

openssl rsautl -decrypt -inkey key.priv -in issue.dat -out issue.txt

Signing contents using our private key

It is the scrambling of data so that it appears without an understandable meaning: scrambled data are said to be hashed, whereas the original data are said to be plain-text. Hashing are one-way algorithms: once a message is hashed, there's no way (in a reasonable time) to get back the plain-text original message.

We can get a list of digest supported by openssl as follows:

openssl list --digest-commands

we can use digest to digitally sign a content as follows:

openssl dgst -sha256 -sign key.priv -out issue.sha256 /etc/issue

since the signature file is made of binary data, it is often convenient to convert it to base64 to improve its portability:

openssl enc -base64 -in issue.sha256 -out issue.sha256.base64

om my system, the contents of issue.sha256.base64 is as follows:

VwP7Hm4WXB0spq6hHB9ysO8ngEaCYg+Q+7WNbCZ943SFTzGTaF5fJ6kCitnZ3CF8
8i/RIDZIslhnBJvZXjYtLWETzdecXZei/eMa6c7PjmCGl9dQnwWEN2gWWSW4ljUl
4qgnv83jTXHBNhyfvsxrvN1XVxrvY9siLA2gWHj9fprzpSpevm5XHYf/lpCxiVqx
rdR231R4VGPhfwl4ZC46lq+uEMNhN1hYUw0oLwak3IzLOLiLvepoSnrcaG/RPouP
rUxYw84EGEAzX2JQOMe1YHJsbzWNprvQ8XnrAqsYSjDtvlLue8AANsszMS+kc55K
swN3HyvktQVXOLq0/rg3QA==

We can verify the signature as follows: convert the signature file back from base64 to binary:

openssl enc -base64 -d -in issue.sha256.base64 -out issue.sha256

perform the actual verification of the binary signature using the public key:

openssl dgst -sha256 -verify key.pub -signature issue.sha256 /etc/issue

if signature is valid, we should get:

Verified OK

If otherwise you get the following output

Verification Failure

it means that the /etc/issue file has been tampered.

Digital Certificates

One issue with asymmetric key crypto systems is the difficulty to ensure that the public key we are using actually belongs to the entity we think it should belong to. And here comes certificates into play: certificates are plain text contents digitally signed by a trusted entity: when dealing with X.509 certificates (the typical certificates used for example by websites) the trusted entity is the Certification Authority, whereas when working with OpenPGP certificates (that most of people simply calls OpenPGP public keys) the trusted entity is the private key of a trusted entity (We'll see this on a post dedicated to PGP and the web of trust).
To clarify the needs of it, think of a digital certificate as the digital version of a real life certificate. So what is a certificate, in real life?
It's a document that is trusted by who consider trustable the entity that signed it
Well, this is valid also for digital certificates..

Shamir's Secret Sharing

One of the problems of keys is how to protect them: of course they are encrypted on disk and so are password protected, but even if you configure things to interactively ask for the password to unlock the key at service start, you should blindly trust the members of your staff that will do this.
An alternative may be to require more people of the staff to enter a password, so that when at least a certain number of them have done it the key gets unlocked.
This can be achieved using Shamir's secret sharing: it consists of splitting the key into multiple parts, called shares, that are used to rebuild the original secret. The algorithm lets you define a threshold of keys you should provide to recreate the master key (for example you can generate 5 shares with a threshold of 3 shares: this means that three share holders can get-back the original key). There are several implementations of this algorithm, for example, when coding in python, you can install the library by using pip:

pip install shamir

Footnotes

Here it ends our cryptography quick guide: I hope you enjoyed it, and that you agree that is nicer having a little bit understanding about it rather than simply blindly run cryptographic suites commands.

Writing a post like this takes a lot of hours. I'm doing it for the only pleasure of sharing knowledge and thoughts, but all of this does not come for free: it is a time consuming volunteering task. This blog is not affiliated to anybody, does not show advertisements nor sells data of visitors. The only goal of this blog is to make ideas flow. So please, if you liked this post, spend a little of your time to share it on Linkedin or Twitter using the buttons below: seeing that posts are actually read is the only way I have to understand if I'm really sharing thoughts or if I'm just wasting time and I'd better give up.

 

 

 

 

12 thoughts on “Cryptography quick guide – understand symmetric and asymmetric cryptography and how to use it with OpenSSL

  1. gerald eggenberger says:

    Keep going writing such nice Posts. To write easy readable content which is easy to understand needs a deep understanding of the topic. Thanks for sharing your grimoire with us. 😀

    • Marco Antonio Carcano says:

      I’m pleased to see you liked the post and appreciate my grimoire, … this is exactly the reason I started with it: sharing thoughts and ideas. You are right, writing this kind of posts needs a deep understanding of the topic, and a lot of time rewriting the things until I feel I explained them in a way that, … can even be understood. So thank you for the feedback Gerald, it’s really appreciated.

Leave a Reply to gerald eggenberger Cancel Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>