Published on in Development

# Implementing Base64 Encoding in Haskell

Last week, we looked at the definition of Base64. Today we’ll try to implement two functions - encode64 and decode64 - in Haskell. Since we are working with binary data, we are using the bytestring library to represent the decoded data. In the end, we want our functions to be encapsulated in a module to make the functions easy to re-use later on.

1
2
3
4
5
6
7
8
9
10
module Base64 (encode64, decode64) where

import           Data.ByteString

encode64 :: ByteString -> String
encode64 data = undefined

-- Decoding can fail for invalid inputs.
decode64 :: String -> Maybe ByteString
decode64 data = undefined


Focusing on encode64 first, our alphabet is a good point to get started. We can define this in terms of another function (private to our module).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
alphabet :: [Char]
alphabet = [ 'A', 'B', 'C', 'D' -- 000000 to 000011
, 'E', 'F', 'G', 'H' -- 000100 to 000111
, 'I', 'J', 'K', 'L' -- 001000 to 001011
, 'M', 'N', 'O', 'P' -- 001100 to 001111
, 'Q', 'R', 'S', 'T' -- 010000 to 010011
, 'U', 'V', 'W', 'X' -- 010100 to 010111
, 'Y', 'Z', 'a', 'b' -- 011000 to 011011
, 'c', 'd', 'e', 'f' -- 011100 to 011111
, 'g', 'h', 'i', 'j' -- 100000 to 100011
, 'k', 'l', 'm', 'n' -- 100100 to 100111
, 'o', 'p', 'q', 'r' -- 101000 to 101011
, 's', 't', 'u', 'v' -- 101100 to 101111
, 'w', 'x', 'y', 'z' -- 110000 to 110011
, '0', '1', '2', '3' -- 110100 to 110111
, '4', '5', '6', '7' -- 111000 to 111011
, '8', '9', '+', '/' -- 111100 to 111111
]


Note, that you have to enable the language extension BinaryLiterals to support binary literals such as 0b110100. We also need the padding character, which can define as another private function. You can think of the alphabet and the paddingCharacter functions as constants.

1