Cryptopals 1 - Convert hex to base64

TL;DR

Challenge 1 in Cryptopals.

The Challenge 1 in Cryptopals makes it clear how similar it is to The Weekly Challenge: use whatever programming language you want, and be the only real judge of whether you made it or not.

So there’s no cheating, unless you’re OK with cheating with yourself. Why do that in the first place then?!?

This allows us to pick our battles, though.

As an example, the first challenge is about transforming a hex-encoded text string into a Base64-encoded text string. Should we take it literally and implement the encoding ourselves? Is it fair to use a library provided by the language of choice, and to what extent?

Well, unless explicitly told so, or unless I think it’s instructive, I’ll allow for using libraries. Which comes handy in this case, because we already saw Base64 in Perl.

There is, of course, the issue of decoding the hex data. This can be done thanks to the venerable pack function, although it requires us to make a choice - or better a guess - about whether we think that the low nybble appears first (code h) or the high nybble appears first (code H). It turns out that uppercase H is needed to go ahead and make that happen.

TIL that nybble is the same as nibble, it seems.

It can be useful to encapsulate this pack and the reverse with unpack into their own aptly named functions:

sub decode_base16 ($base16) {
   die "invalid input hex string\n"
      if $base16 !~ m{\A [a-fA-F0-9]* \z}mxs || length($base16) % 2;
   return pack 'H*', $base16;
}

sub encode_base16 ($data) { return unpack 'H*', $data }

Back to the challenge, the solution can be expressed like this:

#!/usr/bin/env perl
use v5.24;
use warnings;
use experimental 'signatures';
no warnings 'experimental::signatures';
use MIME::Base64 'encode_base64';

my $input =  '49276d206b696c6c696e6720796f757220627261696e206c'
           . '696b65206120706f69736f6e6f7573206d757368726f6f6d';
say encode_base64(decode_base16($input), '');

sub decode_base16 ($base16) {
   die "invalid input hex string\n"
      if $base16 !~ m{\A [a-fA-F0-9]* \z}mxs || length($base16) % 2;
   return pack 'H*', $base16;
}

It works, apparently:

$ perl ch01.pl 
SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t

$ perl ch01.pl | base64 -d
I'm killing your brain like a poisonous mushroom

Stay safe and secure!


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