You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

_digest.py 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. # -*- test-case-name: twisted.cred.test.test_digestauth -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Calculations for HTTP Digest authentication.
  6. @see: U{http://www.faqs.org/rfcs/rfc2617.html}
  7. """
  8. from __future__ import division, absolute_import
  9. from binascii import hexlify
  10. from hashlib import md5, sha1
  11. # The digest math
  12. algorithms = {
  13. b'md5': md5,
  14. # md5-sess is more complicated than just another algorithm. It requires
  15. # H(A1) state to be remembered from the first WWW-Authenticate challenge
  16. # issued and re-used to process any Authorization header in response to
  17. # that WWW-Authenticate challenge. It is *not* correct to simply
  18. # recalculate H(A1) each time an Authorization header is received. Read
  19. # RFC 2617, section 3.2.2.2 and do not try to make DigestCredentialFactory
  20. # support this unless you completely understand it. -exarkun
  21. b'md5-sess': md5,
  22. b'sha': sha1,
  23. }
  24. # DigestCalcHA1
  25. def calcHA1(pszAlg, pszUserName, pszRealm, pszPassword, pszNonce, pszCNonce,
  26. preHA1=None):
  27. """
  28. Compute H(A1) from RFC 2617.
  29. @param pszAlg: The name of the algorithm to use to calculate the digest.
  30. Currently supported are md5, md5-sess, and sha.
  31. @param pszUserName: The username
  32. @param pszRealm: The realm
  33. @param pszPassword: The password
  34. @param pszNonce: The nonce
  35. @param pszCNonce: The cnonce
  36. @param preHA1: If available this is a str containing a previously
  37. calculated H(A1) as a hex string. If this is given then the values for
  38. pszUserName, pszRealm, and pszPassword must be L{None} and are ignored.
  39. """
  40. if (preHA1 and (pszUserName or pszRealm or pszPassword)):
  41. raise TypeError(("preHA1 is incompatible with the pszUserName, "
  42. "pszRealm, and pszPassword arguments"))
  43. if preHA1 is None:
  44. # We need to calculate the HA1 from the username:realm:password
  45. m = algorithms[pszAlg]()
  46. m.update(pszUserName)
  47. m.update(b":")
  48. m.update(pszRealm)
  49. m.update(b":")
  50. m.update(pszPassword)
  51. HA1 = hexlify(m.digest())
  52. else:
  53. # We were given a username:realm:password
  54. HA1 = preHA1
  55. if pszAlg == b"md5-sess":
  56. m = algorithms[pszAlg]()
  57. m.update(HA1)
  58. m.update(b":")
  59. m.update(pszNonce)
  60. m.update(b":")
  61. m.update(pszCNonce)
  62. HA1 = hexlify(m.digest())
  63. return HA1
  64. def calcHA2(algo, pszMethod, pszDigestUri, pszQop, pszHEntity):
  65. """
  66. Compute H(A2) from RFC 2617.
  67. @param pszAlg: The name of the algorithm to use to calculate the digest.
  68. Currently supported are md5, md5-sess, and sha.
  69. @param pszMethod: The request method.
  70. @param pszDigestUri: The request URI.
  71. @param pszQop: The Quality-of-Protection value.
  72. @param pszHEntity: The hash of the entity body or L{None} if C{pszQop} is
  73. not C{'auth-int'}.
  74. @return: The hash of the A2 value for the calculation of the response
  75. digest.
  76. """
  77. m = algorithms[algo]()
  78. m.update(pszMethod)
  79. m.update(b":")
  80. m.update(pszDigestUri)
  81. if pszQop == b"auth-int":
  82. m.update(b":")
  83. m.update(pszHEntity)
  84. return hexlify(m.digest())
  85. def calcResponse(HA1, HA2, algo, pszNonce, pszNonceCount, pszCNonce, pszQop):
  86. """
  87. Compute the digest for the given parameters.
  88. @param HA1: The H(A1) value, as computed by L{calcHA1}.
  89. @param HA2: The H(A2) value, as computed by L{calcHA2}.
  90. @param pszNonce: The challenge nonce.
  91. @param pszNonceCount: The (client) nonce count value for this response.
  92. @param pszCNonce: The client nonce.
  93. @param pszQop: The Quality-of-Protection value.
  94. """
  95. m = algorithms[algo]()
  96. m.update(HA1)
  97. m.update(b":")
  98. m.update(pszNonce)
  99. m.update(b":")
  100. if pszNonceCount and pszCNonce:
  101. m.update(pszNonceCount)
  102. m.update(b":")
  103. m.update(pszCNonce)
  104. m.update(b":")
  105. m.update(pszQop)
  106. m.update(b":")
  107. m.update(HA2)
  108. respHash = hexlify(m.digest())
  109. return respHash