Password generator for Rust

The console application development process will consist of several stages:

  1. Formation of the password structure.

  2. Development of a password generation function.

  3. Creating functions for checking passwords and combining them into one.

  4. Allowing for user input.

  5. Formation of a function for generating a verified password.

1. Formation of the password structure.

The password is a combination of characters and their number. It can use the following symbols:

  1. Lowercase and uppercase letters of the Latin alphabet (A, a, B, b, C, c, etc.).

  2. Numbers (0, 1, 2, etc.).

  3. Special characters (@, !, _, etc.).

Let's create a module in which the structure will be stored and place it there.

pub struct PasswordStructure {
    pub long: usize,
    pub register_up: u8,
    pub register_low: u8,
    pub numbers: u8,
    pub special_char: u8,
}

2. Development of a password generation function.

To create a password, we need to add the allowed characters to the string. To do this, we will use the IteratorRandom module from the rand library. We will also need a string to which we will add characters. Let's create a mutable password variable, with pre-allocated space for storing characters. The with_capacity() method will help us with this. To create a password of a given length, we will use a while loop that will run until the password length is equal to the specified length. While the loop is running, we will take a random symbol from the previously prepared symbolss string and add it to the password string.

fn creating_password(long: usize) -> String {
    let mut rng = rand::thread_rng();
    let symbolss = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%&*;:?_-";
    let mut password = String::with_capacity(long);

    while password.len() != long {
        password.push(symbolss.chars().choose(&mut rng).unwrap());

    }
    password

}

3. Creating functions for checking passwords and combining them into one.

We are creating an application that generates a password based on specified criteria:

  1. Length.

  2. The number of lowercase and capital letters.

  3. Number of digits.

  4. The number of special characters.

To create it correctly, we will need to implement checks. Each function created will return true if the test succeeds and false if it fails.

  1. Password length.

    The function takes the specified length and the generated password.

    To check the password length, we will compare the number of characters in the received password with the required number of characters. In fact, this check is not needed, but implementing an additional function would not hurt.

fn checking_length(long: usize, password: &str) -> bool {
    if password.len() == long {
        return true;
    }
    false

}
  1. Lowercase and capital letters.

    The function takes the password length, the number of small and capital letters, and the generated password.

    We will create two variables in which we will record the number of lowercase and uppercase letters in the generated password. Let's go through the entire password using a for loop. Using the is_ascii_uppercase(), is_ascii_lowercase() and as_bytes() methods we will check each ASCII code of each character. Then we compare the created variables with variables storing the number of small and capital letters.

fn checking_register(long: usize, register_up: u8, register_low: u8, password: &str) -> bool {
    let mut capital_letters_up = 0;
    let mut capital_letters_low = 0;
    for i in 0..long {
        if password.as_bytes()[i].is_ascii_uppercase() {
            capital_letters_up += 1;
        }
        if password.as_bytes()[i].is_ascii_lowercase(){
            capital_letters_low += 1;
        }
    }
    (capital_letters_up >= register_up) && (capital_letters_low >= register_low)
      
}
  1. Number of digits.

    The function takes the length, number of digits and the generated password.

    Checking numbers will be similar to checking letters. Let's create a variable that counts numbers. We organize a for loop based on the length of the passed password. Let's go through all the characters and add one to our created variable every time the character code matches the ASCII digit code. The methods is_ascii_digit() and as_bytes() will help you look for them. Next, compare the resulting value with the required number of digits.

fn checking_numbers(long: usize,numbers: u8, password: &str) -> bool {
    let mut quantity_numbers = 0;
    for i in 0..long{
        if password.as_bytes()[i].is_ascii_digit() {
            quantity_numbers += 1;
        }
    }
    quantity_numbers >= numbers 
  
}
  1. Specialist. symbols.

    The function takes the number of special characters and the generated password.

    Let's create a variable that counts specials. symbols. We organize the for loop in such a way that the ASCII character number is written to the loop variable i. Using match, we will compare the codes of allowed special characters with the code of the current character; if at least one character matches, we will increase the value of the variable by one. At the end, as usual, compare the found number of characters with the required number.

fn checking_special_char(special_char: u8, password: &str) -> bool {
    let mut quantity_special_char = 0;
    for i in password.as_bytes() {
        match i {
            b'!' | b'@' | b'#' | b'$' | b'%' | 
            b'&' | b'*' | b';' | b':' | 
            b'?' | b'_' | b'-' => quantity_special_char += 1,
            _ => (),
        }
    }
    quantity_special_char >= special_char

}

