Tuesday, August 19, 2014

flask ( or itsdangerous ) secret key size.

I recently need to figure out the recommended key size for flask's secret key. Trawling through flasks' source, I discovered that it's using itsdangerous for signing. The signer in turn uses hmac with a defined hash algorithm or a default one.  The default digest method in itsdangerous is SHA-1.
According to wikipedia:

The cryptographic strength of the HMAC depends upon the size of the secret key that is used.
 The HMAC RFC in turn states that:

2. Definition of HMAC
The definition of HMAC requires a cryptographic hash function, which
   we denote by H, and a secret key K. We assume H to be a cryptographic
   hash function where data is hashed by iterating a basic compression
   function on blocks of data.   We denote by B the byte-length of such
   blocks (B=64 for all the above mentioned examples of hash functions),
   and by L the byte-length of hash outputs (L=16 for MD5, L=20 for
   SHA-1).  The authentication key K can be of any length up to B, the
   block length of the hash function.  Applications that use keys longer
   than B bytes will first hash the key using H and then use the
   resultant L byte string as the actual key to HMAC. In any case the
   minimal recommended length for K is L bytes (as the hash output
   length). See section 3 for more information on keys.
3. Keys

   The key for HMAC can be of any length (keys longer than B bytes are
   first hashed using H).  However, less than L bytes is strongly
   discouraged as it would decrease the security strength of the
   function.  Keys longer than L bytes are acceptable but the extra
   length would not significantly increase the function strength. (A
   longer key may be advisable if the randomness of the key is
   considered weak.)

   Keys need to be chosen at random (or using a cryptographically strong
   pseudo-random generator seeded with a random seed), and periodically
   refreshed.  (Current attacks do not indicate a specific recommended
   frequency for key changes as these attacks are practically
   infeasible.  However, periodic key refreshment is a fundamental
   security practice that helps against potential weaknesses of the
   function and keys, and limits the damage of an exposed key.)
So that in effect means that our secret key should be 16 bytes for MD5, 20 bytes for SHA1 and larger if you use SHA-2 or SHA-3. Use the output bits column of this table to figure out what your secret key size ought to be. For the flask secret key size,  I believe that a 32 byte secret key should be sufficient (and a 16 byte secret key risky... :)

My secret key block then becomes:
SECRET_KEY = open("/dev/random","rb").read(KEY_SIZE)

os.urandom from the stdlib may not cut it since it sources /dev/urandom.

Caveat: YMMV, I am not a security expert!