Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/_docs/user-guide/eldritch.md
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,11 @@ The random library is designed to enable generation of cryptogrphically secure r

The <b>random.bool</b> method returns a randomly sourced boolean value.

### random.string

`random.string(length: uint, charset: Optional<str>) -> str`
The <b>random.string</b> method returns a randomly generated string of the specified length. If `charset` is not provided defaults to [Alphanumeric](https://docs.rs/rand_distr/latest/rand_distr/struct.Alphanumeric.html). Warning, the string is stored entirely in memory so exceptionally large files (multiple megabytes) can lead to performance issues.

---

## Regex
Expand Down
6 changes: 6 additions & 0 deletions implants/lib/eldritch/src/random/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod bool_impl;
mod string_impl;

use starlark::{environment::MethodsBuilder, starlark_module, values::starlark_value};

Expand All @@ -19,4 +20,9 @@ fn methods(builder: &mut MethodsBuilder) {
fn bool<'v>(this: &RandomLibrary) -> anyhow::Result<bool> {
bool_impl::bool()
}

#[allow(unused_variables)]
fn string<'v>(this: &RandomLibrary, length: u64, charset: Option<String>) -> anyhow::Result<String> {
string_impl::string(length, charset)
}
}
69 changes: 69 additions & 0 deletions implants/lib/eldritch/src/random/string_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use anyhow::Result;
use rand::distributions::{Alphanumeric, Uniform, DistString, Distribution};

pub fn string(length: u64, charset_opt: Option<String>) -> Result<String> {
match charset_opt {
Some(charset) => {
let strlen = charset.chars().count().into();
let rand_dist = Uniform::from(0..strlen);
let mut rng = rand::thread_rng();
let mut s = "".to_string();
for _ in 0..length {
let index = rand_dist.sample(&mut rng);
s.push(charset.chars().nth(index).unwrap());
};
return Ok(s);
},
None => {
let s = Alphanumeric.sample_string(&mut rand::thread_rng(), length as usize);
return Ok(s);
}
}
}

#[cfg(test)]
mod tests {
use super::*;

const NUM_ITERATION: i32 = 1000000;

#[test]
fn test_string() -> anyhow::Result<()> {
let rand_string = string(5, None)?;
assert_eq!(rand_string.chars().count(), 5);
Ok(())
}

#[test]
fn test_string_charset() -> anyhow::Result<()> {
let rand_string = string(5, Some("a".to_string()))?;
assert_eq!(rand_string.chars().count(), 5);
assert_eq!(rand_string, "aaaaa");
Ok(())
}

#[test]
fn test_string_uniform() -> anyhow::Result<()> {
use std::collections::HashSet;

let mut result_str = HashSet::new();
for _ in 0..=NUM_ITERATION {
let new_str = string(16, None)?;
assert_eq!(new_str.chars().count(), 16);
if !result_str.insert(new_str){
assert!(false);
}
}
Ok(())
}

#[test]
fn test_string_length() -> anyhow::Result<()> {
for i in [0, 1000, 8192000] {
println!("Testing string length {}", i);
let new_str = string(i as u64, None)?;
assert_eq!(new_str.chars().count(), i as usize);
}
Ok(())
}
}
2 changes: 1 addition & 1 deletion implants/lib/eldritch/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ mod tests {
parameters: HashMap::new(),
file_names: Vec::new(),
},
want_text: format!("{}\n", r#"["bool"]"#),
want_text: format!("{}\n", r#"["bool", "string"]"#),
want_error: None,
},
report_bindings: TestCase {
Expand Down