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.
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.
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
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.
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
Asymmetric key pairs can be used for the following purposes:
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.
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.
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-----
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:
Are you enjoying these high quality free contents on a blog without annoying banners? I like doing this for free, but I also have costs so, if you like these contents and you want to help keeping this website free as it is now, please put your tip in the cup below:
Even a small contribution is always welcome!
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
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-----
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
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>
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.
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.
jamal says:
very useful, Thanks a lot
peddro says:
?
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.