Write-Up Crypto 100 - Easy One
Dans un premier temps on analyse le code du programme de chiffrement.
#include
#include
#include
int main(int argc, char **argv) {
if (argc != 3) {
printf("USAGE: %s INPUT OUTPUT\n", argv[0]);
return 0;
}
FILE* input = fopen(argv[1], "rb");
FILE* output = fopen(argv[2], "wb");
if (!input || !output) {
printf("Error\n");
return 0;
}
char k[] = "CENSORED";
char c, p, t = 0;
int i = 0;
while ((p = fgetc(input)) != EOF) {
c = (p + (k[i % strlen(k)] ^ t) + i*i) & 0xff;
t = p;
i++;
fputc(c, output);
}
return 0;
}
Le ET logique avec 0xFF ne changeant rien au résultat, on peut simplifier. La fonction de chiffrement devient
c = p + (k[i % strlen(k)] ^ t) + i*i
ou i vaut initialement 0 et est incrémenté à chaque tour, c->cipher et p->plain.
Disposant d'un message en clair, du chiffre correspondant et de la méthode de chiffrement on peut retrouver la clé. On crée donc un petit programme pour cela:
#include
#include
#include
#define LEN 40
int main(int argc, char **argv) {
if (argc != 4) {
printf("USAGE: %s CRYPT PLAIN OUTPUT\n", argv[0]);
return 0;
}
// char k[] = "CENSORED";
char k[LEN];
char c, p, t = 0;
int i = 0, n = 0;
char r;
FILE* input = fopen(argv[1], "rb");
FILE* plain = fopen(argv[2], "rb");
FILE* output = fopen(argv[3], "wb");
if (!input) {
printf("Error opening Cypher input\n");
return 0;
}
if (!output) {
printf("Error opening Output\n");
return 0;
}
if (!plain) {
printf("Error opening Plain input\n");
return 0;
}
while ( ( (c = fgetc(input)) != EOF) ) {
p =fgetc(plain);
r = c - (i*i);
r = r - p;
r = r^t;
t = p;
if (i < LEN)
k[i] =r;
i++;
}
fputc('\n', output);
fprintf(output, "key= ");
for (n=0; n<LEN; n++) {
fputc(k[n], output);
}
fputc('\n', output);
fputc('\n', output);
fclose(input);
fclose(plain);
fclose(output);
return 0;
}
On obtient:
key=VeryLongK
Mais la clé n'est pas complète. Le caractère suivant du chiffre est un 0xFF qui est interprété comme une fin de fichier et provoque l'arrêt du programme.
On remplace par 0xFE et on relance:
key=VeryLongKdyYouWillNeverGuess
On en déduit la clé: VeryLongKeyYouWillNeverGuess
Maintenant que l'on dispose de la clé ayant servie à chiffrer les messages, nous pouvons déchiffrer le second message en inversant la fonction de chiffrement. On crée pour cela un second programme:
#include
#include
#include
int main(int argc, char **argv) {
if (argc != 3) {
printf("USAGE: %s CYPHER PLAIN\n", argv[0]);
return 0;
}
FILE* input = fopen(argv[1], "rb");
FILE* output = fopen(argv[2], "wb");
if (!input || !output) {
printf("Error\n");
return 0;
}
char k[] = "VeryLongKeyYouWillNeverGuess";
char c, p, t = 0;
int i = 0;
while ((c = fgetc(input)) != EOF) {
p = c - i*i;
p = p - (k[i % strlen(k)] ^ t);
t = p;
i++;
fputc(p, output);
}
return 0;
}
Ce qui nous donne au final:
The known-plaintext attack (KPA) is an attack model for cryptanalysis where the attacker has samples of both the plaintext (called a crib), and its encrypted version (ciphertext). These can be used to reveal further secret information such as secret keys and code books. The term "crib" originated at Bletchley Park, the British World War II decryption operation.
The flag is CTF{6d5eba48508efb13dc87220879306619}
|