Compare commits
13 Commits
8099da0770
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a632ea129 | |||
| 3e183fbb1e | |||
| 7ba5098daa | |||
| c2c8b09dcf | |||
| 126e99113f | |||
| 5f84465e1f | |||
| c8287319b5 | |||
| e41e39e1c3 | |||
| 8c44c653b5 | |||
| bda797f631 | |||
| b9aa998ba7 | |||
| 1fea0c18cf | |||
| 5e03240950 |
13
README.md
13
README.md
@@ -5,7 +5,16 @@ Cryptographie - Outils et algorithmes
|
||||
[Cours crypto](cours/crypto.pdf)
|
||||
|
||||
#### Semaine 1
|
||||
- cm : [Chiffrements par bloc, algorithmes à clefs symétriques](cours/crypto.pdf).
|
||||
- cm : [LFSR, Chiffrements par bloc, algorithmes à clefs symétriques](cours/crypto.pdf).
|
||||
- td : [Généralités, chiffrements par flot](td/td1.pdf)
|
||||
- tp : [lfsr, xtea, hachages](tp/tp1)
|
||||
- tp : [Chiffrement ECB, lfsr, xtea](tp/tp1)
|
||||
|
||||
#### Semaine 2
|
||||
- cm : [Algorithmes à clefs symétriques, Hachages](cours/crypto.pdf).
|
||||
- td : [Chiffrements symétriques par blocs et modes](td/td2.pdf)
|
||||
- tp : [Substitution-Permutation-Network](tp/tp2)
|
||||
#### Semaine 3
|
||||
- cm : [Algorithmes à clefs publiques, signatures](cours/crypto.pdf).
|
||||
- td : [Hachages, Mac, signatures](td/td3.pdf)
|
||||
- tp : [Openssl](tp/tp3)
|
||||
|
||||
|
||||
BIN
cours/crypto_new.pdf
Normal file
BIN
cours/crypto_new.pdf
Normal file
Binary file not shown.
BIN
td/td2.pdf
Normal file
BIN
td/td2.pdf
Normal file
Binary file not shown.
BIN
td/td3.pdf
Normal file
BIN
td/td3.pdf
Normal file
Binary file not shown.
176
tp/tp1/README.md
176
tp/tp1/README.md
@@ -3,7 +3,7 @@
|
||||
L’objectif de cet exercice est de chiffrer une image en ligne de commande à
|
||||
l’aide des outils fournis par la librairie openssl.
|
||||
|
||||
1. Prenez une image de votre choix et convertissez la dans le format ppm à l’aide de la commande
|
||||
1. Prenez ~~une image de votre choix~~ l'image de [tux](https://fr.wikipedia.org/wiki/Tux#/media/Fichier:Tux.svg) et convertissez la dans le format ppm à l’aide de la commande
|
||||
`convert`.
|
||||
|
||||
2. Avec la commande `head`, mettez les 3 premières lignes de votre fichier ppm dans un fichier
|
||||
@@ -25,17 +25,183 @@ le bit $b_0$ est remplacé par un bit, calculé par une fonction linéaire $f$.
|
||||
|
||||
|
||||
|
||||
Vous disposez d'un [fichier](src/ex1/file.crypt) crypté avec un lfsr, en faisant
|
||||
Vous disposez d'un [fichier](src/ex2/file.crypt) crypté avec un lfsr, en faisant
|
||||
un XOR de chacun des octets avec les valeurs successives du registre. L'état
|
||||
initial du registre était `0xa7`, et la fonction utilisée
|
||||
|
||||
|
||||
\[
|
||||
f(b_7,b_6,b_5,b_4,b_3,b_2,b_1,b_0) = b_7\oplus b_6\oplus b_5\oplus b_4\oplus b_3\oplus b_1
|
||||
\]
|
||||
|
||||
$$ f(b_7,b_6,b_5,b_4,b_3,b_2,b_1,b_0) = b_7\oplus b_6\oplus b_5\oplus b_4\oplus b_3\oplus b_1 $$
|
||||
|
||||
Retrouver le fichier initial.
|
||||
|
||||
Vous pouvez utiliser la fonction interne `__builtin_parity` de `gcc`.
|
||||
|
||||
|
||||
## EX3 (si vous avez tout fini)
|
||||
|
||||
eXtended Tiny Encryption Algorithm est un algorithme de chiffrement symétrique par
|
||||
bloc. les algorithmes de chiffrement sysmétrique par bloc crypte/decrypte des
|
||||
**blocs** entiers, en utilisant la même clé secrète (symétrique). XTEA est un
|
||||
exemple simple de tels algorithmes (DES, AES, Blowfish) facile à implanter. La
|
||||
plupart de ces algorithmes utilise ce que l\'on appelle un réseau de Feistel.
|
||||
|
||||
##### Réseau de Feistel
|
||||
|
||||
Désignons par $K$ la clé (un mot binaire). On décompose le bloc à
|
||||
crypter en 2 moitiés $(L_0,R_0)$ On lui applique une
|
||||
transformation de la forme :
|
||||
|
||||
$$
|
||||
(L_0,R_0) \rightarrow (L_1,R_1)
|
||||
\, où \,
|
||||
\left\{\begin{matrix} L_1 & = & R_0 \\
|
||||
R_1 & = & L_0 + f(R_0,K)
|
||||
\end{matrix}\right.
|
||||
$$
|
||||
|
||||
|
||||
- La loi $+$ doit simplement être "réversible" (une loi de
|
||||
groupe). Dans la pratique, il s'agit souvent d'un xor, mais pour
|
||||
TEA, il s\'agit de l'addition binaire.
|
||||
- La fonction $f$ n'a pas besoin d'être inversible pour que la
|
||||
transformation précédente soit réversible.
|
||||
|
||||
Pourquoi ? Comment fait-on ?
|
||||
- Le chiffrement consiste alors à itérer la transformation (appelée
|
||||
round) un certain nombre de fois.
|
||||
|
||||
<div align="center">
|
||||
<img src="./img/feistel.png">
|
||||
</div>
|
||||
|
||||
##### XTEA
|
||||
|
||||
XTEA (cf cours) crypte des blocs de 8 octets, en utilisant une clé de 16 octets.
|
||||
|
||||
Un cycle (2 rounds, itéré 32 fois) de XTEA est donné par le réseau
|
||||
suivant :
|
||||
<div align="center">
|
||||
|
||||
<img src="./img/xtea.png">
|
||||
</div>
|
||||
|
||||
En vert, il s'agit de l'addition binaire sur 32 bits, en rouge le xor.
|
||||
|
||||
- la clé est décomposée 4 sous-clés $K[0],K[1],K[2],K[3]$.
|
||||
- chaque round utilise un multiple de $\delta = ( \sqrt{5} - 1 ) * 2^{31}$ pour rendre les rounds non symétriques.
|
||||
|
||||
Voici un exemple de code correspondant :
|
||||
```c
|
||||
void encrypt(uint32_t v[2], uint32_t const key[4])
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
|
||||
for (i=0; i < 32; i++) {
|
||||
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
|
||||
sum += delta;
|
||||
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
|
||||
}
|
||||
v[0]=v0; v[1]=v1;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### Padding (bourrage)
|
||||
|
||||
Lorsque l'on cherche à crypter un fichier, sa taille n'est pas
|
||||
toujours un multiple de la longueur des blocs chiffrés par
|
||||
l'algortihme. Il existe différentes techniques dites de padding. Nous
|
||||
utiliserons celle-ci :
|
||||
|
||||
- Si le dernier bloc à chiffer du fichier n'est pas entier, on écrit
|
||||
dans son dernier octet le nombre d'octets manquants. Les octets
|
||||
précédents peuvent être zéroifiés, ou remplis aléatoirement.
|
||||
- Si le dernier bloc est entier, on rajoute tout un bloc pour qu'il
|
||||
n'y est pas d'ambiguité.
|
||||
|
||||
Voici un exemple avec des blocs de taille 8 octets. Le fichier en entrée
|
||||
est
|
||||
```
|
||||
ascii : hello word!
|
||||
hex : 68 65 6c 6c 6f 20 77 6f 72 6c 64 21
|
||||
```
|
||||
|
||||
Le dernier bloc est
|
||||
```
|
||||
ascii : ord!
|
||||
hex : 72 6c 64 21 00 00 00 04
|
||||
```
|
||||
|
||||
On ajoute des zéros (ou des octets aléatoires), et le dernier est le
|
||||
nombre d'octets ajoutés (ici, 4). Si le dernier bloc est complet, on
|
||||
rajoute tout un bloc.
|
||||
|
||||
```
|
||||
hex : 00 00 00 00 00 00 00 00 08
|
||||
```
|
||||
|
||||
##### Votre travail
|
||||
|
||||
1. Ecrire une fonction qui decrypte un bloc.
|
||||
2. Ecrire une commande **xtea** qui permet de (dé)chiffrer un fichier.
|
||||
|
||||
```bash
|
||||
xtea -e|-d filekey file1 file2
|
||||
```
|
||||
|
||||
- `filekey` est le fichier ou est stocké la clé. Vous pouvez en
|
||||
générer en utilisant le pseudo fichier `/dev/urandom`, et la
|
||||
commande `dd`.
|
||||
- l'option `-e` crypte. `file1` est alors le fichier à crypter,
|
||||
`file2` le fichier crypté.
|
||||
- l'option `-d` decrypte. `file1` est alors le fichier crypté, `file2`
|
||||
le fichier decrypté.
|
||||
3. Testez avec cette [clé](./src/ex2/key1.k), et ce [fichier
|
||||
crypté](./src/ex2/fichier.crypt) sur une architecture little-endian.
|
||||
|
||||
4. Écrire une version de tea en mode CBC :
|
||||
|
||||
```bash
|
||||
xtea_cbc -e|-d iv filekey file1 file2
|
||||
```
|
||||
|
||||
`iv` est le vecteur d'initialisation (8 octets) donné sur la ligne de commande.
|
||||
|
||||
**Rappel** : en mode CBC, le bloc à chiffrer subit un XOR avec le chiffré du bloc précédent. Le vecteur d'initialisation sert
|
||||
pour le premier bloc.
|
||||
|
||||
## Ex4: une fonction de hachage cryptographique avec XTEA
|
||||
|
||||
Une fonction de hachage cryptographique permet de "résumer" un
|
||||
fichier, message en calculant une empreinte. Une telle fonction,
|
||||
mathématiquement, peut-être formalisée par
|
||||
|
||||
$$
|
||||
\begin{matrix}
|
||||
\{0,1\}^{*} & \rightarrow & \{0,1\}^n \\
|
||||
m &\rightarrow & f(m) \end{matrix}
|
||||
|
||||
$$
|
||||
|
||||
$n$ est la taille de l'empreinte. Elle vaut 128 par exemple pour MD5 et SHA-1.
|
||||
|
||||
Grâce à XTEA, on va construire une telle fonction pour avec $n=64$.
|
||||
|
||||
Voici le principe.
|
||||
|
||||
- Le message ou fichier est décomposé en bloc de 24 octets (on bourrera
|
||||
le dernier bloc suivant le pricincipe déjà vu en ajoutant des octets
|
||||
avec la valeur du nombre d'octets ajoutés).
|
||||
- Chaque bloc est vu comme un bloc suivi d'une clé de XTEA $x,k$
|
||||
(bloc $x$ de 8 octets, clé $k$ de 16 octets). On calcule
|
||||
$hash = xtea(x,k) \oplus x$.
|
||||
- On combine le hash du bloc courant avec le hash du bloc précédent à
|
||||
l'aide d'un xor. Le hash finale est l'empreinte.
|
||||
|
||||
##### Votre travail
|
||||
|
||||
1. Implantez le fonction prédente. Testez-là. Vérifiez que pour un message
|
||||
"assez proche", l'empreinte est "vraiment" différente.
|
||||
|
||||
|
||||
|
||||
BIN
tp/tp1/src/ex3/fichier.crypt
Normal file
BIN
tp/tp1/src/ex3/fichier.crypt
Normal file
Binary file not shown.
1
tp/tp1/src/ex3/key1.k
Normal file
1
tp/tp1/src/ex3/key1.k
Normal file
@@ -0,0 +1 @@
|
||||
÷Nà{q2‘*:¬¨œÇmfU#©`í±Å?&Q3
|
||||
11
tp/tp1/src/ex3/xtea.c
Normal file
11
tp/tp1/src/ex3/xtea.c
Normal file
@@ -0,0 +1,11 @@
|
||||
void encrypt(uint32_t v[2], uint32_t const key[4])
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
|
||||
for (i=0; i < 32; i++) {
|
||||
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
|
||||
sum += delta;
|
||||
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
|
||||
}
|
||||
v[0]=v0; v[1]=v1;
|
||||
}
|
||||
95
tp/tp2/README.md
Normal file
95
tp/tp2/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# TP2
|
||||
|
||||
> Dans ce tp, on implémente un algorithme de chiffrement par Blocs basé
|
||||
> sur un réseau de permutation-substitution (SPN), en mode ECB.
|
||||
|
||||
|
||||
### SPN
|
||||
|
||||
<div align="center">
|
||||
<img src="./img/spn.png">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
Ces algorithmes utilisent en entrée une clé, et applique à chaque bloc
|
||||
plusieurs tours constitués de boîtes de substitutions (S-Box) et de
|
||||
boîtes de permutations (P-Box).
|
||||
|
||||
- Une **S-Box** substitue à un ensemble de bits un autre ensembe de
|
||||
bits (transormation bijective).
|
||||
- Une **P-Box** est une permutation de bits. Elle prend la sortie
|
||||
d'une S-Box, permutte les bits, et les transmet à une S-box au tour
|
||||
d'après.
|
||||
- A chaque tour, on combine le bloc avec la clé (ici un xor).
|
||||
|
||||
#### implantation
|
||||
|
||||
|
||||
|
||||
- la taille de bloc est 8 bits,
|
||||
- le bloc est découpé en 2 sous-blocs de 4 bits chacun,
|
||||
- la taille de la clef est 24 bits,
|
||||
- la clef est décomposée en 3 sous-clefs de 8 bits chacun,
|
||||
- le nombre de tours est égale à 2,
|
||||
- les substitutions et les permutations sont les mêmes à chaque tour.
|
||||
|
||||
Remarques
|
||||
|
||||
On représentera dans le programme une substitution par un tableau
|
||||
d'entiers (unsigned char) de taille 16.
|
||||
|
||||
```c
|
||||
unsigned char s[]={14,3,2,10,12,11,15,9,0,4,7,13,1,8,6,5}
|
||||
```
|
||||
|
||||
Ainsi, le bloc binaire 0011, qui vaut 3, sera remplacé par 1010 car `s[3]=10`
|
||||
|
||||
On représentera une permutation par un tableau d'entiers (`unisgned char`) de taille 16.
|
||||
|
||||
```
|
||||
unsigned char perm[8]={5,0,4,6,7,1,2,3};
|
||||
```
|
||||
|
||||
Ainsi, le bit de poids faible (rang 0) est placé au rang 5.
|
||||
|
||||
#### Votre travail
|
||||
|
||||
1. Ecrivez les fonctions suivantes, qui implantent le spn décrit ci-dessus.
|
||||
|
||||
```c
|
||||
#ifndef _SPN_H
|
||||
#define _SPN_H
|
||||
|
||||
unsigned char do_perm(unsigned char w,unsigned char perm[16]);
|
||||
unsigned char do_subst(unsigned char w,unsigned char subst[16]);
|
||||
|
||||
unsigned char encrypt(
|
||||
unsigned short w,
|
||||
unsigned int key,
|
||||
unsigned char perm[8],
|
||||
unsigned char subst[16]
|
||||
);
|
||||
|
||||
unsigned char decrypt(
|
||||
unsigned short w,
|
||||
unsigned int key,
|
||||
unsigned char perm[8],
|
||||
unsigned char subst[16]
|
||||
);
|
||||
|
||||
#endif
|
||||
```
|
||||
|
||||
2. Ecrivez des programmes spn-encrypt-file.c , spn-decrypt-file.c qui
|
||||
implantent le SPN décrit ci-dessus. Les deux prennent sur la ligne de
|
||||
commande :
|
||||
|
||||
- "nom fichier codé" et "nom fichier décodé "
|
||||
- la clef
|
||||
|
||||
La permutation et la substitution seront codées en dur dans les programmes.
|
||||
|
||||
Testez vos programmes sur un exemple à vous.
|
||||
|
||||
3. Passez vos deux programmes en mode CBC.
|
||||
BIN
tp/tp2/img/SubstitutionPermutationNetwork2.png
Normal file
BIN
tp/tp2/img/SubstitutionPermutationNetwork2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
tp/tp2/img/spn.png
Normal file
BIN
tp/tp2/img/spn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
17
tp/tp2/src/Makefile
Normal file
17
tp/tp2/src/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
all : spn-encrypt-file spn-decrypt-file
|
||||
|
||||
spn-encrypt-file.o : spn-encrypt-file.c
|
||||
gcc -c spn-encrypt-file.c
|
||||
|
||||
spn-decrypt-file.o : spn-decrypt-file.c
|
||||
gcc -c spn-decrypt-file.c
|
||||
|
||||
|
||||
./lib/spn.o:./lib/spn.c
|
||||
gcc -c ./lib/spn.c -o ./lib/spn.o
|
||||
|
||||
spn-encrypt-file : ./lib/spn.o spn-encrypt-file.o
|
||||
gcc -o spn-encrypt-file ./lib/spn.o spn-encrypt-file.o
|
||||
|
||||
spn-decrypt-file : ./lib/spn.o spn-decrypt-file.o
|
||||
gcc -o spn-decrypt-file ./lib/spn.o spn-decrypt-file.o
|
||||
66
tp/tp2/src/lib/spn.c
Normal file
66
tp/tp2/src/lib/spn.c
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "spn.h"
|
||||
|
||||
void calc_inv_perm(unsigned char perm[8],unsigned char inv_perm[8])
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void calc_inv_subst(unsigned char subst[16],unsigned char inv_subst[16])
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
unsigned char do_perm(unsigned char w,unsigned char perm[8])
|
||||
{
|
||||
unsigned char pw = 0; // permuted byte
|
||||
int i;
|
||||
unsigned char mask = 0x1;
|
||||
unsigned char bit;
|
||||
unsigned char place;
|
||||
|
||||
for(i=0;i<8;i++){
|
||||
bit=w&mask;
|
||||
place=perm[i];
|
||||
pw |= bit<<place;
|
||||
w>>=1;
|
||||
}
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
unsigned char do_subst(unsigned char w,unsigned char subst[16])
|
||||
{
|
||||
unsigned char sw=0;
|
||||
|
||||
// TODO
|
||||
return sw;
|
||||
}
|
||||
|
||||
unsigned char encrypt(
|
||||
unsigned char w,
|
||||
unsigned int key,
|
||||
unsigned char perm[8],
|
||||
unsigned char subst[16])
|
||||
{
|
||||
unsigned char k0=key&0xff;
|
||||
unsigned char k1=(key>>8)&0xff;
|
||||
unsigned char k2=(key>>16)&0xff;
|
||||
|
||||
// TODO
|
||||
|
||||
return w;
|
||||
}
|
||||
unsigned char decrypt(
|
||||
unsigned char w,
|
||||
unsigned int key,
|
||||
unsigned char perm[8],
|
||||
unsigned char subst[16])
|
||||
{
|
||||
unsigned char k0=key&0xff;
|
||||
unsigned char k1=(key>>8)&0xff;
|
||||
unsigned char k2=(key>>16)&0xff;
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
24
tp/tp2/src/lib/spn.h
Normal file
24
tp/tp2/src/lib/spn.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _SPN_H
|
||||
#define _SPN_H
|
||||
|
||||
void calc_inv_perm(unsigned char perm[8],unsigned char inv_perm[8]);
|
||||
void calc_inv_subst(unsigned char subst[16],unsigned char inv_subst[16]);
|
||||
|
||||
unsigned char do_perm(unsigned char w,unsigned char perm[8]);
|
||||
unsigned char do_subst(unsigned char w,unsigned char subst[16]);
|
||||
|
||||
unsigned char encrypt(
|
||||
unsigned char w,
|
||||
unsigned int key,
|
||||
unsigned char perm[8],
|
||||
unsigned char subst[16]
|
||||
);
|
||||
|
||||
unsigned char decrypt(
|
||||
unsigned char w,
|
||||
unsigned int key,
|
||||
unsigned char perm[8],
|
||||
unsigned char subst[16]
|
||||
);
|
||||
|
||||
#endif
|
||||
65
tp/tp2/src/spn-decrypt-file.c
Normal file
65
tp/tp2/src/spn-decrypt-file.c
Normal file
@@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "./lib/spn.h"
|
||||
|
||||
void randomize (unsigned char arr[], int n)
|
||||
{
|
||||
unsigned char tmp;
|
||||
for (int i = n - 1; i > 0; i--)
|
||||
{
|
||||
// Pick a random index from 0 to i
|
||||
int j = rand() % (i + 1);
|
||||
|
||||
// Swap arr[i] with the element
|
||||
// at random index
|
||||
// swap(&arr[i], &arr[j]);
|
||||
tmp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd_in,fd_out;
|
||||
unsigned int key;
|
||||
unsigned char perm[8] = {0,1,2,3,4,5,6,7};
|
||||
unsigned char subst[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
||||
|
||||
unsigned char inv_perm[8];
|
||||
unsigned char inv_subst[16];
|
||||
|
||||
unsigned char buf;
|
||||
|
||||
assert(argc == 4);
|
||||
|
||||
srand(0);
|
||||
|
||||
randomize(perm,8);
|
||||
randomize(subst,16);
|
||||
calc_inv_perm(perm,inv_perm);
|
||||
calc_inv_subst(subst,inv_subst);
|
||||
|
||||
|
||||
|
||||
fd_in = open(argv[1],O_RDONLY);
|
||||
fd_out = open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0600);
|
||||
key = (unsigned int)strtol(argv[3],NULL,0);
|
||||
|
||||
|
||||
while(1){
|
||||
ssize_t nb = read(fd_in, &buf, 1);
|
||||
if (nb <=0)
|
||||
break;
|
||||
buf = decrypt(buf, key, inv_perm, inv_subst);
|
||||
write(fd_out, &buf, 1);
|
||||
}
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
58
tp/tp2/src/spn-encrypt-file.c
Normal file
58
tp/tp2/src/spn-encrypt-file.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "./lib/spn.h"
|
||||
|
||||
void randomize (unsigned char arr[], int n)
|
||||
{
|
||||
unsigned char tmp;
|
||||
for (int i = n - 1; i > 0; i--)
|
||||
{
|
||||
// Pick a random index from 0 to i
|
||||
int j = rand() % (i + 1);
|
||||
|
||||
// Swap arr[i] with the element
|
||||
// at random index
|
||||
// swap(&arr[i], &arr[j]);
|
||||
tmp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd_in,fd_out;
|
||||
unsigned int key;
|
||||
unsigned char perm[8] = {0,1,2,3,4,5,6,7};
|
||||
unsigned char subst[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
||||
unsigned char buf;
|
||||
|
||||
assert(argc == 4);
|
||||
|
||||
srand(0);
|
||||
randomize(perm,8);
|
||||
randomize(subst,16);
|
||||
|
||||
|
||||
fd_in = open(argv[1],O_RDONLY);
|
||||
fd_out = open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0600);
|
||||
|
||||
key = (unsigned int)strtol(argv[3],NULL,0);
|
||||
|
||||
while(1){
|
||||
ssize_t nb = read(fd_in, &buf, 1);
|
||||
if (nb <=0)
|
||||
break;
|
||||
|
||||
buf = encrypt(buf, key, perm, subst);
|
||||
write(fd_out, &buf, 1);
|
||||
}
|
||||
close(fd_in);
|
||||
close(fd_out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
tp/tp3/M1.ps.gz
Normal file
BIN
tp/tp3/M1.ps.gz
Normal file
Binary file not shown.
BIN
tp/tp3/M2.ps.gz
Normal file
BIN
tp/tp3/M2.ps.gz
Normal file
Binary file not shown.
447
tp/tp3/README.md
Normal file
447
tp/tp3/README.md
Normal file
@@ -0,0 +1,447 @@
|
||||
# TP4
|
||||
|
||||
> Dans ce tp, on utilise la boîte à outils **openssl** pour :
|
||||
>
|
||||
> - Chiffrage/déchiffrage (symétriques et à clés publiques).
|
||||
> - Hashage.
|
||||
> - Signature.
|
||||
> - Création/utilisation de certificats.
|
||||
|
||||
### OpenSSL
|
||||
<details><summary>Openssl</summary>
|
||||
<div>
|
||||
Vous pouvez utiliser les fonctionnalités suivantes :
|
||||
|
||||
```bash
|
||||
openssl genrsa -out fichier_rsa.priv size
|
||||
```
|
||||
|
||||
génére la clé privé RSA de taille size. les valeurs possible pour size
|
||||
sont : 512, 1024, etc.
|
||||
|
||||
```bash
|
||||
openssl rsa -in fichier_rsa.priv -des3 -out fichier.pem
|
||||
```
|
||||
|
||||
chiffre la clef privé RSA avec l'algorithme DES3. Vous pouvez utiliser DES, 3DES, IDEA,etc.
|
||||
|
||||
```bash
|
||||
openssl rsa -in fichier_rsa.priv -pubout -out fichier_rsa.pub
|
||||
```
|
||||
|
||||
stocke la partie publique dans un fichier à part (création de de la clé
|
||||
publique associée à la clef privée dans le fichier fichier.pem).
|
||||
|
||||
```bash
|
||||
openssl enc -algo -in claire.txt -out chiffre.enc
|
||||
```
|
||||
|
||||
pour le chiffrement de claire.txt avec l'algorithme spécifié (`openssl enc --help` pour avoir la liste des possibilités ou bien openssl
|
||||
list-cipher-commands) dans un fichier chiffre.enc.
|
||||
|
||||
```bash
|
||||
openssl enc -algo -in chiffre -d -out claire
|
||||
```
|
||||
|
||||
pour le déchiffrement.
|
||||
|
||||
```bash
|
||||
openssl dgst -algo -out sortie entrée
|
||||
```
|
||||
|
||||
pour hacher un fichier. L'option -algo est le choix de l'algorithme de
|
||||
hachage (sha, sha1, dss1, md2,md4, md5, ripemd160).
|
||||
|
||||
```bash
|
||||
openssl rand -out clé.key nombre_bits
|
||||
```
|
||||
|
||||
pour générer un nombre aléatoire de taille nombre_bits (utiliser
|
||||
l'option -base 64 pour la lisibilité).
|
||||
|
||||
```bash
|
||||
openssl aes-256-cbc -in claire.txt -out chiffre.enc -e -k clé.key
|
||||
```
|
||||
|
||||
pour chiffrer un fichier avec l'AES.
|
||||
|
||||
```bash
|
||||
openssl rsautl -encrypt -inkey rsa.pub -in clair.txt -out chiffre.enc
|
||||
```
|
||||
|
||||
chiffrer fichier.txt avec la RSA en utilisant la clef publique rsa.pub.
|
||||
|
||||
```bash
|
||||
openssl rsautl -decrypt -inkey rsa.priv -in chiffre.enc -out fihcier.txt
|
||||
```
|
||||
|
||||
pour déchiffrer le fichier fic.dec.
|
||||
|
||||
```bash
|
||||
openssl rsautl -sign -inkey ras.priv -in fichier.txt -out fic.sig
|
||||
```
|
||||
|
||||
pour générer une signature.
|
||||
|
||||
```bash
|
||||
openssl rsautl -verify -pubin -inkey rsa.pub -in fic.sig
|
||||
```
|
||||
|
||||
pour vérifier une signature.
|
||||
</div>
|
||||
</details>
|
||||
|
||||
### Chiffrage symétrique
|
||||
|
||||
#### Avec mot de passe
|
||||
|
||||
La liste des algorithme de chiffrement symétrique est donnée par la
|
||||
commande
|
||||
|
||||
```bash
|
||||
openssl enc -ciphers
|
||||
```
|
||||
|
||||
Pour chiffrer le fichier toto avec le système Blowfish en mode CBC, avec
|
||||
une clé générée par mot de passe, le chiffré étant stocké dans le
|
||||
fichier toto.chiffre , on utilise la commande :
|
||||
|
||||
openssl enc -bf-cbc -in toto -out toto.chiffre
|
||||
|
||||
Pour déchiffrer le même message, on utilise la commande :
|
||||
|
||||
openssl enc -bf-cbc -d -in toto.chiffre -out toto.dechiffre
|
||||
|
||||
**Exercice 1**
|
||||
|
||||
- Chiffrer et déchiffrer un fichier de votre choix. Vérifier avec la
|
||||
commande `diff`.
|
||||
- Comment expliquer la différence de taille du fichier et du fichier
|
||||
chiffré ?
|
||||
- Que se passe-t-il si le mot de passe est invalide ?
|
||||
- Ajouter l'option `-iter` et `-salt` ? à quoi cela sert-il ?
|
||||
|
||||
**Exercice 2**
|
||||
|
||||
Le cryptogramme [cryptogramme](./cryptogramme) a été chiffré avec AES en
|
||||
mode CBC, la clé de 128 bits ayant été obtenue par mot de passe. Sachant
|
||||
le codage en base 64 du mot de passe est `VHN1bmFtaQo=`, déchiffrez le
|
||||
cryptogramme.
|
||||
|
||||
#### Avec clé explicite (mode CBC)
|
||||
|
||||
Pour chiffrer le fichier toto avec une clé explicite, il faut utiliser
|
||||
les options -K (ou -kfile) et -iv
|
||||
|
||||
- `-K` ( K majuscule) suivi de la clé exprimée en hexadécimal ;
|
||||
- `-iv` ( iv en minuscules) suivi du vecteur d'initialisation exprimé
|
||||
en hexadécimal.
|
||||
|
||||
L'exemple qui suit montre la commande pour chiffrer toto avec Blowfish
|
||||
en mode CBC avec un vecteur d'initialisation de 64 bits, et une clé de
|
||||
128 bits :
|
||||
|
||||
openssl enc -bf-cbc -in toto -out toto.chiffre \
|
||||
-iv 0123456789ABCDEF \
|
||||
-K 0123456789ABCDEF0123456789ABCDEF
|
||||
|
||||
**Exercice 3**
|
||||
|
||||
Générez une clé pour aes-256, ainsi qu'un vecteur d'initialisation
|
||||
(128 bits). Chiffrez et déchiffrez (AES 256 en mode CBC) le fichier
|
||||
clair correspondant au cryptogramme de la question précédente.
|
||||
|
||||
### Chiffrage à clé publique
|
||||
|
||||
On peut générer des clés RSA avec la commande
|
||||
|
||||
openssl genrsa -out keyfile size
|
||||
|
||||
**Exercice 4**
|
||||
|
||||
Générez une clé RSA sur 2048 bits dans le fichier key.pem. Que donne
|
||||
`cat key.pem.`
|
||||
|
||||
openssl rsa -in keyfile -text -noout
|
||||
|
||||
permet de visualiser vos clés
|
||||
|
||||
**Exercice 5**
|
||||
|
||||
- Exportez la partie publique de votre clé dans key.pub. Regardez le
|
||||
fichier.
|
||||
- Chiffrez la clé privée avec idea et un mot de passe. Regardez ce que
|
||||
contient le fichier.
|
||||
|
||||
```bash
|
||||
openssl rsa -in maCle.pem -idea -out maCle.pem
|
||||
```
|
||||
|
||||
- Chiffrez "un petit fichier". Quelle est la taille du fichier
|
||||
chiffré ? Déchiffrez-le.
|
||||
- Que se passe-t-il pour un gros fichier ? pourquoi ?
|
||||
- Chiffrez un message avec l'option `-oaep`, et recommencer, en vérifiant que le chiffré
|
||||
change.
|
||||
|
||||
**Exercice 6**
|
||||
|
||||
Envoyez votre clé publique à un camarade. Celui-ci vous enverra la sienne.
|
||||
Générer un petit fichier texte et envoyez-le à votre voisin chiffré avec
|
||||
sa clef publique. Lui vous enverra un fichier chiffré avec sa clef.
|
||||
Renvoyez-lui le message qu'il vous a envoyé mais en clair.
|
||||
|
||||
**Exercice 7**
|
||||
|
||||
Toujours en binome : A génére une clef AES 256 qu'il chiffre avec la
|
||||
clef publique RSA de B et il lui envoye le chiffré. A partir de là, B
|
||||
récupère la clef (en clair), et il chiffre un gros fichier avec l'AES et
|
||||
la clef AES. Il envoie le gros fichier chiffré à A qui doit le
|
||||
déchiffré.
|
||||
|
||||
### Hachage et mots de passe
|
||||
|
||||
Pour calculer un hachage, utiliez la commande
|
||||
|
||||
openssl dgst -algo -out hash fichier
|
||||
**Exercice 8**
|
||||
|
||||
1. Visitez les possibilités de la commande prime d’OPENSSL.
|
||||
2. Testez la primalité d’un nombre donné : en plus de la réponse, constatez que l'écho de ce nombre
|
||||
a lieu en hexadécimal.
|
||||
3. Testez la primalité d’un nombre passé directement en hexadécimal.
|
||||
4. (facultatif) Ecrivez un petit shell-script UNIX de façon à faire afficher les nombres premiers d'un
|
||||
intervalle donné (utilisez seq ou autre).
|
||||
|
||||
**Exercice 9**
|
||||
|
||||
1. À l'aide de la commande dgst, obtenir dans bash.hash, le hachage du
|
||||
fichier exécutable `/usr/bin/bash`, en choisissant SHA256 (Secure
|
||||
Hash Algorithm) comme algorithme de hashage. Refaire pour obtenir la
|
||||
version binaire du hash dans le fichier executable.hash.bin.
|
||||
Comparer la taille de `/usr/bin/bash`, de executable.hash et de
|
||||
executable.hash.bin. Quelle est la longueur du hash en nombre de
|
||||
bits ? On recommence avec un fichier court oof. Quelle est la
|
||||
longueur du hash en nombre de bits ?
|
||||
2. Changer un seul **bit** dans oof. Comment change le hash ?
|
||||
|
||||
3. On recommence avec MD5 (Digest Message) comme algorithme de hashage.
|
||||
Quelle est la longueur des hashs en nombre de bits.
|
||||
|
||||
4. Récupérez les fichiers [fichier1](./M1.ps.gz) et
|
||||
[fichier2](./M2.ps.gz). Décompressez-les, et regardez leur contenu.
|
||||
5. Calculer leur empreinte MD5 avec `openssl`. Conclusion ?
|
||||
|
||||
6. Même question avec SHA-1 et SHA256.
|
||||
7. S'il s'agit tout simplement de calculer des hashs, on peut utiliser
|
||||
directement certaines commandes, sans passer par openssl. Par
|
||||
exemple les commandes md5sum ou shasum. C'est le cas, par exemple,
|
||||
lorsqu'on télécharge des packages dont on veut vérifier l'intégrité
|
||||
de la copie (à condition bien sûr que le site officiel de l'éditeur
|
||||
du package publie le hash du package).
|
||||
|
||||
**Exercice 10**
|
||||
|
||||
Vous vous retrouvez en possession du hachage MD5 d'un mot de passe que
|
||||
vous voulez casser.
|
||||
|
||||
dde2790ce930e3d425305c36afd4e69c
|
||||
|
||||
Ecrivez un programme force brute qui teste tous les mots d'un
|
||||
dictionnaire. Pour calculer le hachage MD5 d'une chaîne, utilisez la
|
||||
fonction MD5 de openssl (-lcrypto à la compilation)
|
||||
|
||||
```c
|
||||
#include <openssl/md5.h>
|
||||
unsigned char *MD5(const unsigned char *d, unsigned long n,
|
||||
unsigned char *md);
|
||||
```
|
||||
|
||||
Testez avec le dictionnaire [cracklib-small](./cracklib-small.gz)
|
||||
|
||||
**Exercice 11**
|
||||
|
||||
Vous avez réussi à récupérer le fichier `/etc/shadow` d'un serveur avec
|
||||
la ligne suivante
|
||||
|
||||
toto:$6$oAwY6QyT$WALN/YdWiU16lh19DqFHgLYYj77Grn3L88L8vX8IkgXQJyxH1r4L9/2zjY1fdM81Sx/cv821MXfPHbP.nvR2W.:16680:0:99999:7:::
|
||||
|
||||
Retrouvez le mot de passe du compte toto en procédant comme à
|
||||
l'exercice précédent (utliser la fonction `crypt`)
|
||||
|
||||
```c
|
||||
#include <crypt.h>
|
||||
char *crypt(const char *key, const char *salt);
|
||||
```
|
||||
|
||||
### Signature
|
||||
|
||||
Pour signer un "document", on calcule d'abord une empreinte de ce
|
||||
document. La commande **dgst** permet de le faire.
|
||||
|
||||
openssl dgst -algo -out hash fichier
|
||||
|
||||
Signer un document revient à signer son empreinte. Pour cela, on utilise
|
||||
l'option `-sign` de la commande **rsautl**.
|
||||
|
||||
openssl rsautl -sign -in hash -inkey cle -out signature
|
||||
|
||||
et pour vérifier
|
||||
|
||||
openssl rsautl -verify -in signature -pubin -inkey cle -out hash
|
||||
|
||||
**Exercice 12**
|
||||
|
||||
Le fichier [signatures.tar.gz](./signatures.tar.gz) contient deux
|
||||
fichiers accompagnés d'une signature, ainsi que la clé publique de la
|
||||
clé RSA ayant produit la signature. De ces deux fichiers, lequels a bien
|
||||
été signé.
|
||||
|
||||
**Exercice 13**
|
||||
|
||||
Reprenez le binôme de la partie RSA. Envoyez à votre binôme le fichier
|
||||
/etc/passwd et une signature, qui la vérifiera.
|
||||
|
||||
### Certificats
|
||||
|
||||
#### Création d'une autorité de certification (permettant de signer les demandes de certificats)
|
||||
|
||||
Vous allez jouer le role d'une autorité de certification.
|
||||
|
||||
Par défaut, OpenSSL utilise le fichier de configuration
|
||||
|
||||
```
|
||||
/etc/ssl/openssl.cnf
|
||||
```
|
||||
|
||||
pour la génération des certificats. Pour utiliser un fichier de
|
||||
configuration personnalisé, il suffit d'ajouter l'argument "-config
|
||||
{fichier_de_configuration_personnalisé}" à la commande openssl.
|
||||
Avant de pouvoir générer un certificat , il faut obligatoirement générer
|
||||
une clé RSA ou DSA. Générez une clé RSA `mykey.pem` pour l'autorité de
|
||||
certification chiffrée avec idea.
|
||||
|
||||
Pour générer ses propres certificats, sans passer par une autorité de
|
||||
certification externe :
|
||||
|
||||
openssl req -new -x509 -key mykey.pem -out ca.crt -days 1095
|
||||
|
||||
On indique pour le paramètre `-out` le nom de l'autorité de
|
||||
certification à générer puis la durée de validité en jour avec le
|
||||
paramètre `-days` Cette autorité de certification permettra de signer
|
||||
les futures demandes de certificats auto-signés. Cette génération est à
|
||||
faire une seule fois. Le Common Name à indiquer ne doit correspondre à
|
||||
aucun nom de domaine ayant besoin d'un certificat. Cette autorité de
|
||||
certification peut-être mis à disposition du public afin d'être intégré
|
||||
dans les différents navigateurs comme étant une autorité de
|
||||
certification reconnue.
|
||||
|
||||
#### Création d'une requête de certificat
|
||||
|
||||
Vous allez jouer le role de quelqu'un qui veut obtenir un certificat
|
||||
pour sa clé RSA. Générez une clé RSA dans mykey.pem.
|
||||
|
||||
**Exercice 14**
|
||||
|
||||
Générez une requête de demande de certificat pour votre clé.
|
||||
|
||||
openssl req -new -key maCle.pem -out maRequete.pem
|
||||
|
||||
Consulez cette requête avec
|
||||
|
||||
openssl req -in maRequete.pem -text -noout
|
||||
|
||||
**Exercice 15**
|
||||
|
||||
Expliquez les différents éléments contenus dans cette requête. La clé
|
||||
privée du sujet y figure-t-elle ?
|
||||
|
||||
#### Génération du certificat final
|
||||
|
||||
**Exercice 16**
|
||||
|
||||
A l'aide de la requête de certificat, générez un certificat pour votre
|
||||
clé publique. Vous jouez donc le role ici de l'authorité de
|
||||
certification.
|
||||
|
||||
openssl x509 -req -in maRequete.pem -out moncertif.pem -CA ca.crt -CAkey mykey.pem -CAcreateserial -CAserial ca.srl -days 90
|
||||
|
||||
Affichez ce que contient le certificat.
|
||||
|
||||
L'option `-CAcreateserial` est à utiliser seulement la première fois.
|
||||
Ceci va générer un identifiant (ca.srl). Lors des prochaines
|
||||
certification (pour renouvellement ou pour d'autres domaines)
|
||||
l'identifiant, contenu dans le fichier ca.srl, sera incrémenté à
|
||||
l'aide de l'option -CAserial ca.srl
|
||||
|
||||
Pour vérifier la validité d'un certificat, on peut utiliser la commande
|
||||
verify :
|
||||
|
||||
openssl verify -CAfile ca.crt moncertif.pem
|
||||
|
||||
**Exercice 17**
|
||||
|
||||
Vérifier le certificat généré.
|
||||
|
||||
#### ncat avec SSL/TLS
|
||||
|
||||
On va utiliser ncat qui supporte SSL/TLS.
|
||||
|
||||
1. Avec tcp, échangez un fichier entre un client et un serveur ncat.
|
||||
Vérifier avec tcpdump que le fichier passe **en clair** !.
|
||||
2. Refaire la question précédente en utilisant SSL/TLS.
|
||||
- Le serveur a maintenant besoin du certificat, et de la clé privé
|
||||
correspondante (option `--ssl-cert` et `--ssl-key`)
|
||||
- Le client doit aussi se connecter avec l'option `--ssl`.
|
||||
- Le contenu du "fichier" échangé passe-t-il encore "en clair"
|
||||
?
|
||||
|
||||
3. Que se passe-t-il coté client si vous rajoutez l'option
|
||||
`--ssl-verify` ?
|
||||
|
||||
ncat --ssl-verify --ssl localhost port
|
||||
|
||||
4. Avec l'option `--ssl-trustfile`, dites à ncat de faire confiance à
|
||||
l'autorité de certification qui a signé le certificat du serveur.
|
||||
5. Connectez-vous au serveur ncat en utilisant votre browser. Pour
|
||||
cela, faites un fichier `rep.http` qui contient une réponse http qui
|
||||
sera renvoyée au navigateur. Par exemple
|
||||
|
||||
```html
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>TP</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TEST</h1>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Le serveur renvoie systématiquement la même réponse :
|
||||
|
||||
ncat -l 8080 < rep.http
|
||||
|
||||
Vérifiez depuis votre navigateur.
|
||||
|
||||
6. On veut cette fois-ci se connecter à notre serveur ncat en https. On
|
||||
utilise localhost comme nom.
|
||||
7. Testez depuis votre navigateur. Que se passe-t-il ? Dites au
|
||||
navigateur que vous faites confiance à l'autorité qui a signé le
|
||||
certificat du serveur (comment ?)
|
||||
8. Malgré tout, cela ne suffit pas. Le navigateur devrait vous réclamer
|
||||
l'extension `subject Alternative Names` qui permet d'associer
|
||||
emails, ip, noms, etc. En l'occurence, il faut associer le nom
|
||||
localhost au certificat.
|
||||
|
||||
En tant qu'autorité de certification, recréez le certificat du
|
||||
serveur en ajoutant localhost comme nom associé au certificat.
|
||||
|
||||
openssl x509 -req -in maRequete.pem -out moncertif.pem -CA ca.crt -CAkey mykey.pem -CAcreateserial -CAserial ca.srl -days 90 -extfile x509.cnf
|
||||
|
||||
le fichier x509.cnf
|
||||
|
||||
subjectAltName = DNS:localhost
|
||||
|
||||
Retestez.
|
||||
BIN
tp/tp3/cracklib-small.gz
Normal file
BIN
tp/tp3/cracklib-small.gz
Normal file
Binary file not shown.
BIN
tp/tp3/cryptogramme
Normal file
BIN
tp/tp3/cryptogramme
Normal file
Binary file not shown.
BIN
tp/tp3/signatures.tar.gz
Normal file
BIN
tp/tp3/signatures.tar.gz
Normal file
Binary file not shown.
Reference in New Issue
Block a user