Password verification with special characters

Jun 15, 2017 at 11:11pm
Hello, I have written a code for class that stats that i need to take a string of passwords and run them through a driver to make sure they are valid passwords. in order to be valid they must
Contain upper and lowercase letters
At least one number
and one of the following special characters.
# $ % & ! ? @
The issue that i am having is I can't figure out the logic for if a password had a illegal character in it.

I ended up hard coding it into the if statement but i know there has to be a better way
I tried to use a nested for loop that compared every pass.at[i] to special character[x], but then if there was at least one special character, it wouldn't be correct

at this point i am just trying to understand why my logic wasn't working and i had to code it all into a single if statement.
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
  #include <iostream>
#include <iomanip>

using namespace std;
const int NUM_STRINGS = 7; // Global named constant: size of testString array
const int MIN_LENGTH = 8; // Global named constant: Min length of password
const int MAX_LENGTH = 10; // Global named constant: Max length of password

bool isValidPassword(string pwd, char spec[], int siz);

int main()
{
    string testString[NUM_STRINGS] = {"12A4&z78", "12A4&z78(", "12A45z78","12A4$Z78", "a124$z78", "12A4&z7", "12A4&z7890T" };
    char special[] = {'#', '$', '%', '&', '!', '?', '@'};
    int numSpecial = sizeof(special)/sizeof(char); // Calculate the size of special array

    // Driver for isValidPassword()
    for (int i = 0; i < NUM_STRINGS; i ++)
        cout << setw(14) << testString[i] << (isValidPassword(testString[i], special, numSpecial)? " is valid": " is not valid") << endl;

    return 0;
}

bool isValidPassword(string pwd, char spec[], int siz)
{

    bool hasDigit = false;
    bool hasLower = false;
    bool hasUpper = false;
    bool hasSpecial = false;
    bool hasIllegal = false;
    for(int i = 0; i < pwd.length(); i++)
    {
        if(isdigit(pwd.at(i)))
            hasDigit = true;
    }
    for(int i = 0; i < pwd.length(); i++)
    {
        if(islower(pwd.at(i)))
            hasLower = true;
    }
    for(int i = 0; i < pwd.length(); i++)
    {
        if(isupper(pwd.at(i)))
            hasUpper = true;
    }
    for(int i = 0; i < pwd.length(); i++)
    {
        for(int x = 0; x < siz; x++)
            if(pwd.at(i) == spec[x])
                hasSpecial = true;
    }

    for(int i = 0; i < pwd.length(); i++)
    {
        if(!isdigit(pwd.at(i)))
        {
            if(!islower(pwd.at(i)))
            {
                if(!isupper(pwd.at(i)))
                {
                    if(pwd.at(i) != '#' && pwd.at(i) != '$' && pwd.at(i) != '%' && pwd.at(i) != '&' && pwd.at(i) != '!' && pwd.at(i) != '?' && pwd.at(i) != '@' )
                    {
                        hasIllegal = true;
                    }
                }
            }
        }
    }

    if (pwd.length() < MIN_LENGTH || pwd.length() > MAX_LENGTH)
    {
        return false;
    }
    else if (hasDigit == true && hasLower == true && hasUpper == true && hasSpecial == true && hasIllegal == false)
        return true;

}
Jun 15, 2017 at 11:36pm
there are no illegal chars. All should be allowed, many people use unprintables etc to make the pwd tougher. Also, does your code handle Unicode? That helps too, makes it harder to crack.

However, in ascii, I think anything under 20 and above 127 is probably considered illegal in many text fields. You can look at the chart, its organized and the low bytes are control stuff, not able to print them, and high stuff includes console drawing art stuff.

I would watch for injectors, more than chars ... you don't want a password like format c:\ or www.viruslink.com or stuff like that which can be used to inject commands into your system. Xml, html, web pages, and some commands are all bad news if a hacker finds a way to activate them after injection.


Jun 15, 2017 at 11:37pm
Sorry, I'm only allowed to use # $ % & ! ? @ for the special characters. If it's not one of those, it's not valid.
Jun 15, 2017 at 11:44pm
the really easy and fast way to do this:

char lut[256] = {0};
char asgn;
for (asgn = 'a'; asgn <= 'z'; asgn++)
lut[asgn] = 1;

for (asgn = 'A'; asgn <= 'Z'; asgn++)
lut[asgn] = 1;

lut['#'] = 1;
lut['$'] = 1;
lut['%'] = 1;
lut['&'] = 1;
etc ... all the legal stuff set to 1.


and later..
if( lut[inputchar] == 0 )
cout << "bad char in password"

you effectively make a Boolean mask for all the possible ascii chars and default all to illegal, then turn the subset you want back on, and use the above line to check (check each char that is entered!)

