-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
Copy pathbase64_encoding.cpp
201 lines (193 loc) · 8.31 KB
/
base64_encoding.cpp
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/**
* @brief [Base64 Encoding and
* Decoding](https://en.wikipedia.org/wiki/Base64)
* @details In programming, [Base64](https://en.wikipedia.org/wiki/Base64) is a
* group of binary-to-text encoding schemes that represent binary data (more
* specifically, a sequence of 8-bit bytes) in an ASCII string format by
* translating the data into a radix-64 representation. The term Base64
* originates from a specific MIME content transfer encoding. Each non-final
* Base64 digit represents exactly 6 bits of data. Three 8-bit bytes (i.e., a
* total of 24 bits) can therefore be represented by four 6-bit Base64
* digits.
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
*/
#include <array> /// for `std::array`
#include <cassert> /// for `assert` operations
#include <cstdint>
#include <iostream> /// for IO operations
/**
* @namespace ciphers
* @brief Cipher algorithms
*/
namespace ciphers {
/**
* @namespace base64_encoding
* @brief Functions for [Base64 Encoding and
* Decoding](https://en.wikipedia.org/wiki/Base64) implementation.
*/
namespace base64_encoding {
// chars denoting the format for encoding and decoding array.
// This array is already decided by
// [RFC4648](https://tools.ietf.org/html/rfc4648#section-4) standard
const std::string chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @brief Base64 Encoder
* @details Converts the given string to Base64 equivalent.
* @param input Input as a string
* @returns Base64 encoded string
*/
std::string base64_encode(const std::string &input) {
std::string base64_string; /// Output of this function: base64 string
// base64 deals with 6-bit chars encoded as per chars, so
// we will always filter 6-bits from input.
for (uint32_t i = 0; i < input.size(); i += 3) {
char first_byte = input[i]; /// First byte of the iteration
// Take first six bits of first character.
// Encode the first six bits with character defined in string `chars`
base64_string.push_back(chars[first_byte >> 2]);
if (i + 1 < input.size()) {
char second_byte = input[i + 1]; /// Second byte of the iteration
// Take remaining two bits of first character, and four first bits
// from second character Combine two numbers as 6-bit digits and
// encode by array chars (first two bits of first byte and next four
// of second byte)
base64_string.push_back(
chars[(((first_byte & 3) << 4) | ((second_byte & 0xF0) >> 4))]);
if (i + 2 < input.size()) {
char third_byte = input[i + 2]; /// Third byte of the iteration
// Take remaining four bits of second character, and first two
// bits from third character Combine two numbers as 6-bit digits
// and encode by array chars (remaining four bits of second byte
// and first two of third byte)
base64_string.push_back(chars[((third_byte & 0xC0) >> 6) |
((second_byte & 0x0F) << 2)]);
// Encode remaining 6-bit of third byte by array chars
base64_string.push_back(chars[(third_byte & 0x3F)]);
} else {
// Take remaining four bits of second character as 6-bit number
base64_string.push_back(chars[((second_byte & 0x0F) << 2)]);
base64_string.push_back('='); // padding characters
}
} else {
// Take remaining two bits of first character as 6-bit number
base64_string.push_back(chars[((first_byte & 3) << 4)]);
base64_string.push_back('='); // padding characters
base64_string.push_back('='); // padding characters
}
}
return base64_string;
}
/**
* @brief Utility function for finding index
* @details Utility function for finding the position of a character in array
* `chars`
* @param c character to search in array `chars`
* @returns integer denoting position of character in array `chars`
*/
uint8_t find_idx(const char c) {
if (c >= 'A' && c <= 'Z') {
return c - 'A';
} else if (c >= 'a' && c <= 'z') {
return c - 'a' + 26;
} else if (c >= '0' && c <= '9') {
return c - '0' + 52;
} else if (c == '+') {
return 62;
} else if (c == '/') {
return 63;
}
return -1;
}
/**
* @brief Base64 Decoder
* @details Decodes the Base64 string
* @param base64_str Input as a Base64 string
* @returns Base64 decoded string
*/
std::string base64_decode(const std::string &base64_str) {
std::string
base64_decoded; /// Output of this function: base64 decoded string
for (uint32_t i = 0; i < base64_str.size(); i += 4) {
/// First 6-bit representation of Base64
char first_byte = base64_str[i];
/// Second 6-bit representation of Base64
char second_byte = base64_str[i + 1];
// Actual str characters are of 8 bits (or 1 byte):
// :: 8 bits are decode by taking 6 bits from 1st byte of base64 string
// and first 2 bits from 2nd byte of base64 string.
char first_actual_byte = static_cast<char>(
(find_idx(first_byte) << 2) | ((find_idx(second_byte)) >> 4));
base64_decoded.push_back(first_actual_byte);
if (i + 2 < base64_str.size() && base64_str[i + 2] != '=') {
/// Third 6-bit representation of Base64
char third_byte = base64_str[i + 2];
// :: Next 8 bits are decode by taking remaining 4 bits from 2nd
// byte of base64 string and first 4 bits from 3rd byte of base64
// string.
char second_actual_byte =
static_cast<char>(((find_idx(second_byte) & 0x0F) << 4) |
(find_idx(third_byte) >> 2));
base64_decoded.push_back(second_actual_byte);
if (i + 3 < base64_str.size() && base64_str[i + 3] != '=') {
/// Fourth 6-bit representation of Base64 string
char fourth_byte = base64_str[i + 3];
// :: Taking remaining 2 bits from 3rd byte of base64 string
// and all 6 bits from 4th byte of base64 string.
char third_actual_byte =
static_cast<char>(((find_idx(third_byte) & 0x03) << 6) |
find_idx(fourth_byte));
base64_decoded.push_back(third_actual_byte);
}
}
}
return base64_decoded;
}
} // namespace base64_encoding
} // namespace ciphers
/**
* @brief Self test-implementations
* @returns void
*/
static void test() {
// 1st Test
std::string str =
"To err is human, but to really foul things up you need a computer.";
std::string base64_str = ciphers::base64_encoding::base64_encode(str);
std::string verify =
"VG8gZXJyIGlzIGh1bWFuLCBidXQgdG8gcmVhbGx5IGZvdWwgdGhpbmdzIHVwIHlvdSBuZW"
"VkIGEgY29tcHV0ZXIu";
// verify encoding
assert(base64_str == verify);
std::string original_str =
ciphers::base64_encoding::base64_decode(base64_str);
// verify decoding
assert(original_str == str);
// 2nd Test from [Wikipedia](https://en.wikipedia.org/wiki/Base64)
str =
"Man is distinguished, not only by his reason, but by this singular "
"passion from other animals, which is a lust of the mind, that by a "
"perseverance of delight in the continued and indefatigable generation "
"of knowledge, exceeds the short vehemence of any carnal pleasure.";
base64_str = ciphers::base64_encoding::base64_encode(str);
verify =
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieS"
"B0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBh"
"IGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodC"
"BpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25v"
"d2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbG"
"Vhc3VyZS4=";
// verify encoding
assert(base64_str == verify);
original_str = ciphers::base64_encoding::base64_decode(base64_str);
// verify decoding
assert(original_str == str);
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
return 0;
}