7
\$\begingroup\$

I've created this C++ random password generator. You can set length, you can enable custom symbols. Then I went to this website: http://www.passwordmeter.com/ and started checking some generated passwords of mine.

Based on the formula here, I've created a simplified version of their grading system, and also created a function for it. Now I can just do password_score(generated_password) and set a limit for the security of my password.

Here are some examples and how my program performs:

###
Generated password strength: 100/100
Password has been copied to clipboard!
### 1a,pA!T0c0&7 (PasswordMeter score: 100%)

###
Generated password strength: 100/100
Password has been copied to clipboard!
### 82F^Vh11Gl}1 (PasswordMeter score: 100%)

###
Generated password strength: 98/100
Password has been copied to clipboard!
### !3V44'w1 (PasswordMeter score: 100%)

###
Generated password strength: 64/100
Password has been copied to clipboard!
### $]1V9q (PasswordMeter score: 70%)

Am I doing it right? I know that there's always some room for improvement. I'll take any advice to make it better. Thanks!

string password_generator(const int length_of_password = 12, bool enable_symbols = false, bool copy_to_clipboard = false)
{
    vector<char> password;
    srand (static_cast<unsigned int>(time(nullptr)));

    //generates lowercase letters
    for(auto c = 1; c <= length_of_password; c = c + 4)
    {
        const auto v1 = rand() % 26;
        password.push_back(v1 + 'a');
    }

    //generates uppercase letters
    for(auto g = 3; g <= length_of_password; g = g + 4)
    {
        const auto v2 = rand() % 26;
        password.push_back(v2 + 'A');
    }

    //generates numbers
    for(auto k = 0; k <= length_of_password; k = k + 2)
    {
        const auto v3 = rand() % 10;
        password.push_back(v3 + '0');
    }

    if(enable_symbols)
    {
        //generates symbols
        for(auto g = 1; g <= length_of_password; g = g + 4)
        {
            const auto choice = rand() % 3;

            if(choice == 0)
            {
                const auto v4 = rand() % 14;
                password.push_back(v4 + '!');
            }

            if(choice == 1)
            {
                const auto v5 = rand() % 5;
                password.push_back(v5 + '[');
            }

            if(choice == 2)
            {
                const auto v6 = rand() % 4;
                password.push_back(v6 + '{');
            }
        }
    }

    random_device r;
    shuffle(password.begin(), password.end(), default_random_engine(r()));

    string returning_password;

    for(auto i = 0; i < length_of_password; i++)
    {
        returning_password.push_back(password[i]);
    }

    if(copy_to_clipboard)
        to_clipboard(returning_password);

    return returning_password;
}

Edit:

Here's a main file: (I've just started learning to work with argvs to there might be some mistakes.) (Most of the functions in this program are something I've created -made easier-, they're custom. I strongly recommend checking bottom GitHub link first.)

#include <duman.h>
using namespace std;

int main(const int argc, char* argv[])
{
    cerr << "###\n";
    if(argc > 1 && argc <= 2)
    {
        if(string(argv[1]) == "-h")
        {
            cerr << "Usage  : " << get_file_name(argv[0]) << " -<Password_Length> -<Minimum_Password_Security_Score out of 100>\n";
            cerr << "Example: " << get_file_name(argv[0]) << " -12 -80\n\n";
            cerr << "Password will be automatically copied to your clipboard!\n";
            cerr << "###\n";
            return 1;
        }
        if(string(argv[1]) == "-v")
        {
            cerr << "Version: 1.3.0\n";
            cerr << "###\n";
            return 2;
        }
        if(string(argv[1]) == "-length" || string(argv[1]) == "-l")
        {
            cerr << "Try to use the command as:\n";
            cerr << get_file_name(argv[0]) << " -8 -98 # for a password that has length of 8 and security score of minimum 98\n";
            cerr << "###\n";
            return 2;
        }
    }
    if(argc > 2 && argc <= 3)
    {
        string raw_argument1 = argv[1];
        string raw_argument2 = argv[2];
        if(isalpha(raw_argument1[1]) || isalpha(raw_argument2[1]))
        {
            cerr << "Invalid parameters! Use -h to see how to use this program.\n";
            cerr << "###\n";
            return 1;
        }
        if(raw_argument1[0] != '-')
        {
            cerr << "Did you mean: " << get_file_name(argv[0]) << " -" << argv[1] << " " << raw_argument2 << " # missing dash before an argument!\n";
            cerr << "###\n";
            return 1;
        }
        if(raw_argument2[0] != '-')
        {
            cerr << "Did you mean: " << get_file_name(argv[0]) << " " << raw_argument1 << " -" << argv[2] << " # missing dash before an argument!\n";
            cerr << "###\n";
            return 1;
        }
        if(string(argv[1]).empty() || string(argv[2]).empty())
        {
            cerr << "Missing parameters! Use -h to see how to use this program!\n";
            cerr << "###\n";
            return 1;
        }
        raw_argument1.erase(raw_argument1.begin());
        raw_argument2.erase(raw_argument2.begin());
        const auto first_argument = stoi(raw_argument1);
        const auto second_argument = stoi(raw_argument2);
        auto seconds_since_start = 0;

        const auto start = time(nullptr);
        auto generated_password = password_generator(first_argument, true, true);

        while(password_score(generated_password) < second_argument)
        {
            if(password_score(generated_password) >= second_argument)
            {
                break;
            }
            generated_password = password_generator(first_argument, true, true);
            seconds_since_start += static_cast<int>(difftime(time(nullptr), start));
            if(seconds_since_start > 50)
            {
                cerr << "Request timed out. Couldn't generate a password with the given parameters.\n";
                cerr << "###\n";
                return 1;
            }
        }
        cerr << "Generated password strength: " << password_score(generated_password) << "/100\n";
        cerr << "Password has been copied to clipboard!\n";
        cerr << "###\n";
        return 0;
    }
    if(argc > 3)
    {
        cerr << "Unsupported number of parameters!\n";
        return 1;
    }
    cerr << "Commands:\n";
    cerr << "1. " << get_file_name(argv[0]) << " -length -security_level # Security level is XYZ out of 100\n";
    cerr << "2. " << get_file_name(argv[0]) << " -h\n";
    cerr << "3. " << get_file_name(argv[0]) << " -v\n";
    cerr << "###\n";
}

