Home Creating a base64 encoder/decoder with Python - Part 2
Post
Cancel

Creating a base64 encoder/decoder with Python - Part 2

Hello friend,

In this post, we are going to continue from where we left off, please check the first part if you haven’t.

In the previous post, we built a base64 encoder. Now we are going to be building a decoder, working our way backwards.

Creating the decoder

Theory

Here is how it is going to work :

Implementation

Here is the complete function, respecting the steps above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def b64_decode(word):

    #stripping away '='
    word = word.split("=")[0]

    #finding the index of each character in b64_index_table
    indexes = []
    for c in word:
        indexes.append(base64_symbol_table.index(c))

    # index to binary ( 6 bits)
    binary = []
    for i in indexes:
        binary.append(bin(i).split("b")[-1].rjust(6,'0'))

    # groupping the bits together
    binary = "".join(binary) # this is a string


    # forming group of 8 bits
    new_word = []
    while len(binary):
        new_word.append(binary[0:8])
        binary = binary[8:]

    # transform each byte to its ascii representation
    result = ""
    for c in new_word:
        result += chr(bin_to_int(c)) #you can use int(c,2)
        # instead of bin_to_int(c)
    return result
1
2
word = "SGk="
print(b64_decode(word))
1
2
Program stdout
Hi

Adding a main function

All working as expected, now let’s add a main function to hundle user input.

Here is the expected behaviour:

1
2
python b64.py
[/_\] Usage : python b64.py <string> (-d | -e )
1
2
3
4
5
python b64.py Hi -e
[+] Hi ---> SGk=

python b64.py SGk= -d
[+] SGk= ---> Hi

You can have fun implementing your own functionalities, here is a simple one using the sys module.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if __name__ == '__main__':
    
    len_args = len(sys.argv)
    if (len_args != 3):
        print(f"[] Usage : python {sys.argv[0]} <string> (-d | -e )")
        exit(0)
    option = sys.argv[2]
    if not (option == '-d' or option == '-e'):
        print(f"[] Usage : python {sys.argv[0]} <string> (-d | -e )")
        exit(0)

    word = sys.argv[1]
    if (option == '-d'):
        print(f"[+] {word} ---> {b64_decode(word)}")
    else:
        print(f"[+] {word} ---> {b64_encode(word)}")

Wrapping up

Putting all of it together, we get something like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import sys

# creating base64 table index
A_Z = [chr(i) for i in range(65,91)]
a_z = [chr(i) for i in range(97,123)]
zero_nine = [chr(i) for i in range(48,58)]
additional_chars = ['+','/']
base64_symbol_table = A_Z + a_z + zero_nine + additional_chars

# binary to decimal custom function
def bin_to_int(byte):
        #110101
        result = 0
        k = 1
        for i in range(0,len(byte)):
            result += int(byte[len(byte) - 1 - i]) * k
            k = k * 2
        return result

def b64_encode(word):

    # converting the word into its binary format
    binary = []
    for c in word:
        binary.append(bin(ord(c)).split("b")[-1].rjust(8,'0'))

    binary = "".join(binary)

    # splitting the binary format into chunks of 6 bits
    new_word = []

    while len(binary):
        new_word.append(binary[0:6])
        binary = binary[6:]

    # adding padding to the last elem
    new_word[-1] = new_word[-1].ljust(6, '0')


    # encrypting the text
    result = ""
    for byte in new_word:
        index = bin_to_int(byte)
        result += base64_symbol_table[index]

    # adding padding of "="
    def get_multiple_of_4(num):

        while num % 4 != 0:
            num += 1
        return num
    result = result.ljust(get_multiple_of_4(len(result)),'=')
    return result

def b64_decode(word):

    #stripping away '='
    word = word.split("=")[0]

    #finding the index of each character in b64_index_table
    indexes = []
    for c in word:
        indexes.append(base64_symbol_table.index(c))

    # index to binary ( 6 bits)
    binary = []
    for i in indexes:
        binary.append(bin(i).split("b")[-1].rjust(6,'0'))

    # groupping the bits together
    binary = "".join(binary) # this is a string


    # forming group of 8 bits
    new_word = []
    while len(binary):
        new_word.append(binary[0:8])
        binary = binary[8:]

    # transform each byte to its ascii representation
    result = ""
    for c in new_word:
        result += chr(bin_to_int(c)) #you can use int(c,2)
        # instead of bin_to_int(c)
    return result

if __name__ == '__main__':
    
    len_args = len(sys.argv)
    if (len_args != 3):
        print(f"[/_\\] Usage : python {sys.argv[0]} <string> (-d | -e )")
        exit(0)
    option = sys.argv[2]
    if not (option == '-d' or option == '-e'):
        print(f"[/_\\] Usage : python {sys.argv[0]} <string> (-d | -e )")
        exit(0)

    word = sys.argv[1]
    if (option == '-d'):
        print(f"[+] {word} ---> {b64_decode(word)}")
    else:
        print(f"[+] {word} ---> {b64_encode(word)}")

That’s it for this article, hope you learned something !

This post is licensed under CC BY 4.0 by the author.

picoCTF 2022 - buffer overflow 2

Protostar - stack challenges