[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 noticed a typo/bug/error or have any suggestions, do not hesitate to drop me a note: my emails. Or use my zulip for feedback. Thanks in advance!
Also, among my services is writing examples-rich manuals and references. If you like my work and want something similar for your (commercial) product: contact me.
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.