duman.h is a header file I've created for myself. So, whenever I solve a problem in someway I turn it into a function and save it in that header. You can reach it here: https://github.com/duman/duman.h

As I've written in readme, the solutions inside of that file are not the greatest. Pardon for my mistakes already.

\$\endgroup\$
5
\$\begingroup\$

Advice 1

The most important issue with your password generator function is the fact that you keep creating the character vector over and over again. I suggest you roll a class that has that character vector as a field and construct it only once:

class password_generator {
public:
    password_generator() {
        ... // Construct your alphabet.
    }

private:
    std::vector<char> m_alphabet;
};

Advice 2

if(choice == 0)
{
    ...
}

if(choice == 1)
{
    ...
}

Just use switch here:

switch (rand() % 2) {
    case 0:
        ...
    case 1:
        ...
    case 2:
        ...
}

Advice 3

#include "stdafx.h": In the build settings of Visual Studio, search something like "Use precompiled headers"; set to No. This will remove the need for including that header file.

Advice 4

#include <duman.h>: this won't compile on Xcode. The convention is that you use <header> for standard C++ library headers, and "header.h" for your own header files.

Advice 5

using namespace std; This one is a poor practice since it abuses your scope with bunch of identifiers/type names. Use instead:

#include "funky.hpp"
using funky::person;
using funky::darth_vader;

Advice 6

In your main driver you output to cerr. This is not what is expected of a command line program. *nix like OS'es has two "handles" one for standard output and one for standard error stream. Your conventional *nix guru will expect normal output to cout and only error stuff to cerr.

\$\endgroup\$
  • \$\begingroup\$ 1. Great suggestion! Will do now. 2. Is it better performance wise? 3. That thing was annoying thanks. 4. Oh... didn't know that. I just put the file inside INCLUDE folders of Visual Studio and using it from there. 5. Well... alright. 6. I thought since cerr doesn't have any buffers it could give faster output. Obviously cout is there to "out"put. \$\endgroup\$ – Tuğberk Kaan Duman Jan 5 '18 at 20:36
  • \$\begingroup\$ @TuğberkKaanDuman 2.: Most definitely. When there is a match, other two values will not be tested. Also, I believe that for very large switch statement, the compiler may perform binary search over case values. \$\endgroup\$ – coderodde Jan 5 '18 at 20:53
2
\$\begingroup\$

Just a word on password strength: the string '$]1V9q' should not get rated 70% safe. It shouldn't even be rated any percentage safe, because it's a very weak password. Length is the decisive factor in password strength and should weigh far more strongly than other element. Even though the website is originally at fault here for using an inaccurate algorithm, you should avoid making the same mistake!

Also, please use <random>.

\$\endgroup\$
  • \$\begingroup\$ It was checked against passwordmeter.com if you read the post. Then again my library uses it -> github.com/duman/duman.h/blob/master/duman.h thanks for answering 1 year old question though. :) \$\endgroup\$ – Tuğberk Kaan Duman Jun 3 at 13:39
  • \$\begingroup\$ I know it was, my point is that the website itself uses a nonsensical algorithm and you should be wary of copying anything without checking the source when you're working on cryptographic systems. \$\endgroup\$ – Daniel Jun 3 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.