diff options
Diffstat (limited to 'md5.py')
-rwxr-xr-x | md5.py | 25 |
1 files changed, 15 insertions, 10 deletions
@@ -12,7 +12,7 @@ little bit wierd. | |||
12 | 12 | ||
13 | This is a pythonic adaption of the C code in the APR library. | 13 | This is a pythonic adaption of the C code in the APR library. |
14 | If there are any questions please refer directly to the C code. | 14 | If there are any questions please refer directly to the C code. |
15 | You'll find it in apache subversion under | 15 | You'll find it in apache subversion under |
16 | /ap/apr-util/crypto/apr_md5.c | 16 | /ap/apr-util/crypto/apr_md5.c |
17 | """ | 17 | """ |
18 | 18 | ||
@@ -21,11 +21,12 @@ from hashlib import md5 | |||
21 | from random import random | 21 | from random import random |
22 | from math import floor | 22 | from math import floor |
23 | 23 | ||
24 | __all__ = [ "generate_md5", "generate_salt", "generate_short_salt" ] | 24 | __all__ = ["generate_md5", "generate_salt", "generate_short_salt"] |
25 | 25 | ||
26 | # Defined as such for brevity | 26 | # Defined as such for brevity |
27 | md5digest = lambda x: md5(x).digest() | 27 | md5digest = lambda x: md5(x).digest() |
28 | 28 | ||
29 | |||
29 | def ap_to64(input, count=4): | 30 | def ap_to64(input, count=4): |
30 | """Weird-ass implementation of base64 conversion used by the | 31 | """Weird-ass implementation of base64 conversion used by the |
31 | APR library. | 32 | APR library. |
@@ -33,19 +34,21 @@ def ap_to64(input, count=4): | |||
33 | chars = "./0123456789%s%s" % (string.uppercase, string.lowercase) | 34 | chars = "./0123456789%s%s" % (string.uppercase, string.lowercase) |
34 | output = "" | 35 | output = "" |
35 | input = int(input) # Need ints to do binary math | 36 | input = int(input) # Need ints to do binary math |
36 | 37 | ||
37 | for i in range(0, count): | 38 | for i in range(0, count): |
38 | output += chars[input & 0x3f] # Take 6 bits right | 39 | output += chars[input & 0x3f] # Take 6 bits right |
39 | input >>= 6 # shift by 6 bits | 40 | input >>= 6 # shift by 6 bits |
40 | 41 | ||
41 | return output | 42 | return output |
42 | 43 | ||
44 | |||
43 | def generate_short_salt(): | 45 | def generate_short_salt(): |
44 | """Generate a short, 2-character salt. | 46 | """Generate a short, 2-character salt. |
45 | This is suitable for use in the htpasswd crypt routine. | 47 | This is suitable for use in the htpasswd crypt routine. |
46 | """ | 48 | """ |
47 | return generate_salt()[0:2] | 49 | return generate_salt()[0:2] |
48 | 50 | ||
51 | |||
49 | def generate_salt(): | 52 | def generate_salt(): |
50 | """Mine a little salt for your passwords. | 53 | """Mine a little salt for your passwords. |
51 | Returns 8 random characters in base64. It is 4 + 4 because the original | 54 | Returns 8 random characters in base64. It is 4 + 4 because the original |
@@ -55,6 +58,7 @@ def generate_salt(): | |||
55 | salt += ap_to64(floor(random() * 16777215)) | 58 | salt += ap_to64(floor(random() * 16777215)) |
56 | return salt | 59 | return salt |
57 | 60 | ||
61 | |||
58 | def generate_md5(passwd, salt=None): | 62 | def generate_md5(passwd, salt=None): |
59 | """Generate an APRfied MD5 hash. | 63 | """Generate an APRfied MD5 hash. |
60 | This was adapted directly from the C code in the APR library. | 64 | This was adapted directly from the C code in the APR library. |
@@ -66,10 +70,10 @@ def generate_md5(passwd, salt=None): | |||
66 | # I don't think it is really "checked" by Apache but I'm too | 70 | # I don't think it is really "checked" by Apache but I'm too |
67 | # lazy to confirm this. | 71 | # lazy to confirm this. |
68 | MAGIC_TOKEN = "$apr1$" | 72 | MAGIC_TOKEN = "$apr1$" |
69 | 73 | ||
70 | # Mainly just used for testing but why not leave it? | 74 | # Mainly just used for testing but why not leave it? |
71 | salt = salt if salt else generate_salt() | 75 | salt = salt if salt else generate_salt() |
72 | 76 | ||
73 | # Start with our password in the clear, a little magic and | 77 | # Start with our password in the clear, a little magic and |
74 | # a pinch of salt | 78 | # a pinch of salt |
75 | message = "%s%s%s" % (passwd, MAGIC_TOKEN, salt) | 79 | message = "%s%s%s" % (passwd, MAGIC_TOKEN, salt) |
@@ -89,21 +93,21 @@ def generate_md5(passwd, salt=None): | |||
89 | message += chr(0) | 93 | message += chr(0) |
90 | else: | 94 | else: |
91 | message += passwd[0] | 95 | message += passwd[0] |
92 | passlen >>= 1 | 96 | passlen >>= 1 |
93 | 97 | ||
94 | retval = md5digest(message) | 98 | retval = md5digest(message) |
95 | 99 | ||
96 | for i in range(0, 1000): | 100 | for i in range(0, 1000): |
97 | if i & 1: | 101 | if i & 1: |
98 | message = passwd | 102 | message = passwd |
99 | else: | 103 | else: |
100 | message = retval[0:16] | 104 | message = retval[0:16] |
101 | 105 | ||
102 | if i % 3: | 106 | if i % 3: |
103 | message += salt | 107 | message += salt |
104 | 108 | ||
105 | if i % 7: | 109 | if i % 7: |
106 | message += passwd | 110 | message += passwd |
107 | 111 | ||
108 | if i & 1: | 112 | if i & 1: |
109 | message += retval[0:16] | 113 | message += retval[0:16] |
@@ -111,7 +115,7 @@ def generate_md5(passwd, salt=None): | |||
111 | message += passwd | 115 | message += passwd |
112 | 116 | ||
113 | retval = md5digest(message) | 117 | retval = md5digest(message) |
114 | 118 | ||
115 | # Now make the output string | 119 | # Now make the output string |
116 | output = ap_to64((ord(retval[0]) << 16) | (ord(retval[6]) << 8) | ord(retval[12])) | 120 | output = ap_to64((ord(retval[0]) << 16) | (ord(retval[6]) << 8) | ord(retval[12])) |
117 | output += ap_to64((ord(retval[1]) << 16) | (ord(retval[7]) << 8) | ord(retval[13])) | 121 | output += ap_to64((ord(retval[1]) << 16) | (ord(retval[7]) << 8) | ord(retval[13])) |
@@ -122,6 +126,7 @@ def generate_md5(passwd, salt=None): | |||
122 | 126 | ||
123 | return "%s%s$%s" % (MAGIC_TOKEN, salt, output) | 127 | return "%s%s$%s" % (MAGIC_TOKEN, salt, output) |
124 | 128 | ||
129 | |||
125 | def test_driver(): | 130 | def test_driver(): |
126 | """Run this to verify that the library is functioning properly. | 131 | """Run this to verify that the library is functioning properly. |
127 | This one test case should be enough to verify the functionality. | 132 | This one test case should be enough to verify the functionality. |