Skip to content

Commit ffddabe

Browse files
authored
Add support for utf16 and wide modifiers (#18)
fix #17
1 parent 81b8579 commit ffddabe

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

src/error.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ pub enum ParserError {
1010
)]
1111
Utf16WithoutBase64,
1212

13-
#[error(
14-
"The modifier '{0}' is ambiguous and therefore unsupported; use utf16le or utf16be instead"
15-
)]
16-
AmbiguousUtf16Modifier(String),
17-
1813
#[error("No values provided for field '{0}'")]
1914
EmptyValues(String),
2015

src/field/modifier.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ pub enum MatchModifier {
2121
pub enum Utf16Modifier {
2222
Utf16le,
2323
Utf16be,
24+
Utf16,
25+
Wide,
2426
}
2527

2628
#[derive(Debug, PartialEq, Display, EnumString)]
@@ -48,7 +50,8 @@ impl FromStr for Utf16Modifier {
4850
match s.to_lowercase().as_str() {
4951
"utf16le" => Ok(Utf16Modifier::Utf16le),
5052
"utf16be" => Ok(Utf16Modifier::Utf16be),
51-
"utf16" | "wide" => Err(ParserError::AmbiguousUtf16Modifier(s.to_string())),
53+
"utf16" => Ok(Utf16Modifier::Utf16),
54+
"wide" => Ok(Utf16Modifier::Wide),
5255
_ => Err(ParserError::UnknownModifier(s.to_string())),
5356
}
5457
}
@@ -177,12 +180,6 @@ mod test {
177180
assert!(matches!(err, ParserError::ConflictingModifiers(_, _)));
178181
}
179182

180-
#[test]
181-
fn test_ambiguous_utf16_modifier() {
182-
let err = Modifier::from_str("hello|base64offset|utf16").unwrap_err();
183-
assert!(matches!(err, ParserError::AmbiguousUtf16Modifier(ref a) if a == "utf16"));
184-
}
185-
186183
#[test]
187184
fn test_conflicting_utf16_modifiers() {
188185
let err = Modifier::from_str("test|base64offset|utf16le|contains|utf16be").unwrap_err();

src/field/transformation.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::collections::HashMap;
55

66
pub fn encode_base64(input: &FieldValue, utf16modifier: &Option<Utf16Modifier>) -> String {
77
let mut encoded = match utf16modifier {
8-
Some(Utf16Modifier::Utf16le) => STANDARD_NO_PAD.encode(
8+
Some(Utf16Modifier::Utf16le | Utf16Modifier::Wide) => STANDARD_NO_PAD.encode(
99
input
1010
.value_to_string()
1111
.encode_utf16()
@@ -19,6 +19,16 @@ pub fn encode_base64(input: &FieldValue, utf16modifier: &Option<Utf16Modifier>)
1919
.flat_map(|x| x.to_be_bytes())
2020
.collect::<Vec<u8>>(),
2121
),
22+
Some(Utf16Modifier::Utf16) => {
23+
let mut bytes = vec![0xFF, 0xFE];
24+
bytes.extend(
25+
input
26+
.value_to_string()
27+
.encode_utf16()
28+
.flat_map(|x| x.to_le_bytes()),
29+
);
30+
STANDARD_NO_PAD.encode(bytes)
31+
}
2232
None => STANDARD_NO_PAD.encode(input.value_to_string()),
2333
};
2434
if encoded.len() % 4 == 2 || encoded.len() % 4 == 3 {
@@ -36,7 +46,7 @@ pub fn encode_base64_offset(
3646
let mut encoded = vec![];
3747

3848
let char_width = match utf16modifier {
39-
Some(Utf16Modifier::Utf16be) | Some(Utf16Modifier::Utf16le) => 2,
49+
Some(_) => 2,
4050
None => 1,
4151
};
4252

@@ -151,6 +161,37 @@ mod tests {
151161
assert_eq!(encode_base64(&input, &Some(Utf16Modifier::Utf16be)), "");
152162
}
153163

164+
#[test]
165+
fn test_base64_sub_modifiers_docs_example() {
166+
// https://github.com/SigmaHQ/sigma-specification/blob/main/appendix/sigma-modifiers-appendix.md#encoding
167+
168+
let input = FieldValue::from("cmd");
169+
170+
// utf16le: Transforms value to UTF16-LE encoding, e.g. cmd > 63 00 6d 00 64 00
171+
assert_eq!(
172+
encode_base64(&input, &Some(Utf16Modifier::Utf16le)),
173+
"YwBtAGQA"
174+
);
175+
176+
// utf16be: Transforms value to UTF16-BE encoding, e.g. cmd > 00 63 00 6d 00 64
177+
assert_eq!(
178+
encode_base64(&input, &Some(Utf16Modifier::Utf16be)),
179+
"AGMAbQBk"
180+
);
181+
182+
// utf16: Prepends a byte order mark and encodes UTF16, e.g. cmd > FF FE 63 00 6d 00 64 00
183+
assert_eq!(
184+
encode_base64(&input, &Some(Utf16Modifier::Utf16)),
185+
"//5jAG0AZA"
186+
);
187+
188+
// wide: an alias for the utf16le modifier.
189+
assert_eq!(
190+
encode_base64(&input, &Some(Utf16Modifier::Wide)),
191+
"YwBtAGQA"
192+
);
193+
}
194+
154195
#[test]
155196
fn test_base64_offset_bash() {
156197
let encoded = encode_base64_offset(&FieldValue::from("/bin/bash"), &None);

0 commit comments

Comments
 (0)