rust_web_server/core/base64/
mod.rs

1use std::collections::HashMap;
2use crate::symbol::SYMBOL;
3
4#[cfg(test)]
5mod tests;
6
7pub struct Base64;
8
9impl Base64 {
10
11    pub fn encode(bytes: &[u8]) -> Result<String, String> {
12        if bytes.len() == 0 {
13            return Ok("".to_string())
14        }
15
16
17        let mut result : Vec<String> = vec![];
18
19
20        let mut index = 0;
21        let length = bytes.len();
22
23        while index < length {
24            let mut to_encrypt_chunk: Vec<u8> = vec![];
25            let boxed_char_as_u8 = bytes.get(index);
26            if boxed_char_as_u8.is_none() {
27                return Err(format!("unable to get char at index: {}", index));
28            }
29            to_encrypt_chunk.push(*boxed_char_as_u8.unwrap());
30
31            if index + 1 < length {
32                index = index + 1;
33
34                let boxed_char_as_u8 = bytes.get(index);
35                if boxed_char_as_u8.is_none() {
36                    return Err(format!("unable to get char at index: {}", index));
37                }
38                to_encrypt_chunk.push(*boxed_char_as_u8.unwrap());
39            }
40
41            if index + 1 < length {
42                index = index + 1;
43
44                let boxed_char_as_u8 = bytes.get(index);
45                if boxed_char_as_u8.is_none() {
46                    return Err(format!("unable to get char at index: {}", index));
47                }
48                to_encrypt_chunk.push(*boxed_char_as_u8.unwrap());
49            }
50
51            let chunk : &[u8] = to_encrypt_chunk.as_ref();
52            let boxed_encrypted_chunk = Base64::encode_sequence(chunk);
53            if boxed_encrypted_chunk.is_err() {
54                return Err(boxed_encrypted_chunk.err().unwrap());
55            }
56
57            let encrypted_chunk = boxed_encrypted_chunk.unwrap();
58            result.push(encrypted_chunk);
59
60            index = index + 1
61
62        }
63
64        let encoded_string = result.join(SYMBOL.empty_string);
65        Ok(encoded_string)
66    }
67
68    pub fn decode(text: String) -> Result<Vec<u8>, String> {
69        if text.chars().count() == 0 {
70            return Ok(vec![])
71        }
72
73        let mut result : Vec<u8> = vec![];
74
75        let mut index = 0;
76        let length = text.len();
77
78        while index < length {
79            let mut to_decrypt_chunk = vec![];
80
81            let boxed_char_as_u8 = text.chars().nth(index);
82            if boxed_char_as_u8.is_none() {
83                return Err(format!("unable to get char at index: {}", index));
84            }
85            to_decrypt_chunk.push(boxed_char_as_u8.unwrap() as u8);
86
87            if index + 1 < length {
88                index = index + 1;
89
90                let boxed_char_as_u8 = text.chars().nth(index);
91                if boxed_char_as_u8.is_none() {
92                    return Err(format!("unable to get char at index: {}", index));
93                }
94                to_decrypt_chunk.push(boxed_char_as_u8.unwrap() as u8);
95            }
96
97            if index + 1 < length {
98                index = index + 1;
99
100                let boxed_char_as_u8 = text.chars().nth(index);
101                if boxed_char_as_u8.is_none() {
102                    return Err(format!("unable to get char at index: {}", index));
103                }
104                to_decrypt_chunk.push(boxed_char_as_u8.unwrap() as u8);
105            }
106
107            if index + 1 < length {
108                index = index + 1;
109
110                let boxed_char_as_u8 = text.chars().nth(index);
111                if boxed_char_as_u8.is_none() {
112                    return Err(format!("unable to get char at index: {}", index));
113                }
114                to_decrypt_chunk.push(boxed_char_as_u8.unwrap() as u8);
115            }
116
117            let boxed_string = String::from_utf8(to_decrypt_chunk);
118            if boxed_string.is_err() {
119                let message = boxed_string.err().unwrap().to_string();
120                return Err(message)
121            }
122            let chunk : String = boxed_string.unwrap();
123            let boxed_decrypted_chunk = Base64::decode_sequence(chunk);
124            if boxed_decrypted_chunk.is_err() {
125                return Err(boxed_decrypted_chunk.err().unwrap());
126            }
127
128            let encrypted_chunk : Vec<u8> = boxed_decrypted_chunk.unwrap();
129            result.extend(encrypted_chunk);
130
131            index = index + 1
132
133        }
134
135
136        Ok(result)
137    }
138
139    pub fn decode_sequence(text: String) -> Result<Vec<u8>, String> {
140        let result : Vec<u8> = vec![];
141
142        let number_of_equal_signs = text.matches(SYMBOL.equals).count();
143
144        if number_of_equal_signs == 2 {
145            let boxed_first_byte = text.chars().nth(0);
146            if boxed_first_byte.is_none() {
147                return Err("unexpected error, unable to get char at position 0".to_string());
148            }
149            let first_byte = boxed_first_byte.unwrap() as u8;
150            let _first_byte_as_string = format!("{first_byte:b}");
151
152            let boxed_conversion = Base64::convert_base64_char_to_number(first_byte as char);
153            if boxed_conversion.is_err() {
154                let message = boxed_conversion.err().unwrap();
155                return Err(message);
156            }
157            let converted_first_byte = boxed_conversion.unwrap();
158            let shifted_converted_first_byte = converted_first_byte << 2;
159            let _shifted_converted_first_byte_as_string = format!("{converted_first_byte:b}");
160
161
162
163            let boxed_second_byte = text.chars().nth(1);
164            if boxed_second_byte.is_none() {
165                return Err("unexpected error, unable to get char at position 0".to_string());
166            }
167            let second_byte = boxed_second_byte.unwrap() as u8;
168            let _second_byte_as_string = format!("{second_byte:b}");
169
170
171            let boxed_conversion = Base64::convert_base64_char_to_number(second_byte as char);
172            if boxed_conversion.is_err() {
173                let message = boxed_conversion.err().unwrap();
174                return Err(message);
175            }
176            let converted_second_byte = boxed_conversion.unwrap();
177
178
179            let shifted_converted_second_byte = converted_second_byte >> 4;
180            let _shifted_second_byte_as_string = format!("{shifted_converted_second_byte:b}");
181
182
183            let resulted_byte = shifted_converted_first_byte | shifted_converted_second_byte;
184            return Ok(vec![resulted_byte]);
185
186        }
187
188        if number_of_equal_signs == 1 {
189            let boxed_first_byte = text.chars().nth(0);
190            if boxed_first_byte.is_none() {
191                return Err("unexpected error, unable to get char at position 0".to_string());
192            }
193            let first_byte = boxed_first_byte.unwrap() as u8;
194            let _first_byte_as_string = format!("{first_byte:b}");
195
196            let boxed_conversion = Base64::convert_base64_char_to_number(first_byte as char);
197            if boxed_conversion.is_err() {
198                let message = boxed_conversion.err().unwrap();
199                return Err(message);
200            }
201            let converted_first_byte = boxed_conversion.unwrap();
202            let shifted_converted_first_byte = converted_first_byte << 2;
203            let _shifted_converted_first_byte_as_string = format!("{converted_first_byte:b}");
204
205
206
207            let boxed_second_byte = text.chars().nth(1);
208            if boxed_second_byte.is_none() {
209                return Err("unexpected error, unable to get char at position 1".to_string());
210            }
211            let second_byte = boxed_second_byte.unwrap() as u8;
212            let _second_byte_as_string = format!("{second_byte:b}");
213
214
215            let boxed_conversion = Base64::convert_base64_char_to_number(second_byte as char);
216            if boxed_conversion.is_err() {
217                let message = boxed_conversion.err().unwrap();
218                return Err(message);
219            }
220            let converted_second_byte = boxed_conversion.unwrap();
221
222
223            let shifted_converted_second_byte = converted_second_byte >> 4;
224            let _shifted_second_byte_as_string = format!("{shifted_converted_second_byte:b}");
225
226
227            let first_char_as_byte = shifted_converted_first_byte | shifted_converted_second_byte;
228
229
230
231
232            // second char
233            let second_char_part_one = (converted_second_byte & 0b00001111) << 4;
234            let boxed_third_byte = text.chars().nth(2);
235            if boxed_third_byte.is_none() {
236                return Err("unexpected error, unable to get char at position 2".to_string());
237            }
238            let third_byte = boxed_third_byte.unwrap() as u8;
239
240            let boxed_conversion = Base64::convert_base64_char_to_number(third_byte as char);
241            if boxed_conversion.is_err() {
242                let message = boxed_conversion.err().unwrap();
243                return Err(message);
244            }
245            let converted_third_byte = boxed_conversion.unwrap();
246            let shifted_third_byte = (0b00111100 & converted_third_byte)  >> 2;
247
248            let second_char_as_byte = shifted_third_byte | second_char_part_one;
249
250            return Ok(vec![first_char_as_byte, second_char_as_byte]);
251
252        }
253
254        if number_of_equal_signs == 0 {
255            let boxed_first_byte = text.chars().nth(0);
256            if boxed_first_byte.is_none() {
257                return Err("unexpected error, unable to get char at position 0".to_string());
258            }
259            let first_byte = boxed_first_byte.unwrap() as u8;
260            let _first_byte_as_string = format!("{first_byte:b}");
261
262            let boxed_conversion = Base64::convert_base64_char_to_number(first_byte as char);
263            if boxed_conversion.is_err() {
264                let message = boxed_conversion.err().unwrap();
265                return Err(message);
266            }
267            let converted_first_byte = boxed_conversion.unwrap();
268            let shifted_converted_first_byte = converted_first_byte << 2;
269            let _shifted_converted_first_byte_as_string = format!("{converted_first_byte:b}");
270
271
272
273            let boxed_second_byte = text.chars().nth(1);
274            if boxed_second_byte.is_none() {
275                return Err("unexpected error, unable to get char at position 1".to_string());
276            }
277            let second_byte = boxed_second_byte.unwrap() as u8;
278            let _second_byte_as_string = format!("{second_byte:b}");
279
280            let boxed_conversion = Base64::convert_base64_char_to_number(second_byte as char);
281            if boxed_conversion.is_err() {
282                let message = boxed_conversion.err().unwrap();
283                return Err(message);
284            }
285            let converted_second_byte = boxed_conversion.unwrap();
286
287
288            let shifted_converted_second_byte = converted_second_byte >> 4;
289            let _shifted_second_byte_as_string = format!("{shifted_converted_second_byte:b}");
290
291
292            let first_char_as_byte = shifted_converted_first_byte | shifted_converted_second_byte;
293
294
295
296
297            // second char
298            let second_char_part_one = (converted_second_byte & 0b00001111) << 4;
299            let boxed_third_byte = text.chars().nth(2);
300            if boxed_third_byte.is_none() {
301                return Err("unexpected error, unable to get char at position 2".to_string());
302            }
303            let third_byte = boxed_third_byte.unwrap() as u8;
304
305            let boxed_conversion = Base64::convert_base64_char_to_number(third_byte as char);
306            if boxed_conversion.is_err() {
307                let message = boxed_conversion.err().unwrap();
308                return Err(message);
309            }
310            let converted_third_byte = boxed_conversion.unwrap();
311            let shifted_third_byte = (0b00111100 & converted_third_byte)  >> 2;
312
313            let second_char_as_byte = shifted_third_byte | second_char_part_one;
314
315            let boxed_conversion = Base64::convert_base64_char_to_number(third_byte as char);
316            if boxed_conversion.is_err() {
317                let message = boxed_conversion.err().unwrap();
318                return Err(message);
319            }
320            let converted_third_byte = boxed_conversion.unwrap();
321            let masked_third_byte = converted_third_byte & 0b00000011;
322            let shifted_masked_third_byte = masked_third_byte << 6;
323
324
325            let boxed_fourth_byte = text.chars().nth(3);
326            if boxed_fourth_byte.is_none() {
327                return Err("unexpected error, unable to get char at position 3".to_string());
328            }
329            let fourth_byte = boxed_fourth_byte.unwrap() as u8;
330
331            let boxed_conversion = Base64::convert_base64_char_to_number(fourth_byte as char);
332            if boxed_conversion.is_err() {
333                let message = boxed_conversion.err().unwrap();
334                return Err(message);
335            }
336            let converted_fourth_byte = boxed_conversion.unwrap();
337            let masked_fourth_byte = converted_fourth_byte & 0b00111111;
338
339            let third_char_as_byte = shifted_masked_third_byte | masked_fourth_byte;
340
341
342            return Ok(vec![first_char_as_byte, second_char_as_byte, third_char_as_byte]);
343
344        }
345
346        Ok(result)
347    }
348
349    pub fn encode_sequence(bytes: &[u8]) -> Result<String, String> {
350        if bytes.len() > 3 {
351            return Err("sequence encodes at most 3 bytes at once".to_string());
352        }
353
354        if bytes.len() == 0 {
355            return Err("sequence encodes at least 1 byte".to_string());
356        }
357
358        if bytes.len() == 1 {
359            let boxed_byte = bytes.get(0);
360            if boxed_byte.is_none() {
361                return Err("byte at pos 1 is empty".to_string());
362            }
363
364            let byte = boxed_byte.unwrap();
365            let _byte_as_string = format!("{byte:b}");
366            let shifted_first_sextet = byte >> 2;
367            let _shifted_first_sextet_as_string = format!("{shifted_first_sextet:b}");
368
369            let shifted_second_sextet = (byte & 0b00000011) << 4;
370            let _shifted_first_sextet_as_string = format!("{shifted_second_sextet:b}");
371
372            let mut result_buffer: Vec<String> = vec![];
373
374            let boxed_encoded_char = Base64::convert_number_to_base64_char(shifted_first_sextet);
375            if boxed_encoded_char.is_err() {
376                return Err(boxed_encoded_char.err().unwrap());
377            }
378
379            result_buffer.push(boxed_encoded_char.unwrap().to_string());
380
381            let boxed_encoded_char = Base64::convert_number_to_base64_char(shifted_second_sextet);
382            if boxed_encoded_char.is_err() {
383                return Err(boxed_encoded_char.err().unwrap());
384            }
385
386            result_buffer.push(boxed_encoded_char.unwrap().to_string());
387
388            result_buffer.push(SYMBOL.equals.to_string());
389            result_buffer.push(SYMBOL.equals.to_string());
390
391            let result : String = result_buffer.join(SYMBOL.empty_string);
392            return Ok(result);
393        }
394
395        if bytes.len() == 2 {
396            let boxed_byte = bytes.get(0);
397            if boxed_byte.is_none() {
398                return Err("byte at pos 1 is empty".to_string());
399            }
400
401            let byte = boxed_byte.unwrap();
402            let _byte_as_string = format!("{byte:b}");
403            let shifted_first_sextet = byte >> 2;
404            let _shifted_first_sextet_as_string = format!("{shifted_first_sextet:b}");
405
406
407
408            let mut result_buffer: Vec<String> = vec![];
409
410            let boxed_encoded_char = Base64::convert_number_to_base64_char(shifted_first_sextet);
411            if boxed_encoded_char.is_err() {
412                return Err(boxed_encoded_char.err().unwrap());
413            }
414
415            let char : String =  boxed_encoded_char.unwrap().to_string();
416            result_buffer.push(char);
417
418
419            // base64 second sextet part 1 (from first u8)
420            let shifted_second_sextet_part_one = (byte & 0b00000011) << 4;
421            let _shifted_second_sextet_as_string = format!("{shifted_second_sextet_part_one:b}");
422
423
424            // base64 second sextet part 2 (from second u8)
425            let boxed_byte = bytes.get(1);
426            if boxed_byte.is_none() {
427                return Err("byte at pos 1 is empty".to_string());
428            }
429
430            let second_byte = boxed_byte.unwrap();
431            let shifted_second_byte_part_two = second_byte >> 4;
432
433
434            let second_sextet = shifted_second_sextet_part_one | shifted_second_byte_part_two;
435            let boxed_second_encoded_char = Base64::convert_number_to_base64_char(second_sextet);
436            if boxed_second_encoded_char.is_err() {
437                return Err(boxed_second_encoded_char.err().unwrap());
438            }
439
440            let char =  boxed_second_encoded_char.unwrap();
441            result_buffer.push(char.to_string());
442
443
444            // base64 third char
445            let base64_third_char = (second_byte & 0b00001111) << 2;
446            let boxed_third_encoded_char = Base64::convert_number_to_base64_char(base64_third_char);
447            if boxed_third_encoded_char.is_err() {
448                return Err(boxed_third_encoded_char.err().unwrap());
449            }
450            let char =  boxed_third_encoded_char.unwrap();
451            result_buffer.push(char.to_string());
452
453
454
455            result_buffer.push(SYMBOL.equals.to_string());
456
457            let result : String = result_buffer.join(SYMBOL.empty_string);
458            return Ok(result);
459        }
460
461        if bytes.len() == 3 {
462            let boxed_byte = bytes.get(0);
463            if boxed_byte.is_none() {
464                return Err("byte at pos 1 is empty".to_string());
465            }
466
467            let byte = boxed_byte.unwrap();
468            let _byte_as_string = format!("{byte:b}");
469            let shifted_first_sextet = byte >> 2;
470            let _shifted_first_sextet_as_string = format!("{shifted_first_sextet:b}");
471
472
473
474            let mut result_buffer: Vec<String> = vec![];
475
476            let boxed_encoded_char = Base64::convert_number_to_base64_char(shifted_first_sextet);
477            if boxed_encoded_char.is_err() {
478                return Err(boxed_encoded_char.err().unwrap());
479            }
480
481            let char : String =  boxed_encoded_char.unwrap().to_string();
482            result_buffer.push(char);
483
484
485            // base64 second sextet part 1 (from first u8)
486            let shifted_second_sextet_part_one = (byte & 0b00000011) << 4;
487            let _shifted_second_sextet_as_string = format!("{shifted_second_sextet_part_one:b}");
488
489
490            // base64 second sextet part 2 (from second u8)
491            let boxed_byte = bytes.get(1);
492            if boxed_byte.is_none() {
493                return Err("byte at pos 1 is empty".to_string());
494            }
495
496            let second_byte = boxed_byte.unwrap();
497            let shifted_second_byte_part_two = second_byte >> 4;
498
499
500            let second_sextet = shifted_second_sextet_part_one | shifted_second_byte_part_two;
501            let boxed_second_encoded_char = Base64::convert_number_to_base64_char(second_sextet);
502            if boxed_second_encoded_char.is_err() {
503                return Err(boxed_second_encoded_char.err().unwrap());
504            }
505
506            let char =  boxed_second_encoded_char.unwrap();
507            result_buffer.push(char.to_string());
508
509
510            // base64 third char
511            let base64_third_char = (second_byte & 0b00001111) << 2;
512
513
514            let boxed_byte = bytes.get(2);
515            if boxed_byte.is_none() {
516                return Err("byte at pos 1 is empty".to_string());
517            }
518
519            let third_byte = boxed_byte.unwrap();
520            let third_encoded_char_part2 = (third_byte & 0b11000000) >> 6;
521
522            let third_encoded_char = base64_third_char | third_encoded_char_part2;
523
524            let boxed_third_encoded_char = Base64::convert_number_to_base64_char(third_encoded_char);
525            if boxed_third_encoded_char.is_err() {
526                return Err(boxed_third_encoded_char.err().unwrap());
527            }
528            let char =  boxed_third_encoded_char.unwrap();
529            result_buffer.push(char.to_string());
530
531            let fourth_encoded_char = third_byte & 0b00111111;
532            let boxed_fourth_encoded_char = Base64::convert_number_to_base64_char(fourth_encoded_char);
533            if boxed_fourth_encoded_char.is_err() {
534                return Err(boxed_fourth_encoded_char.err().unwrap());
535            }
536            let char =  boxed_fourth_encoded_char.unwrap();
537            result_buffer.push(char.to_string());
538
539            let result : String = result_buffer.join(SYMBOL.empty_string);
540            return Ok(result);
541        }
542
543        Ok("".to_string())
544    }
545
546    pub fn convert_base64_char_to_number(char: char) -> Result<u8, String> {
547        let base64_char_list : Vec<char> = Base64::get_base64_char_list();
548        let mut map : HashMap<char, u8> = HashMap::new();
549
550        for (index, char) in base64_char_list.iter().enumerate() {
551            map.insert(*char, index as u8);
552        }
553
554        let boxed_get = map.get(&char);
555        if boxed_get.is_none() {
556            let message = format!("unable to get char number: {}", char);
557            return Err(message);
558        }
559        let index : &u8 = map.get(&char).unwrap();
560
561        Ok(*index)
562    }
563
564    pub fn get_base64_char_list() -> Vec<char> {
565        let mut base64_table : Vec<char> = vec![];
566
567        let mut uppercase = ('A'..='Z').into_iter().collect::<Vec<char>>();
568        base64_table.append(&mut uppercase);
569
570        let mut lowercase = ('a'..='z').into_iter().collect::<Vec<char>>();
571        base64_table.append(&mut lowercase);
572
573        let mut numbers = ('0'..='9').into_iter().collect::<Vec<char>>();
574        base64_table.append(&mut numbers);
575
576        base64_table.push('+');
577        base64_table.push('/');
578
579        base64_table
580    }
581
582    pub fn convert_number_to_base64_char(number: u8) -> Result<char, String> {
583        if number > 63 {
584            return Err("number exceeds range 0 - 63".to_string());
585        }
586
587        let base64_table : Vec<char> = Base64::get_base64_char_list();
588
589        let boxed_get : Option<char> = base64_table.get(number as usize).copied();
590        if boxed_get.is_none() {
591            return Err(format!("unable to convert number to base64 char: {}", number).to_string())
592        }
593
594        let char: char = boxed_get.unwrap();
595        Ok(char)
596    }
597}