]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
base64: expose no padding and padding optional variants
authorJason Ish <jason.ish@oisf.net>
Thu, 30 Jan 2025 16:49:37 +0000 (10:49 -0600)
committerVictor Julien <victor@inliniac.net>
Thu, 13 Feb 2025 18:21:05 +0000 (19:21 +0100)
A no padding option is provided as a mode, as its a variant suitable
for encoding and decoding.

A padding optional function is added that is indifferent to padding
when decoding. This can be useful when you're not sure if padding
exists, and don't really care.

rust/src/ffi/base64.rs

index 8b07c5fadc1c472e02f20a1abf686c604b2edbdc..711ca19e108e0efe9c58ade0a8440a7d9846edaf 100644 (file)
  * 02110-1301, USA.
  */
 
-use crate::utils::base64::{decode_rfc4648, decode_rfc2045, get_decoded_buffer_size, Decoder};
+use crate::utils::base64::{decode_rfc2045, decode_rfc4648, get_decoded_buffer_size, Decoder};
+use base64::{
+    engine::general_purpose::{STANDARD, STANDARD_NO_PAD},
+    Engine,
+};
 use libc::c_ulong;
 use std::os::raw::c_uchar;
-use base64::{Engine, engine::general_purpose::STANDARD};
 
 #[repr(C)]
 #[allow(non_camel_case_types)]
@@ -64,6 +67,12 @@ pub enum SCBase64Mode {
      * encountered
      * */
     SCBase64ModeRFC4648, /* reject the encoded data if it contains characters outside the base alphabet */
+
+    /// Standard base64 without padding, and strict about it.
+    SCBase64ModeNoPad,
+
+    /// Standard base64 with optional padding: decode only.
+    SCBase64ModePadOpt,
 }
 
 #[no_mangle]
@@ -79,7 +88,8 @@ pub unsafe extern "C" fn SCBase64DecodeBufferSize(input_len: u32) -> u32 {
 /// It allows decoding in the modes described by ``SCBase64Mode`` enum.
 #[no_mangle]
 pub unsafe extern "C" fn SCBase64Decode(
-    input: *const u8, len: usize, mode: SCBase64Mode, output: *mut u8) -> u32 {
+    input: *const u8, len: usize, mode: SCBase64Mode, output: *mut u8,
+) -> u32 {
     if input.is_null() || len == 0 {
         return 0;
     }
@@ -106,13 +116,26 @@ pub unsafe extern "C" fn SCBase64Decode(
                 num_decoded = decoded_len as u32;
             }
         }
+        SCBase64Mode::SCBase64ModeNoPad => {
+            if let Ok(decoded_len) = STANDARD_NO_PAD.decode_slice(in_vec, out_vec) {
+                num_decoded = decoded_len as u32;
+            }
+        }
+        SCBase64Mode::SCBase64ModePadOpt => {
+            let config = base64::engine::GeneralPurposeConfig::new()
+                .with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent);
+            let decoder = base64::engine::GeneralPurpose::new(&base64::alphabet::STANDARD, config);
+            if let Ok(decoded_len) = decoder.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.
+/// Base64 encode a buffer with a provided mode.
 ///
 /// This method exposes the Rust base64 encoder to C and should not be called from
 /// Rust code.
@@ -121,14 +144,18 @@ pub unsafe extern "C" fn SCBase64Decode(
 /// from SCBase64EncodeBufferSize for the input_len, and this length must be provided
 /// in the output_len variable.
 #[no_mangle]
-pub unsafe extern "C" fn SCBase64Encode(
+pub unsafe extern "C" fn SCBase64EncodeWithMode(
     input: *const u8, input_len: c_ulong, output: *mut c_uchar, output_len: *mut c_ulong,
+    mode: SCBase64Mode,
 ) -> SCBase64ReturnCode {
     if input.is_null() || output.is_null() || output_len.is_null() {
         return SCBase64ReturnCode::SC_BASE64_INVALID_ARG;
     }
     let input = std::slice::from_raw_parts(input, input_len as usize);
-    let encoded = STANDARD.encode(input);
+    let encoded = match mode {
+        SCBase64Mode::SCBase64ModeNoPad => STANDARD_NO_PAD.encode(input),
+        _ => STANDARD.encode(input),
+    };
     if encoded.len() + 1 > *output_len as usize {
         return SCBase64ReturnCode::SC_BASE64_OVERFLOW;
     }
@@ -139,6 +166,27 @@ pub unsafe extern "C" fn SCBase64Encode(
     SCBase64ReturnCode::SC_BASE64_OK
 }
 
+/// Base64 encode a buffer.
+///
+/// This method exposes the Rust base64 encoder to C and should not be called from
+/// Rust code.
+///
+/// The output parameter must be an allocated buffer of at least the size returned
+/// from SCBase64EncodeBufferSize for the input_len, and this length must be provided
+/// in the output_len variable.
+#[no_mangle]
+pub unsafe extern "C" fn SCBase64Encode(
+    input: *const u8, input_len: c_ulong, output: *mut c_uchar, output_len: *mut c_ulong,
+) -> SCBase64ReturnCode {
+    SCBase64EncodeWithMode(
+        input,
+        input_len,
+        output,
+        output_len,
+        SCBase64Mode::SCBase64ModeStrict,
+    )
+}
+
 /// Ratio of output bytes to input bytes for Base64 Encoding is 4:3, hence the
 /// required output bytes are 4 * ceil(input_len / 3) and an additional byte for
 /// storing the NULL pointer.