Lab Doc 3 (deliverable 4)

Data Protection - Master in Cyber Security (UPC)
Jorge L. Villar, 2026

Last updated: Sep 3 15:21:14 2026
(Generated by lineprocx v2.97)

Contents

1 Key Generation with openssl
 1.1 RSA Keys
 1.2 Diffie-Hellman Keys
 1.3 Elliptic Curves
 1.4 File Formats
 1.5 Public Key Extraction
2 Public Key Encryption and Decryption
3 Diffie-Hellman Key Agreement
4 Practical Work: Hashed ElGamal + Hybrid Encryption + MAC

1 Key Generation with openssl

The openssl tool provides specific commands for key generation of some public key encryption schemes.

The command genpkey is used to generate a public / secret keypair.

The way this command is used depends on the selected public key algorithm.

1.1 RSA Keys

$ openssl genpkey -algorithm rsa

outputs a text encoding of a public key and a secret key for the RSA encryption scheme, with the default parameters (e.g., the size of the modulus). For example, the previous call results in the output

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDoZCHtGHhaKo8g
cM8STl8w7rs7L28VWCfcI3LGC8NkRTuyt/7W9siGUV4EtOd9CtTvuhNTLE7NgxOa
PbhlAFZEIAGubeKlPx0Qu+JskQ7S5OTfXeMgmLIuw60OEUjOmrDsZyK0xoWu1SGg
kWF+ZhS/4dYdGAt4Lu0ktuFxKTqhKvbbpcfdZOvAurwgmsZhOcj+CDMmudWuYOOE
zGdoSGSQZJOulaBBTOMN1YJSQJMrV9QwsPYRgk/8PdSnEmmDORBYYvvXFKj1pNL0
majXTVofnZG/QPQs9gfzMir9Uw5O/4lPnrgg8hy5r53bBlSwAtzN1En7BH22ZD0n
nYcZKNR/AgMBAAECggEAIdibnFWJCdDTAa2MayUg9hZ/DHKvIhOx0n0TNUb3UT5I
IJJtuk89C1sEb3kNkgem1bdrIxz76TCjBT7iAUvYRJnIxOfaL6kOiaZjpt5Fo2+U
6fdZoiC7KtZy+O6JhRXAmN24j02uoLUH7cPeyDMD6KJytdAPs5RaE5PTJ9ESafB5
54AezAtEF9NG52iY26VlBvhd1bD8xpXlckKToAO4aA1DzMEovSb1mBLitAOxefO7
y6oqDWpZg7XG/3xTeJQr2GDhhLuauledtYZTbgvDltipixjPMm/btGgNrZVAX0wU
0s0MxVN9B8u/k+yuK6GoqYmH+APEhyghg63+73L0uQKBgQDsEap5Z7671Eblkbsb
UpwKu4CVlmJt67sv4aUTncfyeBfgXqTnPQGVIy82EHmOlSmNNyeIrbTjXdY82XJ8
WSh4bxSrf9Ckl6wlbrnvNvJnaMgbDpbotfd3KXuh48W/WYG1I23H/54OXkN51Zk7
w1pe2/URPGR/Jq22nC2FcdVwbQKBgQD8Avlk7jtN9b/M8CM4sE8kP29STfBnGe3t
kKWglqz0xQgEfzLm7MEGi/zhPxyPxE5ccniC4ltVH2AyynODXFXwe/CiGX7Endki
wDUKsbrJcrr0Z0Y9DIsFEuKnGD1btfEnKGmziHIO92N3vHfLzsISGFO+Dcdg/naY
QEzUGcw9GwKBgQDOrCizYUB68L2g/pTwtsImI0HPtHk4Ask+gi4jnl8OyFUe+b0l
NSPNjaAnlQTW74ARQdg6sNlMtTp6y2SPuP7VcWqHOr9PWfo8S1Q9Ob2/Ct0l0wAL
fEPK72ZttRvLCnGkRAA4uHGH4r7wSzB8Qes8YRWMoXLaXuJ2nQS9b4uNgQKBgFLT
G2objewiX2YYaksATxJnssuHCAKql/Li/jxYKQHNG8R2laEloI7pRTQ2TMnHR8XE
bWz+veutAy3OMcazex8tbLmpzWsLQcjVCNm57dy1U1Jt+rynuazyNwGZytiwZFBt
TMgPiQT4M32vuGOIUWonCqbE2ok7OHjzcQyoaeKPAoGBAI0BvipxqWAct95q2AeJ
TxKDNncMSQnuPOfWl7yw7t7o2PRy5XmEMavngwyswt/dwwQ0/9oZ5kC8e/8nMGb+
FqSApQ253u2ll0Cmu6Ws953Ck1FkHrJ5Dm6zaBXFhIvmN59xl1QcjZ+wXPtdivDS
PnxPQVzC54zud6JkpELf6Zxi
-----END PRIVATE KEY-----

