1 /*
2  ** Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3  ** Copyright (C) 1998-2013 Sourcefire, Inc.
4  **
5  ** Written by Patrick Mullen <pmullen@sourcefire.com>
6  ** 9/11/2013 - Changed uint32_t to size_t
7  **
8  ** This program is free software; you can redistribute it and/or modify
9  ** it under the terms of the GNU General Public License Version 2 as
10  ** published by the Free Software Foundation.  You may not use, modify or
11  ** distribute this program under any other version of the GNU General
12  ** Public License.
13  **
14  ** This program is distributed in the hope that it will be useful,
15  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  ** GNU General Public License for more details.
18  **
19  ** You should have received a copy of the GNU General Public License
20  ** along with this program; if not, write to the Free Software
21  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "clamav-config.h"
26 #endif
27 
28 #include "sf_base64decode.h"
29 
30 // clang-format off
31 uint8_t sf_decode64tab[256] = {
32         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
33         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
34         100,100,100,100,100,100,100,100,100,100,100,62 ,100,100,100, 63,
35          52, 53, 54, 55, 56, 57, 58, 59, 60, 61,100,100,100, 99,100,100,
36         100,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
37          15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,100,100,100,100,100,
38         100, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
39          41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,100,100,100,100,100,
40         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
41         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
42         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
43         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
44         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
45         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
46         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,
47         100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100};
48 // clang-format on
49 
50 /* base64decode assumes the input data terminates with '=' and/or at the end of the input buffer
51  * at inbuf_size.  If extra characters exist within inbuf before inbuf_size is reached, it will
52  * happily decode what it can and skip over what it can't.  This is consistent with other decoders
53  * out there.  So, either terminate the string, set inbuf_size correctly, or at least be sure the
54  * data is valid up until the point you care about.  Note base64 data does NOT have to end with
55  * '=' and won't if the number of bytes of input data is evenly divisible by 3.
56 */
sf_base64decode(uint8_t * inbuf,size_t inbuf_size,uint8_t * outbuf,size_t outbuf_size,size_t * bytes_written)57 int sf_base64decode(uint8_t *inbuf, size_t inbuf_size, uint8_t *outbuf, size_t outbuf_size, size_t *bytes_written)
58 {
59     uint8_t *cursor, *endofinbuf;
60     uint8_t *outbuf_ptr;
61     uint8_t base64data[4], *base64data_ptr; /* temporary holder for current base64 chunk */
62     uint8_t tableval_a, tableval_b, tableval_c, tableval_d;
63 
64     size_t n;
65     size_t max_base64_chars; /* The max number of decoded base64 chars that fit into outbuf */
66 
67     int error = 0;
68 
69     /* This algorithm will waste up to 4 bytes but we really don't care.
70       At the end we're going to copy the exact number of bytes requested. */
71     max_base64_chars = (outbuf_size / 3) * 4 + 4; /* 4 base64 bytes gives 3 data bytes, plus
72                                                     an extra 4 to take care of any rounding */
73 
74     base64data_ptr = base64data;
75     endofinbuf     = inbuf + inbuf_size;
76 
77     /* Strip non-base64 chars from inbuf and decode */
78     n              = 0;
79     *bytes_written = 0;
80     cursor         = inbuf;
81     outbuf_ptr     = outbuf;
82     while ((cursor < endofinbuf) && (n < max_base64_chars)) {
83         if (sf_decode64tab[*cursor] != 100) {
84             *base64data_ptr++ = *cursor;
85             n++; /* Number of base64 bytes we've stored */
86             if (!(n % 4)) {
87                 /* We have four databytes upon which to operate */
88 
89                 if ((base64data[0] == '=') || (base64data[1] == '=')) {
90                     /* Error in input data */
91                     error = 1;
92                     break;
93                 }
94 
95                 /* retrieve values from lookup table */
96                 tableval_a = sf_decode64tab[base64data[0]];
97                 tableval_b = sf_decode64tab[base64data[1]];
98                 tableval_c = sf_decode64tab[base64data[2]];
99                 tableval_d = sf_decode64tab[base64data[3]];
100 
101                 if (*bytes_written < outbuf_size) {
102                     *outbuf_ptr++ = (tableval_a << 2) | (tableval_b >> 4);
103                     (*bytes_written)++;
104                 }
105 
106                 if ((base64data[2] != '=') && (*bytes_written < outbuf_size)) {
107                     *outbuf_ptr++ = (tableval_b << 4) | (tableval_c >> 2);
108                     (*bytes_written)++;
109                 } else {
110                     break;
111                 }
112 
113                 if ((base64data[3] != '=') && (*bytes_written < outbuf_size)) {
114                     *outbuf_ptr++ = (tableval_c << 6) | tableval_d;
115                     (*bytes_written)++;
116                 } else {
117                     break;
118                 }
119 
120                 /* Reset our decode pointer for the next group of four */
121                 base64data_ptr = base64data;
122             }
123         }
124         cursor++;
125     }
126 
127     if (error)
128         return (-1);
129     else
130         return (0);
131 }
132