src/eric7/EricUtilities/crypto/py3PBKDF2.py

branch
eric7
changeset 10928
46651e194fbe
parent 10439
21c28b0f9e41
child 11090
f5f5f5803935
equal deleted inserted replaced
10927:ce599998be7d 10928:46651e194fbe
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2024 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing PBKDF2 functions.
8 """
9
10 import base64
11 import hashlib
12 import hmac
13 import os
14
15 Hashes = {
16 "sha1": hashlib.sha1,
17 "sha224": hashlib.sha224,
18 "sha256": hashlib.sha256,
19 "sha384": hashlib.sha384,
20 "sha512": hashlib.sha512,
21 "md5": hashlib.md5,
22 }
23
24 Delimiter = "$"
25
26
27 def pbkdf2(password, salt, iterations, digestMod):
28 """
29 Module function to hash a password according to the PBKDF2 specification.
30
31 @param password clear text password
32 @type bytes
33 @param salt salt value
34 @type bytes
35 @param iterations number of times hash function should be applied
36 @type int
37 @param digestMod hash function
38 @type function
39 @return hashed password
40 @rtype bytes
41 """
42 pwHash = password
43 for _ in range(iterations):
44 pwHash = hmac.new(salt, pwHash, digestMod).digest()
45 return pwHash
46
47
48 def hashPasswordTuple(
49 password, digestMod=hashlib.sha512, iterations=10000, saltSize=32
50 ):
51 """
52 Module function to hash a password according to the PBKDF2 specification.
53
54 @param password clear text password
55 @type str
56 @param digestMod hash function
57 @type function
58 @param iterations number of times hash function should be applied
59 @type int
60 @param saltSize size of the salt
61 @type int
62 @return tuple of digestname, number of iterations, salt and hashed password
63 @rtype tuple of (str, int, bytes, bytes)
64 """
65 salt = os.urandom(saltSize)
66 password = password.encode("utf-8")
67 pwHash = pbkdf2(password, salt, iterations, digestMod)
68 digestname = digestMod.__name__.replace("openssl_", "")
69 return digestname, iterations, salt, pwHash
70
71
72 def hashPassword(password, digestMod=hashlib.sha512, iterations=10000, saltSize=32):
73 """
74 Module function to hash a password according to the PBKDF2 specification.
75
76 @param password clear text password
77 @type str
78 @param digestMod hash function
79 @type function
80 @param iterations number of times hash function should be applied
81 @type int
82 @param saltSize size of the salt
83 @type int
84 @return hashed password entry according to PBKDF2 specification
85 @rtype str
86 """
87 digestname, iterations, salt, pwHash = hashPasswordTuple(
88 password, digestMod, iterations, saltSize
89 )
90 return Delimiter.join(
91 [
92 digestname,
93 str(iterations),
94 base64.b64encode(salt).decode("ascii"),
95 base64.b64encode(pwHash).decode("ascii"),
96 ]
97 )
98
99
100 def verifyPassword(password, pwHash):
101 """
102 Module function to verify a password against a hash encoded password.
103
104 @param password clear text password
105 @type str
106 @param pwHash hash encoded password in the form
107 'digestmod$iterations$salt$hashed_password' as produced by the
108 hashPassword function
109 @type str
110 @return flag indicating a successfull verification
111 @rtype bool
112 @exception ValueError the hash is not of the expected format or the
113 digest is not one of the known ones
114 """
115 try:
116 digestname, iterations, salt, pwHash = pwHash.split(Delimiter)
117 except ValueError:
118 raise ValueError(
119 "Expected hash encoded password in format "
120 "'digestmod{0}iterations{0}salt{0}hashed_password".format(Delimiter)
121 )
122
123 if digestname not in Hashes:
124 raise ValueError(
125 "Unsupported hash algorithm '{0}' for hash encoded password '{1}'.".format(
126 digestname, pwHash
127 )
128 )
129
130 iterations = int(iterations)
131 salt = base64.b64decode(salt.encode("ascii"))
132 pwHash = base64.b64decode(pwHash.encode("ascii"))
133 password = password.encode("utf-8")
134 return pwHash == pbkdf2(password, salt, iterations, Hashes[digestname])
135
136
137 def rehashPassword(password, hashParameters):
138 """
139 Module function to recreate a password hash given the hash parameters.
140
141 @param password clear text password
142 @type str
143 @param hashParameters hash parameters in the form
144 'digestmod$iterations$salt'
145 @type str
146 @return hashed password
147 @rtype bytes
148 @exception ValueError the hash parameters string is not of the expected
149 format or the digest is not one of the known ones
150 """
151 try:
152 digestname, iterations, salt = hashParameters.split(Delimiter)
153 except ValueError:
154 raise ValueError(
155 "Expected hash parameters string in format "
156 "'digestmod{0}iterations{0}salt".format(Delimiter)
157 )
158
159 if digestname not in Hashes:
160 raise ValueError(
161 "Unsupported hash algorithm '{0}' for hash parameters '{1}'.".format(
162 digestname, hashParameters
163 )
164 )
165
166 iterations = int(iterations)
167 salt = base64.b64decode(salt.encode("ascii"))
168 password = password.encode("utf-8")
169 return pbkdf2(password, salt, iterations, Hashes[digestname])

eric ide

mercurial