Is this secure?

mk mrkafk at gmail.com
Wed Feb 24 18:23:17 CET 2010


On 2010-02-24 03:50, Paul Rubin wrote:
> The stuff about converting 4 random bytes to a decimal string and then
> peeling off 2 digits at a time is pretty awful, and notice that since
> 2**32 is 4294967296, in the cases where you get 10 digits, the first
> 2-digit pair is never higher than 42.

Yikes! I didn't think about that. This is probably where (some part of) 
probability skewing comes from.

Anyway, the passwords for authorized users will be copied and pasted 
from email into in the application GUI which will remember it for them, 
so they will not have to remember and type them in. So I have little in 
the way of limitations of password length - even though in *some* cases 
somebody might have to (or be ignorant enough) to retype the password 
instead of pasting it in.

In that case the "diceware" approach is not necessary, even though I 
will certainly remember this approach for a case when users will have to 
remember & type the passwords in.

The main application will access the data using HTTP (probably), so the 
main point is that an attacker is not able to guess passwords using 
brute force.

Using A-z with 10-char password seems to provide 3 orders of magnitude 
more combinations than a-z:

 >>> 57 ** 10
362033331456891249L
 >>> 25 ** 10
95367431640625L

Even though I'm not sure it is worth it, assuming 1000 brute-force 
guesses per second (which over the web would amount pretty much to DOS), 
this would take # days:

 >>> 57 ** 10 / (1000 * 3600 * 24)
4190200595L
 >>> 25 ** 10 / (1000 * 3600 * 24)
1103789L

Even then I'm not getting completely uniform distribution for some reason:

d 39411
l 39376
f 39288
a 39275
s 39225
r 39172
p 39159
t 39073
k 39071
u 39064
e 39005
o 39005
n 38995
j 38993
h 38975
q 38958
c 38938
b 38906
g 38894
i 38847
m 38819
v 38712
z 35321
y 35228
w 35189
x 35075

Code:

import operator

def gen_rand_word(n):
     with open('/dev/urandom') as f:
         return ''.join([chr(ord('a') + ord(x) % 26) for x in f.read(n)])

def count_chars(chardict, word):
     for c in word:
         try:
             chardict[c] += 1
         except KeyError:
             chardict[c] = 0

if __name__ == "__main__":
     chardict = {}
     for i in range(100000):
         w = gen_rand_word(10)
         count_chars(chardict, w)
     counts = list(chardict.items())
     counts.sort(key = operator.itemgetter(1), reverse = True)
     for char, count in counts:
         print char, count

> I'd write your code something like this:
>
>      nletters = 5
>
>      def randomword(n):
>          with open('/dev/urandom') as f:
>              return ''.join([chr(ord('a')+ord(c)%26) for c in f.read(n)])
>
>      print randomword(nletters)

Aw shucks when will I learn to do the stuff in 3 lines well instead of 
20, poorly. :-/

Regards,
mk






More information about the Python-list mailing list