Cryptopals 4 - Detect single-character XOR


Challenge 4 in Cryptopals.

There are two things I appreciate a lot about Cryptopals:

  • it provides a path, usually building upon the previous step(s) to assemble/discover something new and more powerful;
  • it tells you what to do but not necessarily how. There’s a lot of places around for the how and it’s interesting to try and find a how by ourselves, right?

In this challenge, the suggestion is to use the single_char_decrypt function from the previous one, and build a higher level artificial intelligence to sift through several candidate ciphertext and spot the one that’s been encoded with that basic technique.

I thought of the simplest way of doing it: collect both the decrypted text and the score, then get the best among all that have a non-0 score. To this regard, the fact that single_char_decrypt from last post provides us the score too (when called in list context) helps a lot 😅. Again, it’s been migrated in the Cryptopals helper module to avoid cluttering today’s code.

#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
use English '-no_match_vars';
use CryptoPals qw< decode_base16 single_char_decrypt >;

# keep track of best solution and associated best score, to get the best
my ($best, $best_score);

open my $fh, '<:raw', '4.txt' or die "open('4.txt'): $OS_ERROR\n";
while (<$fh>) {
   s{\s+}{}gmxs; # spaces don't belong to the hex encoding

   # try to decrypt this candidate line, collect score on the way
   my ($candidate, $score) = single_char_decrypt(decode_base16($_));
   next unless $score; # no reason to look for non-0 scores

   # usual incantation to select the best by comparison
   ($best, $best_score) = ($candidate, $score)
      if ! $best_score || $best_score < $score;

say "Best found: <$best>";

The code pretty much explains itself and… works!

Stay safe and secure!

Comments? Octodon, Twitter, GitHub, Reddit, or drop me a line!