A SQLite thread safe password store, revisited

In a previous article I showed how to implement a thread safe persistent password store that was based on SQLite. In this article a reimplementation of that module is presented base on the persistentdict module.

A SQLite thread safe password store

As you can see in the code presented below, we can put our PersistentDict class developed earlier to good use. Because we use two instances of PersistentDict (lines 45, 46) to store the salt and the hashed passwords instead of interacting with a SQLite database ourselves, the code is much cleaner and therefore easier to maintain.

  1. ''''' 
  2.  dbpassword.py Copyright 2011, Michel J. Anders 
  3.  
  4.  $Revision: 70 $ $Date: 2011-06-10 16:34:28 +0200 (vr, 10 jun 2011) $ 
  5.   
  6.  This program is free software: you can redistribute it 
  7.  and/or modify it under the terms of the GNU General Public 
  8.  License as published by the Free Software Foundation, 
  9.  either version 3 of the License, or (at your option) any 
  10.  later version. 
  11.  
  12.  This program is distributed in the hope that it will be  
  13.  useful, but WITHOUT ANY WARRANTY; without even the implied 
  14.  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
  15.  PURPOSE. See the GNU General Public License for more 
  16.  details. 
  17.  
  18.  You should have received a copy of the GNU General Public 
  19.  License along with this program.  If not, see  
  20.  www.gnu.org/licenses. 
  21. '''  
  22.   
  23. import hashlib  
  24. from random import SystemRandom as sr  
  25. from persistentdict import PersistentDict  
  26.   
  27. class dbpassword:  
  28.  
  29.  @staticmethod  
  30.  def hashpassword(name,salt,plaintextpassword,n=10):  
  31.   if n<1 : raise ValueError("n < 1")  
  32.   d = hashlib.new(name,(salt+plaintextpassword).encode()).digest()  
  33.   while n:  
  34.    n -= 1  
  35.    d = hashlib.new(name,d).digest()  
  36.   return hashlib.new(name,d).hexdigest()  
  37.  
  38.  @staticmethod  
  39.  def getsalt(randombits=64):  
  40.   if randombits<16 : raise ValueError("randombits < 16")  
  41.   return "%016x"%sr().getrandbits(randombits)  
  42.   
  43.  def __init__(self,db='password.db',  
  44.     secure_hash='sha256',iterations=1000,saltbits=64):  
  45.   self.saltdict = PersistentDict(db=db,table='salt')  
  46.   self.pwdict = PersistentDict(db=db,table='password')  
  47.   self.secure_hash = secure_hash  
  48.   self.iterations = iterations  
  49.   self.saltbits = 64  
  50.     
  51.  def update(self,user,plaintextpassword):  
  52.   salt=dbpassword.getsalt(self.saltbits)  
  53.   self.saltdict[user]=salt  
  54.   self.pwdict[user]=dbpassword.hashpassword(  
  55.      self.secure_hash,salt,plaintextpassword,  
  56.      self.iterations)  
  57.   
  58.  def check(self,user,plaintextpassword):  
  59.   salt=self.saltdict[user]  
  60.   return self.pwdict[user]==dbpassword.hashpassword(  
  61.    self.secure_hash,salt,plaintextpassword,  
  62.    self.iterations)