tp1
This commit is contained in:
parent
849f17f570
commit
2ba0a03f03
11
README.md
11
README.md
@ -1,3 +1,12 @@
|
||||
# BUT2FI_R4.B.10
|
||||
|
||||
Cryptographie - Outils et algorithmes
|
||||
Cryptographie - Outils et algorithmes
|
||||
|
||||
[Cours crypto](cours/crypto.pdf)
|
||||
|
||||
#### Semaine 1
|
||||
- cm : [Chiffrements par bloc, algorithmes à clefs symétriques](cours/crypto.pdf).
|
||||
- tp : [lfsr, tea, hachages](td_tp/tp1)
|
||||
|
||||
|
||||
|
||||
|
193
td_tp/tp1/README.md
Normal file
193
td_tp/tp1/README.md
Normal file
@ -0,0 +1,193 @@
|
||||
# TP1
|
||||
- Registre à décalage à rétroaction linéaire (lfsr),
|
||||
- Chiffrement par bloc symmétrique (TEA), fonction de hachage.
|
||||
|
||||
## EX1
|
||||
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/ex1/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`.
|
||||
|
||||
## Ex2
|
||||
|
||||
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). TEA 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.
|
||||
|
||||
### Ex3: 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
td_tp/tp1/aide.md
Normal file
41
td_tp/tp1/aide.md
Normal 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
td_tp/tp1/img/TEA.png
Normal file
BIN
td_tp/tp1/img/TEA.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 26 KiB |
BIN
td_tp/tp1/img/feistel.png
Normal file
BIN
td_tp/tp1/img/feistel.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 63 KiB |
1263
td_tp/tp1/img/feistel.svg
Normal file
1263
td_tp/tp1/img/feistel.svg
Normal file
File diff suppressed because one or more lines are too long
After (image error) Size: 80 KiB |
BIN
td_tp/tp1/img/xtea.png
Normal file
BIN
td_tp/tp1/img/xtea.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 4.8 KiB |
BIN
td_tp/tp1/src/ex1/file.crypt
Normal file
BIN
td_tp/tp1/src/ex1/file.crypt
Normal file
Binary file not shown.
42
td_tp/tp1/src/ex1/lfsr.c
Normal file
42
td_tp/tp1/src/ex1/lfsr.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define MASK_BIT_7 0x80
|
||||
#define MASK_BIT_6 0x40
|
||||
#define MASK_BIT_5 0x20
|
||||
#define MASK_BIT_4 0x10
|
||||
#define MASK_BIT_3 0x08
|
||||
#define MASK_BIT_2 0x04
|
||||
#define MASK_BIT_1 0x02
|
||||
#define MASK_BIT_0 0x01
|
||||
|
||||
|
||||
unsigned char next(unsigned char lfsr)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fd_in,fd_out;
|
||||
unsigned char w,buf;;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
while(1){
|
||||
ssize_t nb = read(fd_in,&buf,1);
|
||||
if (nb <=0)
|
||||
break;
|
||||
buf ^= w;
|
||||
write(fd_out,&buf,1);
|
||||
w=next(w);
|
||||
}
|
||||
return 0;
|
||||
}
|
1
td_tp/tp1/src/ex2/key1.k
Normal file
1
td_tp/tp1/src/ex2/key1.k
Normal file
@ -0,0 +1 @@
|
||||
÷Nà{q2‘*:¬¨œÇmfU#©`í±Å?&Q3
|
11
td_tp/tp1/src/ex2/xtea.c
Normal file
11
td_tp/tp1/src/ex2/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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user