snippetcMinor
Matasano Cryptopals Challenge 1: convert hex to base64
Viewed 0 times
matasanochallengeconvertcryptopalshexbase64
Problem
Cryptopals challenge 1
Using binary strings to convert from hex to binary felt kinda hacky. I'd like to hear if there are better ways to do that.
I used
EDIT: follow up question
```
#include
#include
char hex_2_base64(char _hex)
{
char *hex_2_bin[16] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
char *dec_2_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//allocating memory for binary string
int bin_size = strlen(_hex) * 4;
while (bin_size % 6 != 0) //add space for zero padding
bin_size += 8;
char *bin = malloc(bin_size + 1);
memset(bin, 0, bin_size + 1);
//these are for strtol, its arguments need the zero terminator
char buf[2] = { 0 };
char b64buf[6 + 1] = { 0 };
//converting hex input to binary
char *bin_end = bin;
for (int i = 0; i < strlen(_hex); i++)
{
buf[0] = _hex[i];
memcpy(bin_end, hex_2_bin[strtol(buf, NULL, 16)], 4);
bin_end += 4;
}
//pad binary string w/ zeroes
while (strlen(bin) < bin_size)
strcat(bin, "00000000");
//allocating memory for b64 output
int b64size = (strlen(bin) / 6) + 1;
char *out = malloc(b64size);
memset(out, 0, b64size);
//walk through binary string, converting chunks of 6 bytes into base64 chars
char *bin_ptr = bin;
char *out_end = out;
int index_b64;
while (*bin_ptr)
{
strncpy(b64buf, bin_ptr, 6);
index_b64 = strtol(b64buf, NULL, 2);
if (index_b64 == 0)
buf[0] = '=';
else
buf[0] = dec_2_base64[index_b64];
memcpy(out_end, buf, 1);
out_end += 1;
bin_ptr += 6;
}
free(bin);
return out;
}
int main(void) {
char *out = NULL;
out = hex_2_base64("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d");
assert(strcmp(out, "SSdtIGtpbG
Using binary strings to convert from hex to binary felt kinda hacky. I'd like to hear if there are better ways to do that.
I used
memcpy() and pointer to the end of the string instead of strcat() to avoid the Shlemiel the Painter problem.EDIT: follow up question
```
#include
#include
char hex_2_base64(char _hex)
{
char *hex_2_bin[16] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
char *dec_2_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//allocating memory for binary string
int bin_size = strlen(_hex) * 4;
while (bin_size % 6 != 0) //add space for zero padding
bin_size += 8;
char *bin = malloc(bin_size + 1);
memset(bin, 0, bin_size + 1);
//these are for strtol, its arguments need the zero terminator
char buf[2] = { 0 };
char b64buf[6 + 1] = { 0 };
//converting hex input to binary
char *bin_end = bin;
for (int i = 0; i < strlen(_hex); i++)
{
buf[0] = _hex[i];
memcpy(bin_end, hex_2_bin[strtol(buf, NULL, 16)], 4);
bin_end += 4;
}
//pad binary string w/ zeroes
while (strlen(bin) < bin_size)
strcat(bin, "00000000");
//allocating memory for b64 output
int b64size = (strlen(bin) / 6) + 1;
char *out = malloc(b64size);
memset(out, 0, b64size);
//walk through binary string, converting chunks of 6 bytes into base64 chars
char *bin_ptr = bin;
char *out_end = out;
int index_b64;
while (*bin_ptr)
{
strncpy(b64buf, bin_ptr, 6);
index_b64 = strtol(b64buf, NULL, 2);
if (index_b64 == 0)
buf[0] = '=';
else
buf[0] = dec_2_base64[index_b64];
memcpy(out_end, buf, 1);
out_end += 1;
bin_ptr += 6;
}
free(bin);
return out;
}
int main(void) {
char *out = NULL;
out = hex_2_base64("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d");
assert(strcmp(out, "SSdtIGtpbG
Solution
Base 16 -> Base 2 -> Base 64: Cut out the middleman
You are currently converting each hex digit to 4 binary digits, then converting 6 binary digits into one Base64 digit. Instead of doing two conversions, how about if you took each three hex digits (= 12 binary digits) and converted that into two Base64 digits? You can do this up until the end of your hex string, where you might have 1 or 2 leftover hex digits. You can handle those leftover digits by padding with extra zero bits and outputting extra Base64 digits, including the special
Bug
Your code doesn't convert zeros correctly. The problem is here:
As you can see, you output
You are currently converting each hex digit to 4 binary digits, then converting 6 binary digits into one Base64 digit. Instead of doing two conversions, how about if you took each three hex digits (= 12 binary digits) and converted that into two Base64 digits? You can do this up until the end of your hex string, where you might have 1 or 2 leftover hex digits. You can handle those leftover digits by padding with extra zero bits and outputting extra Base64 digits, including the special
'=' digit.Bug
Your code doesn't convert zeros correctly. The problem is here:
if (index_b64 == 0)
buf[0] = '=';
else
buf[0] = dec_2_base64[index_b64];As you can see, you output
'=' for each Base64 zero digit. However, the correct digit to output is 'A'. The special '=' digit is only used to indicate zero bits for padding. Therefore, if I try to convert the hex string "0000", your program returns "====" when the correct answer is "AAA=".Code Snippets
if (index_b64 == 0)
buf[0] = '=';
else
buf[0] = dec_2_base64[index_b64];Context
StackExchange Code Review Q#143361, answer score: 4
Revisions (0)
No revisions yet.