use crate::detect::parser::{parse_var, take_until_whitespace, ResultValue};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
+use crate::ffi::base64::Base64Mode;
use nom7::bytes::complete::tag;
use nom7::character::complete::multispace0;
use nom7::{Err, IResult};
use std::str;
-#[repr(u8)]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum DetectBase64Mode {
- Base64ModeRelax = 0,
- /* If the following strings were to be passed to the decoder with RFC2045 mode,
- * the results would be as follows. See the unittest B64TestVectorsRFC2045 in
- * src/util-base64.c
- *
- * BASE64("") = ""
- * BASE64("f") = "Zg=="
- * BASE64("fo") = "Zm8="
- * BASE64("foo") = "Zm9v"
- * BASE64("foob") = "Zm9vYg=="
- * BASE64("fooba") = "Zm9vYmE="
- * BASE64("foobar") = "Zm9vYmFy"
- * BASE64("foobar") = "Zm 9v Ym Fy" <-- Notice how the spaces are ignored
- * BASE64("foobar") = "Zm$9vYm.Fy" # According to RFC 2045, All line breaks or *other
- * characters* not found in base64 alphabet must be ignored by decoding software
- * */
- Base64ModeRFC2045, /* SPs are allowed during transfer but must be skipped by Decoder */
- Base64ModeStrict,
- /* If the following strings were to be passed to the decoder with RFC4648 mode,
- * the results would be as follows. See the unittest B64TestVectorsRFC4648 in
- * src/util-base64.c
- *
- * BASE64("") = ""
- * BASE64("f") = "Zg=="
- * BASE64("fo") = "Zm8="
- * BASE64("foo") = "Zm9v"
- * BASE64("foob") = "Zm9vYg=="
- * BASE64("fooba") = "Zm9vYmE="
- * BASE64("foobar") = "Zm9vYmFy"
- * BASE64("f") = "Zm 9v Ym Fy" <-- Notice how the processing stops once space is encountered
- * BASE64("f") = "Zm$9vYm.Fy" <-- Notice how the processing stops once an invalid char is
- * encountered
- * */
- Base64ModeRFC4648, /* reject the encoded data if it contains characters outside the base alphabet */
-}
-
-pub const TRANSFORM_FROM_BASE64_MODE_DEFAULT: DetectBase64Mode = DetectBase64Mode::Base64ModeRFC4648;
+pub const TRANSFORM_FROM_BASE64_MODE_DEFAULT: Base64Mode = Base64Mode::Base64ModeRFC4648;
const DETECT_TRANSFORM_BASE64_MAX_PARAM_COUNT: usize = 3;
pub const DETECT_TRANSFORM_BASE64_FLAG_MODE: u8 = 0x01;
nbytes_str: *const c_char,
offset: u32,
offset_str: *const c_char,
- mode: DetectBase64Mode,
+ mode: Base64Mode,
}
impl Drop for SCDetectTransformFromBase64Data {
}
}
-fn get_mode_value(value: &str) -> Option<DetectBase64Mode> {
+fn get_mode_value(value: &str) -> Option<Base64Mode> {
let res = match value {
- "rfc4648" => Some(DetectBase64Mode::Base64ModeRFC4648),
- "rfc2045" => Some(DetectBase64Mode::Base64ModeRFC2045),
- "strict" => Some(DetectBase64Mode::Base64ModeStrict),
+ "rfc4648" => Some(Base64Mode::Base64ModeRFC4648),
+ "rfc2045" => Some(Base64Mode::Base64ModeRFC2045),
+ "strict" => Some(Base64Mode::Base64ModeStrict),
_ => None,
};
nbytes_str: &str,
offset: u32,
offset_str: &str,
- mode: DetectBase64Mode,
+ mode: Base64Mode,
flags: u8,
) {
let tbd = SCDetectTransformFromBase64Data {
assert_eq!(val, tbd);
tbd.flags = DETECT_TRANSFORM_BASE64_FLAG_MODE;
- tbd.mode = DetectBase64Mode::Base64ModeRFC2045;
+ tbd.mode = Base64Mode::Base64ModeRFC2045;
tbd.offset = 0;
tbd.nbytes = 0;
let (_, val) = parse_transform_base64("mode rfc2045").unwrap();
"",
3933,
"",
- DetectBase64Mode::Base64ModeStrict,
+ Base64Mode::Base64ModeStrict,
DETECT_TRANSFORM_BASE64_FLAG_NBYTES
| DETECT_TRANSFORM_BASE64_FLAG_OFFSET
| DETECT_TRANSFORM_BASE64_FLAG_MODE,
"",
3933,
"",
- DetectBase64Mode::Base64ModeRFC2045,
+ Base64Mode::Base64ModeRFC2045,
DETECT_TRANSFORM_BASE64_FLAG_NBYTES
| DETECT_TRANSFORM_BASE64_FLAG_OFFSET
| DETECT_TRANSFORM_BASE64_FLAG_MODE,
"",
3933,
"",
- DetectBase64Mode::Base64ModeRFC4648,
+ Base64Mode::Base64ModeRFC4648,
DETECT_TRANSFORM_BASE64_FLAG_NBYTES
| DETECT_TRANSFORM_BASE64_FLAG_OFFSET
| DETECT_TRANSFORM_BASE64_FLAG_MODE,
"",
0,
"var",
- DetectBase64Mode::Base64ModeRFC4648,
+ Base64Mode::Base64ModeRFC4648,
DETECT_TRANSFORM_BASE64_FLAG_NBYTES
| DETECT_TRANSFORM_BASE64_FLAG_OFFSET_VAR
| DETECT_TRANSFORM_BASE64_FLAG_OFFSET
"var",
3933,
"",
- DetectBase64Mode::Base64ModeRFC4648,
+ Base64Mode::Base64ModeRFC4648,
DETECT_TRANSFORM_BASE64_FLAG_NBYTES
| DETECT_TRANSFORM_BASE64_FLAG_NBYTES_VAR
| DETECT_TRANSFORM_BASE64_FLAG_OFFSET
* 02110-1301, USA.
*/
-use std::os::raw::c_uchar;
+use crate::utils::base64::{decode_rfc4648, decode_rfc2045, get_decoded_buffer_size, Decoder};
use libc::c_ulong;
+use std::os::raw::c_uchar;
use base64::{Engine, engine::general_purpose::STANDARD};
#[repr(C)]
SC_BASE64_OVERFLOW,
}
+#[repr(C)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum Base64Mode {
+ /* If the following strings were to be passed to the decoder with RFC2045 mode,
+ * the results would be as follows. See the unittest B64TestVectorsRFC2045 in
+ * src/util-base64.c
+ *
+ * BASE64("") = ""
+ * BASE64("f") = "Zg=="
+ * BASE64("fo") = "Zm8="
+ * BASE64("foo") = "Zm9v"
+ * BASE64("foob") = "Zm9vYg=="
+ * BASE64("fooba") = "Zm9vYmE="
+ * BASE64("foobar") = "Zm9vYmFy"
+ * BASE64("foobar") = "Zm 9v Ym Fy" <-- Notice how the spaces are ignored
+ * BASE64("foobar") = "Zm$9vYm.Fy" # According to RFC 2045, All line breaks or *other
+ * characters* not found in base64 alphabet must be ignored by decoding software
+ * */
+ Base64ModeRFC2045 = 0, /* SPs are allowed during transfer but must be skipped by Decoder */
+ Base64ModeStrict,
+ /* If the following strings were to be passed to the decoder with RFC4648 mode,
+ * the results would be as follows. See the unittest B64TestVectorsRFC4648 in
+ * src/util-base64.c
+ *
+ * BASE64("") = ""
+ * BASE64("f") = "Zg=="
+ * BASE64("fo") = "Zm8="
+ * BASE64("foo") = "Zm9v"
+ * BASE64("foob") = "Zm9vYg=="
+ * BASE64("fooba") = "Zm9vYmE="
+ * BASE64("foobar") = "Zm9vYmFy"
+ * BASE64("f") = "Zm 9v Ym Fy" <-- Notice how the processing stops once space is encountered
+ * BASE64("f") = "Zm$9vYm.Fy" <-- Notice how the processing stops once an invalid char is
+ * encountered
+ * */
+ Base64ModeRFC4648, /* reject the encoded data if it contains characters outside the base alphabet */
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Base64DecodeBufferSize(input_len: u32) -> u32 {
+ return get_decoded_buffer_size(input_len);
+}
+
+/// Base64 decode a buffer.
+///
+/// This method exposes the Rust base64 decoder to C and should not be called from
+/// Rust code.
+///
+/// It allows decoding in the modes described by ``Base64Mode`` enum.
+#[no_mangle]
+pub unsafe extern "C" fn Base64Decode(
+ input: *const u8, len: usize, mode: Base64Mode, output: *mut u8) -> u32 {
+ if input.is_null() || len == 0 {
+ return 0;
+ }
+
+ let in_vec = build_slice!(input, len);
+ let out_vec = std::slice::from_raw_parts_mut(output, len);
+ let mut num_decoded: u32 = 0;
+ let mut decoder = Decoder::new();
+ match mode {
+ Base64Mode::Base64ModeRFC2045 => {
+ if decode_rfc2045(&mut decoder, in_vec, out_vec, &mut num_decoded).is_err() {
+ debug_validate_bug_on!(num_decoded >= len as u32);
+ return num_decoded;
+ }
+ }
+ Base64Mode::Base64ModeRFC4648 => {
+ if decode_rfc4648(&mut decoder, in_vec, out_vec, &mut num_decoded).is_err() {
+ debug_validate_bug_on!(num_decoded >= len as u32);
+ return num_decoded;
+ }
+ }
+ Base64Mode::Base64ModeStrict => {
+ if let Ok(decoded_len) = STANDARD.decode_slice(in_vec, out_vec) {
+ num_decoded = decoded_len as u32;
+ }
+ }
+ }
+
+ debug_validate_bug_on!(num_decoded >= len as u32);
+ return num_decoded;
+}
+
/// Base64 encode a buffer.
///
/// This method exposes the Rust base64 encoder to C and should not be called from
pub mod filetracker;
pub mod kerberos;
pub mod detect;
+pub mod utils;
pub mod ja4;
*/
use super::mime;
+use crate::utils::base64;
use crate::core::StreamingBufferConfig;
use crate::filecontainer::FileContainer;
use digest::generic_array::{typenum::U16, GenericArray};
use digest::Update;
use md5::Md5;
use std::ffi::CStr;
-use std::io;
use std::os::raw::c_uchar;
#[repr(u8)]
pub(crate) urls: Vec<Vec<u8>>,
boundaries: Vec<Vec<u8>>,
encoding: MimeSmtpEncoding,
- decoder: Option<MimeBase64Decoder>,
+ decoder: Option<base64::Decoder>,
content_type: MimeSmtpContentType,
decoded_line: Vec<u8>,
// small buffer for end of line
pub(crate) md5_result: GenericArray<u8, U16>,
}
-#[derive(Debug)]
-pub struct MimeBase64Decoder {
- tmp: [u8; 4],
- nb: u8,
-}
-
-impl MimeBase64Decoder {
- pub fn new() -> MimeBase64Decoder {
- MimeBase64Decoder { tmp: [0; 4], nb: 0 }
- }
-}
-
-impl Default for MimeBase64Decoder {
- fn default() -> Self {
- Self::new()
- }
-}
-
pub fn mime_smtp_state_init(
files: &mut FileContainer, sbcfg: *const StreamingBufferConfig,
) -> Option<MimeStateSMTP> {
} else if mime::slice_equals_lowercase(&h.name, b"content-transfer-encoding") {
if mime::slice_equals_lowercase(&h.value, b"base64") {
ctx.encoding = MimeSmtpEncoding::Base64;
- ctx.decoder = Some(MimeBase64Decoder::new());
+ ctx.decoder = Some(base64::Decoder::new());
} else if mime::slice_equals_lowercase(&h.value, b"quoted-printable") {
ctx.encoding = MimeSmtpEncoding::QuotedPrintable;
}
}
}
-fn mime_base64_map(input: u8) -> io::Result<u8> {
- match input {
- 43 => Ok(62), // +
- 47 => Ok(63), // /
- 48 => Ok(52), // 0
- 49 => Ok(53), // 1
- 50 => Ok(54), // 2
- 51 => Ok(55), // 3
- 52 => Ok(56), // 4
- 53 => Ok(57), // 5
- 54 => Ok(58), // 6
- 55 => Ok(59), // 7
- 56 => Ok(60), // 8
- 57 => Ok(61), // 9
- 65 => Ok(0), // A
- 66 => Ok(1), // B
- 67 => Ok(2), // C
- 68 => Ok(3), // D
- 69 => Ok(4), // E
- 70 => Ok(5), // F
- 71 => Ok(6), // G
- 72 => Ok(7), // H
- 73 => Ok(8), // I
- 74 => Ok(9), // J
- 75 => Ok(10), // K
- 76 => Ok(11), // L
- 77 => Ok(12), // M
- 78 => Ok(13), // N
- 79 => Ok(14), // O
- 80 => Ok(15), // P
- 81 => Ok(16), // Q
- 82 => Ok(17), // R
- 83 => Ok(18), // S
- 84 => Ok(19), // T
- 85 => Ok(20), // U
- 86 => Ok(21), // V
- 87 => Ok(22), // W
- 88 => Ok(23), // X
- 89 => Ok(24), // Y
- 90 => Ok(25), // Z
- 97 => Ok(26), // a
- 98 => Ok(27), // b
- 99 => Ok(28), // c
- 100 => Ok(29), // d
- 101 => Ok(30), // e
- 102 => Ok(31), // f
- 103 => Ok(32), // g
- 104 => Ok(33), // h
- 105 => Ok(34), // i
- 106 => Ok(35), // j
- 107 => Ok(36), // k
- 108 => Ok(37), // l
- 109 => Ok(38), // m
- 110 => Ok(39), // n
- 111 => Ok(40), // o
- 112 => Ok(41), // p
- 113 => Ok(42), // q
- 114 => Ok(43), // r
- 115 => Ok(44), // s
- 116 => Ok(45), // t
- 117 => Ok(46), // u
- 118 => Ok(47), // v
- 119 => Ok(48), // w
- 120 => Ok(49), // x
- 121 => Ok(50), // y
- 122 => Ok(51), // z
- _ => Err(io::Error::new(io::ErrorKind::InvalidData, "invalid base64")),
- }
-}
-
-fn mime_base64_decode(decoder: &mut MimeBase64Decoder, input: &[u8]) -> io::Result<Vec<u8>> {
- let mut i = input;
- let maxlen = ((decoder.nb as usize + i.len()) * 3) / 4;
- let mut r = vec![0; maxlen];
- let mut offset = 0;
- while !i.is_empty() {
- while decoder.nb < 4 && !i.is_empty() {
- if mime_base64_map(i[0]).is_ok() || i[0] == b'=' {
- decoder.tmp[decoder.nb as usize] = i[0];
- decoder.nb += 1;
- }
- i = &i[1..];
- }
- if decoder.nb == 4 {
- decoder.tmp[0] = mime_base64_map(decoder.tmp[0])?;
- decoder.tmp[1] = mime_base64_map(decoder.tmp[1])?;
- if decoder.tmp[2] == b'=' {
- r[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
- offset += 1;
- } else {
- decoder.tmp[2] = mime_base64_map(decoder.tmp[2])?;
- if decoder.tmp[3] == b'=' {
- r[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
- r[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
- offset += 2;
- } else {
- decoder.tmp[3] = mime_base64_map(decoder.tmp[3])?;
- r[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
- r[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
- r[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
- offset += 3;
- }
- }
- decoder.nb = 0;
- }
- }
- r.truncate(offset);
- return Ok(r);
-}
-
const MAX_LINE_LEN: u32 = 998; // Def in RFC 2045, excluding CRLF sequence
const MAX_ENC_LINE_LEN: usize = 76; /* Def in RFC 2045, excluding CRLF sequence */
const MAX_HEADER_NAME: usize = 75; /* 75 + ":" = 76 */
for _i in 0..4 - decoder.nb {
v.push(b'=');
}
- if let Ok(dec) = mime_base64_decode(decoder, &v) {
+ let dec_size = base64::get_decoded_buffer_size((decoder.nb as usize + v.len()) as u32);
+ let mut dec = vec![0; dec_size as usize];
+ let mut dec_len = 0;
+ if base64::decode_rfc2045(decoder, &v, &mut dec, &mut dec_len).is_ok() {
unsafe {
FileAppendData(
ctx.files,
ctx.sbcfg,
dec.as_ptr(),
- dec.len() as u32,
+ dec_len,
);
}
}
if i.len() > MAX_ENC_LINE_LEN {
warnings |= MIME_ANOM_LONG_ENC_LINE;
}
- if let Ok(dec) = mime_base64_decode(decoder, i) {
+ let dec_size = base64::get_decoded_buffer_size((decoder.nb as usize + i.len()) as u32);
+ let mut dec = vec![0; dec_size as usize];
+ let mut dec_len = 0; // unnecessary but required by fn args
+ if base64::decode_rfc2045(decoder, i, &mut dec, &mut dec_len).is_ok() {
mime_smtp_find_url_strings(ctx, &dec);
} else {
warnings |= MIME_ANOM_INVALID_BASE64;
if i.len() > MAX_ENC_LINE_LEN {
warnings |= MIME_ANOM_LONG_ENC_LINE;
}
- if let Ok(dec) = mime_base64_decode(decoder, i) {
+ let dec_size = base64::get_decoded_buffer_size((decoder.nb as usize + i.len()) as u32);
+ let mut dec = vec![0; dec_size as usize];
+ let mut dec_len = 0;
+ if base64::decode_rfc2045(decoder, i, &mut dec, &mut dec_len).is_ok() {
mime_smtp_find_url_strings(ctx, &dec);
unsafe {
FileAppendData(
ctx.files,
ctx.sbcfg,
dec.as_ptr(),
- dec.len() as u32,
+ dec_len,
);
}
} else {
--- /dev/null
+/* Copyright (C) 2024 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+// Author: Shivani Bhardwaj <shivani@oisf.net>
+
+use std::io::{Error, ErrorKind, Result};
+
+fn base64_map(input: u8) -> Result<u8> {
+ match input {
+ 43 => Ok(62), // +
+ 47 => Ok(63), // /
+ 48 => Ok(52), // 0
+ 49 => Ok(53), // 1
+ 50 => Ok(54), // 2
+ 51 => Ok(55), // 3
+ 52 => Ok(56), // 4
+ 53 => Ok(57), // 5
+ 54 => Ok(58), // 6
+ 55 => Ok(59), // 7
+ 56 => Ok(60), // 8
+ 57 => Ok(61), // 9
+ 65 => Ok(0), // A
+ 66 => Ok(1), // B
+ 67 => Ok(2), // C
+ 68 => Ok(3), // D
+ 69 => Ok(4), // E
+ 70 => Ok(5), // F
+ 71 => Ok(6), // G
+ 72 => Ok(7), // H
+ 73 => Ok(8), // I
+ 74 => Ok(9), // J
+ 75 => Ok(10), // K
+ 76 => Ok(11), // L
+ 77 => Ok(12), // M
+ 78 => Ok(13), // N
+ 79 => Ok(14), // O
+ 80 => Ok(15), // P
+ 81 => Ok(16), // Q
+ 82 => Ok(17), // R
+ 83 => Ok(18), // S
+ 84 => Ok(19), // T
+ 85 => Ok(20), // U
+ 86 => Ok(21), // V
+ 87 => Ok(22), // W
+ 88 => Ok(23), // X
+ 89 => Ok(24), // Y
+ 90 => Ok(25), // Z
+ 97 => Ok(26), // a
+ 98 => Ok(27), // b
+ 99 => Ok(28), // c
+ 100 => Ok(29), // d
+ 101 => Ok(30), // e
+ 102 => Ok(31), // f
+ 103 => Ok(32), // g
+ 104 => Ok(33), // h
+ 105 => Ok(34), // i
+ 106 => Ok(35), // j
+ 107 => Ok(36), // k
+ 108 => Ok(37), // l
+ 109 => Ok(38), // m
+ 110 => Ok(39), // n
+ 111 => Ok(40), // o
+ 112 => Ok(41), // p
+ 113 => Ok(42), // q
+ 114 => Ok(43), // r
+ 115 => Ok(44), // s
+ 116 => Ok(45), // t
+ 117 => Ok(46), // u
+ 118 => Ok(47), // v
+ 119 => Ok(48), // w
+ 120 => Ok(49), // x
+ 121 => Ok(50), // y
+ 122 => Ok(51), // z
+ _ => Err(Error::new(ErrorKind::InvalidData, "invalid base64")),
+ }
+}
+
+#[derive(Debug)]
+pub struct Decoder {
+ tmp: [u8; 4],
+ pub nb: u8,
+}
+
+impl Decoder {
+ pub fn new() -> Decoder {
+ Decoder { tmp: [0; 4], nb: 0 }
+ }
+}
+
+impl Default for Decoder {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+pub fn get_decoded_buffer_size(encoded_len: u32) -> u32 {
+ return ((encoded_len * 3) + (encoded_len % 4)) / 4;
+}
+
+pub fn decode_rfc4648(decoder: &mut Decoder, input: &[u8], output: &mut [u8], decoded_bytes: &mut u32) -> Result<()>
+{
+ let mut i = input;
+ let mut offset = 0;
+ let mut stop = false;
+ while !i.is_empty() {
+ while decoder.nb < 4 {
+ if !i.is_empty() && (base64_map(i[0]).is_ok() || i[0] == b'=') {
+ decoder.tmp[decoder.nb as usize] = i[0];
+ decoder.nb += 1;
+ } else {
+ while decoder.nb > 0
+ && decoder.nb < 4
+ {
+ decoder.tmp[decoder.nb as usize] = b'=';
+ decoder.nb += 1;
+ }
+ stop = true;
+ break;
+ }
+ i = &i[1..];
+ }
+ if decoder.nb == 4 {
+ decoder.tmp[0] = base64_map(decoder.tmp[0])?;
+ decoder.tmp[1] = base64_map(decoder.tmp[1])?;
+ if decoder.tmp[2] == b'=' {
+ output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
+ offset += 1;
+ } else {
+ decoder.tmp[2] = base64_map(decoder.tmp[2])?;
+ if decoder.tmp[3] == b'=' {
+ output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
+ output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
+ offset += 2;
+ } else {
+ decoder.tmp[3] = base64_map(decoder.tmp[3])?;
+ output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
+ output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
+ output[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
+ offset += 3;
+ }
+ }
+ decoder.nb = 0;
+ }
+ if stop {
+ break;
+ }
+ }
+
+ *decoded_bytes = offset as u32;
+
+ return Ok(());
+}
+
+pub fn decode_rfc2045(decoder: &mut Decoder, input: &[u8], output: &mut [u8], decoded_bytes: &mut u32) -> Result<()>
+{
+ let mut i = input;
+ let mut offset = 0;
+
+ while !i.is_empty() {
+ while decoder.nb < 4 && !i.is_empty() {
+ if base64_map(i[0]).is_ok() || i[0] == b'=' {
+ decoder.tmp[decoder.nb as usize] = i[0];
+ decoder.nb += 1;
+ }
+ i = &i[1..];
+ }
+ if decoder.nb == 4 {
+ decoder.tmp[0] = base64_map(decoder.tmp[0])?;
+ decoder.tmp[1] = base64_map(decoder.tmp[1])?;
+ if decoder.tmp[2] == b'=' {
+ output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
+ offset += 1;
+ } else {
+ decoder.tmp[2] = base64_map(decoder.tmp[2])?;
+ if decoder.tmp[3] == b'=' {
+ output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
+ output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
+ offset += 2;
+ } else {
+ decoder.tmp[3] = base64_map(decoder.tmp[3])?;
+ output[offset] = (decoder.tmp[0] << 2) | (decoder.tmp[1] >> 4);
+ output[offset + 1] = (decoder.tmp[1] << 4) | (decoder.tmp[2] >> 2);
+ output[offset + 2] = (decoder.tmp[2] << 6) | decoder.tmp[3];
+ offset += 3;
+ }
+ }
+ decoder.nb = 0;
+ }
+ }
+ *decoded_bytes = offset as u32;
+
+ return Ok(());
+}
--- /dev/null
+/* Copyright (C) 2024 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+pub mod base64;
util-action.h \
util-affinity.h \
util-atomic.h \
- util-base64.h \
util-bpf.h \
util-buffer.h \
util-byte.h \
util-action.c \
util-affinity.c \
util-atomic.c \
- util-base64.c \
util-bpf.c \
util-buffer.c \
util-byte.c \
-/* Copyright (C) 2017-2019 Open Information Security Foundation
+/* Copyright (C) 2017-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "datasets-md5.h"
#include "util-thash.h"
#include "util-print.h"
-#include "util-base64.h" // decode base64
int Md5StrSet(void *dst, void *src)
{
-/* Copyright (C) 2017-2019 Open Information Security Foundation
+/* Copyright (C) 2017-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "datasets-sha256.h"
#include "util-thash.h"
#include "util-print.h"
-#include "util-base64.h" // decode base64
int Sha256StrSet(void *dst, void *src)
{
-/* Copyright (C) 2017-2019 Open Information Security Foundation
+/* Copyright (C) 2017-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "datasets-string.h"
#include "util-thash.h"
#include "util-print.h"
-#include "util-base64.h" // decode base64
#include "rust.h"
#if 0
#include "util-conf.h"
#include "util-thash.h"
#include "util-print.h"
-#include "util-base64.h" // decode base64
#include "util-byte.h"
#include "util-misc.h"
#include "util-path.h"
if (r == NULL) {
line[strlen(line) - 1] = '\0';
SCLogDebug("line: '%s'", line);
-
+ uint32_t decoded_size = Base64DecodeBufferSize(strlen(line));
// coverity[alloc_strlen : FALSE]
- uint8_t decoded[strlen(line)];
- uint32_t consumed = 0, num_decoded = 0;
- Base64Ecode code = DecodeBase64(decoded, (uint32_t)strlen(line), (const uint8_t *)line,
- (uint32_t)strlen(line), &consumed, &num_decoded, Base64ModeStrict);
- if (code == BASE64_ECODE_ERR) {
+ uint8_t decoded[decoded_size];
+ uint32_t num_decoded =
+ Base64Decode((const uint8_t *)line, strlen(line), Base64ModeStrict, decoded);
+ if (num_decoded == 0 && strlen(line) > 0) {
FatalErrorOnInit("bad base64 encoding %s/%s", set->name, set->load);
continue;
}
*r = '\0';
- // coverity[alloc_strlen : FALSE]
- uint8_t decoded[strlen(line)];
- uint32_t consumed = 0, num_decoded = 0;
- Base64Ecode code = DecodeBase64(decoded, (uint32_t)strlen(line), (const uint8_t *)line,
- (uint32_t)strlen(line), &consumed, &num_decoded, Base64ModeStrict);
- if (code == BASE64_ECODE_ERR) {
+ uint32_t decoded_size = Base64DecodeBufferSize(strlen(line));
+ uint8_t decoded[decoded_size];
+ uint32_t num_decoded =
+ Base64Decode((const uint8_t *)line, strlen(line), Base64ModeStrict, decoded);
+ if (num_decoded == 0) {
FatalErrorOnInit("bad base64 encoding %s/%s", set->name, set->load);
continue;
}
{
if (set == NULL)
return -1;
+ if (strlen(string) == 0)
+ return -1;
switch (set->type) {
case DATASET_TYPE_STRING: {
- // coverity[alloc_strlen : FALSE]
- uint8_t decoded[strlen(string)];
- uint32_t consumed = 0, num_decoded = 0;
- Base64Ecode code =
- DecodeBase64(decoded, (uint32_t)strlen(string), (const uint8_t *)string,
- (uint32_t)strlen(string), &consumed, &num_decoded, Base64ModeStrict);
- if (code == BASE64_ECODE_ERR) {
+ uint32_t decoded_size = Base64DecodeBufferSize(strlen(string));
+ uint8_t decoded[decoded_size];
+ uint32_t num_decoded = Base64Decode(
+ (const uint8_t *)string, strlen(string), Base64ModeStrict, decoded);
+ if (num_decoded == 0) {
return -2;
}
-/* Copyright (C) 2020-2022 Open Information Security Foundation
+/* Copyright (C) 2020-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "detect.h"
#include "detect-parse.h"
#include "detect-base64-decode.h"
-#include "util-base64.h"
#include "util-byte.h"
#include "util-print.h"
#include "detect-engine-build.h"
+#include "rust.h"
/* Arbitrary maximum buffer size for decoded base64 data. */
#define BASE64_DECODE_MAX 65535
decode_len = MIN(payload_len, data->bytes);
+ DEBUG_VALIDATE_BUG_ON(decode_len < 0);
#if 0
printf("Decoding:\n");
PrintRawDataFp(stdout, payload, decode_len);
#endif
- uint32_t consumed = 0, num_decoded = 0;
- (void)DecodeBase64(det_ctx->base64_decoded, det_ctx->base64_decoded_len_max, payload,
- decode_len, &consumed, &num_decoded, Base64ModeRFC4648);
- det_ctx->base64_decoded_len = num_decoded;
- SCLogDebug("Decoded %d bytes from base64 data.",
- det_ctx->base64_decoded_len);
+ if (decode_len > 0) {
+ uint32_t num_decoded =
+ Base64Decode(payload, decode_len, Base64ModeRFC4648, det_ctx->base64_decoded);
+ det_ctx->base64_decoded_len = num_decoded;
+ SCLogDebug("Decoded %d bytes from base64 data.", det_ctx->base64_decoded_len);
+ }
#if 0
if (det_ctx->base64_decoded_len) {
printf("Decoded data:\n");
#include "detect-transform-base64.h"
-#include "util-base64.h"
#include "util-unittest.h"
#include "util-print.h"
SCDetectTransformFromBase64Data *b64d = options;
const uint8_t *input = buffer->inspect;
const uint32_t input_len = buffer->inspect_len;
- /*
- * The output buffer is larger than needed. On average,
- * a base64 encoded string is 75% of the encoded
- * string.
- */
- uint8_t output[input_len];
uint32_t decode_length = input_len;
- DetectBase64Mode mode = b64d->mode;
+ Base64Mode mode = b64d->mode;
uint32_t offset = b64d->offset;
uint32_t nbytes = b64d->nbytes;
decode_length = nbytes;
}
- // PrintRawDataFp(stdout, input, input_len);
- uint32_t decoded_length = 0;
- uint32_t consumed = 0;
- Base64Ecode code =
- DecodeBase64(output, input_len, input, decode_length, &consumed, &decoded_length, mode);
- if (code != BASE64_ECODE_ERR) {
- // PrintRawDataFp(stdout, output, decoded_length);
- if (decoded_length) {
- InspectionBufferCopy(buffer, output, decoded_length);
- }
+ uint32_t decoded_size = Base64DecodeBufferSize(decode_length);
+ uint8_t decoded[decoded_size];
+ uint32_t num_decoded = Base64Decode((const uint8_t *)input, decode_length, mode, decoded);
+ if (num_decoded > 0) {
+ // PrintRawDataFp(stdout, output, b64data->decoded_len);
+ InspectionBufferCopy(buffer, decoded, num_decoded);
}
}
-/* Copyright (C) 2013-2022 Open Information Security Foundation
+/* Copyright (C) 2013-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "util-memcmp.h"
#include "util-misc.h"
#include "util-signal.h"
-#include "util-base64.h"
#include "reputation.h"
#include "util-atomic.h"
ThreadMacrosRegisterTests();
UtilSpmSearchRegistertests();
UtilActionRegisterTests();
- Base64RegisterTests();
SCClassConfRegisterTests();
SCThresholdConfRegisterTests();
SCRConfRegisterTests();
#include "suricata-common.h"
#include "suricata.h"
-#include "util-base64.h"
+#include "rust.h"
#define BLK_SIZE 2
static int initialized = 0;
-static void Base64FuzzTest(const uint8_t *src, size_t len, size_t dest_size)
+static void Base64FuzzTest(const uint8_t *src, size_t len)
{
- uint8_t *dest = malloc(dest_size);
- if (dest == NULL)
- return;
+ uint32_t decoded_len = Base64DecodeBufferSize(len);
+ uint8_t *decoded = SCCalloc(decoded_len, sizeof(uint8_t));
- for (uint8_t mode = Base64ModeRelax; mode <= Base64ModeRFC4648; mode++) {
- uint32_t consumed_bytes = 0;
- uint32_t decoded_bytes = 0;
-
- DecodeBase64(dest, dest_size, src, len, &consumed_bytes, &decoded_bytes, mode);
+ for (uint8_t mode = Base64ModeRFC2045; mode <= Base64ModeStrict; mode++) {
+ (void)Base64Decode(src, len, mode, decoded);
}
- free(dest);
+ SCFree(decoded);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (size < BLK_SIZE)
return 0;
- uint32_t dest_size = (uint32_t)(data[0] << 8) | (uint32_t)(data[1]);
- Base64FuzzTest(data + BLK_SIZE, size - BLK_SIZE, dest_size);
+ Base64FuzzTest(data, size);
return 0;
}
+++ /dev/null
-/* Copyright (C) 2007-2024 Open Information Security Foundation
- *
- * You can copy, redistribute or modify this Program under the terms of
- * the GNU General Public License version 2 as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-/**
- * \file
- *
- * \author David Abarbanel <david.abarbanel@baesystems.com>
- *
- */
-
-#include "util-base64.h"
-#include "util-debug.h"
-#include "util-validate.h"
-#include "util-unittest.h"
-/* Constants */
-#define BASE64_TABLE_MAX 122
-
-/* Base64 character to index conversion table */
-/* Characters are mapped as "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */
-static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
- -1, -1, -1, -1, -1, 0, 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, -1, -1, -1, -1, -1, -1, 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 };
-
-/**
- * \brief Gets a base64-decoded value from an encoded character
- *
- * \param c The encoded character
- *
- * \return The decoded value (0 or above), or -1 if the parameter is invalid
- */
-static inline int GetBase64Value(uint8_t c)
-{
- int val = -1;
-
- /* Pull from conversion table */
- if (c <= BASE64_TABLE_MAX) {
- val = b64table[(int) c];
- }
-
- return val;
-}
-
-/**
- * \brief Checks if the given char in a byte array is Base64 alphabet
- *
- * \param Char that needs to be checked
- *
- * \return True if the char was Base64 alphabet, False otherwise
- */
-bool IsBase64Alphabet(uint8_t encoded_byte)
-{
- if (GetBase64Value(encoded_byte) < 0 && encoded_byte != '=') {
- return false;
- }
- return true;
-}
-
-/**
- * \brief Decodes a 4-byte base64-encoded block into a 3-byte ascii-encoded block
- *
- * \param ascii the 3-byte ascii output block
- * \param b64 the 4-byte base64 input block
- *
- * \return none
- */
-static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK])
-{
- ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4);
- ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2);
- ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]);
-}
-
-/**
- * \brief Decode a base64 encoded string as per RFC 2045.
- * RFC 2045 states that any characters that do not fall under the Base64
- * alphabet must be skipped by the decoding software.
- * Following are some important considerations:
- * 1. This Decoding algorithm is used by MIME parser currently.
- * 2. The number of decoded bytes are constrained by the destination buffer size.
- * 3. The leftover bytes are not handled by the decoder but the caller.
- *
- * \param dest destination buffer
- * \param dest_size destination buffer size
- * \param src base64 encoded string
- * \param len length of the base64 encoded string
- * \param consumed_bytes number of bytes successfully consumed by the decoder
- * \param decoded_bytes number of bytes successfully decoded by the decoder
- *
- * \return Base64Ecode BASE64_ECODE_OK if all went well
- * BASE64_ECODE_BUF if destination buffer got full before all could be decoded
- */
-static inline Base64Ecode DecodeBase64RFC2045(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
- uint32_t len, uint32_t *consumed_bytes, uint32_t *decoded_bytes)
-{
- int val;
- uint32_t padding = 0, bbidx = 0, non_b64_chars = 0;
- uint8_t *dptr = dest;
- uint8_t b64[B64_BLOCK] = { 0, 0, 0, 0 };
-
- for (uint32_t i = 0; i < len; i++) {
- val = GetBase64Value(src[i]);
- if (val < 0) {
- if (src[i] != '=') {
- non_b64_chars++;
- continue;
- } else {
- padding++;
- }
- }
-
- /* For each alpha-numeric letter in the source array, find the numeric value */
- b64[bbidx++] = val > 0 ? (uint8_t)val : 0;
-
- /* Decode every 4 base64 bytes into 3 ascii bytes */
- if (bbidx == B64_BLOCK) {
- /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */
- uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK);
- if (dest_size - *decoded_bytes < ASCII_BLOCK)
- return BASE64_ECODE_BUF;
- /* Decode base-64 block into ascii block and move pointer */
- DecodeBase64Block(dptr, b64);
- dptr += numDecoded_blk;
- *decoded_bytes += numDecoded_blk;
- /* Reset base-64 block and index */
- bbidx = 0;
- padding = 0;
- *consumed_bytes += B64_BLOCK + non_b64_chars;
- non_b64_chars = 0;
- memset(&b64, 0, sizeof(b64));
- }
- }
-
- DEBUG_VALIDATE_BUG_ON(*consumed_bytes > len);
- DEBUG_VALIDATE_BUG_ON(bbidx == B64_BLOCK);
- /* Any leftover bytes must be handled by the caller */
- return BASE64_ECODE_OK;
-}
-
-/**
- * \brief Decode a base64 encoded string as per RFC 4648.
- * RFC 4648 states that if a character is encountered that does not fall under
- * the Base64 alphabet, the decoding software should stop processing the string further.
- * Following are some important considerations:
- * 1. This Decoding algorithm is used by base64_decode keyword currently.
- * 2. This Decoding algorithm in strict mode is used by datasets currently.
- * 3. The number of decoded bytes are constrained by the destination buffer size.
- * 4. The leftover bytes are handled by the decoder.
- *
- * \param dest destination buffer
- * \param dest_size destination buffer size
- * \param src base64 encoded string
- * \param len length of the base64 encoded string
- * \param consumed_bytes number of bytes successfully consumed by the decoder
- * \param decoded_bytes number of bytes successfully decoded by the decoder
- * \param strict whether an invalid base64 encoding should be strictly rejected
- *
- * \return Base64Ecode BASE64_ECODE_OK if all went well
- * BASE64_ECODE_BUF if destination buffer got full before all could be decoded
- * BASE64_ECODE_ERR if an invalid char was found in strict mode or nothing was
- * decoded
- */
-static inline Base64Ecode DecodeBase64RFC4648(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
- uint32_t len, uint32_t *consumed_bytes, uint32_t *decoded_bytes, bool strict)
-{
- int val;
- uint32_t padding = 0, bbidx = 0;
- uint8_t *dptr = dest;
- uint8_t b64[B64_BLOCK] = { 0, 0, 0, 0 };
-
- for (uint32_t i = 0; i < len; i++) {
- val = GetBase64Value(src[i]);
- if (val < 0) {
- if (src[i] != '=') {
- if (strict) {
- *decoded_bytes = 0;
- return BASE64_ECODE_ERR;
- }
- break;
- }
- padding++;
- }
- /* For each alpha-numeric letter in the source array, find the numeric value */
- b64[bbidx++] = (val > 0 ? (uint8_t)val : 0);
-
- /* Decode every 4 base64 bytes into 3 ascii bytes */
- if (bbidx == B64_BLOCK) {
- /* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */
- uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK);
- if (dest_size - *decoded_bytes < ASCII_BLOCK)
- return BASE64_ECODE_BUF;
-
- /* Decode base-64 block into ascii block and move pointer */
- DecodeBase64Block(dptr, b64);
- dptr += numDecoded_blk;
- *decoded_bytes += numDecoded_blk;
- /* Reset base-64 block and index */
- bbidx = 0;
- padding = 0;
- *consumed_bytes += B64_BLOCK;
- memset(&b64, 0, sizeof(b64));
- }
- }
-
- DEBUG_VALIDATE_BUG_ON(bbidx == B64_BLOCK);
-
- /* Handle any leftover bytes by adding padding to them as long as they do not
- * violate the destination buffer size */
- if (bbidx > 0) {
- /*
- * --------------------
- * | bbidx | padding |
- * --------------------
- * | 1 | 2 |
- * | 2 | 2 |
- * | 3 | 1 |
- * --------------------
- * Note: Padding for 1 byte is set to 2 to have at least one
- * decoded byte while calculating numDecoded_blk
- * This does not affect the decoding as the b64 array is already
- * populated with all padding bytes unless overwritten.
- * */
- padding = bbidx > 1 ? B64_BLOCK - bbidx : 2;
- uint32_t numDecoded_blk = ASCII_BLOCK - padding;
- if (dest_size - *decoded_bytes < ASCII_BLOCK)
- return BASE64_ECODE_BUF;
- /* Decode base-64 block into ascii block and move pointer */
- DecodeBase64Block(dptr, b64);
- *decoded_bytes += numDecoded_blk;
- /* Consumed bytes should not have the padding bytes added by us */
- *consumed_bytes += bbidx;
- }
- if (*decoded_bytes == 0)
- return BASE64_ECODE_ERR;
-
- DEBUG_VALIDATE_BUG_ON(*consumed_bytes > len);
- return BASE64_ECODE_OK;
-}
-
-/**
- * \brief Decodes a base64-encoded string buffer into an ascii-encoded byte buffer
- *
- * \param dest The destination byte buffer
- * \param dest_size The destination byte buffer size
- * \param src The source string
- * \param len The length of the source string
- * \param consumed_bytes The bytes that were actually processed/consumed
- * \param decoded_bytes The bytes that were decoded
- * \param mode The mode in which decoding should happen
- *
- * \return Error code indicating success or failures with parsing
- */
-Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len,
- uint32_t *consumed_bytes, uint32_t *decoded_bytes, DetectBase64Mode mode)
-{
- *decoded_bytes = 0;
- Base64Ecode ret = BASE64_ECODE_OK;
- switch (mode) {
- case Base64ModeRFC4648:
- ret = DecodeBase64RFC4648(
- dest, dest_size, src, len, consumed_bytes, decoded_bytes, false);
- break;
- case Base64ModeRFC2045:
- ret = DecodeBase64RFC2045(dest, dest_size, src, len, consumed_bytes, decoded_bytes);
- break;
- case Base64ModeStrict:
- ret = DecodeBase64RFC4648(
- dest, dest_size, src, len, consumed_bytes, decoded_bytes, true);
- break;
- default:
- return BASE64_ECODE_ERR;
- }
- return ret;
-}
-
-#ifdef UNITTESTS
-
-#define TEST_RFC2045(src, fin_str, dest_size, exp_decoded, exp_consumed, ecode) \
- { \
- uint32_t consumed_bytes = 0, num_decoded = 0; \
- uint8_t dst[dest_size]; \
- Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \
- &consumed_bytes, &num_decoded, Base64ModeRFC2045); \
- FAIL_IF(code != ecode); \
- FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \
- FAIL_IF(num_decoded != exp_decoded); \
- FAIL_IF(consumed_bytes != exp_consumed); \
- }
-
-#define TEST_RFC4648(src, fin_str, dest_size, exp_decoded, exp_consumed, ecode) \
- { \
- uint32_t consumed_bytes = 0, num_decoded = 0; \
- uint8_t dst[dest_size]; \
- Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \
- &consumed_bytes, &num_decoded, Base64ModeRFC4648); \
- FAIL_IF(code != ecode); \
- FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \
- FAIL_IF(num_decoded != exp_decoded); \
- FAIL_IF(consumed_bytes != exp_consumed); \
- }
-
-static int B64DecodeCompleteString(void)
-{
- /*
- * SGVsbG8gV29ybGR6 : Hello Worldz
- * */
- const char *src = "SGVsbG8gV29ybGR6";
- const char *fin_str = "Hello Worldz";
- TEST_RFC2045(src, fin_str, 12, 12, 16, BASE64_ECODE_OK);
- PASS;
-}
-
-static int B64DecodeInCompleteString(void)
-{
- /*
- * SGVsbG8gV29ybGR6 : Hello Worldz
- * */
- const char *src = "SGVsbG8gV29ybGR";
- const char *fin_str = "Hello Wor";
- TEST_RFC2045(src, fin_str, 9, 9, 12, BASE64_ECODE_OK);
- PASS;
-}
-
-static int B64DecodeCompleteStringWSp(void)
-{
- /*
- * SGVsbG8gV29ybGQ= : Hello World
- * */
-
- const char *src = "SGVs bG8 gV29y bGQ=";
- const char *fin_str = "Hello World";
- TEST_RFC2045(src, fin_str, 14, 11, 19, BASE64_ECODE_OK);
- PASS;
-}
-
-static int B64DecodeInCompleteStringWSp(void)
-{
- /*
- * SGVsbG8gV29ybGQ= : Hello World
- * Special handling for this case (sp in remainder) done in ProcessBase64Remainder
- * */
-
- const char *src = "SGVs bG8 gV29y bGQ";
- const char *fin_str = "Hello Wor";
- TEST_RFC2045(src, fin_str, 9, 9, 14, BASE64_ECODE_OK);
- PASS;
-}
-
-static int B64DecodeStringBiggerThanBuffer(void)
-{
- /*
- * SGVsbG8gV29ybGQ= : Hello World
- * */
-
- const char *src = "SGVs bG8 gV29y bGQ=";
- const char *fin_str = "Hello Wor";
- TEST_RFC2045(src, fin_str, 10, 9, 14, BASE64_ECODE_BUF);
- PASS;
-}
-
-static int B64DecodeStringEndingSpaces(void)
-{
- const char *src = "0YPhA d H";
- uint32_t consumed_bytes = 0, num_decoded = 0;
- uint8_t dst[10];
- Base64Ecode code = DecodeBase64(dst, sizeof(dst), (const uint8_t *)src, 9, &consumed_bytes,
- &num_decoded, Base64ModeRFC2045);
- FAIL_IF(code != BASE64_ECODE_OK);
- FAIL_IF(num_decoded != 3);
- FAIL_IF(consumed_bytes != 4);
- PASS;
-}
-
-static int B64TestVectorsRFC2045(void)
-{
- const char *src1 = "";
- const char *fin_str1 = "";
-
- const char *src2 = "Zg==";
- const char *fin_str2 = "f";
-
- const char *src3 = "Zm8=";
- const char *fin_str3 = "fo";
-
- const char *src4 = "Zm9v";
- const char *fin_str4 = "foo";
-
- const char *src5 = "Zm9vYg==";
- const char *fin_str5 = "foob";
-
- const char *src6 = "Zm9vYmE=";
- const char *fin_str6 = "fooba";
-
- const char *src7 = "Zm9vYmFy";
- const char *fin_str7 = "foobar";
-
- const char *src8 = "Zm 9v Ym Fy";
- const char *fin_str8 = "foobar";
-
- const char *src9 = "Zm$9vYm.Fy";
- const char *fin_str9 = "foobar";
-
- const char *src10 = "Y21Wd2IzSjBaVzFoYVd4bWNtRjFaRUJoZEc4dVoyOTJMbUYxOmpqcHh4b3Rhb2w%5";
- const char *fin_str10 = "cmVwb3J0ZW1haWxmcmF1ZEBhdG8uZ292LmF1:jjpxxotaol9";
-
- const char *src11 = "Zm 9v Ym Fy 7fy";
- const char *fin_str11 = "foobar";
-
- TEST_RFC2045(src1, fin_str1, ASCII_BLOCK * 2, strlen(fin_str1), strlen(src1), BASE64_ECODE_OK);
- TEST_RFC2045(src2, fin_str2, ASCII_BLOCK * 2, strlen(fin_str2), strlen(src2), BASE64_ECODE_OK);
- TEST_RFC2045(src3, fin_str3, ASCII_BLOCK * 2, strlen(fin_str3), strlen(src3), BASE64_ECODE_OK);
- TEST_RFC2045(src4, fin_str4, ASCII_BLOCK * 2, strlen(fin_str4), strlen(src4), BASE64_ECODE_OK);
- TEST_RFC2045(src5, fin_str5, ASCII_BLOCK * 2, strlen(fin_str5), strlen(src5), BASE64_ECODE_OK);
- TEST_RFC2045(src6, fin_str6, ASCII_BLOCK * 2, strlen(fin_str6), strlen(src6), BASE64_ECODE_OK);
- TEST_RFC2045(src7, fin_str7, ASCII_BLOCK * 2, strlen(fin_str7), strlen(src7), BASE64_ECODE_OK);
- TEST_RFC2045(src8, fin_str8, ASCII_BLOCK * 2, strlen(fin_str8), strlen(src8), BASE64_ECODE_OK);
- TEST_RFC2045(src9, fin_str9, ASCII_BLOCK * 2, strlen(fin_str9), strlen(src9), BASE64_ECODE_OK);
- TEST_RFC2045(src10, fin_str10, 50, 48, 65, BASE64_ECODE_OK);
- TEST_RFC2045(src11, fin_str11, ASCII_BLOCK * 2, 6, 11, BASE64_ECODE_OK);
- PASS;
-}
-
-static int B64TestVectorsRFC4648(void)
-{
- const char *src1 = "";
- const char *fin_str1 = "";
-
- const char *src2 = "Zg==";
- const char *fin_str2 = "f";
-
- const char *src3 = "Zm8=";
- const char *fin_str3 = "fo";
-
- const char *src4 = "Zm9v";
- const char *fin_str4 = "foo";
-
- const char *src5 = "Zm9vYg==";
- const char *fin_str5 = "foob";
-
- const char *src6 = "Zm9vYmE=";
- const char *fin_str6 = "fooba";
-
- const char *src7 = "Zm9vYmFy";
- const char *fin_str7 = "foobar";
-
- const char *src8 = "Zm 9v Ym Fy";
- const char *fin_str8 = "f";
-
- const char *src9 = "Zm$9vYm.Fy";
- const char *fin_str9 = "f";
-
- const char *src10 = "Y21Wd2IzSjBaVzFoYVd4bWNtRjFaRUJoZEc4dVoyOTJMbUYxOmpqcHh4b3Rhb2w%3D";
- const char *fin_str10 = "cmVwb3J0ZW1haWxmcmF1ZEBhdG8uZ292LmF1:jjpxxotaol";
-
- const char *src11 = "Zm9vYg==";
- const char *fin_str11 = "foo";
-
- TEST_RFC4648(src1, fin_str1, ASCII_BLOCK * 2, strlen(fin_str1), strlen(src1), BASE64_ECODE_ERR);
- TEST_RFC4648(src2, fin_str2, ASCII_BLOCK * 2, strlen(fin_str2), strlen(src2), BASE64_ECODE_OK);
- TEST_RFC4648(src3, fin_str3, ASCII_BLOCK * 2, strlen(fin_str3), strlen(src3), BASE64_ECODE_OK);
- TEST_RFC4648(src4, fin_str4, ASCII_BLOCK * 2, strlen(fin_str4), strlen(src4), BASE64_ECODE_OK);
- TEST_RFC4648(src5, fin_str5, ASCII_BLOCK * 2, strlen(fin_str5), strlen(src5), BASE64_ECODE_OK);
- TEST_RFC4648(src6, fin_str6, ASCII_BLOCK * 2, strlen(fin_str6), strlen(src6), BASE64_ECODE_OK);
- TEST_RFC4648(src7, fin_str7, ASCII_BLOCK * 2, strlen(fin_str7), strlen(src7), BASE64_ECODE_OK);
- TEST_RFC4648(src8, fin_str8, ASCII_BLOCK * 2, 1 /* f */, 2 /* Zm */, BASE64_ECODE_OK);
- TEST_RFC4648(src9, fin_str9, ASCII_BLOCK * 2, 1 /* f */, 2 /* Zm */, BASE64_ECODE_OK);
- TEST_RFC4648(src10, fin_str10, 48, 47, 63, BASE64_ECODE_OK);
- TEST_RFC4648(src11, fin_str11, 3, 3, 4, BASE64_ECODE_BUF);
- PASS;
-}
-
-void Base64RegisterTests(void)
-{
- UtRegisterTest("B64DecodeCompleteStringWSp", B64DecodeCompleteStringWSp);
- UtRegisterTest("B64DecodeInCompleteStringWSp", B64DecodeInCompleteStringWSp);
- UtRegisterTest("B64DecodeCompleteString", B64DecodeCompleteString);
- UtRegisterTest("B64DecodeInCompleteString", B64DecodeInCompleteString);
- UtRegisterTest("B64DecodeStringBiggerThanBuffer", B64DecodeStringBiggerThanBuffer);
- UtRegisterTest("B64DecodeStringEndingSpaces", B64DecodeStringEndingSpaces);
- UtRegisterTest("B64TestVectorsRFC2045", B64TestVectorsRFC2045);
- UtRegisterTest("B64TestVectorsRFC4648", B64TestVectorsRFC4648);
-}
-#endif
+++ /dev/null
-/* Copyright (C) 2007-2012 Open Information Security Foundation
- *
- * You can copy, redistribute or modify this Program under the terms of
- * the GNU General Public License version 2 as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-/**
- * \file
- *
- * \author David Abarbanel <david.abarbanel@baesystems.com>
- *
- */
-
-#ifndef SURICATA_UTIL_BASE64_H_
-#define SURICATA_UTIL_BASE64_H_
-
-#include "suricata-common.h"
-#include "rust.h"
-
-/* Constants */
-#define ASCII_BLOCK 3
-#define B64_BLOCK 4
-
-typedef enum {
- BASE64_ECODE_ERR = -1,
- BASE64_ECODE_OK = 0,
- BASE64_ECODE_BUF,
-} Base64Ecode;
-
-/* Function prototypes */
-Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len,
- uint32_t *consumed_bytes, uint32_t *decoded_bytes, DetectBase64Mode mode);
-bool IsBase64Alphabet(uint8_t encoded_byte);
-
-#endif
-
-#ifdef UNITTESTS
-void Base64RegisterTests(void);
-#endif