goto_top

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}