this is another one of those totally unrealistic assignments I guess. Whats gotten into the professors lately?
Last edited on Jun 15, 2017 at 11:46pm
Jun 16, 2017 at 2:15am
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
# include <iostream>
# include <string>
# include <cctype>
# include <algorithm>
# include <iomanip>

bool specialCharChecker (const std::string& password)
{
    std::string specialChar = "#$%&!?@";
    for (const auto& elem : password)
    {
        if (!std::isalnum(elem))
        {
            if(specialChar.find(elem) == std::string::npos)
            {
                return false;
            }
        }
    }
    return true;
}

bool passwordChecker (const std::string& password)
{
    if(!std::any_of(password.cbegin(), password.cend(), ::isdigit))
    {
        return false;
    }
    else if (!std::any_of(password.cbegin(), password.cend(), ::isupper))
    {
        return false;
    }
    else if (!std::any_of(password.cbegin(), password.cend(), ::islower))
    {
        return false;
    }
    else if(!specialCharChecker(password))
    {
        return false;
    }
    else
    {
        return true;
    }
}

int main()
{
    std::cout << "enter password: \n";
    std::string password;
    getline (std::cin, password);
    std::cout << std::boolalpha << passwordChecker(password) << "\n";
}
Jun 16, 2017 at 3:17am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool is_special( char c )
{
    static const std::string special = "#$%&!?@" ;
    return special.find(c) != std::string::npos ;
}

bool valid( const std::string& pword )
{
    if( pword.size() < MIN_LENGTH || pword.size() > MAX_LENGTH ) return false ;

    bool upper = false, lower = false, digit = false, special = false ;

    for( char c : pword ) 
    {
        if( std::isupper(c) ) upper = true ;
        else if( std::islower(c) ) lower = true ;
        else if( std::isdigit(c) ) digit = true ;
        else if( is_special(c) ) special = true ;
        else return false ; // invalid character
    }

    return upper && lower && digit && special ; // true if at least one of each is present
}
Jun 16, 2017 at 3:50am
Thanks everyone. That really gave me some ideas on how i can make a separate function to check if it has special characters.
Jun 16, 2017 at 4:22am
Could also use lambda to wrap everthing into one function instead of the two:
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
# include <iostream>
# include <string>
# include <cctype>
# include <algorithm>
# include <iomanip>

bool passwordChecker (const std::string& password)
{
    auto specialCharChecker = [](const std::string& password)
    //http://en.cppreference.com/w/cpp/language/lambda
    //note password here is local to the lambda, not the string passed to the function
    {
        std::string specialChar = "#$%&!?@";
        for (const auto& elem : password)
        {
            if (!std::isalnum(elem))
            {
                if(specialChar.find(elem) == std::string::npos)
                {
                    return false;
                }
            }
        }
        return true;
    };

    if(!std::any_of(password.cbegin(), password.cend(), ::isdigit))
    {
        return false;
    }
    else if (!std::any_of(password.cbegin(), password.cend(), ::isupper))
    {
        return false;
    }
    else if (!std::any_of(password.cbegin(), password.cend(), ::islower))
    {
        return false;
    }
    else if(!specialCharChecker(password))
    {
        return false;
    }
    else
    {
        return true;
    }
}

int main()
{
    std::cout << "enter password: \n";
    std::string password;
    getline (std::cin, password);
    std::cout << std::boolalpha << passwordChecker(password) << "\n";
}
Last edited on Jun 16, 2017 at 4:24am
Jun 16, 2017 at 6:57am
Rule of 3?

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
#include <iostream>
#include <string>
using namespace std;

const string chars[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "0123456789", "#$%&!?@" };
const string charAll = chars[0] + chars[1] + chars[2] + chars[3];

const int MIN_LENGTH = 8, MAX_LENGTH = 10;

bool isValid( string passwd );

//======================================================================

int main()
{
   string testString[] = {"12A4&z78", "12A4&z78(", "12A45z78","12A4$Z78", "a124$z78", "12A4&z7", "12A4&z7890T" };
   for ( string s : testString ) cout << s << ( isValid( s ) ? " is" : " is not" ) << " a valid password\n";
}

//======================================================================

bool isValid( string passwd )
{
   if ( passwd.size() < MIN_LENGTH || passwd.size() > MAX_LENGTH ) return false;

   for ( string s : chars )
   {
      if ( passwd.find_first_of( s ) == string::npos ) return false;         // none in that set
   }

   if ( passwd.find_first_not_of( charAll ) != string::npos ) return false;  // mustn't contain any OTHER chars

   return true;
}


12A4&z78 is a valid password
12A4&z78( is not a valid password
12A45z78 is not a valid password
12A4$Z78 is not a valid password
a124$z78 is not a valid password
12A4&z7 is not a valid password
12A4&z7890T is not a valid password

Last edited on Jun 16, 2017 at 7:04am
Topic archived. No new replies allowed.