md5crypt.py
author Julien Cristau <julien.cristau@logilab.fr>
Tue, 06 Oct 2015 11:44:51 +0200
changeset 10775 4b3c1069bd4e
parent 10609 e2d8e81bfe68
permissions -rw-r--r--
Fix md5crypt and crypt_password test for python3 Make sure to always work with bytes for hashing.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     1
# md5crypt.py
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     2
#
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     3
# 0423.2000 by michal wallace http://www.sabren.com/
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     4
# based on perl's Crypt::PasswdMD5 by Luis Munoz (lem@cantv.net)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     5
# based on /usr/src/libcrypt/crypt.c from FreeBSD 2.2.5-RELEASE
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     6
#
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     7
# MANY THANKS TO
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     8
#
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
     9
#  Carey Evans - http://home.clear.net.nz/pages/c.evans/
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    10
#  Dennis Marti - http://users.starpower.net/marti1/
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    11
#
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    12
#  For the patches that got this thing working!
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    13
#
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    14
# modification by logilab:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    15
# * remove usage of the string module
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    16
# * don't include the magic string in the output string
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    17
#   for true crypt.crypt compatibility
5771
c077df1d0333 [md5script] cleanup
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5770
diff changeset
    18
# * use hashlib module instead of md5
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    19
#########################################################
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    20
"""md5crypt.py - Provides interoperable MD5-based crypt() function
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    21
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    22
SYNOPSIS
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    23
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    24
        import md5crypt.py
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    25
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    26
        cryptedpassword = md5crypt.md5crypt(password, salt);
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    27
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    28
DESCRIPTION
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    29
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    30
unix_md5_crypt() provides a crypt()-compatible interface to the
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    31
rather new MD5-based crypt() function found in modern operating systems.
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    32
It's based on the implementation found on FreeBSD 2.2.[56]-RELEASE and
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    33
contains the following license in it:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    34
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    35
 "THE BEER-WARE LICENSE" (Revision 42):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    36
 <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    37
 can do whatever you want with this stuff. If we meet some day, and you think
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    38
 this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    39
"""
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    40
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    41
MAGIC = b'$1$'                        # Magic string
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    42
ITOA64 = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    43
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5771
diff changeset
    44
from hashlib import md5 # pylint: disable=E0611
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    45
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    46
from six import text_type, indexbytes
10609
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 8317
diff changeset
    47
from six.moves import range
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 8317
diff changeset
    48
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 8317
diff changeset
    49
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    50
def to64 (v, n):
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    51
    ret = bytearray()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    52
    while (n - 1 >= 0):
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    53
        n = n - 1
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    54
        ret.append(ITOA64[v & 0x3f])
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    55
        v = v >> 6
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    56
    return ret
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    57
8317
9c59258e7798 [security] use a stronger encryption algorythm for password, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7879
diff changeset
    58
def crypt(pw, salt):
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    59
    if isinstance(pw, text_type):
3149
c6a85fafb155 note about licence, fix copyright, fix case of unicode argument
Aurelien Campeas
parents: 2172
diff changeset
    60
        pw = pw.encode('utf-8')
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    61
    if isinstance(salt, text_type):
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    62
        salt = salt.encode('ascii')
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    63
    # Take care of the magic string if present
8317
9c59258e7798 [security] use a stronger encryption algorythm for password, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7879
diff changeset
    64
    if salt.startswith(MAGIC):
9c59258e7798 [security] use a stronger encryption algorythm for password, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7879
diff changeset
    65
        salt = salt[len(MAGIC):]
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    66
    # salt can have up to 8 characters:
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    67
    salt = salt.split(b'$', 1)[0]
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    68
    salt = salt[:8]
8317
9c59258e7798 [security] use a stronger encryption algorythm for password, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7879
diff changeset
    69
    ctx = pw + MAGIC + salt
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5771
diff changeset
    70
    final = md5(pw + salt + pw).digest()
10609
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 8317
diff changeset
    71
    for pl in range(len(pw), 0, -16):
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    72
        if pl > 16:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    73
            ctx = ctx + final[:16]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    74
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    75
            ctx = ctx + final[:pl]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    76
    # Now the 'weird' xform (??)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    77
    i = len(pw)
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    78
    while i:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    79
        if i & 1:
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    80
            ctx = ctx + b'\0'  #if ($i & 1) { $ctx->add(pack("C", 0)); }
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    81
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    82
            ctx = ctx + pw[0]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    83
        i = i >> 1
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5771
diff changeset
    84
    final = md5(ctx).digest()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    85
    # The following is supposed to make
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1977
diff changeset
    86
    # things run slower.
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    87
    # my question: WTF???
10609
e2d8e81bfe68 [py3k] import range using six.moves
Rémi Cardona <remi.cardona@logilab.fr>
parents: 8317
diff changeset
    88
    for i in range(1000):
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
    89
        ctx1 = b''
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    90
        if i & 1:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    91
            ctx1 = ctx1 + pw
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    92
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    93
            ctx1 = ctx1 + final[:16]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    94
        if i % 3:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    95
            ctx1 = ctx1 + salt
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    96
        if i % 7:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    97
            ctx1 = ctx1 + pw
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    98
        if i & 1:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
    99
            ctx1 = ctx1 + final[:16]
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   100
        else:
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   101
            ctx1 = ctx1 + pw
7879
9aae456abab5 [pylint] fix pylint detected errors and tweak it so that pylint -E will be much less verbose next time (+ update some copyrights on the way)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5771
diff changeset
   102
        final = md5(ctx1).digest()
0
b97547f5f1fa Showtime !
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents:
diff changeset
   103
    # Final xform
10775
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   104
    passwd = b''
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   105
    passwd += to64((indexbytes(final, 0) << 16)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   106
                   |(indexbytes(final, 6) << 8)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   107
                   |(indexbytes(final, 12)),4)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   108
    passwd += to64((indexbytes(final, 1) << 16)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   109
                   |(indexbytes(final, 7) << 8)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   110
                   |(indexbytes(final, 13)), 4)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   111
    passwd += to64((indexbytes(final, 2) << 16)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   112
                   |(indexbytes(final, 8) << 8)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   113
                   |(indexbytes(final, 14)), 4)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   114
    passwd += to64((indexbytes(final, 3) << 16)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   115
                   |(indexbytes(final, 9) << 8)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   116
                   |(indexbytes(final, 15)), 4)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   117
    passwd += to64((indexbytes(final, 4) << 16)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   118
                   |(indexbytes(final, 10) << 8)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   119
                   |(indexbytes(final, 5)), 4)
4b3c1069bd4e Fix md5crypt and crypt_password test for python3
Julien Cristau <julien.cristau@logilab.fr>
parents: 10609
diff changeset
   120
    passwd += to64((indexbytes(final, 11)), 2)
8317
9c59258e7798 [security] use a stronger encryption algorythm for password, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7879
diff changeset
   121
    return passwd