The text output is given in PEM (Privacy-Enhanced Mail) format, but you can also produce a human readable text format by adding the option -text to the command line:

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

In this version of OpenSSL (3.0.2g), the defaults for RSA are a size of 2048 bits and the public exponent 65537. Newer or future versions could enlarge the default RSA key size. The additional fields named exponent1 , exponent2 and coefficient can be useful to speed up the decryption operation.

You can override the default parameters by providing the desired values via the option -pkeyopt . For instance,

$ openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:1024 -pkeyopt rsa_keygen_pubexp:17 

will use the (insecure) specified values for the key generation.

1.2 Diffie-Hellman Keys

Other public key cryptosystems, like the Diffie-Hellman key exchange, require a previous generation of some public parameters.

The same command genpkey can be used for public parameter generation with the option -genparam .

For instance, (the order of the options matters!)

$ openssl genpkey -genparam -algorithm dh -text

produces the output

-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA8ClCIPVTf6epmsEpsrw9UqgbWfgn66w5+C6Gjt+aXghlxBwAwIJM
JGDH96685xhGauTCttWv02hsw5X/ESdUBfSdeU2kWWlOrcC48N2F35XA/qV0fajv
gojBB3lIaf6kVLulLrFxwnFre1tUVrg+3jCllkRgPf2CtaKZK5vcjcQn1PfkvBNe
90TNcyDdzEbrlhgcuFFo9aD/j6Tskhp4UmtSZbwjNqrfjJzRYr0mmM3U61qcWX+H
0b2Tlvb0imefR3WixEyvBFn7C7F4TcVZneWcrI3N/520z3vE20tpfFJB63TxTs7t
5SxF8+AgWBkUFt5fiy5jMKG9ULzQwuKVVwIBAg==
-----END DH PARAMETERS-----
DH Parameters: (2048 bit)
P:   
    00:f0:29:42:20:f5:53:7f:a7:a9:9a:c1:29:b2:bc:
    3d:52:a8:1b:59:f8:27:eb:ac:39:f8:2e:86:8e:df:
    9a:5e:08:65:c4:1c:00:c0:82:4c:24:60:c7:f7:ae:
    bc:e7:18:46:6a:e4:c2:b6:d5:af:d3:68:6c:c3:95:
    ff:11:27:54:05:f4:9d:79:4d:a4:59:69:4e:ad:c0:
    b8:f0:dd:85:df:95:c0:fe:a5:74:7d:a8:ef:82:88:
    c1:07:79:48:69:fe:a4:54:bb:a5:2e:b1:71:c2:71:
    6b:7b:5b:54:56:b8:3e:de:30:a5:96:44:60:3d:fd:
    82:b5:a2:99:2b:9b:dc:8d:c4:27:d4:f7:e4:bc:13:
    5e:f7:44:cd:73:20:dd:cc:46:eb:96:18:1c:b8:51:
    68:f5:a0:ff:8f:a4:ec:92:1a:78:52:6b:52:65:bc:
    23:36:aa:df:8c:9c:d1:62:bd:26:98:cd:d4:eb:5a:
    9c:59:7f:87:d1:bd:93:96:f6:f4:8a:67:9f:47:75:
    a2:c4:4c:af:04:59:fb:0b:b1:78:4d:c5:59:9d:e5:
    9c:ac:8d:cd:ff:9d:b4:cf:7b:c4:db:4b:69:7c:52:
    41:eb:74:f1:4e:ce:ed:e5:2c:45:f3:e0:20:58:19:
    14:16:de:5f:8b:2e:63:30:a1:bd:50:bc:d0:c2:e2:
    95:57
G:    2 (0x2)

corresponding to the PEM and the plain text output formats. Observe that no public / secret keys are generated, but only the description of the Diffie-Hellman group. The labels P and G can be different across OpenSSL versions. In this OpenSSl version, the default size of the prime modulus is 2048. You can specify a different size (e.g., 1024) with the option -pkeyopt dh_paramgen_prime_len:1024 .

You can save the PEM output to a file (e.g., providing the option -out filename) and use it for actual key generation. This way, you can reuse the same parameters for several keys (e.g., for the two parties in a Diffie-Hellman key exchange).

Given the DH parameter file mydhgroup.pem , you can now generate a keypair with

$ openssl genpkey -paramfile mydhgroup.pem -text

You don't need to provide the name of the public key algorithm or the size parameters, because they can be inferred from the public parameters file header. The output produced by the above command is:

