sts10 / tidy

Combine and clean word lists

Home Page:https://sts10.github.io/2021/12/09/tidy-0-2-0.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Review/audit security of passphrase sample

sts10 opened this issue · comments

Tidy offers the option for users to generate 5 6-word passphrase samples from its newly created list (--samples).

Here is that rather convuluted function:

use rand::seq::SliceRandom;
/// Print 5 sample 6-word passphrases from the newly created
/// word list.
pub fn generate_samples(
    list: &[String],
    ignore_ending_metadata_delimiter: Option<char>,
    ignore_starting_metadata_delimiter: Option<char>,
) -> Vec<String> {
    let mut samples: Vec<String> = vec![];
    for _n in 0..30 {
        match list.choose(&mut rand::thread_rng()) {
            Some(word) => {
                match (
                    ignore_ending_metadata_delimiter,
                    ignore_starting_metadata_delimiter,
                ) {
                    (Some(delimiter), None) => {
                        let delimiter = parse_delimiter(delimiter).unwrap();
                        samples
                            .push(split_and_vectorize(word, &delimiter.to_string())[0].to_string())
                    }
                    (None, Some(delimiter)) => {
                        let delimiter = parse_delimiter(delimiter).unwrap();
                        samples
                            .push(split_and_vectorize(word, &delimiter.to_string())[1].to_string())
                    }
                    (Some(_delimiter1), Some(_delimiter2)) => {
                        panic!("Can't have starting and ending delimiters")
                    }

                    (None, None) => samples.push(word.to_string()),
                }
            }
            None => panic!("Couldn't pick a random word"),
        }
    }
    samples
}

While I do not intend for Tidy users to use these generated sample passphrases as actual passphrases, I was wondering if there's anything we can do in the code to make these passphrases more cryptographically secure.

I've refactored this code a bit by splitting it into two functions:

use rand::seq::SliceRandom;
/// Print 5 sample 6-word passphrases from the newly created
/// word list.
pub fn generate_samples(
    list: &[String],
    ignore_ending_metadata_delimiter: Option<char>,
    ignore_starting_metadata_delimiter: Option<char>,
) -> Vec<String> {
    let mut samples: Vec<String> = vec![];
    for _n in 0..30 {
        match list.choose(&mut rand::thread_rng()) {
            Some(word) => samples.push(clean_word_of_metadata_using_delimiter(
                word,
                ignore_ending_metadata_delimiter,
                ignore_starting_metadata_delimiter,
            )),
            None => panic!("Couldn't pick a random word"),
        }
    }
    samples
}

/// Removes "metadata" from word, as specified by ending or starting
/// delimiter
fn clean_word_of_metadata_using_delimiter(
    word: &str,
    ignore_ending_metadata_delimiter: Option<char>,
    ignore_starting_metadata_delimiter: Option<char>,
) -> String {
    match (
        ignore_ending_metadata_delimiter,
        ignore_starting_metadata_delimiter,
    ) {
        (Some(delimiter), None) => {
            let delimiter = parse_delimiter(delimiter).unwrap();
            split_and_vectorize(word, &delimiter.to_string())[1].to_string()
        }
        (None, Some(delimiter)) => {
            let delimiter = parse_delimiter(delimiter).unwrap();
            split_and_vectorize(word, &delimiter.to_string())[0].to_string()
        }
        (Some(_delimiter1), Some(_delimiter2)) => {
            panic!("Can't have starting and ending delimiters")
        }

        (None, None) => word.to_string(),
    }
}
commented

While I do not intend for Tidy users to use these generated sample passphrases as actual passphrases, I was wondering if there's anything we can do in the code to make these passphrases more cryptographically secure.

As far as I can tell, the security of the passphrases in this case hinges on 2 things:

  1. rand::thread_rng()
  2. The size word list itself

The first one you're relying on a library that would be fairly catastrophic for the ecosystem if it was broken, the second one is variable, but you could add some warnings along the lines of

Warning: passphrase has an entropy below n bits

But yeah, it would be pretty funny for someone to use tidy as their passphrase generator 😉

The size word list itself

At one point I thought about having it print words until each passphrase was, say, 70 bits of entropy or more. So for a 7,776-word list, it'd print 6 words per sample, but for a short, 1,296-word list, it'd print 7 words per sample.

Pros: Would add a visual illustration of the importance/effect of list length. Cons: Forces me to choose an acceptable level of entropy. Plus it's a bit complex/out-of-scope code-wise. And it might encourage users to use Tidy's samples as a passphrase generator....