~ubuntu-branches/ubuntu/raring/trac-accountmanager/raring

« back to all changes in this revision

Viewing changes to acct_mgr/md5crypt.py

  • Committer: Bazaar Package Importer
  • Author(s): Leo Costela
  • Date: 2008-07-15 17:21:11 UTC
  • Revision ID: james.westby@ubuntu.com-20080715172111-ool7wmy573gqolfr
Tags: upstream-0.2.1~vcs20080715
ImportĀ upstreamĀ versionĀ 0.2.1~vcs20080715

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
#
 
3
# Based on FreeBSD src/lib/libcrypt/crypt.c 1.2
 
4
# http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libcrypt/crypt.c?rev=1.2&content-type=text/plain
 
5
 
 
6
# Original license:
 
7
# * "THE BEER-WARE LICENSE" (Revision 42):
 
8
# * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
 
9
# * can do whatever you want with this stuff. If we meet some day, and you think
 
10
# * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
 
11
 
 
12
# This port adds no further stipulations.  I forfeit any copyright interest.
 
13
 
 
14
import md5
 
15
 
 
16
def md5crypt(password, salt, magic='$1$'):
 
17
    # /* The password first, since that is what is most unknown */ /* Then our magic string */ /* Then the raw salt */
 
18
    m = md5.new()
 
19
    m.update(password + magic + salt)
 
20
 
 
21
    # /* Then just as many characters of the MD5(pw,salt,pw) */
 
22
    mixin = md5.md5(password + salt + password).digest()
 
23
    for i in range(0, len(password)):
 
24
        m.update(mixin[i % 16])
 
25
 
 
26
    # /* Then something really weird... */
 
27
    # Also really broken, as far as I can tell.  -m
 
28
    i = len(password)
 
29
    while i:
 
30
        if i & 1:
 
31
            m.update('\x00')
 
32
        else:
 
33
            m.update(password[0])
 
34
        i >>= 1
 
35
 
 
36
    final = m.digest()
 
37
 
 
38
    # /* and now, just to make sure things don't run too fast */
 
39
    for i in range(1000):
 
40
        m2 = md5.md5()
 
41
        if i & 1:
 
42
            m2.update(password)
 
43
        else:
 
44
            m2.update(final)
 
45
 
 
46
        if i % 3:
 
47
            m2.update(salt)
 
48
 
 
49
        if i % 7:
 
50
            m2.update(password)
 
51
 
 
52
        if i & 1:
 
53
            m2.update(final)
 
54
        else:
 
55
            m2.update(password)
 
56
 
 
57
        final = m2.digest()
 
58
 
 
59
    # This is the bit that uses to64() in the original code.
 
60
 
 
61
    itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
 
62
 
 
63
    rearranged = ''
 
64
    for a, b, c in ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15), (4, 10, 5)):
 
65
        v = ord(final[a]) << 16 | ord(final[b]) << 8 | ord(final[c])
 
66
        for i in range(4):
 
67
            rearranged += itoa64[v & 0x3f]; v >>= 6
 
68
 
 
69
    v = ord(final[11])
 
70
    for i in range(2):
 
71
        rearranged += itoa64[v & 0x3f]; v >>= 6
 
72
 
 
73
    return magic + salt + '$' + rearranged
 
74
 
 
75
if __name__ == '__main__':
 
76
 
 
77
    def test(clear_password, the_hash):
 
78
        magic, salt = the_hash[1:].split('$')[:2]
 
79
        magic = '$' + magic + '$'
 
80
        return md5crypt(clear_password, salt, magic) == the_hash
 
81
 
 
82
    test_cases = (
 
83
        (' ', '$1$yiiZbNIH$YiCsHZjcTkYd31wkgW8JF.'),
 
84
        ('pass', '$1$YeNsbWdH$wvOF8JdqsoiLix754LTW90'),
 
85
        ('____fifteen____', '$1$s9lUWACI$Kk1jtIVVdmT01p0z3b/hw1'),
 
86
        ('____sixteen_____', '$1$dL3xbVZI$kkgqhCanLdxODGq14g/tW1'),
 
87
        ('____seventeen____', '$1$NaH5na7J$j7y8Iss0hcRbu3kzoJs5V.'),
 
88
        ('__________thirty-three___________', '$1$HO7Q6vzJ$yGwp2wbL5D7eOVzOmxpsy.'),
 
89
        ('apache', '$apr1$J.w5a/..$IW9y6DR0oO/ADuhlMF5/X1')
 
90
    )
 
91
 
 
92
    for clearpw, hashpw in test_cases:
 
93
        if test(clearpw, hashpw):
 
94
            print '%s: pass' % clearpw
 
95
        else:
 
96
            print '%s: FAIL' % clearpw