Hipass is a CLI (Command Line Interface) Password Generator that generates random, strong passwords. The intent of the project is to generate passwords in a fast, concise way and copy them directly into the clipboard, without having to rely on internet services.
Passwords must be strong and unique to each service you're using. This way, attackers will have a harder time guessing your passwords, or even "brute forcing" the services you can potentially have an account. By having strong and random passwords, it is less likely that an attacker can try combinations with information they have about you, such as birth date, names of your family members or even the name of your dog.
That's why password generators comes in handy. They can create strong, unique, random passwords each time they're prompted. They can output uppercase A-Z, lowercase a-z, special characters and numbers to be as random as possible so they are difficult for an attacker to remember, as well as extremely difficult to brute force.
Since, according to NIST (as cited by Gary Orenstein, from Bitwarden) the "Password length has been found to be a primary factor in characterizing password strength" I've capped the minimum value of generating a password with a minimum of 14 characters length. With that, it's possible to generate password that would take at least a century to crack.
Password managers, period. Also, it's recommended that you keep a very strong password for that too, with a separate e-mail to login. Usually a 2FA is also recommended for "further improvement on security", but for a password manager this is pratically mandatory for obvious reasons. You can use offline or online solutions for that. My top 3 recommendations are: BitWarden, Kaspersky and Proton Pass. Of course they also offer robust password generators, but if you want an offline, fast solution, you can recursively use Hipass.
- To see how to build the project, please take a look at the developer documentation and follow the Build Manual.
- To see how we style our code, please refer to the Code Style Guide
./hipass [--flag] [f]
*no flags* User will be prompted to choose character length of a random password with
A-Z uppercase, a-z lowercase, numbers and special characters
The following arguments will generate passwords with the ones user had selected.
Example: ./hipass AZ num sym az
AZ Include A to Z uppercase characters
az Include a to z lowercase characters
sym Include special symbols (!@#^&*$)
num Include digits from 0 to 9
The following arguments can be passed as flags:
--h --help Print out help text
--v --version Print version
--prefix PREFIX Generate password with a desired prefix
--sufix SUFIX Generate password with a desired sufix
-p --passphrase 'sep' Generate passphrase with a desired char separator and a random number in the end
hipass --passphrase '-'
Can output:
▘▗ Hipass Password Generator
Separator -
Type in number of words (between 3 and 20): 5
rollback-toothpicks-snowstorms-mercury-ledger-866
Do you want to copy the password to the clipboard? (y/n): y
Password copied to clipboard.
Generating random characters and random numbers based on a seed of time such as srand(time(NULL))
and rand()
may lead to several password exploits. A simple example of this is that seeding a random
generator with time(NULL)
and calling generate_password
twice in main()
will generate the same password twice. This means that seeding with time(NULL)
will not generate milisecond time and will not use any kernel processes of the user's computer (adding solely GETPID in the equation won't help much either). Writing random number generators with specific design is a non-trivial task, being not only an exercise, but also a huge research topic on its own.
Initially, this password generator was using this set of functions written by Jonathan Leffler. His random seed generation uses the widespread /dev/random
and /dev/urandom
devices as a cryptographically secure pseudorandom number generator with rand48
seeding.
Although this solution was satisfactory enough for the scope of this project, C++ has more variety of random seed generation algorithms to choose from and consequently algorithms that have more bits of entropy and better uniform distributions, such as the mt19937. The stock device
from the C++'s random library is known for not having the need of being non-deterministic (i.e. being truly random in runtime, as opposed from compile time, meaning it could generate the same number in every run for some systems). For the aforementioned reasons, this password generator uses the randutils.hpp
C++ random number generator API by Melissa E. O'Neill, carefully explained in her blog, pcg-random.org
The random number generator is defined in the rand.cpp
file, integrated with the C code via the C++ ABI (Application Binary Interface), called by the generator.c
file:
rand.cpp:
//----------------------------------------------------------------------------
// Random number generator that implements the randutils auto_seed_256 seed engine.
// More information on the seed engine in
// https://www.pcg-random.org/posts/simple-portable-cpp-seed-entropy.html
int random_nr(int min, int max)
{
std::uniform_int_distribution dist{min, max};
static std::mt19937 engine{randutils::auto_seed_256{}.base()};
return dist(engine);
}
- Further reading: https://www.pcg-random.org/
Generating passphrases is a great feature for password generators because they are hard enough for computers to guess (given it hass a significant amount of entropy), but easy for humans to remember or write. Passphrases are usually a set of "non-sensical" or "barely-sensical" words attached together by separators with the bonus of having a number somewhere.
To feed the "randomness" aspect of a passphrase, there are many wordlist dictionaries such as the EFF wordlist that contain rare words, nonsensical words and unusual names. Each word is picked using the diceware, meaning one can roll a dice six times to pick a random word from the list.
As imaginable, coming up with a wordlist is also a topic of study on its own, given wordlists usually include 7,000 to 40,000 words each, and may have different rulesets to make words possible to remember and yet difficult to crack.
This passphrase generator uses the sts10's ud2.txt wordlist
, "a uniquely decodable list, based on Google Ngram data and Niceware v. 4.0 list. It is free of some common homophones and British spellings of certain words". It was selected for this project because it has 40,000 uniquely decodable words, creating 15.288 bits of entropy per word.
- Further reading:
- information on how to make a wordlist in this post from sts10.
- sts10 methodology on wordlist generation here.
Since this project is now using the C++ ABI, generating and allocating memory for a passphrase — in order to copy it to the clipboard — is easier than doing it manually in C, given we now have the std::string
class to work with, therefore using the append(str)
function to keep appending words and separators into the string and pass it as a const char* password
to the clipboard.
// Select words from the dictionary using the random_nr(min, max) function and append to string.
for (uint i = 0; i < wordcount; i++)
{
password.append(word[random_nr(0, 0xABCDEF) % word.size()]);
password.append(sep);
}
password.append(number);
...
copy_to_clipboard_prompt(password.c_str());
Further on, randomizing the selected wordlist dictionary for each word used in the passphrase generation could also make it more efficient against dictionary brute force attacks. This could be achieved by making a dictionaries index list and randomizing the index to select which dictionary will be loaded to pick a random word from. It is definately an insteresting exercise to understand if this would give more entropy for passphrase generation. Additionally, mixing wordlist dictionaries with fictional words dictionaries, such as randomly generated made-up words can have a potential benefit in helping even further to avoid the aforementioned dictionary brute-force attacks.
Making an efficient random password/passphrase generator is not a very trivial task as it might seem if you care for security and true random number generators. Achieving true randomness to pick characters or words in a list is a difficult task that can be a topic of extensive research to understand different methods and behaviors for unpredictability, specially for password generation.
Hopefully, understanding such methods can be very beneficial in order to comprehend different tasks and applications they might be used, such as simulation and statistics. For the scope of this project I was only able to scratch the surface in this huge topic, but researching different libraries of PRNG and studying their intricacies was a very enriching experience.
This project uses GNU GENERAL PUBLIC LICENSE 3.0.