-----BEGIN PRIVATE KEY-----
MIICJgIBADCCARcGCSqGSIb3DQEDATCCAQgCggEBAPApQiD1U3+nqZrBKbK8PVKo
G1n4J+usOfguho7fml4IZcQcAMCCTCRgx/euvOcYRmrkwrbVr9NobMOV/xEnVAX0
nXlNpFlpTq3AuPDdhd+VwP6ldH2o74KIwQd5SGn+pFS7pS6xccJxa3tbVFa4Pt4w
pZZEYD39grWimSub3I3EJ9T35LwTXvdEzXMg3cxG65YYHLhRaPWg/4+k7JIaeFJr
UmW8Izaq34yc0WK9JpjN1OtanFl/h9G9k5b29Ipnn0d1osRMrwRZ+wuxeE3FWZ3l
nKyNzf+dtM97xNtLaXxSQet08U7O7eUsRfPgIFgZFBbeX4suYzChvVC80MLilVcC
AQIEggEEAoIBAE1zlNqDYLe6j8tH1X2678l/0zknv8iQXzzge7hHVXKBQftV/mQu
m/zVkf1Uhf9NpoaWA7DG0Rvct1tto/RaW2tUcH/Pr3LK6xgHoTF7Gl5OgM0TAdIX
eRhYDBZTnBY2twiZi2XkrdZ//aaYBaR9xCU0+F8g2c8WCzoXTmZ8sZpDjXl0J01S
Sh8iQjYRvdOPahmHQDXXf/td99Tpm2AzeDRrHn9bm9UELptKhy/T3h6BfaQzPgma
SOqu0VUHD8Q1xSgF7reLvOP3ghVX3hbjkY4CYH3YwutKtDySFL0g3knYDEksQEmf
6rvh5ChTkTX5QLoHy8+yHPH2xpUQNyzTCho=
-----END PRIVATE KEY-----
DH Private-Key: (2048 bit)
private-key:
    4d:73:94:da:83:60:b7:ba:8f:cb:47:d5:7d:ba:ef:
    c9:7f:d3:39:27:bf:c8:90:5f:3c:e0:7b:b8:47:55:
    72:81:41:fb:55:fe:64:2e:9b:fc:d5:91:fd:54:85:
    ff:4d:a6:86:96:03:b0:c6:d1:1b:dc:b7:5b:6d:a3:
    f4:5a:5b:6b:54:70:7f:cf:af:72:ca:eb:18:07:a1:
    31:7b:1a:5e:4e:80:cd:13:01:d2:17:79:18:58:0c:
    16:53:9c:16:36:b7:08:99:8b:65:e4:ad:d6:7f:fd:
    a6:98:05:a4:7d:c4:25:34:f8:5f:20:d9:cf:16:0b:
    3a:17:4e:66:7c:b1:9a:43:8d:79:74:27:4d:52:4a:
    1f:22:42:36:11:bd:d3:8f:6a:19:87:40:35:d7:7f:
    fb:5d:f7:d4:e9:9b:60:33:78:34:6b:1e:7f:5b:9b:
    d5:04:2e:9b:4a:87:2f:d3:de:1e:81:7d:a4:33:3e:
    09:9a:48:ea:ae:d1:55:07:0f:c4:35:c5:28:05:ee:
    b7:8b:bc:e3:f7:82:15:57:de:16:e3:91:8e:02:60:
    7d:d8:c2:eb:4a:b4:3c:92:14:bd:20:de:49:d8:0c:
    49:2c:40:49:9f:ea:bb:e1:e4:28:53:91:35:f9:40:
    ba:07:cb:cf:b2:1c:f1:f6:c6:95:10:37:2c:d3:0a:
    1a
public-key:
    7d:d7:89:71:0c:26:21:8e:97:07:e0:a4:af:e5:63:
    b4:b6:0a:b4:9e:e1:d5:a0:c1:d7:5e:b4:b5:46:3f:
    15:0f:4c:7c:c0:e9:e6:a5:ec:eb:18:ce:9c:26:80:
    26:a0:b9:30:b9:24:a0:ce:11:41:08:d3:cc:f3:2a:
    01:03:c3:7d:9f:e9:3a:ae:78:62:2d:d2:c7:1a:35:
    eb:d5:5a:b6:fe:3a:f9:37:de:6f:2b:0e:5e:07:e8:
    c2:bd:82:8f:50:84:56:26:ef:83:71:24:ec:72:f9:
    21:a3:1e:b6:86:1a:1b:b3:b9:8f:e3:58:1c:ef:5e:
    f6:33:f6:da:61:2d:bb:f9:db:f2:2d:7c:0d:9e:96:
    ea:da:8c:69:3e:dd:df:9a:d6:58:2d:28:cb:6d:c4:
    09:9a:2f:3f:3d:9d:74:ee:f8:f7:15:14:f5:b8:68:
    92:92:a6:d8:d7:16:ff:72:c8:e6:5e:a2:0b:81:e5:
    e3:e6:e9:b3:bf:bf:65:35:64:e1:bb:10:2d:dc:c1:
    50:d0:43:4e:e7:21:27:1b:f8:c9:37:e3:3d:73:e6:
    93:be:79:dd:1f:e5:66:54:28:5d:95:15:73:96:99:
    b4:ec:73:c4:9d:81:36:f3:38:ab:65:7c:22:af:91:
    73:4f:ea:9a:cc:88:1c:0e:ef:ca:61:90:60:79:c8:
    56
P:   
    00:f0:29:42:20:f5:53:7f:a7:a9:9a:c1:29:b2:bc:
    3d:52:a8:1b:59:f8:27:eb:ac:39:f8:2e:86:8e:df:
    9a:5e:08:65:c4:1c:00:c0:82:4c:24:60:c7:f7:ae:
    bc:e7:18:46:6a:e4:c2:b6:d5:af:d3:68:6c:c3:95:
    ff:11:27:54:05:f4:9d:79:4d:a4:59:69:4e:ad:c0:
    b8:f0:dd:85:df:95:c0:fe:a5:74:7d:a8:ef:82:88:
    c1:07:79:48:69:fe:a4:54:bb:a5:2e:b1:71:c2:71:
    6b:7b:5b:54:56:b8:3e:de:30:a5:96:44:60:3d:fd:
    82:b5:a2:99:2b:9b:dc:8d:c4:27:d4:f7:e4:bc:13:
    5e:f7:44:cd:73:20:dd:cc:46:eb:96:18:1c:b8:51:
    68:f5:a0:ff:8f:a4:ec:92:1a:78:52:6b:52:65:bc:
    23:36:aa:df:8c:9c:d1:62:bd:26:98:cd:d4:eb:5a:
    9c:59:7f:87:d1:bd:93:96:f6:f4:8a:67:9f:47:75:
    a2:c4:4c:af:04:59:fb:0b:b1:78:4d:c5:59:9d:e5:
    9c:ac:8d:cd:ff:9d:b4:cf:7b:c4:db:4b:69:7c:52:
    41:eb:74:f1:4e:ce:ed:e5:2c:45:f3:e0:20:58:19:
    14:16:de:5f:8b:2e:63:30:a1:bd:50:bc:d0:c2:e2:
    95:57
G:    2 (0x2)

Observe that both the prime and the generator are the same as in the given parameters file.

The prime generated with the previous commands is a safe prime (i.e., is has the form p=2q+1, where q is also prime). This option makes the parameter generation slow and also impacts the performance of the public key operations for these parameters, without a real security improvement

You can use a faster generation following the X9.42 specification (see RFC2631 for more details), in which p=kq+1 and the prime q can be smaller (e.g., 224 bits long).

In this case, the name of the algorithm in the openssl call must be dhx instead of dh . Then the corresponding is

$ openssl genpkey -genparam -algorithm dhx -text

with an output like

