1
# -*- test-case-name: twisted.test.test_digestauth -*-
2
# Copyright (c) 2008 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
Calculations for HTTP Digest authentication.
8
@see: U{http://www.faqs.org/rfcs/rfc2617.html}
11
from twisted.python.hashlib import md5, sha1
20
# md5-sess is more complicated than just another algorithm. It requires
21
# H(A1) state to be remembered from the first WWW-Authenticate challenge
22
# issued and re-used to process any Authorization header in response to
23
# that WWW-Authenticate challenge. It is *not* correct to simply
24
# recalculate H(A1) each time an Authorization header is received. Read
25
# RFC 2617, section 3.2.2.2 and do not try to make DigestCredentialFactory
26
# support this unless you completely understand it. -exarkun
33
def calcHA1(pszAlg, pszUserName, pszRealm, pszPassword, pszNonce, pszCNonce,
36
Compute H(A1) from RFC 2617.
38
@param pszAlg: The name of the algorithm to use to calculate the digest.
39
Currently supported are md5, md5-sess, and sha.
40
@param pszUserName: The username
41
@param pszRealm: The realm
42
@param pszPassword: The password
43
@param pszNonce: The nonce
44
@param pszCNonce: The cnonce
46
@param preHA1: If available this is a str containing a previously
47
calculated H(A1) as a hex string. If this is given then the values for
48
pszUserName, pszRealm, and pszPassword must be C{None} and are ignored.
51
if (preHA1 and (pszUserName or pszRealm or pszPassword)):
52
raise TypeError(("preHA1 is incompatible with the pszUserName, "
53
"pszRealm, and pszPassword arguments"))
56
# We need to calculate the HA1 from the username:realm:password
57
m = algorithms[pszAlg]()
65
# We were given a username:realm:password
66
HA1 = preHA1.decode('hex')
68
if pszAlg == "md5-sess":
69
m = algorithms[pszAlg]()
77
return HA1.encode('hex')
80
def calcHA2(algo, pszMethod, pszDigestUri, pszQop, pszHEntity):
82
Compute H(A2) from RFC 2617.
84
@param pszAlg: The name of the algorithm to use to calculate the digest.
85
Currently supported are md5, md5-sess, and sha.
86
@param pszMethod: The request method.
87
@param pszDigestUri: The request URI.
88
@param pszQop: The Quality-of-Protection value.
89
@param pszHEntity: The hash of the entity body or C{None} if C{pszQop} is
91
@return: The hash of the A2 value for the calculation of the response
94
m = algorithms[algo]()
97
m.update(pszDigestUri)
98
if pszQop == "auth-int":
101
return m.digest().encode('hex')
104
def calcResponse(HA1, HA2, algo, pszNonce, pszNonceCount, pszCNonce, pszQop):
106
Compute the digest for the given parameters.
108
@param HA1: The H(A1) value, as computed by L{calcHA1}.
109
@param HA2: The H(A2) value, as computed by L{calcHA2}.
110
@param pszNonce: The challenge nonce.
111
@param pszNonceCount: The (client) nonce count value for this response.
112
@param pszCNonce: The client nonce.
113
@param pszQop: The Quality-of-Protection value.
115
m = algorithms[algo]()
120
if pszNonceCount and pszCNonce:
121
m.update(pszNonceCount)
128
respHash = m.digest().encode('hex')