After implementing all the checks, we will collect them into one small function that announces true or false depending on the results of all checks.

fn password_verification(long: usize, register_up: u8, register_low: u8, numbers: u8, special_char: u8, password: &str) -> bool {
    matches!((checking_length(long, password), checking_register(long, register_up, register_low, password), checking_numbers(long, numbers, password), checking_special_char(special_char, password)), (true, true, true, true))

}

4. Enable user input.

Now we need a function that will provide criteria for generating a password. To begin with, using the created structure, we will create functions that return structures with specified fields. They will be stored in the same module as the mother structure.

pub fn vk() -> PasswordStructure {
    let long: usize = 8;
    let register_up: u8 = 1;
    let register_low: u8 = 1;
    let numbers: u8 = 1;
    let special_char: u8 = 1;
    PasswordStructure {long, register_up, register_low, numbers, special_char}
}

pub fn ok() -> PasswordStructure {
    let long: usize = 12;
    let register_up: u8 = 1;
    let register_low: u8 = 1;
    let numbers: u8 = 1;
    let special_char: u8 = 1;
    PasswordStructure {long, register_up, register_low, numbers, special_char}
}

pub fn default() -> PasswordStructure {
    let long: usize = 15;
    let register_up: u8 = 1;
    let register_low: u8 = 1;
    let numbers: u8 = 1;
    let special_char: u8 = 1;
    PasswordStructure {long, register_up, register_low, numbers, special_char}
}

Let's set up user input. The person using the program must choose which password he wants to generate. At the moment, passwords for VK, OK and default values ​​are presented.

fn sites_standards() -> Option<(usize, u8, u8, u8, u8)> {

    let mut site_name = String::new();

    println!("\nВыбирете сайт, для которого хотите сгенерировать пароль(введите цифру): \n1. VK \n2. OK \n3. Стандартный пароль\n");

    let _ = io::stdin().read_line( &mut site_name);

        match site_name.as_str().trim() {
            "1" => Some((vk().long, vk().register_up, vk().register_low, vk().numbers, vk().special_char)),
            "2" => Some((ok().long, vk().register_up, ok().register_low, ok().numbers, ok().special_char)),
            "3" => Some((default().long, default().register_up, default().register_low, default().numbers, default().special_char)),
            _ => {
                println!("\n{}Вы ввели неверное значение! Мы создадим пароль по дефольтным значениям.\n", color::Fg(color::Red));
                Some((default().long, default().register_up, default().register_low, default().numbers, default().special_char))
            } 
    }

}

This function will return the values ​​that are in the user-selected structure.

3. Formation of a function for generating a verified password.

Once we have implemented all the necessary functions, it's time to combine them. We'll create a variable that takes a tuple from the password criteria function. Next, using match, we will process the values ​​​​passed to the variable. Inside match we will create the password and verification variables. In password we will write the created password, and in verification the result of checking the password. Then we will create a while loop that will run until verification becomes true. Until this point, we will overwrite the password variable, generating new passwords. The result of executing the function will be a correctly generated password.

fn verified_password() -> Option<String> {    
    let site_values = sites_standards();
    match site_values {
        Some((long, register_up, register_low, numbers, special_char)) => {

            let mut password = creating_password(long);
            let mut verification = password_verification(long, register_up, register_low, numbers, special_char, &password.clone());
            if !verification {
                while  !verification {
                    password = creating_password(long);
                    verification = password_verification(long, register_up, register_low, numbers, special_char, &password.clone());        
                }
            }
            Some(password)

        }
        None => None,
        
    }

}

All that remains is to display the password nicely in the main() function.

fn main() {
    let password: Option<_> =  verified_password();
    match password {
        Some(password) => println!("{}Ваш пароль: {}", color::Fg(color::Green), password),
        None => println!("{}!!!ОШИБКА!!!", color::Fg(color::Red)),
    }

}

Conclusion

We have created a simple console program in Rust that quickly and accurately generates a password based on the given values.

I left a lot of room for further development. For example, you can implement the ability to manually enter password criteria or create a web application based on the logic of this code. If anyone does or has already done something similar, please share in the comments.

Link to full code

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *