Merge pull request #73 from d0/master
Updated regression tests and simplified code a bit
This commit is contained in:
@@ -203,11 +203,12 @@ def protect_string(string, password, cipherspec=None):
|
|||||||
|
|
||||||
#Derive a key and a salt from password
|
#Derive a key and a salt from password
|
||||||
pbk = crypt(password)
|
pbk = crypt(password)
|
||||||
regex = re.compile('\$p5k2\$\$[\w./]*\$')
|
regex = re.compile('\$p5k2\$(\d*)\$([\w./]*)\$([\w./]*)')
|
||||||
match = regex.match(pbk)
|
match = regex.match(pbk)
|
||||||
if match != None:
|
if match != None:
|
||||||
salt = pbk[7:match.end()-1]
|
iterations = match.group(1)
|
||||||
key = pbk[match.end():]
|
salt = match.group(2)
|
||||||
|
key = match.group(3)
|
||||||
else:
|
else:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
|
|
||||||
@@ -231,11 +232,11 @@ def read_protected_string(string, password, cipherspec=None):
|
|||||||
hmac_length = 32 #FIXME: Ugly
|
hmac_length = 32 #FIXME: Ugly
|
||||||
|
|
||||||
#Check if the string has the structure, that is generated by protect_string
|
#Check if the string has the structure, that is generated by protect_string
|
||||||
regex = re.compile('\$p5k2\$\$[\w./]*\$')
|
regex = re.compile('\$p5k2\$\$([\w./]*)\$')
|
||||||
match = regex.match(string)
|
match = regex.match(string)
|
||||||
if match != None:
|
if match != None:
|
||||||
|
salt = match.group(1)
|
||||||
crypted = string[match.end():len(string) - hmac_length]
|
crypted = string[match.end():len(string) - hmac_length]
|
||||||
salt = string[7:match.end() - 1]
|
|
||||||
hmac = string[len(string) - hmac_length:]
|
hmac = string[len(string) - hmac_length:]
|
||||||
else:
|
else:
|
||||||
raise ValueError("Wrong string format")
|
raise ValueError("Wrong string format")
|
||||||
@@ -323,8 +324,7 @@ def crypt(word, salt=None, iterations=None):
|
|||||||
else:
|
else:
|
||||||
salt = "$p5k2$%x$%s" % (iterations, salt)
|
salt = "$p5k2$%x$%s" % (iterations, salt)
|
||||||
rawhash = pbkdf2_hmac('sha1', salt, word, iterations, 24)
|
rawhash = pbkdf2_hmac('sha1', salt, word, iterations, 24)
|
||||||
# return salt + "$" + b64encode(rawhash, "./") DO: Original return line
|
return salt + "$" + b64encode(rawhash, "./")
|
||||||
return salt + "$" + rawhash
|
|
||||||
|
|
||||||
def _makesalt():
|
def _makesalt():
|
||||||
"""Return a 48-bit pseudorandom salt for crypt().
|
"""Return a 48-bit pseudorandom salt for crypt().
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ class TestCryptoUtils(unittest.TestCase):
|
|||||||
# The data generated by protect_string should actually consist of
|
# The data generated by protect_string should actually consist of
|
||||||
# printable characters only but that would break backwards
|
# printable characters only but that would break backwards
|
||||||
# compatibility with the (buggy) legacy implementation
|
# compatibility with the (buggy) legacy implementation
|
||||||
self.protectedTestString = "2470356b322424504f63775949487224ffa330e33b2d76b82e91a4c88ff722414d3522bcbdb8a4a45cd7c61963b52825e1361354d5b5efbcfeabfb66fa3f97dfecd5e57617b8e0172017785f4001e9653366363763323639363965313261386363623738326435326639653563633339".decode('hex')
|
self.protectedTestString = "2470356b32242478424f50746f6d712448b8f6285ac8462fffc6aef921f2ad84855219c5aaafb39c4cc9e54d1634c60cfc9347c67fa55967c5b0130469c96a44f0b73c53f5ddfc43cd8c1ef68965ebb23330393265383732333937353465653838643135363830666637336134316532".decode('hex')
|
||||||
self.salt = "POcwYIHr"
|
self.salt = "POcwYIHr"
|
||||||
self.cryptedWord = "2470356b322424504f63775949487224993c1d36e308d941d0fa240d18f4097ce8d0995226f04800".decode('hex')
|
self.cryptedWord = "$p5k2$$POcwYIHr$SPaWqD3NpmLZc6gXbeybnAoCxo7Oc//K"
|
||||||
|
self.cryptedWordThousandIterations = "$p5k2$3e8$POcwYIHr$f/mEOCulo6v7Nq2ooS3480xTet6zdGbI"
|
||||||
|
|
||||||
def test_padding(self):
|
def test_padding(self):
|
||||||
padded = append_padding(16, self.teststring)
|
padded = append_padding(16, self.teststring)
|
||||||
@@ -49,8 +50,12 @@ class TestCryptoUtils(unittest.TestCase):
|
|||||||
self.assertEqual(unprotectedString, self.teststring)
|
self.assertEqual(unprotectedString, self.teststring)
|
||||||
|
|
||||||
def test_crypt(self):
|
def test_crypt(self):
|
||||||
cryptedWord = crypt(self.teststring, self.salt, 400)
|
cryptedWord = crypt(self.teststring, self.salt)
|
||||||
self.assertEqual(cryptedWord, self.cryptedWord)
|
self.assertEqual(cryptedWord, self.cryptedWord)
|
||||||
|
|
||||||
|
def test_crypt_non_default_iterations(self):
|
||||||
|
cryptedWord = crypt(self.teststring, self.salt, 1000)
|
||||||
|
self.assertEqual(cryptedWord, self.cryptedWordThousandIterations)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user