-----BEGIN X9.42 DH PARAMETERS-----
MIICTAKCAQEA95H6n1jzWhkdiR9gmG8M4W1sxoObc/uFT5r7D5lYTS6hz60AkBQ+
JKpHzZ54TRJOHHMH5NmTOmLHM2yOqnTFphw0PlZVUvgPveOQhzf8subnKvuGQOon
0FuVc/RrTUCUbhRKpuhkBKOrhcpluvxsairoojyWwzFFwoOs6EHYI25K6pIWRDbI
/GZuGT5cjrvy2/XGJY2oaLsWZ5oxJQoF1mIDtYOEBZdeaV9U79vAc2f8CW59f0D+
Y6P8M3SmHMn2S5t61/mBodG/C00qhq/EWrvybnYgbG31rTUdtls7MjZB1KNjMutq
mOlvkJa0vcv8ms3vJaVdKhDNzNVVpzx68QKCAQBBUOa0qoS5QAfIvvvqx+4niyuz
g09TdOFZclKUcWm3sPEbrTydI66Sads9mX6pJYD8DVVbUa3+JGQxKMREZpoquo5I
cAn4Vj7CPSuVPDCY78UULrIh6PLX22O25SCCppAKdI0NSYcAso7GRwOmPfPxHCGx
HXBD8xOZE2gUD5FeMzhEEeQ3BInGSRBSfbks7ffilVtYFUf/ARrgujyZoVZNzWE8
5Z6H5i/wIL/xMaIVWZyi0jgfFwWtqutp6Qlkpm4IaW/kwbRdRZ50Eq29ZYv3rkUy
av1t1z5n7/F1uZ6MDJSArcbJ7Cm4bvCYA7QgcthNmzq9QzplvNxKfxvwqL4zAh0A
7wGNSMzf9JPprvmH3jqzItqBuSiQ/u7eHJv6QTAiAx0A2VFUJIRfH/nt0AqCRGTU
YNC8naOJCWKVJ8Y7cQIBNA==
-----END X9.42 DH PARAMETERS-----
DH Parameters: (2048 bit)
P:   
    00:f7:91:fa:9f:58:f3:5a:19:1d:89:1f:60:98:6f:
    0c:e1:6d:6c:c6:83:9b:73:fb:85:4f:9a:fb:0f:99:
    58:4d:2e:a1:cf:ad:00:90:14:3e:24:aa:47:cd:9e:
    78:4d:12:4e:1c:73:07:e4:d9:93:3a:62:c7:33:6c:
    8e:aa:74:c5:a6:1c:34:3e:56:55:52:f8:0f:bd:e3:
    90:87:37:fc:b2:e6:e7:2a:fb:86:40:ea:27:d0:5b:
    95:73:f4:6b:4d:40:94:6e:14:4a:a6:e8:64:04:a3:
    ab:85:ca:65:ba:fc:6c:6a:2a:e8:a2:3c:96:c3:31:
    45:c2:83:ac:e8:41:d8:23:6e:4a:ea:92:16:44:36:
    c8:fc:66:6e:19:3e:5c:8e:bb:f2:db:f5:c6:25:8d:
    a8:68:bb:16:67:9a:31:25:0a:05:d6:62:03:b5:83:
    84:05:97:5e:69:5f:54:ef:db:c0:73:67:fc:09:6e:
    7d:7f:40:fe:63:a3:fc:33:74:a6:1c:c9:f6:4b:9b:
    7a:d7:f9:81:a1:d1:bf:0b:4d:2a:86:af:c4:5a:bb:
    f2:6e:76:20:6c:6d:f5:ad:35:1d:b6:5b:3b:32:36:
    41:d4:a3:63:32:eb:6a:98:e9:6f:90:96:b4:bd:cb:
    fc:9a:cd:ef:25:a5:5d:2a:10:cd:cc:d5:55:a7:3c:
    7a:f1
Q:   
    00:ef:01:8d:48:cc:df:f4:93:e9:ae:f9:87:de:3a:
    b3:22:da:81:b9:28:90:fe:ee:de:1c:9b:fa:41
G:   
    41:50:e6:b4:aa:84:b9:40:07:c8:be:fb:ea:c7:ee:
    27:8b:2b:b3:83:4f:53:74:e1:59:72:52:94:71:69:
    b7:b0:f1:1b:ad:3c:9d:23:ae:92:69:db:3d:99:7e:
    a9:25:80:fc:0d:55:5b:51:ad:fe:24:64:31:28:c4:
    44:66:9a:2a:ba:8e:48:70:09:f8:56:3e:c2:3d:2b:
    95:3c:30:98:ef:c5:14:2e:b2:21:e8:f2:d7:db:63:
    b6:e5:20:82:a6:90:0a:74:8d:0d:49:87:00:b2:8e:
    c6:47:03:a6:3d:f3:f1:1c:21:b1:1d:70:43:f3:13:
    99:13:68:14:0f:91:5e:33:38:44:11:e4:37:04:89:
    c6:49:10:52:7d:b9:2c:ed:f7:e2:95:5b:58:15:47:
    ff:01:1a:e0:ba:3c:99:a1:56:4d:cd:61:3c:e5:9e:
    87:e6:2f:f0:20:bf:f1:31:a2:15:59:9c:a2:d2:38:
    1f:17:05:ad:aa:eb:69:e9:09:64:a6:6e:08:69:6f:
    e4:c1:b4:5d:45:9e:74:12:ad:bd:65:8b:f7:ae:45:
    32:6a:fd:6d:d7:3e:67:ef:f1:75:b9:9e:8c:0c:94:
    80:ad:c6:c9:ec:29:b8:6e:f0:98:03:b4:20:72:d8:
    4d:9b:3a:bd:43:3a:65:bc:dc:4a:7f:1b:f0:a8:be:
    33
SEED:
    d9:51:54:24:84:5f:1f:f9:ed:d0:0a:82:44:64:d4:
    60:d0:bc:9d:a3:89:09:62:95:27:c6:3b:71
pcounter: 52
h: 2

You can also custom the prime sizes with the two options dh_paramgen_prime_len and dh_paramgen_subprime_len , as for example

$ openssl genpkey -genparam -algorithm dhx -pkeyopt dh_paramgen_prime_len:1024 \
$ -pkeyopt dh_paramgen_subprime_len:160 -text

Valid values for dh_paramgen_subprime_len are 160, 224 and 256.

You can also use any of the three standarized DH groups (see RFC5114, sections 2.1, 2.2, 2.3) with the option -pkeyopt dh_rfc5114: value, where value is one of 1, 2 or 3, as in the example

$ openssl genpkey -genparam -algorithm dhx -pkeyopt dh_rfc5114:3 -text

Observe that the algorithm name for this option must also be dhx .

When using one of these groups predefined in RFC5114, there is no need to store the parameters in a file. Thus, we can directly generate a keypair in a single call. For example, using the first group in RFC5114, we can build the following keyfile:

$ openssl genpkey -algorithm dhx -text -pkeyopt dh_rfc5114:1
DH Private-Key: (1024 bit)
    private-key:
        3d:0f:71:1e:47:44:b2:e1:b7:37:50:01:ea:34:c5:
        a5:93:91:71:7f
    public-key:
        7e:ee:7b:7e:7f:83:c8:5e:68:1c:6b:6e:43:49:11:
        4f:c3:1d:9a:8c:6e:3c:62:68:d6:fd:ff:06:bc:39:
        21:4f:ec:5a:64:a4:ed:16:6e:1f:07:e4:e6:83:31:
        79:e8:07:8b:61:e0:07:ce:33:12:0b:ec:d9:5a:51:
        0e:62:1c:68:c7:f4:01:53:f8:5b:b1:0f:2d:aa:31:
        1e:39:50:85:83:ff:76:b1:93:f7:67:e5:5c:af:36:
        6a:e7:bf:78:b1:6e:1d:d3:dc:95:60:b5:9f:a1:d0:
        14:ea:b7:eb:a6:3c:be:31:2d:90:b6:e6:2a:c8:f9:
        08:43:4e:c4:fc:59:c4:1e
    GROUP: dh_1024_160

Observe that the public parameters are not explicitly included in the file, but only the reference to dh_1024_160 is given.

1.3 Elliptic Curves

The elliptic curve version of Diffie-Hellman key generation is very similar, but it currently supports only known (standarized) elliptic curve groups (that is, you cannot use openssl to generate new random elliptic curves with the required security properties). In order to create the parameters file for one of the preimplemented elliptic curve groups (e.g., P-256 , or equivalently, prime256v1 ), you simply use

$ openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -pkeyopt \
$ ec_param_enc:named_curve -text

producing the output

-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
EC-Parameters: (256 bit)
ASN1 OID: prime256v1
NIST CURVE: P-256

You can also generate the explicit values of the parameters providing the value explicit to the parameter ec_param_enc , like in

$ openssl genpkey -genparam -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -pkeyopt \
$ ec_param_enc:explicit -text

and the output is now

-----BEGIN EC PARAMETERS-----
MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////
/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6
k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+
kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK
fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz
ucrC/GMlUQIBAQ==
-----END EC PARAMETERS-----
EC-Parameters: (256 bit)
Field Type: prime-field
Prime:
    00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
    00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:ff
A:   
    00:ff:ff:ff:ff:00:00:00:01:00:00:00:00:00:00:
    00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:
    ff:ff:fc
B:   
    5a:c6:35:d8:aa:3a:93:e7:b3:eb:bd:55:76:98:86:
    bc:65:1d:06:b0:cc:53:b0:f6:3b:ce:3c:3e:27:d2:
    60:4b
Generator (uncompressed):
    04:6b:17:d1:f2:e1:2c:42:47:f8:bc:e6:e5:63:a4:
    40:f2:77:03:7d:81:2d:eb:33:a0:f4:a1:39:45:d8:
    98:c2:96:4f:e3:42:e2:fe:1a:7f:9b:8e:e7:eb:4a:
    7c:0f:9e:16:2b:ce:33:57:6b:31:5e:ce:cb:b6:40:
    68:37:bf:51:f5
Order: 
    00:ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff:
    ff:ff:bc:e6:fa:ad:a7:17:9e:84:f3:b9:ca:c2:fc:
    63:25:51
Cofactor:  1 (0x1)
Seed:
    c4:9d:36:08:86:e7:04:93:6a:66:78:e1:13:9d:26:
    b7:81:9f:7e:90

where you can see the values of the prime defining the finite field, the coefficients a,b of the curve, the generator (both the x- and y-coordinates of the point are packed into a single string), the order or size q of the generated group, and other parameters (cofactor and seed).

You can obtain a list of implemented elliptic curves with

$ openssl ecparam -list_curves 

Finally, the generation of a keypair from a given parameters file (e.g., P-128_ecgroup.pem ) is exactly as above:

$ openssl genpkey -paramfile P-128_ecgroup.pem -text

producing the output

