# Convert hex to base64 (Cryptopals challenge 1)

I've been spending some time learning Rust and I came across the Cryptopals Challenges. This is my implementation of challenge 1

Convert hex to base64 The string:

49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d


Should produce:

SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t


So go ahead and make that happen. You'll need to use this code for the rest of the exercises.

Cryptopals Rule: Always operate on raw bytes, never on encoded strings. Only use hex and base64 for pretty-printing.

I did go ahead and pull in a crate for handling base64 encoding. It didn't seem important to implement that myself.

mod basics {
extern crate base64;
use self::base64::encode;

pub fn hex_to_base64(hex: &str) -> String {
encode(&hex_to_bytes(hex))
}

pub fn hex_to_bytes(hex: &str) -> Vec<u8> {
hex.chars()
.collect::<Vec<_>>() //convert to slice-able
.chunks(2)           //each char is one nibble
.map(|byte| byte.iter().collect::<String>())
.map(|byte| u8::from_str_radix(&byte[..], 16).unwrap())
.collect()
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn can_convert_hex_to_base64() {
let hex_as_string =
"49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
let base64_as_string =
"SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";

assert_eq!(hex_to_base64(hex_as_string), base64_as_string);
}

#[test]
fn ff_byte_hex_string_to_byte_vector() {
let hex = "FF";
assert_eq!(vec![0xFF], hex_to_bytes(hex));
}

#[test]
fn single_byte_hex_string_to_byte_vector() {
let hex = "2A";
assert_eq!(vec![0x2A], hex_to_bytes(hex));
}

#[test]
fn multibyte_hex_string_to_byte_vector() {
let hex = "2ABE";
assert_eq!(vec![0x2A, 0xBE], hex_to_bytes(hex));
}
}
}

• Related: Hex string to Base64 Sep 15, 2018 at 23:53
• Yeah. I’ve seen that @Shepmaster. Makes me think I might go back and implement base64 at some point in the future. Sep 15, 2018 at 23:58

## 1 Answer

pub fn hex_to_base64(hex: &str) -> String {
encode(&hex_to_bytes(hex))


I would not use self::base64::encode and instead refer to base64::encode here so that it is clearer what is being encoded.

}

pub fn hex_to_bytes(hex: &str) -> Vec<u8> {
hex.chars()
.collect::<Vec<_>>() //convert to slice-able


Given that you are doing hex, which is all in the ASCII range, you may want to use as_bytes() which will give you a slice of bytes without copying the whole string into a new Vec.

        .chunks(2)           //each char is one nibble


What happens if the string length isn't a multiple of two?

        .map(|byte| byte.iter().collect::<String>())


byte isn't correct here as it is a slice of chars. Further, if you don't use chars() as I suggest as above, you can use std::str::from_utf8 to get a &str without allocating a new String.

        .map(|byte| u8::from_str_radix(&byte[..], 16).unwrap())


byte really isn't correct here as you have a String. Additionally, there is no need to take a slice.

        .collect()
}

• It took some doing, but I did end up with something I feel is a little bit better. Thanks! hex.as_bytes().chunks(2).map(|nibbles| str::from_utf8(&nibbles).unwrap()).map(|s| u8::from_str_radix(&s, 16)).collect::<Vec<u8>>() Sep 25, 2018 at 0:08