Authors: João Paulo Barraca, Vitor Cunha, Paulo C. Bartolomeu, Alfredo Matos, Catarina Silva
Slides
Download here
Introduction
In this guide we will develop programs that use cryptographic methods,
relying in the Python3 Cryptography module.
The module can be installed using the typical package management methods
(e.g, apt install python3-cryptography
), or using the pip3
tool
(e.g. pip3 install cryptography
). The apt
method is preferred to pip3
.
RSA
RSA key pair generation
Create a small program to generate an RSA
key pair, with a key length specified by the user (1024, 2048, 3072 or 4096). The program must save the key pair in two files, one for the private key and the other one for the public key, whose names should also be specified by the user. The keys can be saved as binary blobs but, probably, the PEM
format will be more appropriate.
Run the program, several times, varying the key length and register the elapsed time using the time
program in the shell (use man time
for more information), for example:
time python keygen.py ./pub.txt ./priv.txt 4096
Questions:
- What do you think of using 4096 bit keys by default in relation to speed?
- How the actual key size varies with the number of bits?
RSA
Encryption
Create a small program to encrypt a file using the RSA
algorithm.
The user must indicate the following data:
- Name of the original file to encrypt
- Name of the file with the public key
- Name for the encrypted file.
For the encryption select the PKCS #1
padding scheme. Note that this scheme is not recommended for new applications. Also, pay attention to the size of the original file, i.e., the file to encrypt. Using the PKCS #1
default configuration, the block size is equal to the key size minus eleven bytes (eleven bytes for padding). So, for example using a 1024 bits RSA
key (128 bytes), the block size is 117 bytes (128 - 11).
RSA
Decryption
Create a small program to decrypt the contents of a file, whose name is
provided by the user, using the RSA
algorithm. The user must also indicate:
- Name of the encrypted file;
- Name of the file to save the decrypted content;
- Name of the file containing the private key to use.
Large file encryption
As should be known by now, RSA
encryption is not efficient and is not
recommended to encrypt data bigger than its block size. Let’s conduct a benchmark.
Symmetric vs. Asymmetric cryptography benchmark
Generate two files with 100 kB and 10 MB of size. Using these files and the time
application, register the time it takes to encrypt and decrypt these files with RSA
(key = 1024 bits) and AES128
. Employ the applications developed in this guide and in the previous one.
The following bash command can be used to generate a 100 kB file:
dd if=/dev/zero of=file.txt bs=1024 count=100
Symmetric and Asymmetric cryptography combination
Consider a large file (500 MB, for example) that you want to
send to some person, with the guarantee that only that person can
decrypt the file. More, you have the public key of that person, and you
are not able to contact the person before sending the file. So, you have
a big file to transmit to a person, from which you know the public key,
but the process will be very slow if you encrypt the file using RSA
.
However, you can use any other encryption algorithm to encrypt the file, but remember you want that only the receiver must be able to decrypt the file.
Questions: What combination of encryption technologies allow to efficiently send the file to the recipient, with the guarantee that only that person can decrypt the file?
A typical solution is called Hybrid Encryption, which combines two ciphers, a symmetric to encrypt the file with a random key, and a asymmetric to encrypt the key used in the previous step.
Implement a program that is able to encrypt/decrypt a large file using the AES128
algorithm, employing a randomly generated secret. The secret should be supplied to the intended receiver ciphered with RSA
using its own public key. The receiver should be able to reverse the process and obtain the original version of the large file. The program should accept the following arguments:
- Operation to perform (encrypt/decrypt);
- Name of the (large) file to encrypt/decrypt;
- Name of the file with the key to be used (public/private).
Questions:
- With this method, what is sent to the destination?
- Should we always send the pubic key?
Elliptic curves
Elliptic Curve Cryptography (ECC
) is a lot different from RSA
.
First, whilst in RSA
one chooses the length of the RSA
modulus (in
bits), in ECC
one chooses a curve, and the curve defines the key length.
Second, the private and public keys that belong to the same key pair
are of a different nature: the private key is an integer (a
scalar), whilst the public key is a two-coordinate point. The
public component is a point given by the multiplication of the
private key with a so-called curve generator (G
), which is a point
of the curve. Since the sum of two points defines a new point
(elliptic curves have a special algebra…), and the multiplication
of G
by the private key (a scalar) is nothing more than a sum of G
values, it is simple to conclude that the public key is a point.
Third, there is no such thing as an encryption with a public key and a posterior decryption with the corresponding private key. This is not used at all. Instead, a method similar to a Diffie-Hellman key agreement is used. For encrypting a message to a receiver B, the sender A uses B’s public and a new private key to compute a point in the curve, and from that point derives a secret, symmetric key. The message is then encrypted with that symmetric key and sent to B, together with the public component of the random private key created by A. The receiver B multiplies the received public key with its own private key and reaches the same point in the curve, which it can use to derive the exact same secret, symmetric key and use it to decipher the message.
There are many elliptic curves, both proposed in standards and
other publications. NIST proposed 15 curves, known as P
, B
and K
curve (5 of each). The name stems from the mathematical elements
used in the curves – P
from prime, B
from binary, K
from Koblitz, a
variant a B
curves. Other curves are recommended by de facto
standards, such as RFC 7748
, which describes Curve25519
and
Curve448
). The SafeCurves
publication provides some guidelines for selecting a god curve.
ECC key pair generation
ECC
key pair generation is fairly simple. First, one chooses a
curve; we will use P-521
.
Then, we generate a random private key for that curve. This is a 521-bit random integer. Then, from that private key, we generate the public key.
Create a program the generates a key pair and saves it in a file.
The private component should be protected by a password, provided as
a program parameter. You can use the PEM
format for encapsulating
each of the keys. We will assume this program will be called p256_gen
.
p256_gen one_password > KPair
Note: you can generate two PEM
contents, one for the private
component, another for the public component, and store them in the
same PEM
file. We will consider this approach below.
Secure messaging with public encryption and private decryption
Create a program ECC_encrypt
that encrypts the contents received
from the standard input to the standard output. The program should
have a parameter a file containing the public of the receiver.
The contents produced must contain both the encrypted input and the
originator’s public key. You can use any message format for that,
for instance, JSON
(do not forget to use Base64
for encoding binary
contents into strings for JSON
). For symmetric encryption, you can
use AES
in CTR
mode and an IV
derived from the secret key (e.g., by
hashing it).
ECC_encrypt KPair < plaintext > ciphertext
Create a program ECC_decrypt
that decrypts the contents received
from the standard input to the standard output. The program should
have as parameters a file containing the private key of the receiver
and a password for having access to that private key. The format of
the input is the one produced by ECC_encrypt
.
ECC_decrypt KPair one_password < ciphertext > recovered_plaintex
After these two command, the contents of plaintext
should be equal
to the contents of recovered_plaintext
.