root/accountmanagerplugin/0.9/acct_mgr/md5crypt.py

Revision 76, 3.0 kB (checked in by mgood, 3 years ago)

AccountManagerPlugin:

Check in version 0.1 of the TracAccountManagerPlugin?

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