File: digest_md5.py

package info (click to toggle)
python-sievelib 1.4.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 392 kB
  • sloc: python: 3,531; makefile: 7; sh: 5
file content (86 lines) | stat: -rw-r--r-- 2,622 bytes parent folder | download
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
"""
Simple Digest-MD5 implementation (client side)

Implementation based on RFC 2831 (http://www.ietf.org/rfc/rfc2831.txt)
"""

import base64
import hashlib
import binascii
import re
import random


class DigestMD5(object):
    def __init__(self, challenge, digesturi):
        self.__digesturi = digesturi
        self.__challenge = challenge

        self.__params = {}
        pexpr = re.compile(r'(\w+)="(.+)"')
        for elt in base64.b64decode(challenge).split(","):
            m = pexpr.match(elt)
            if m is None:
                continue
            self.__params[m.group(1)] = m.group(2)

    def __make_cnonce(self):
        ret = ""
        for i in xrange(12):
            ret += chr(random.randint(0, 0xFF))
        return base64.b64encode(ret)

    def __digest(self, value):
        return hashlib.md5(value).digest()

    def __hexdigest(self, value):
        return binascii.hexlify(hashlib.md5(value).digest())

    def __make_response(self, username, password, check=False):
        a1 = "%s:%s:%s" % (
            self.__digest("%s:%s:%s" % (username, self.realm, password)),
            self.__params["nonce"],
            self.cnonce,
        )
        if check:
            a2 = ":%s" % self.__digesturi
        else:
            a2 = "AUTHENTICATE:%s" % self.__digesturi
        resp = "%s:%s:00000001:%s:auth:%s" % (
            self.__hexdigest(a1),
            self.__params["nonce"],
            self.cnonce,
            self.__hexdigest(a2),
        )

        return self.__hexdigest(resp)

    def response(self, username, password, authz_id=""):
        self.realm = self.__params["realm"] if self.__params.has_key("realm") else ""
        self.cnonce = self.__make_cnonce()
        respvalue = self.__make_response(username, password)

        dgres = (
            'username="%s",%snonce="%s",cnonce="%s",nc=00000001,qop=auth,'
            'digest-uri="%s",response=%s'
            % (
                username,
                ('realm="%s",' % self.realm) if len(self.realm) else "",
                self.__params["nonce"],
                self.cnonce,
                self.__digesturi,
                respvalue,
            )
        )
        if authz_id:
            if type(authz_id) is unicode:
                authz_id = authz_id.encode("utf-8")
            dgres += ',authzid="%s"' % authz_id

        return base64.b64encode(dgres)

    def check_last_challenge(self, username, password, value):
        challenge = base64.b64decode(value.strip('"'))
        return challenge == (
            "rspauth=%s" % self.__make_response(username, password, True)
        )