Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/src/utils/base64.rs
Line
Count
Source
1
/* Copyright (C) 2024 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
// Author: Shivani Bhardwaj <shivani@oisf.net>
19
20
use std::io::{Error, ErrorKind, Result};
21
22
34.9M
fn base64_map(input: u8) -> Result<u8> {
23
34.9M
    match input {
24
4.00k
        43 => Ok(62),  // +
25
66.9k
        47 => Ok(63),  // /
26
8.17M
        48 => Ok(52),  // 0
27
207k
        49 => Ok(53),  // 1
28
182k
        50 => Ok(54),  // 2
29
104k
        51 => Ok(55),  // 3
30
112k
        52 => Ok(56),  // 4
31
104k
        53 => Ok(57),  // 5
32
103k
        54 => Ok(58),  // 6
33
108k
        55 => Ok(59),  // 7
34
165k
        56 => Ok(60),  // 8
35
103k
        57 => Ok(61),  // 9
36
199k
        65 => Ok(0),   // A
37
24.1k
        66 => Ok(1),   // B
38
257k
        67 => Ok(2),   // C
39
14.7k
        68 => Ok(3),   // D
40
44.2k
        69 => Ok(4),   // E
41
191k
        70 => Ok(5),   // F
42
403k
        71 => Ok(6),   // G
43
4.76k
        72 => Ok(7),   // H
44
9.42k
        73 => Ok(8),   // I
45
43.8k
        74 => Ok(9),   // J
46
252k
        75 => Ok(10),  // K
47
13.7k
        76 => Ok(11),  // L
48
1.22M
        77 => Ok(12),  // M
49
1.04k
        78 => Ok(13),  // N
50
255k
        79 => Ok(14),  // O
51
249k
        80 => Ok(15),  // P
52
1.46k
        81 => Ok(16),  // Q
53
35.6k
        82 => Ok(17),  // R
54
28.3k
        83 => Ok(18),  // S
55
190k
        84 => Ok(19),  // T
56
1.22M
        85 => Ok(20),  // U
57
123k
        86 => Ok(21),  // V
58
916
        87 => Ok(22),  // W
59
16.8k
        88 => Ok(23),  // X
60
936
        89 => Ok(24),  // Y
61
362k
        90 => Ok(25),  // Z
62
9.69M
        97 => Ok(26),  // a
63
51.3k
        98 => Ok(27),  // b
64
63.9k
        99 => Ok(28),  // c
65
35.8k
        100 => Ok(29), // d
66
42.9k
        101 => Ok(30), // e
67
725k
        102 => Ok(31), // f
68
22.9k
        103 => Ok(32), // g
69
4.75k
        104 => Ok(33), // h
70
54.5k
        105 => Ok(34), // i
71
5.86k
        106 => Ok(35), // j
72
901
        107 => Ok(36), // k
73
300k
        108 => Ok(37), // l
74
21.9k
        109 => Ok(38), // m
75
51.3k
        110 => Ok(39), // n
76
603k
        111 => Ok(40), // o
77
259k
        112 => Ok(41), // p
78
10.3k
        113 => Ok(42), // q
79
27.7k
        114 => Ok(43), // r
80
22.0k
        115 => Ok(44), // s
81
1.16M
        116 => Ok(45), // t
82
1.77k
        117 => Ok(46), // u
83
8.18k
        118 => Ok(47), // v
84
42.3k
        119 => Ok(48), // w
85
33.7k
        120 => Ok(49), // x
86
4.19k
        121 => Ok(50), // y
87
7.85k
        122 => Ok(51), // z
88
7.04M
        _ => Err(Error::new(ErrorKind::InvalidData, "invalid base64")),
89
    }
90
34.9M
}
91
92
#[derive(Debug)]
93
pub struct Decoder {
94
    tmp: [u8; 4],
95
    pub nb: u8,
96
}
97
98
impl Decoder {
99
2.02k
    pub fn new() -> Decoder {
100
2.02k
        Decoder { tmp: [0; 4], nb: 0 }
101
2.02k
    }
102
}
103
104
impl Default for Decoder {
105
0
    fn default() -> Self {
106
0
        Self::new()
107
0
    }
108
}
109
110
1.01k
pub fn get_decoded_buffer_size(encoded_len: u32) -> u32 {
111
1.01k
    return ((encoded_len * 3) + (encoded_len % 4)) / 4;
112
1.01k
}
113
114
0
pub fn decode_rfc4648(decoder: &mut Decoder, input: &[u8], output: &mut [u8], decoded_bytes: &mut u32) -> Result<()>
115
{
116
0
    let mut i = input;
117
0
    let mut offset = 0;
118
0
    let mut stop = false;
119
0
    while !i.is_empty() {
120
0
        while decoder.nb < 4 {
121
0
            if !i.is_empty() && (base64_map(i[0]).is_ok() || i[0] == b'=') {
122
0
                decoder.tmp[decoder.nb as usize] = i[0];
123
0
                decoder.nb += 1;
124
0
            } else {
125
0
                while decoder.nb > 0
126
0
                    && decoder.nb < 4
127
0
                {
128
0
                    decoder.tmp[decoder.nb as usize] = b'=';
129
0
                    decoder.nb += 1;
130
0
                }
131
0
                stop = true;
132
0
                break;
133
            }
134
0
            i = &i[1..];
135
        }
136
0
        if decoder.nb == 4 {
137
0
            decoder.tmp[0] = base64_map(decoder.tmp[0])?;
138
0
            decoder.tmp[1] = base64_map(decoder.tmp[1])?;
139
0
            if decoder.tmp[2] == b'=' {
140
0
                output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
141
0
                offset += 1;
142
0
            } else {
143
0
                decoder.tmp[2] = base64_map(decoder.tmp[2])?;
144
0
                if decoder.tmp[3] == b'=' {
145
0
                    output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
146
0
                    output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
147
0
                    offset += 2;
148
0
                } else {
149
0
                    decoder.tmp[3] = base64_map(decoder.tmp[3])?;
150
0
                    output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
151
0
                    output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
152
0
                    output[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
153
0
                    offset += 3;
154
                }
155
            }
156
0
            decoder.nb = 0;
157
0
        }
158
0
        if stop {
159
0
            break;
160
0
        }
161
    }
162
163
0
    *decoded_bytes = offset as u32;
164
165
0
    return Ok(());
166
0
}
167
168
1.01k
pub fn decode_rfc2045(decoder: &mut Decoder, input: &[u8], output: &mut [u8], decoded_bytes: &mut u32) -> Result<()>
169
{
170
1.01k
    let mut i = input;
171
1.01k
    let mut offset = 0;
172
173
3.48M
    while !i.is_empty() {
174
24.4M
        while decoder.nb < 4 && !i.is_empty() {
175
20.9M
            if base64_map(i[0]).is_ok() || i[0] == b'=' {
176
13.9M
                decoder.tmp[decoder.nb as usize] = i[0];
177
13.9M
                decoder.nb += 1;
178
13.9M
            }
179
20.9M
            i = &i[1..];
180
        }
181
3.48M
        if decoder.nb == 4 {
182
3.48M
            decoder.tmp[0] = base64_map(decoder.tmp[0])?;
183
3.48M
            decoder.tmp[1] = base64_map(decoder.tmp[1])?;
184
3.48M
            if decoder.tmp[2] == b'=' {
185
2.55k
                output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
186
2.55k
                offset += 1;
187
2.55k
            } else {
188
3.48M
                decoder.tmp[2] = base64_map(decoder.tmp[2])?;
189
3.48M
                if decoder.tmp[3] == b'=' {
190
2.25k
                    output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
191
2.25k
                    output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
192
2.25k
                    offset += 2;
193
2.25k
                } else {
194
3.48M
                    decoder.tmp[3] = base64_map(decoder.tmp[3])?;
195
3.48M
                    output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
196
3.48M
                    output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
197
3.48M
                    output[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
198
3.48M
                    offset += 3;
199
                }
200
            }
201
3.48M
            decoder.nb = 0;
202
392
        }
203
    }
204
935
    *decoded_bytes = offset as u32;
205
206
935
    return Ok(());
207
1.01k
}