Login

A complete Usercake compatible password hasher

Author:
moshthepitt
Posted:
April 19, 2014
Language:
Python
Version:
1.6
Score:
0 (after 0 ratings)

Use this class to authenticate against Usercake (http://usercake.com/) password strings. When importing passwords from Usercake, the database values should be prefixed with "usercake$".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from django.contrib.auth.hashers import BasePasswordHasher
from collections import OrderedDict
from django.utils.translation import ugettext_noop as _
from django.utils.crypto import get_random_string
import hashlib

class UserCakePasswordHasher(BasePasswordHasher):
    """
        Authenticate against Usercake passwords in Django.
        (http://usercake.com/)

        Use this class to authenticate against Usercake password strings. When importing passwords from Usercake, the database values should be prefixed with "usercake$".

        Usercake passwords consist of a 65 character string.
        The first 25 characters are the salt
        The next block of 40 characters is the password encrypted using Sha1 and the salt

        h = UserCakePasswordHasher()
        h.verify("123456789", "usercake$860b4cefa917c430ed85d89525e0158d5be9e1515333a9dcfefd51a2419a119d1")
        >>>>True

        r = h.encode("123456789")
        h.verify("123456789", r)
        >>>>True

    """
    algorithm = "usercake"

    def _apply_hash(self, salt, password):
        return hashlib.sha1( salt + password ).hexdigest()

    def _mask_hash(self, hash, show=6, char="*"):
        """
        Returns the given hash, with only the first ``show`` number shown. The
        rest are masked with ``char`` for security reasons.
        """
        masked = hash[:show]
        masked += char * len(hash[show:])
        return masked

    def salt(self):
        return get_random_string(25)

    def encode(self, password, salt=None):
        if not salt:
            salt = self.salt()

        assert len(salt) == 25

        encoded_hash =  self._apply_hash(salt, password)

        return self.algorithm + "$" + salt + encoded_hash

    def verify(self, password, encoded):
        algorithm, encoded = encoded.split("$", 1)
        assert algorithm == self.algorithm

        encoded_salt = encoded[:25]
        encoded_pass = encoded[25:]

        password_hash = self._apply_hash(encoded_salt, password)

        return password_hash == encoded_pass

    def safe_summary(self, encoded):
        algorithm, encoded = encoded.split("$", 1)
        assert algorithm == self.algorithm

        encoded_salt = encoded[:25]
        encoded_pass = encoded[25:]

        return OrderedDict([
            (_('algorithm'), self.algorithm),
            (_('iterations'), "0"),
            (_('salt'), self._mask_hash( encoded_salt )),
            (_('hash'), self._mask_hash( encoded_pass )),
        ])

    def must_update(self, encoded):
        """
        Forces usercake passwords to be updated to a more secure algorithm
        """
        algorithm, encoded = encoded.split("$", 1)
        if algorithm == self.algorithm:
            return True
        return False

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 9 months, 4 weeks ago
  5. Help text hyperlinks by sa2812 10 months, 3 weeks ago

Comments

Please login first before commenting.