2
# -*- coding: ascii -*-
3
###########################################################################
4
# pbkdf2 - PKCS#5 v2.0 Password-Based Key Derivation
6
# Copyright (C) 2007-2011 Dwayne C. Litzenberger <dlitz@dlitz.net>
8
# Permission is hereby granted, free of charge, to any person obtaining
9
# a copy of this software and associated documentation files (the
10
# "Software"), to deal in the Software without restriction, including
11
# without limitation the rights to use, copy, modify, merge, publish,
12
# distribute, sublicense, and/or sell copies of the Software, and to
13
# permit persons to whom the Software is furnished to do so, subject to
14
# the following conditions:
16
# The above copyright notice and this permission notice shall be
17
# included in all copies or substantial portions of the Software.
19
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
# Country of origin: Canada
29
###########################################################################
30
# Sample PBKDF2 usage:
31
# from Crypto.Cipher import AES
32
# from pbkdf2 import PBKDF2
35
# salt = os.urandom(8) # 64-bit salt
36
# key = PBKDF2("This passphrase is a secret.", salt).read(32) # 256-bit key
37
# iv = os.urandom(16) # 128-bit IV
38
# cipher = AES.new(key, AES.MODE_CBC, iv)
41
# Sample crypt() usage:
42
# from pbkdf2 import crypt
43
# pwhash = crypt("secret")
44
# alleged_pw = raw_input("Enter password: ")
45
# if pwhash == crypt(alleged_pw, pwhash):
46
# print "Password good"
48
# print "Invalid password"
50
###########################################################################
53
__all__ = ['PBKDF2', 'crypt']
55
from struct import pack
56
from random import randint
61
# Use PyCrypto (if available).
62
from Crypto.Hash import HMAC, SHA as SHA1
64
# PyCrypto not available. Use the Python standard library.
67
from hashlib import sha1 as SHA1
69
# hashlib not available. Use the old sha module.
73
# Python 2.1 thru 3.2 compatibility
76
if sys.version_info[0] == 2:
77
_0xffffffffL = long(1) << 32
79
return isinstance(s, unicode)
81
return isinstance(s, str)
83
return isinstance(n, (int, long))
87
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])
88
def b64encode(data, chars="+/"):
89
tt = string.maketrans("+/", chars)
90
return data.encode('base64').replace("\n", "").translate(tt)
91
from binascii import b2a_hex
93
_0xffffffffL = 0xffffffff
95
return isinstance(s, str)
97
return isinstance(s, bytes)
99
return isinstance(n, int)
101
return hasattr(obj, '__call__')
103
return s.encode("latin-1")
105
return bytes([x ^ y for (x, y) in zip(a, b)])
106
from base64 import b64encode as _b64encode
107
def b64encode(data, chars="+/"):
109
return _b64encode(data, chars.encode('utf-8')).decode('utf-8')
111
return _b64encode(data, chars)
112
from binascii import b2a_hex as _b2a_hex
114
return _b2a_hex(s).decode('us-ascii')
117
class PBKDF2(object):
118
"""PBKDF2.py : PKCS#5 v2.0 Password-Based Key Derivation
120
This implementation takes a passphrase and a salt (and optionally an
121
iteration count, a digest module, and a MAC module) and provides a
122
file-like object from which an arbitrarily-sized key can be read.
124
If the passphrase and/or salt are unicode objects, they are encoded as
125
UTF-8 before they are processed.
127
The idea behind PBKDF2 is to derive a cryptographic key from a
128
passphrase and a salt.
130
PBKDF2 may also be used as a strong salted password hash. The
131
'crypt' function is provided for that purpose.
133
Remember: Keys generated using PBKDF2 are only as strong as the
134
passphrases they are derived from.
137
def __init__(self, passphrase, salt, iterations=1000,
138
digestmodule=SHA1, macmodule=HMAC):
139
self.__macmodule = macmodule
140
self.__digestmodule = digestmodule
141
self._setup(passphrase, salt, iterations, self._pseudorandom)
143
def _pseudorandom(self, key, msg):
144
"""Pseudorandom function. e.g. HMAC-SHA1"""
145
return self.__macmodule.new(key=key, msg=msg,
146
digestmod=self.__digestmodule).digest()
148
def read(self, bytes):
149
"""Read the specified number of key bytes."""
151
raise ValueError("file-like object is closed")
153
size = len(self.__buf)
154
blocks = [self.__buf]
158
if i > _0xffffffffL or i < 1:
159
# We could return "" here, but
160
raise OverflowError("derived key too long")
164
buf = b("").join(blocks)
166
self.__buf = buf[bytes:]
171
# i must fit within 32 bits
172
assert 1 <= i <= _0xffffffffL
173
U = self.__prf(self.__passphrase, self.__salt + pack("!L", i))
175
for j in xrange(2, 1+self.__iterations):
176
U = self.__prf(self.__passphrase, U)
177
result = binxor(result, U)
180
def hexread(self, octets):
181
"""Read the specified number of octets. Return them as hexadecimal.
183
Note that len(obj.hexread(n)) == 2*n.
185
return b2a_hex(self.read(octets))
187
def _setup(self, passphrase, salt, iterations, prf):
190
# passphrase and salt must be str or unicode (in the latter
191
# case, we convert to UTF-8)
192
if isunicode(passphrase):
193
passphrase = passphrase.encode("UTF-8")
194
elif not isbytes(passphrase):
195
raise TypeError("passphrase must be str or unicode")
197
salt = salt.encode("UTF-8")
198
elif not isbytes(salt):
199
raise TypeError("salt must be str or unicode")
201
# iterations must be an integer >= 1
202
if not isinteger(iterations):
203
raise TypeError("iterations must be an integer")
205
raise ValueError("iterations must be at least 1")
207
# prf must be callable
208
if not callable(prf):
209
raise TypeError("prf must be callable")
211
self.__passphrase = passphrase
213
self.__iterations = iterations
220
"""Close the stream."""
222
del self.__passphrase
224
del self.__iterations
230
def crypt(word, salt=None, iterations=None):
231
"""PBKDF2-based unix crypt(3) replacement.
233
The number of iterations specified in the salt overrides the 'iterations'
236
The effective hash length is 192 bits.
239
# Generate a (pseudo-)random salt if the user hasn't provided one.
243
# salt must be a string or the us-ascii subset of unicode
245
salt = salt.encode('us-ascii').decode('us-ascii')
247
salt = salt.decode('us-ascii')
249
raise TypeError("salt must be a string")
251
# word must be a string or unicode (in the latter case, we convert to UTF-8)
253
word = word.encode("UTF-8")
254
elif not isbytes(word):
255
raise TypeError("word must be a string or unicode")
257
# Try to extract the real salt and iteration count from the salt
258
if salt.startswith("$p5k2$"):
259
(iterations, salt, dummy) = salt.split("$")[2:5]
263
converted = int(iterations, 16)
264
if iterations != "%x" % converted: # lowercase hex, minimum digits
265
raise ValueError("Invalid salt")
266
iterations = converted
267
if not (iterations >= 1):
268
raise ValueError("Invalid salt")
270
# Make sure the salt matches the allowed character set
271
allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
273
if ch not in allowed:
274
raise ValueError("Illegal character %r in salt" % (ch,))
276
if iterations is None or iterations == 400:
278
salt = "$p5k2$$" + salt
280
salt = "$p5k2$%x$%s" % (iterations, salt)
281
rawhash = PBKDF2(word, salt, iterations).read(24)
282
return salt + "$" + b64encode(rawhash, "./")
284
# Add crypt as a static method of the PBKDF2 class
285
# This makes it easier to do "from PBKDF2 import PBKDF2" and still use
287
PBKDF2.crypt = staticmethod(crypt)
290
"""Return a 48-bit pseudorandom salt for crypt().
292
This function is not suitable for generating cryptographic secrets.
294
binarysalt = b("").join([pack("@H", randint(0, 0xffff)) for i in range(3)])
295
return b64encode(binarysalt, "./")
297
# vim:set ts=4 sw=4 sts=4 expandtab: