1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/*! # mkpasswd - Library and command-line tool to generate passwords ## Command line tool Install the command line tool with `cargo install mkpasswd`. You can then use the `mkpasswd` command, run it with `--help` to get more information. ## Library The library exposes only a few functions dedicated to random password generation. - If you want it simple and can risk panics, use the [`mkpasswd`] function. If you want more control and error handling, use [`generate`] and [`generate_with_rng`]. These functions take an alphabet, which is a set of characters that the password may contain. - The most control is offered by [`generate_with_rng`], because it uses an external random number generator. You should this if you want to generate multiple passwords. [`mkpasswd`]: fn.mkpasswd.html [`generate`]: fn.generate.html [`generate_with_rng`]: fn.generate_with_rng.html */ pub extern crate rand_core; pub mod alphabets; mod default; pub use {alphabets::Password, default::mkpasswd}; use rand_core::{CryptoRng, Error, OsRng, RngCore}; /// Generates a `length` long password made of bytes from `alphabet`. /// /// This function uses the cryptographically secure [`OsRng`] internally. /// /// Also see [`generate_with_rng`] for more information. /// /// # Errors /// /// See the [error section of `generate_with_rng`]. /// /// # Example /// /// ``` /// use mkpasswd::{generate, Password}; /// /// let password = generate(&Password, 10).unwrap(); /// // `Password` contains only valid UTF-8 characters /// let password = String::from_utf8(password).unwrap(); /// /// assert_eq!(password.len(), 10); /// /// println!("Your password: {}", password); /// ``` /// /// [`OsRng`]: https://docs.rs/rand_os/0.2.1/rand_os/struct.OsRng.html /// [`generate_with_rng`]: fn.generate_with_rng.html /// [error section of `generate_with_rng`]: fn.generate_with_rng.html#errors #[inline] pub fn generate(alphabet: &[u8], length: usize) -> Result<Vec<u8>, Error> { generate_with_rng(alphabet, length, &mut OsRng) } /// Generates a `length` long password made of bytes from `alphabet` /// using random data provided by `rng`. /// /// If the input alphabet only contains valid UTF-8 bytes, this function /// is guaranteed to only return valid UTF-8 as well. /// /// # Example /// /// This example is using a custom alphabet as well. /// /// ``` /// use mkpasswd::generate_with_rng; /// use rand_core::OsRng; /// /// let alphabet = b"qwerty+asdfgh-zxcvbn"; /// let mut rng = OsRng; /// let password = generate_with_rng(alphabet, 16, &mut rng).unwrap(); /// /// assert_eq!(password.len(), 16); /// ``` /// /// It is recommended to sanitize the alphabet before, removing duplicate values: /// /// ``` /// let mut my_alphabet = b"Hello world!".to_vec(); /// /// my_alphabet.sort(); /// my_alphabet.dedup(); /// /// // 'l' and 'o' is only once in the buffer now /// assert_eq!(my_alphabet, b" !Hdelorw"); /// ``` /// /// # Errors /// /// This functions returns an error if `rng` fails to generate random data. /// /// If `alphabet.len()` is `0`, this functions panics. pub fn generate_with_rng<R>(alphabet: &[u8], length: usize, rng: &mut R) -> Result<Vec<u8>, Error> where R: RngCore + CryptoRng, { assert!(!alphabet.is_empty(), "The alphabet may not be empty"); if length == 0 { return Ok(Vec::new()); }; let mut buf = Vec::with_capacity(length); while buf.len() < length { let bytes = rng.next_u64().to_ne_bytes(); for i in bytes.iter() { if alphabet.contains(i) { buf.push(*i); }; } } unsafe { // Drop excess bytes buf.set_len(length); }; Ok(buf) }