-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgohhdkTqmahz8bwgh
BbDhmVyaTT4K+f4qatP6/oF8pb+hRANCAAQhmFI+84JDC+eHPmsbDl7qjZlAFDHM
9263g2FZjEs/zZ5W8T6ipYhu+krsX+j8/our09tWrV+5V0L1jkQtcPOb
-----END PRIVATE KEY-----
Private-Key: (256 bit)
priv:
    00:a2:18:5d:91:3a:a6:6a:1c:fc:6f:08:21:05:b0:
    e1:99:5c:9a:4d:3e:0a:f9:fe:2a:6a:d3:fa:fe:81:
    7c:a5:bf
pub: 
    04:21:98:52:3e:f3:82:43:0b:e7:87:3e:6b:1b:0e:
    5e:ea:8d:99:40:14:31:cc:f7:6e:b7:83:61:59:8c:
    4b:3f:cd:9e:56:f1:3e:a2:a5:88:6e:fa:4a:ec:5f:
    e8:fc:fe:8b:ab:d3:db:56:ad:5f:b9:57:42:f5:8e:
    44:2d:70:f3:9b
ASN1 OID: prime256v1
NIST CURVE: P-256

where the secret key is an integer modulo the size of the group q, and the public key is a point in the elliptic curve (again, the two coordinates of the point are packed into a single string).

As all elliptic curves accepted by OpenSSL are indeed predefined curves, you can also skip the public parameters file generation and directly produce a keyfile with

$ openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 -text

1.4 File Formats

In the previous examples you can see the need of packing different mathematical objects together in a single file, and this requires the use of some formatting rules. Along with the human readable text output, OpenSSL uses a printable compressed format PEM and a binary format DER to store keys, ciphertext, signatures and certificates, among other binary objects.

The PEM format is a printable version (using the Base64 printable encoding) of the binary DER format, with additional headers and footers, like for instance:

-----BEGIN PRIVATE KEY-----
                ...
 (base64 encoded binary DER content)
                ...
-----END PRIVATE KEY-----

DER format is basically an unambiguous way to pack a sequence of objects, and each individual object has three parts: type specification, length of the data, and the data itself. For instance, an integer is encoded by as a byte sequence starting with the type identifier 0x02 followed by the number of bytes used in the binary representation of the integer, and then the binary representation itself. The predefined types in DER include booleans, integers, bit strings, octet strings among other types, and aggregations of them.

You can use the command asn1parse of openssl to look inside a DER or a PEM file and to retrieve all individual entities stored into them. In some openssl commands the user can choose the specific output format (DER or PEM) to store keys, ciphertexts, certificates and other binary objects. For instance, the option -outform format, where format is one of der or pem , used in conjunction with openssl genpkey selects the format used to store the generated keypair.

1.5 Public Key Extraction

The previous commands show how to generate public / secret keypairs and store them into files. However, in the public key cryptography setting, public keys must be transmitted without revealing the corresponding secret keys. In OpenSSL one can extract the public part of the generated keypair and store it into a separate file. The command

$ openssl pkey -in private.pem -pubout -out public.pem 

reads the keypair from the file private.pem , probably generated with openssl genpkey , and extracts and stores the public key into the file public.pem . Default input and output formats are PEM, but you can specify DER format in either input or output files with the options -inform der and -outform der .

Now, the resulting public key can be used in encryption or in signature verification, while the private key file is required for decryption and for signature generation. Private key files can be generated in a protected way, by encrypting them with a symmetric key encryption scheme in the same call to openssl genpkey . See the openssl documentation for more details.


2 Public Key Encryption and Decryption

Form the keypairs generated as explained in the previous section one can perform public key encryption and decryption.

For the (plain) RSA public key encryption scheme the use of OpenSSL in the command line is quite easy, with the openssl pkeyutl command used in conjunction with the -encrypt and -decrypt options.

The main problem is that a public key encryption only allows encrypting messages with a very precise format (e.g., in RSA a message must be the binary encoding of an integer between 1 and n-1, where n is the public modulus). This means that, in practice, we would need a padding scheme, and possibly a chaining mode for long messages.

From a practical point of view, public key encryption schemes are only used to encrypt ephemeral keys to be used in symmetric encryption primitives (like encryption or MAC). Thus, in OpenSSL you can use

$ openssl pkeyutl -pubin -inkey myrsapubkey.pem -in ephemeralkey.bin -encrypt -pkeyopt \
$ rsa_padding_mode:oaep -out ciphertext.bin

to encrypt the short file ephemeralkey.bin with the RSA key contained in myrsapubkey.pem using a specific padding scheme like OAEP (see the documentation of OpenSSL for the implemented RSA padding algorithms), and store the encrypted data in ciphertext.bin .

There exist a maximum length for the message to be encrypted (the maximum length could be smaller than the length of n, because the padding string takes some minimal space). Normally, short messages can be encrypted successfully, except if you specify -pkeyopt rsa_padding_mode:none , in which only messages with exactly the same binary length of n, and not greater than n as an integer, can be encrypted.

Decryption is performed in a similar way (you also have to specify the same padding scheme used in encryption), but now you provide the private key instead of the public one, and use the option -decrypt instead of -encrypt .

$ openssl pkeyutl -inkey myrsaprivkey.pem -in ciphertext.bin -decrypt -pkeyopt \
$ rsa_padding_mode:oaep -out decrypted.bin

3 Diffie-Hellman Key Agreement

The generation of the common key in the Diffie-Hellman Key Agreement requires one secret key (say, Alice's secret key) and one public key (sat, Bob's public key). Given the files (generated as above) alice_priv.pem and bob_publ.pem , Alice can generate the common secret with

$ openssl pkeyutl -inkey alice_priv.pem -peerkey bob_publ.pem -derive -out common.bin

Similarly, Bob can execute

$ openssl pkeyutl -inkey bob_priv.pem -peerkey alice_publ.pem -derive -out common.bin

to obtain the same result.

According to the specification of the Diffie-Hellman Key Agreement protocol, the two keypairs must be produced with the same group (i.e., the same parameters file). If the group corresponds to the normal (i.e., non elliptic curve based) Diffie-Hellman Agreement, then the common secret is the binary representation of gsAsB, where sA and sB are the secret keys of the two parties, and g is the group generator. Otherwise, in the elliptic curve based protocol, the common secret is the binary representation of the x-coordinate of the point (sAsB)G, where G is the base point (generator) of the subgroup.

The common secret must never be directly used as a symmetric key. Instead, it must be hashed or transformed with a secure key derivation function. For instance, you can pipe the previous generation commands and the hash computation with

$ openssl pkeyutl -inkey alice_priv.pem -peerkey bob_publ.pem -derive | openssl dgst \
$ -sha256 -binary > commonkey.bin

which produces a secure shared 256 bit symmetric key, ready to be used with any encryption or MAC operation.


4 Practical Work: Hashed ElGamal + Hybrid Encryption + HMAC

In this practical exercise you will implement a hybrid encryption scheme consisting of the combination of a version of Hashed ElGamal encryption, a symmetric encryption scheme and a MAC.

Namely, you will use a normal Diffie-Hellman key exchange, with a group size of 256 bits. The common secret resulting from a Diffie-Hellman key agreement is 256 bits long. Then, the hash function SHA256 is applied to the common secret to obtain a 256 bits symmetric key, that is split into two 128 bits keys: one, k1, for AES-128-CBC encryption and the other, k2, for SHA256-HMAC.

At system setup, all parties willing to exchange encrypted messages must agree on a particular DH public parameters file. In this lab the third group in RFC5114 will be used.

Any party can generate the public parameters file with

$ openssl genpkey -genparam -algorithm dhx -pkeyopt dh_rfc5114:3 -out param.pem

Before encrypting a file, the recipient (say Alice) must have been generated a long-term Diffie-Hellman keypair, and then she must have published the corresponding public key. Namely, the recipient needs to perform the following steps:

Now, the encryption operation run by the sender (say Bob) consists of:

Ideally, a single file in PEM or DER format joining the previous four files would be a better option. You can do that by concatenating the printable (base64 encoded) files with adequate headers and footers. For instance, you can start from the file ephpubkey.pem that already is in PEM format, then concatenate it with the base64 encoding of ciphertext.bin , iv.bin and tag.bin with some PEM style headers and footers added:

   (put here the file ephpubkey.pem as it is)
   (it already contains its own header and footer lines)
-----BEGIN AES-128-CBC IV-----
   (put here the 64bit encoding of file iv.bin)
-----END AES-128-CBC IV-----
-----BEGIN AES-128-CBC CIPHERTEXT-----
   (put here the 64bit encoding of file ciphertext.bin)
-----END AES-128-CBC CIPHERTEXT-----
-----BEGIN SHA256-HMAC TAG-----
   (put here the 64bit encoding of file tag.bin)
-----END SHA256-HMAC TAG-----

To convert files between binary and base64 encoding you can use the special OpenSSL pseudocipher in openssl enc with the -a option. In the encryption direction the input is interpreted as a binary file and the output is the corresponding printable base64 encoding. In the decryption direction (with the -d option), the conversion is done in the opposite way.

Decryption can be performed with a similar procedure:

As a result you would provide three scripts: one for parameter and key generation, another for encryption and a third one for decryption.

You can test your scripts at different levels:

To perform these tests (specially the two last ones) you must use the auxiliary files (keys and ciphertext) available on the subject webpage.