[Math][Pentesting] Password requirements are harmful. A password with required digit/special character may be weaker. Part II.

(Previously.)

Dahua CCTV cameras

Password requirements:

...Also, to ensure a higher level of security please use passwords with these requirements:

    At least 8 characters long
    At least one lower case letter : a
    At least one upper case letter : A
    At least one number : 1
    At least one symbol : !

Example: HIgh91!? 

( https://dahuawiki.com/IPCamera/Change_Password_5.0_UI )

Now let's see if has a problem.

This is a script that generates all possible templates/masks for 8-char passwords:

#!/usr/bin/env python3

import itertools

for az_total in range(1, 7+1):
    for AZ_total in range(1, 7+1):
        for digits_total in range(1, 7+1):
            for punct_total in range(1, 7+1):
                if az_total+AZ_total+digits_total+punct_total != 8:
                    continue
                pw_tpl="l"*az_total + "u"*AZ_total + "d"*digits_total + "s"*punct_total
                print (pw_tpl)
                for tpl in itertools.permutations(pw_tpl):
                    print ("".join(tpl))

Now that script will count password for a given template:

#!/usr/bin/env python3

import sys

az="qwertyuiopasdfghjklzxcvbnm"
AZ="QWERTYUIOPASDFGHJKLZXCVBNM"
digits="0123456789"

punct=" !\"#$%&'()*+,-./:;<=>?"
#        ^ note the escape char before double quotes

for pw_tpl in sys.stdin:
    pw_tpl=pw_tpl.rstrip()
    pw_total=1
    for c in pw_tpl:
        if c=='l':
            pw_total*=len(az)
        elif c=='u':
            pw_total*=len(AZ)
        elif c=='d':
            pw_total*=len(digits)
        elif c=='s':
            pw_total*=len(punct)
        else:
            assert False
    print (pw_total)

Count them all:

 % ./dahua_gen_tpls.py | sort | uniq | ./count_passwords_in_tpl.py | ./sum_numbers_in_list.sh
1221185292687360

Now the script that count all 8-char passwords possible, without any requirements:

#!/usr/bin/env python3

import sys

az="qwertyuiopasdfghjklzxcvbnm"
AZ="QWERTYUIOPASDFGHJKLZXCVBNM"
digits="0123456789"

punct=" !\"#$%&'()*+,-./:;<=>?"
#        ^ note the escape char before double quotes

alphabet_size=len(az) + len(AZ) + len(digits) + len(punct)
print (alphabet_size**8)
print ("%e" % (alphabet_size**8))

Twice as much:

 % ./count_all.py
2478758911082496
2.478759e+15

Hikvision CCTV cameras

Paradoxically, but Hikvision requirements are better:

8 to 16 characters allowed, including upper-case letters, lower-case letters,
digits and special characters (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ space).
At least two of above mentioned types are required.

Let's generate all possible templates/masks:

#!/usr/bin/env python3

import itertools

for az_total in range(0, 7+1):
    for AZ_total in range(0, 7+1):
        for digits_total in range(0, 7+1):
            for punct_total in range(0, 7+1):
                categories_total=0
                if az_total>0:
                    categories_total+=1
                if AZ_total>0:
                    categories_total+=1
                if digits_total>0:
                    categories_total+=1
                if punct_total>0:
                    categories_total+=1
                if categories_total<2:
                    continue
                if az_total+AZ_total+digits_total+punct_total != 8:
                    continue
                pw_tpl="l"*az_total + "u"*AZ_total + "d"*digits_total + "s"*punct_total
                print (pw_tpl)
                for tpl in itertools.permutations(pw_tpl):
                    print ("".join(tpl))

This number is very close to all possible 8-char passwords:

 % ./hikvision_gen_tpls.py | sort | uniq | ./count_passwords_in_tpl.py | ./sum_numbers_in_list.sh
2478286281079808

All files.

(the post first published at 20260112.)


List of my other blog posts. Subscribe to my news feed,
If you enjoy my work, you can support it on patreon.
Some time ago (before 24-Mar-2025) there was Disqus JS script for comments. I dropped it --- it was so motley, distracting, animated, with too much ads. I never liked it. Also, comments din't appeared correctly (Disqus was buggy). Also, my blog is too chamberlike --- not many people write comments here. So I decided to switch to the model I once had at least in 2020 --- send me your comments by email (don't forget to include URL to this blog post) and I will copy&paste it here manually.
Let's party like it's ~1993-1996, in this ultimate, radical and uncompromisingly primitive pre-web1.0-style blog and website. This website is best viewed under lynx/links/elinks/w3m.
Or use my zulip for feedback.