0

I wan't to make 1000 passwords and give them to users. Passwords contain 6 digits - they look like random 6 digits.

When user comes there is no information besides this password, and I want to validate it.

I can walk through the database to look for this password, but I want to decrease the difficulty of this operation from O(N) to O(1), where N is the number of passwords.

Is there any method of generating 1000 'random-likely' passwords with simple ways of check them?

UPD: Right now I'm thinking of making encryption. For example (Python)

key = 'top_secret'
N = 1000
passwords = [encrypt(i, key) for i in range(N)]

def check(s):
    try:
        return int(decrypt(s, key))<1000
    except ValueError:
        return False

But this I suppose there is a better solution

UPD2: 3 digits and 6 digits are just for example. They may be 64 and 128 digits

Павел Тявин
  • 2,529
  • 4
  • 25
  • 32
  • 1
    It's not the solution you want, but simply by indexing the passwords, you can reduce the search operation to O(log N) – DavidA Mar 15 '13 at 20:29
  • 2
    If you have 1000 passwords out of 1000000 possible values, that means 1/1000 guesses will work. Once upon a time, there was a long distance phone card company named MetroCall that used 6-digit codes, and added a new dialup number for every 1000 users, figuring that was "safe enough". 25 years later, there are a lot of 40-year-olds today who can tell exactly you how long it took on average for their first modems to try 1000 random numbers… – abarnert Mar 15 '13 at 21:23
  • 1
    So - are you in effect giving a user an "authentication token" ? – Jon Clements Mar 15 '13 at 22:10
  • 2
    If N=1000 just store the password hashes in memory (set or dict). Dictionary lookup in Python is quite close to O(1). This of course shifts the complexity into memory which might become a problem for large values of N. – Pankrat Mar 15 '13 at 22:31

4 Answers4

0

Create a hash with passwords as a keys. On example in Perl, hashes provide constant time lookup (O(1)).

This could look like this:

my %pass;

foreach ( 1 .. 1000 ) {
        # generate_next_pass() is your algorithm
        # of getting new password.
        my $p = generate_next_pass();
        $pass{$p} = 1;
}

Then O(1) check if a password is in a hash would be:

# $user_input is a password to be validated.
if ( exists $pass{$user_input} ) {
  # password correct
} else {
  # password incorrect
}
kamituel
  • 34,606
  • 6
  • 81
  • 98
0

If the passwords are only digits, you can use them as list indices:

# Create a list of all possible passwords
pwds = [False for n in xrange(10**6)]
# Make 1000 valid passwords
for j in xrange(1000):
    i = random.randint(0, 10**6)
    print 'password is {:06d}'.format(i)
    pwds[i] = True

Looking them up should be O(1):

testpw = '103076'
if pwds[int(testpw)]:
    print 'Password is OK'
else:
    print 'Invalid password!'

Note that six-digit passwords are not very secure. They are easily guessed.

A better approach is to let the user choose a passphrase. Then store a SHA512 hash of that passphrase as the key of a dict, with e.g. the user's data as the value. When the user gives its passphrase, hash it and and see if that key is in the dict.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
0

Not 100% sure, but you could just generate a uuid4 and store it as an authentication->username lookup, an eg:

import uuid

userpass = {uuid.uuid4().hex:'user{:05}'.format(idx) for idx in xrange(1, 1001)}
an_item = next(iter(userpass)) # one we know is in there
for check in (an_item, 'bob'): # 'bob' we know won't be...
    print check, 'belongs to', userpass.get(check, '*nobody*')

# 8411d50aa7ec42d8a6b4736284d1837b belongs to user00381
# bob belongs to *nobody*
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
0

Since the password is short you may want to use a bitmap. You need 1000000 bits = 125000 bytes ~= 122kB, i.e., fairly small amount of memory.

So, create a bitmap and initialize it (totally unset). Generate your passwords and set the appropriate bits in the bitmap. Check the bitmap when the user tries to login.

VERY IMPORTANT WARNING!

What you are trying to do here is EXTREMELY UNSECURE.

You wrote that the user only uses its password to login, therefore, independently of the data-structure you select to keep the passwords, to login into the system one only has to try to guess one password. Since 1000 exist in the range [0;1000000[ the probability of guessing a password at first try is 0,001 which is a very high value. Essentially, as you described it, your system does not ask for passwords - it asks for usernames.

6 digit passwords may be ok for some cases, but never use a password as username+password.

João Fernandes
  • 1,101
  • 5
  • 11
  • As I said (upd2), 3 digits and 6 digits are only for example. They could be 64 and 128 digits – Павел Тявин Mar 17 '13 at 01:06
  • Independent of size, my warning persists. Imagine that ATM machines would not need cards, just pins. You would go to one, make a up a pin (e.g., 12345) and the probability that the made up pin belongs to **someone** is quite big if you have lots of users. – João Fernandes Mar 17 '13 at 14:29
  • it's not big. it can be 2^(-64) as I said – Павел Тявин Mar 17 '13 at 19:00
  • The "problem" ends up not being how many digits passwords have but how many users there are. – João Fernandes Mar 18 '13 at 09:00
  • There are no registered users. Every user is annonymous. – Павел Тявин Mar 18 '13 at 09:14
  • That is not the point. By registered I meant how many passwords exist in the system, i.e., give access to the system (no matter the account). Imagine your passwords are 4 digit numbers and you have 10000 passwords in the system. In that case you will be able to enter the system with **ANY** 4 digit number. You are definitely failing to see the point here... – João Fernandes Mar 18 '13 at 15:52