Compare commits

...

13 Commits

Author SHA1 Message Date
7ba5098daa td3 2026-03-19 15:12:58 +01:00
c2c8b09dcf oups 2026-03-16 10:24:12 +01:00
126e99113f ajout tp2 2026-03-16 08:23:15 +01:00
5f84465e1f td2 2026-03-13 08:33:57 +01:00
c8287319b5 avec tux 2026-03-09 10:50:16 +01:00
e41e39e1c3 oups 2026-03-09 10:46:48 +01:00
8c44c653b5 ajout exo 2026-03-09 08:59:23 +01:00
bda797f631 ajout exo 2026-03-09 08:58:09 +01:00
b9aa998ba7 ajout exo 2026-03-09 08:56:20 +01:00
1fea0c18cf typo 2026-03-04 10:54:27 +01:00
5e03240950 typo 2026-03-04 10:52:51 +01:00
8099da0770 tp1 2026-03-04 10:50:42 +01:00
79c0839aa1 tp1 2026-03-02 18:34:04 +01:00
23 changed files with 1891 additions and 2 deletions

View File

@@ -5,8 +5,12 @@ Cryptographie - Outils et algorithmes
[Cours crypto](cours/crypto.pdf) [Cours crypto](cours/crypto.pdf)
#### Semaine 1 #### 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) - 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)

BIN
cours/crypto_new.pdf Normal file

Binary file not shown.

BIN
td/td2.pdf Normal file

Binary file not shown.

BIN
td/td3.pdf Normal file

Binary file not shown.

207
tp/tp1/README.md Normal file
View File

@@ -0,0 +1,207 @@
# TP1
## Ex1
Lobjectif de cet exercice est de chiffrer une image en ligne de commande à
laide des outils fournis par la librairie openssl.
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 à laide de la commande
`convert`.
2. Avec la commande `head`, mettez les 3 premières lignes de votre fichier ppm dans un fichier
header.txt.
3. Avec la commande tail mettez tout le fichier ppm sauf les 3 premières lignes dans un fichier
body.bin.
4. Chiffrez avec openssl en AES-ECB le fichier body.bin.
5. Remettez len-tête header.txt au début du fichier obtenu à la question précédente pour avoir
une image chiffrée, et observez le résultat.
## EX2
Le but est d'implanter un registre à décalage linéaire, sur un octet.
À chaque étape, le registre (un octet) $(b_7,b_6,b_5,b_4,b_3,b_2,b_1,b_0)$ est décalé à gauche, et
le bit $b_0$ est remplacé par un bit, calculé par une fonction linéaire $f$.
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 $$
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.

41
tp/tp1/aide.md Normal file
View File

@@ -0,0 +1,41 @@
### Setting a bit
Use the bitwise OR operator (|) to set a bit.
`number |= 1 << x;`
That will set bit x.
### Clearing a bit
Use the bitwise AND operator (&) to clear a bit.
`number &= ~(1 << x);`
That will clear bit x. You must invert the bit string with the bitwise NOT operator (~), then AND it.
### Toggling a bit
The XOR operator (^) can be used to toggle a bit.
`number ^= 1 << x;`
That will toggle bit x.
### Checking a bit
You didn't ask for this but I might as well add it.
To check a bit, shift the number x to the right, then bitwise AND it:
`bit = (number >> x) & 1;`
That will put the value of bit x into the variable bit.
### Changing the nth bit to x
Setting the nth bit to either 1 or 0 can be achieved with the following:
`number ^= (-x ^ number) & (1 << n);`
Bit n will be set if x is 1, and cleared if x is 0.

BIN
tp/tp1/img/TEA.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
tp/tp1/img/feistel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

1263
tp/tp1/img/feistel.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 80 KiB

BIN
tp/tp1/img/xtea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
tp/tp1/src/ex2/file.crypt Normal file

Binary file not shown.

37
tp/tp1/src/ex2/lfsr.c Normal file
View File

@@ -0,0 +1,37 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
unsigned char next(
unsigned char lfsr, // le registre
unsigned char retroaction_f // les bits selectionnés par la
) // fonction de retroaction
{
// TODO
}
int main(int argc, char *argv[])
{
int fd_in,fd_out;
unsigned char w,buf,f;
assert(argc >= 4);
fd_in = open(argv[1],O_RDONLY);
fd_out = open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0600);
w = (unsigned char)strtol(argv[3],NULL,0);
f = ; // TODO
while(1){
ssize_t nb = read(fd_in,&buf,1);
if (nb <=0)
break;
// TODO
}
return 0;
}

Binary file not shown.

1
tp/tp1/src/ex3/key1.k Normal file
View File

@@ -0,0 +1 @@
÷Nà {q2*:¬¨œÇmfU#© `í±Å?&Q3

11
tp/tp1/src/ex3/xtea.c Normal file
View 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
View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

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
View 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
View 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
View 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

View 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;
}

View 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;
}