--- twisted/python/filepath.py (revision 24240)
+++ twisted/python/filepath.py (revision 25457)
@@ -10,5 +10,4 @@
 import errno
 import random
-import sha
 import base64
 
@@ -26,4 +25,5 @@
 
 from twisted.python.runtime import platform
+from twisted.python.hashlib import sha1
 
 from twisted.python.win32 import ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND
@@ -121,5 +121,5 @@
     Create a pseudorandom, 16-character string for use in secure filenames.
     """
-    return armor(sha.new(randomBytes(64)).digest())[:16]
+    return armor(sha1(randomBytes(64)).digest())[:16]
 
 
--- twisted/python/otp.py (revision 11450)
+++ twisted/python/otp.py (revision 25457)
@@ -1,6 +1,8 @@
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# -*- test-case-name: twisted.python.test.test_otp -*-
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
-""" A One-Time Password System based on RFC 2289
+"""
+A One-Time Password System based on RFC 2289
 
 The class Authenticator contains the hashing-logic, and the parser for the
@@ -18,8 +20,18 @@
 
 Todo: RFC2444, SASL (perhaps), parsing hex-responses
+
+This module is deprecated.  Consider using U{another Python OTP
+library<http://labix.org/python-otp>} instead.
 """
 
+import warnings
 import string
 import random
+
+warnings.warn(
+    "twisted.python.otp is deprecated since Twisted 8.3.",
+    category=DeprecationWarning,
+    stacklevel=2)
+
 
 def stringToLong(s):
@@ -48,7 +60,7 @@
         l = l / 256L
     return result
-        
-import md5, sha
-hashid = {md5: 'md5', sha: 'sha1'}
+
+from twisted.python.hashlib import md5, sha1
+hashid = {md5: 'md5', sha1: 'sha1'}
 
 INITIALSEQUENCE = 1000
@@ -57,5 +69,5 @@
 class Unauthorized(Exception):
     """the Unauthorized exception
-    
+
     This exception is raised when an action is not allowed, or a user is not
     authenticated properly.
@@ -63,16 +75,20 @@
 
 class OTPAuthenticator:
-    """A One Time Password System
-    
+    """
+    A One Time Password System
+
     Based on RFC 2289, which is based on a the S/KEY Authentication-scheme.
     It uses the MD5- and SHA-algorithms for hashing
-    
-    The variable OTP is at all times a 64bit string"""
-
+
+    The variable OTP is at all times a 64bit string.
+
+    @ivar hash: An object which can be used to compute hashes.  This is either
+        L{md5} or L{sha1}.
+    """
     def __init__(self, hash = md5):
         "Set the hash to either md5 or sha1"
         self.hash = hash
-        pass
-    
+
+
     def generateSeed(self):
         "Return a 10 char random seed, with 6 lowercase chars and 4 digits"
@@ -87,7 +103,7 @@
         if self.hash == md5:
             return self.foldDigest128(otp)
-        if self.hash == sha:
+        if self.hash == sha1:
             return self.foldDigest160(otp)
-    
+
     def foldDigest128(self, otp128):
         "Fold a 128 bit digest to 64 bit"
@@ -121,7 +137,7 @@
     def hashUpdate(self, digest):
         "Run through the hash and fold to 64 bit"
-        h = self.hash.new(digest)
+        h = self.hash(digest)
         return self.foldDigest(h.digest())
-    
+
     def generateOTP(self, seed, passwd, sequence):
         """Return a 64 bit OTP based on inputs
@@ -139,5 +155,5 @@
             parity = parity + otp & 0x3
             otp = otp >> 2
-        return parity        
+        return parity
 
     def makeReadable(self, otp):
@@ -152,5 +168,5 @@
 
     def challenge(self, seed, sequence):
-        """Return a challenge in the format otp-<hash> <sequence> <seed>"""  
+        """Return a challenge in the format otp-<hash> <sequence> <seed>"""
         return "otp-%s %i %s" % (hashid[self.hash], sequence, seed)
 
@@ -179,7 +195,7 @@
     up against the one given by the user. If they match, the sequencecounter
     is decreased and the circle is closed.
-    
+
     This object should be glued to each user
-    
+
     Note:
     It does NOT reset the sequence when the combinations left approach zero,
@@ -479,3 +495,2 @@
 "YARD",  "YARN",  "YAWL",  "YAWN",  "YEAH",  "YEAR",  "YELL",  "YOGA",
 "YOKE"]
-
--- twisted/python/hashlib.py (revision 25457)
+++ twisted/python/hashlib.py (revision 25457)
@@ -0,0 +1,24 @@
+# -*- test-case-name: twisted.python.test.test_hashlib -*-
+# Copyright (c) 2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+L{twisted.python.hashlib} presents a subset of the interface provided by
+U{hashlib<http://docs.python.org/library/hashlib.html>}.  The subset is the
+interface required by various parts of Twisted.  This allows application code
+to transparently use APIs which existed before C{hashlib} was introduced or to
+use C{hashlib} if it is available.
+"""
+
+
+try:
+    _hashlib = __import__("hashlib")
+except ImportError:
+    from md5 import md5
+    from sha import sha as sha1
+else:
+    md5  = _hashlib.md5
+    sha1 = _hashlib.sha1
+
+
+__all__ = ["md5", "sha1"]
--- twisted/python/test/test_hashlib.py (revision 25457)
+++ twisted/python/test/test_hashlib.py (revision 25457)
@@ -0,0 +1,90 @@
+# Copyright (c) 2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Tests for L{twisted.python.hashlib}
+"""
+
+from twisted.trial.unittest import TestCase
+
+from twisted.python.hashlib import md5, sha1
+
+
+class HashObjectTests(TestCase):
+    """
+    Tests for the hash object APIs presented by L{hashlib}, C{md5} and C{sha1}.
+    """
+    def test_md5(self):
+        """
+        L{hashlib.md5} returns an object which can be used to compute an MD5
+        hash as defined by U{RFC 1321<http://www.ietf.org/rfc/rfc1321.txt>}.
+        """
+        # Test the result using values from section A.5 of the RFC.
+        self.assertEqual(
+            md5().hexdigest(), "d41d8cd98f00b204e9800998ecf8427e")
+        self.assertEqual(
+            md5("a").hexdigest(), "0cc175b9c0f1b6a831c399e269772661")
+        self.assertEqual(
+            md5("abc").hexdigest(), "900150983cd24fb0d6963f7d28e17f72")
+        self.assertEqual(
+            md5("message digest").hexdigest(),
+            "f96b697d7cb7938d525a2f31aaf161d0")
+        self.assertEqual(
+            md5("abcdefghijklmnopqrstuvwxyz").hexdigest(),
+            "c3fcd3d76192e4007dfb496cca67e13b")
+        self.assertEqual(
+            md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+                "0123456789").hexdigest(),
+            "d174ab98d277d9f5a5611c2c9f419d9f")
+        self.assertEqual(
+            md5("1234567890123456789012345678901234567890123456789012345678901"
+                "2345678901234567890").hexdigest(),
+            "57edf4a22be3c955ac49da2e2107b67a")
+
+        # It should have digest and update methods, too.
+        self.assertEqual(
+            md5().digest().encode('hex'),
+            "d41d8cd98f00b204e9800998ecf8427e")
+        hash = md5()
+        hash.update("a")
+        self.assertEqual(
+            hash.digest().encode('hex'),
+            "0cc175b9c0f1b6a831c399e269772661")
+
+        # Instances of it should have a digest_size attribute
+        self.assertEqual(md5().digest_size, 16)
+
+
+    def test_sha1(self):
+        """
+        L{hashlib.sha1} returns an object which can be used to compute a SHA1
+        hash as defined by U{RFC 3174<http://tools.ietf.org/rfc/rfc3174.txt>}.
+        """
+        def format(s):
+            return ''.join(s.split()).lower()
+        # Test the result using values from section 7.3 of the RFC.
+        self.assertEqual(
+            sha1("abc").hexdigest(),
+            format(
+                "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D"))
+        self.assertEqual(
+            sha1("abcdbcdecdefdefgefghfghighijhi"
+                 "jkijkljklmklmnlmnomnopnopq").hexdigest(),
+            format(
+                "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1"))
+
+        # It should have digest and update methods, too.
+        self.assertEqual(
+            sha1("abc").digest().encode('hex'),
+            format(
+                "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D"))
+        hash = sha1()
+        hash.update("abc")
+        self.assertEqual(
+            hash.digest().encode('hex'),
+            format(
+                "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D"))
+
+        # Instances of it should have a digest_size attribute.
+        self.assertEqual(
+            sha1().digest_size, 20)
--- twisted/python/test/test_zipstream.py (revision 22464)
+++ twisted/python/test/test_zipstream.py (revision 25457)
@@ -7,8 +7,8 @@
 import sys
 import random
-import md5
 import zipfile
 
 from twisted.python import zipstream, filepath
+from twisted.python.hashlib import md5
 from twisted.trial import unittest
 
@@ -348,5 +348,5 @@
         """
         junk = ' '.join([str(random.random()) for n in xrange(1000)])
-        junkmd5 = md5.new(junk).hexdigest()
+        junkmd5 = md5(junk).hexdigest()
 
         tempdir = filepath.FilePath(self.mktemp())
@@ -365,5 +365,5 @@
             pass
         self.assertEqual(r, 0)
-        newmd5 = md5.new(
+        newmd5 = md5(
             tempdir.child("zipstreamjunk").open().read()).hexdigest()
         self.assertEqual(newmd5, junkmd5)
--- twisted/protocols/sip.py (revision 17451)
+++ twisted/protocols/sip.py (revision 25457)
@@ -1,5 +1,5 @@
 # -*- test-case-name: twisted.test.test_sip -*-
 
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -15,5 +15,4 @@
 import random
 import time
-import md5
 import sys
 from zope.interface import implements, Interface
@@ -21,4 +20,5 @@
 # twisted imports
 from twisted.python import log, util
+from twisted.python.hashlib import md5
 from twisted.internet import protocol, defer, reactor
 
@@ -133,5 +133,5 @@
     pszCNonce,
 ):
-    m = md5.md5()
+    m = md5()
     m.update(pszUserName)
     m.update(":")
@@ -141,5 +141,5 @@
     HA1 = m.digest()
     if pszAlg == "md5-sess":
-        m = md5.md5()
+        m = md5()
         m.update(HA1)
         m.update(":")
@@ -160,5 +160,5 @@
     pszHEntity,
 ):
-    m = md5.md5()
+    m = md5()
     m.update(pszMethod)
     m.update(":")
@@ -169,5 +169,5 @@
     HA2 = m.digest().encode('hex')
     
-    m = md5.md5()
+    m = md5()
     m.update(HA1)
     m.update(":")
--- twisted/conch/test/test_transport.py (revision 24770)
+++ twisted/conch/test/test_transport.py (revision 25457)
@@ -5,6 +5,4 @@
 Tests for ssh/transport.py and the classes therein.
 """
-
-import md5, sha
 
 try:
@@ -28,4 +26,5 @@
 from twisted.python import randbytes
 from twisted.python.reflect import qual
+from twisted.python.hashlib import md5, sha1
 from twisted.conch.ssh import service
 from twisted.test import proto_helpers
@@ -857,7 +856,6 @@
         self.proto.sessionID = 'EF'
 
-        k1 = sha.new('AB' + 'CD'
-                     + 'K' + self.proto.sessionID).digest()
-        k2 = sha.new('ABCD' + k1).digest()
+        k1 = sha1('AB' + 'CD' + 'K' + self.proto.sessionID).digest()
+        k2 = sha1('ABCD' + k1).digest()
         self.assertEquals(self.proto._getKey('K', 'AB', 'CD'), k1 + k2)
 
@@ -1110,5 +1108,5 @@
         sharedSecret = common._MPpow(e, y, transport.DH_PRIME)
 
-        h = sha.new()
+        h = sha1()
         h.update(common.NS(self.proto.ourVersionString) * 2)
         h.update(common.NS(self.proto.ourKexInitPayload) * 2)
@@ -1191,5 +1189,5 @@
         f = common._MPpow(self.proto.g, y, self.proto.p)
         sharedSecret = common._MPpow(e, y, self.proto.p)
-        h = sha.new()
+        h = sha1()
         h.update(common.NS(self.proto.ourVersionString) * 2)
         h.update(common.NS(self.proto.ourKexInitPayload) * 2)
@@ -1222,5 +1220,5 @@
         f = common._MPpow(self.proto.g, y, self.proto.p)
         sharedSecret = common._MPpow(e, y, self.proto.p)
-        h = sha.new()
+        h = sha1()
         h.update(common.NS(self.proto.ourVersionString) * 2)
         h.update(common.NS(self.proto.ourKexInitPayload) * 2)
@@ -1361,5 +1359,5 @@
         self.assertEquals(pubKey, self.blob)
         self.assertEquals(fingerprint.replace(':', ''),
-                          md5.new(pubKey).hexdigest())
+                          md5(pubKey).hexdigest())
         return defer.succeed(True)
 
@@ -1428,5 +1426,5 @@
         sharedSecret = common._MPpow(transport.DH_GENERATOR,
                                      self.proto.x, transport.DH_PRIME)
-        h = sha.new()
+        h = sha1()
         h.update(common.NS(self.proto.ourVersionString) * 2)
         h.update(common.NS(self.proto.ourKexInitPayload) * 2)
@@ -1477,5 +1475,5 @@
         self.test_KEX_DH_GEX_GROUP()
         sharedSecret = common._MPpow(3, self.proto.x, self.proto.p)
-        h = sha.new()
+        h = sha1()
         h.update(common.NS(self.proto.ourVersionString) * 2)
         h.update(common.NS(self.proto.ourKexInitPayload) * 2)
@@ -1655,5 +1653,5 @@
                 self.assertEquals(mod[2],
                                   Crypto.Cipher.XOR.new('\x5c').encrypt(key))
-                self.assertEquals(mod[3], len(mod[0].new().digest()))
+                self.assertEquals(mod[3], len(mod[0]().digest()))
 
 
@@ -1694,5 +1692,5 @@
             inMac.setKeys('', '', '', '', '', key)
             if mod:
-                ds = mod.digest_size
+                ds = mod().digest_size
             else:
                 ds = 0
@@ -1704,5 +1702,5 @@
             packet = '\x00' * 4 + key
             if mod:
-                mac = mod.new(o + mod.new(i + packet).digest()).digest()
+                mac = mod(o + mod(i + packet).digest()).digest()
             else:
                 mac = ''
--- twisted/conch/test/test_keys.py (revision 25365)
+++ twisted/conch/test/test_keys.py (revision 25457)
@@ -13,8 +13,9 @@
     from twisted.conch.ssh import keys, common, sexpy, asn1
 
+import os, base64
 from twisted.conch.test import keydata
 from twisted.python import randbytes
+from twisted.python.hashlib import sha1
 from twisted.trial import unittest
-import sha, os, base64
 
 class SSHKeysHandlingTestCase(unittest.TestCase):
@@ -331,5 +332,5 @@
         self.assertEquals(keys.pkcs1Pad(data, messageSize),
                 '\x01\xff\x00ABC')
-        hash = sha.new().digest()
+        hash = sha1().digest()
         messageSize = 40
         self.assertEquals(keys.pkcs1Digest('', messageSize),
@@ -363,5 +364,5 @@
         data = 'data'
         key, sig = self._signDSA(data)
-        sigData = sha.new(data).digest()
+        sigData = sha1(data).digest()
         v = key.sign(sigData, '\x55' * 19)
         self.assertEquals(sig, common.NS('ssh-dss') + common.NS(
--- twisted/conch/test/test_ckeygen.py (revision 25457)
+++ twisted/conch/test/test_ckeygen.py (revision 25457)
@@ -0,0 +1,73 @@
+# Copyright (c) 2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Tests for L{twisted.conch.scripts.ckeygen}.
+"""
+
+import sys
+from StringIO import StringIO
+
+from twisted.python.filepath import FilePath
+from twisted.trial.unittest import TestCase
+from twisted.conch.ssh.keys import Key
+from twisted.conch.scripts.ckeygen import printFingerprint, _saveKey
+from twisted.conch.test.keydata import publicRSA_openssh, privateRSA_openssh
+
+
+
+class KeyGenTests(TestCase):
+    """
+    Tests for various functions used to implement the I{ckeygen} script.
+    """
+    def setUp(self):
+        """
+        Patch C{sys.stdout} with a L{StringIO} instance to tests can make
+        assertions about what's printed.
+        """
+        self.stdout = StringIO()
+        self.patch(sys, 'stdout', self.stdout)
+
+
+    def test_printFingerprint(self):
+        """
+        L{printFingerprint} writes a line to standard out giving the number of
+        bits of the key, its fingerprint, and the basename of the file from it
+        was read.
+        """
+        filename = self.mktemp()
+        FilePath(filename).setContent(publicRSA_openssh)
+        printFingerprint({'filename': filename})
+        self.assertEqual(
+            self.stdout.getvalue(),
+            '768 3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af temp\n')
+
+
+    def test_saveKey(self):
+        """
+        L{_saveKey} writes the private and public parts of a key to two
+        different files and writes a report of this to standard out.
+        """
+        base = FilePath(self.mktemp())
+        base.makedirs()
+        filename = base.child('id_rsa').path
+        key = Key.fromString(privateRSA_openssh)
+        _saveKey(
+            key.keyObject,
+            {'filename': filename, 'pass': 'passphrase'})
+        self.assertEqual(
+            self.stdout.getvalue(),
+            "Your identification has been saved in %s\n"
+            "Your public key has been saved in %s.pub\n"
+            "The key fingerprint is:\n"
+            "3d:13:5f:cb:c9:79:8a:93:06:27:65:bc:3d:0b:8f:af\n" % (
+                filename,
+                filename))
+        self.assertEqual(
+            key.fromString(
+                base.child('id_rsa').getContent(), None, 'passphrase'),
+            key)
+        self.assertEqual(
+            Key.fromString(base.child('id_rsa.pub').getContent()),
+            key.public())
+
--- twisted/conch/scripts/ckeygen.py (revision 21376)
+++ twisted/conch/scripts/ckeygen.py (revision 25457)
@@ -1,15 +1,11 @@
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# -*- test-case-name: twisted.conch.test.test_ckeygen -*-
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
-#
-# $Id: ckeygen.py,v 1.8 2003/05/10 14:03:40 spiv Exp $
+"""
+Implementation module for the `ckeygen` command.
+"""
 
-#""" Implementation module for the `ckeygen` command.
-#"""
-
-from twisted.conch.ssh import keys
-from twisted.python import log, usage, randbytes
-
-import sys, os, getpass, md5, socket
+import sys, os, getpass, socket
 if getpass.getpass == getpass.unix_getpass:
     try:
@@ -19,4 +15,8 @@
         sys.modules['termios'] = None
         reload(getpass)
+
+from twisted.conch.ssh import keys
+from twisted.python import filepath, log, usage, randbytes
+
 
 class GeneralOptions(usage.Options):
@@ -89,4 +89,5 @@
     _saveKey(key, options)
 
+
 def printFingerprint(options):
     if not options['filename']:
@@ -96,9 +97,10 @@
         options['filename'] += '.pub'
     try:
-        string = keys.getPublicKeyString(options['filename'])
-        obj = keys.getPublicKeyObject(string)
+        key = keys.Key.fromFile(options['filename'])
+        obj = key.keyObject
+        string = key.blob()
         print '%s %s %s' % (
-            obj.size()+1,
-            ':'.join(['%02x' % ord(x) for x in md5.new(string).digest()]),
+            obj.size() + 1,
+            key.fingerprint(),
             os.path.basename(options['filename']))
     except:
@@ -164,15 +166,19 @@
             print 'Passphrases do not match.  Try again.'
         options['pass'] = p1
+
+    keyObj = keys.Key(key)
     comment = '%s@%s' % (getpass.getuser(), socket.gethostname())
-    open(options['filename'], 'w').write(
-            keys.makePrivateKeyString(key, passphrase=options['pass']))
+
+    filepath.FilePath(options['filename']).setContent(
+        keyObj.toString('openssh', options['pass']))
     os.chmod(options['filename'], 33152)
-    open(options['filename']+'.pub', 'w').write(
-            keys.makePublicKeyString(key, comment = comment))
-    pubKey = keys.getPublicKeyString(data=keys.makePublicKeyString(key, comment=comment))
+
+    filepath.FilePath(options['filename'] + '.pub').setContent(
+        keyObj.public().toString('openssh', comment))
+
     print 'Your identification has been saved in %s' % options['filename']
     print 'Your public key has been saved in %s.pub' % options['filename']
     print 'The key fingerprint is:'
-    print ':'.join(['%02x' % ord(x) for x in md5.new(pubKey).digest()])
+    print keyObj.fingerprint()
 
 if __name__ == '__main__':
--- twisted/conch/ssh/keys.py (revision 25365)
+++ twisted/conch/ssh/keys.py (revision 25457)
@@ -11,5 +11,4 @@
 # base library imports
 import base64
-import sha, md5
 import warnings
 
@@ -21,4 +20,5 @@
 # twisted
 from twisted.python import randbytes
+from twisted.python.hashlib import md5, sha1
 
 # sibling imports
@@ -206,6 +206,6 @@
             if not passphrase:
                 raise EncryptedKeyError('encrypted key with no passphrase')
-            ba = md5.new(passphrase + iv).digest()
-            bb = md5.new(ba + passphrase + iv).digest()
+            ba = md5(passphrase + iv).digest()
+            bb = md5(ba + passphrase + iv).digest()
             decKey = (ba + bb)[:24]
             b64Data = base64.decodestring(''.join(lines[3:-1]))
@@ -444,5 +444,5 @@
         @rtype: L{str}
         """
-        return ':'.join([x.encode('hex') for x in md5.md5(self.blob()).digest()])
+        return ':'.join([x.encode('hex') for x in md5(self.blob()).digest()])
 
 
@@ -598,6 +598,6 @@
                 lines.append('Proc-Type: 4,ENCRYPTED')
                 lines.append('DEK-Info: DES-EDE3-CBC,%s\n' % hexiv)
-                ba = md5.new(extra + iv).digest()
-                bb = md5.new(ba + extra + iv).digest()
+                ba = md5(extra + iv).digest()
+                bb = md5(ba + extra + iv).digest()
                 encKey = (ba + bb)[:24]
             asn1Data = asn1.pack([objData])
@@ -682,5 +682,5 @@
             ret = common.NS(Util.number.long_to_bytes(signature))
         elif self.type() == 'DSA':
-            digest = sha.new(data).digest()
+            digest = sha1(data).digest()
             randomBytes = randbytes.secureRandom(19)
             sig = self.keyObject.sign(digest, randomBytes)
@@ -711,5 +711,5 @@
             numbers = [Util.number.bytes_to_long(n) for n in signature[:20],
                     signature[20:]]
-            digest = sha.new(data).digest()
+            digest = sha1(data).digest()
         return self.keyObject.verify(digest, numbers)
 
@@ -864,5 +864,5 @@
     @type messageLength: C{str}
     """
-    digest = sha.new(data).digest()
+    digest = sha1(data).digest()
     return pkcs1Pad(ID_SHA1+digest, messageLength)
 
--- twisted/conch/ssh/transport.py (revision 24441)
+++ twisted/conch/ssh/transport.py (revision 25457)
@@ -14,6 +14,4 @@
 # base library imports
 import struct
-import md5
-import sha
 import zlib
 import array
@@ -27,4 +25,5 @@
 from twisted.conch import error
 from twisted.python import log, randbytes
+from twisted.python.hashlib import md5, sha1
 
 # sibling imports
@@ -533,7 +532,7 @@
         @type exchangeHash: C{str}
         """
-        k1 = sha.new(sharedSecret + exchangeHash + c + self.sessionID)
+        k1 = sha1(sharedSecret + exchangeHash + c + self.sessionID)
         k1 = k1.digest()
-        k2 = sha.new(sharedSecret + exchangeHash + k1).digest()
+        k2 = sha1(sharedSecret + exchangeHash + k1).digest()
         return k1 + k2
 
@@ -724,5 +723,5 @@
             serverDHpublicKey = _MPpow(DH_GENERATOR, y, DH_PRIME)
             sharedSecret = _MPpow(clientDHpublicKey, y, DH_PRIME)
-            h = sha.new()
+            h = sha1()
             h.update(NS(self.otherVersionString))
             h.update(NS(self.ourVersionString))
@@ -793,5 +792,5 @@
         serverDHpublicKey = _MPpow(self.g, y, self.p)
         sharedSecret = _MPpow(clientDHpublicKey, y, self.p)
-        h = sha.new()
+        h = sha1()
         h.update(NS(self.otherVersionString))
         h.update(NS(self.ourVersionString))
@@ -934,5 +933,5 @@
             signature, packet = getNS(packet)
             fingerprint = ':'.join([ch.encode('hex') for ch in
-                                    md5.new(pubKey).digest()])
+                                    md5(pubKey).digest()])
             d = self.verifyHostKey(pubKey, fingerprint)
             d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature)
@@ -963,5 +962,5 @@
         serverKey = keys.Key.fromString(pubKey)
         sharedSecret = _MPpow(f, self.x, DH_PRIME)
-        h = sha.new()
+        h = sha1()
         h.update(NS(self.ourVersionString))
         h.update(NS(self.otherVersionString))
@@ -993,5 +992,5 @@
         signature, packet = getNS(packet)
         fingerprint = ':'.join(map(lambda c: '%02x'%ord(c),
-            md5.new(pubKey).digest()))
+            md5(pubKey).digest()))
         d = self.verifyHostKey(pubKey, fingerprint)
         d.addCallback(self._continueGEX_REPLY, pubKey, f, signature)
@@ -1016,5 +1015,5 @@
         serverKey = keys.Key.fromString(pubKey)
         sharedSecret = _MPpow(f, self.x, self.p)
-        h = sha.new()
+        h = sha1()
         h.update(NS(self.ourVersionString))
         h.update(NS(self.otherVersionString))
@@ -1170,7 +1169,7 @@
     }
     macMap = {
-        'hmac-sha1': sha,
+        'hmac-sha1': sha1,
         'hmac-md5': md5,
-        'none':None
+        'none': None
      }
 
@@ -1244,8 +1243,5 @@
         if not mod:
             return (None, '', '', 0)
-        #if not hasattr(mod, 'digest_size'):
-        #     ds = len(mod.new().digest())
-        #else:
-        ds = mod.digest_size
+        ds = mod().digest_size
         key = key[:ds] + '\x00' * (64 - ds)
         i = XOR.new('\x36').encrypt(key)
@@ -1288,6 +1284,6 @@
         data = struct.pack('>L', seqid) + data
         mod, i, o, ds = self.outMAC
-        inner = mod.new(i + data)
-        outer = mod.new(o + inner.digest())
+        inner = mod(i + data)
+        outer = mod(o + inner.digest())
         return outer.digest()
 
@@ -1310,6 +1306,6 @@
         data = struct.pack('>L', seqid) + data
         mod, i, o, ds = self.inMAC
-        inner = mod.new(i + data)
-        outer = mod.new(o + inner.digest())
+        inner = mod(i + data)
+        outer = mod(o + inner.digest())
         return mac == outer.digest()
 
--- twisted/words/test/test_msn.py (revision 24660)
+++ twisted/words/test/test_msn.py (revision 25457)
@@ -1,3 +1,3 @@
-# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -7,5 +7,5 @@
 
 # System imports
-import StringIO, sys
+import StringIO
 
 # Twisted imports
@@ -25,4 +25,5 @@
 
 
+from twisted.python.hashlib import md5
 from twisted.protocols import loopback
 from twisted.internet.defer import Deferred
@@ -256,7 +257,32 @@
 
 
+    def test_challenge(self):
+        """
+        L{NotificationClient} responds to a I{CHL} message by sending a I{QRY}
+        back which included a hash based on the parameters of the I{CHL}.
+        """
+        transport = StringIOWithoutClosing()
+        self.client.makeConnection(transport)
+        transport.seek(0)
+        transport.truncate()
+
+        challenge = "15570131571988941333"
+        self.client.dataReceived('CHL 0 ' + challenge + '\r\n')
+        # md5 of the challenge and a magic string defined by the protocol
+        response = "8f2f5a91b72102cd28355e9fc9000d6e"
+        # Sanity check - the response is what the comment above says it is.
+        self.assertEqual(
+            response, md5(challenge + "Q1P7W2E4J9R8U3S5").hexdigest())
+        self.assertEqual(
+            transport.getvalue(),
+            # 2 is the next transaction identifier.  32 is the length of the
+            # response.
+            "QRY 2 msmsgs@msnmsgr.com 32\r\n" + response)
+
+
     def testLogin(self):
         self.client.lineReceived('USR 1 OK foo@bar.com Test%20Screen%20Name 1 0')
         self.failUnless((self.client.state == 'LOGIN'), msg='Failed to detect successful login')
+
 
     def testProfile(self):
--- twisted/words/test/test_oscar.py (revision 25457)
+++ twisted/words/test/test_oscar.py (revision 25457)
@@ -0,0 +1,24 @@
+# Copyright (c) 2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Tests for L{twisted.words.protocols.oscar}.
+"""
+
+from twisted.trial.unittest import TestCase
+
+from twisted.words.protocols.oscar import encryptPasswordMD5
+
+
+class PasswordTests(TestCase):
+    """
+    Tests for L{encryptPasswordMD5}.
+    """
+    def test_encryptPasswordMD5(self):
+        """
+        L{encryptPasswordMD5} hashes the given password and key and returns a
+        string suitable to use to authenticate against an OSCAR server.
+        """
+        self.assertEqual(
+            encryptPasswordMD5('foo', 'bar').encode('hex'),
+            'd73475c370a7b18c6c20386bcf1339f2')
--- twisted/words/test/test_jabbercomponent.py (revision 25272)
+++ twisted/words/test/test_jabbercomponent.py (revision 25457)
@@ -6,7 +6,6 @@
 """
 
-import sha
-
 from twisted.python import failure
+from twisted.python.hashlib import sha1
 from twisted.trial import unittest
 from twisted.words.protocols.jabber import component, xmlstream
@@ -51,5 +50,5 @@
         self.assertEquals('handshake', handshake.name)
         self.assertEquals('test:component', handshake.uri)
-        self.assertEquals(sha.new("%s%s" % ('12345', 'secret')).hexdigest(),
+        self.assertEquals(sha1("%s%s" % ('12345', 'secret')).hexdigest(),
                           unicode(handshake))
 
@@ -81,5 +80,5 @@
 
         # Calculate what we expect the handshake value to be
-        hv = sha.new("%s%s" % ("12345", "secret")).hexdigest()
+        hv = sha1("%s%s" % ("12345", "secret")).hexdigest()
 
         self.assertEquals(outlist[1], "<handshake>%s</handshake>" % (hv))
--- twisted/words/test/test_jabberclient.py (revision 20997)
+++ twisted/words/test/test_jabberclient.py (revision 25457)
@@ -1,3 +1,3 @@
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -6,5 +6,5 @@
 """
 
-import sha
+from twisted.python.hashlib import sha1
 from twisted.trial import unittest
 from twisted.words.protocols.jabber import client, error, jid, xmlstream
@@ -118,5 +118,5 @@
                           (iq.children[0].uri, iq.children[0].name))
         self.assertEquals('user', unicode(iq.query.username))
-        self.assertEquals(sha.new('12345secret').hexdigest(),
+        self.assertEquals(sha1('12345secret').hexdigest(),
                           unicode(iq.query.digest))
         self.assertEquals('resource', unicode(iq.query.resource))
--- twisted/words/protocols/msn.py (revision 24770)
+++ twisted/words/protocols/msn.py (revision 25457)
@@ -1,7 +1,5 @@
 # -*- test-case-name: twisted.words.test -*-
-# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
-
-#
 
 """
@@ -19,5 +17,5 @@
 You will want to subclass this and handle the gotNotificationReferral
 method appropriately.
-    
+
 I{Notification Server}
 
@@ -74,9 +72,10 @@
 """
 
-import types, operator, os, md5
+import types, operator, os
 from random import randint
 from urllib import quote, unquote
 
 from twisted.python import failure, log
+from twisted.python.hashlib import md5
 from twisted.internet import reactor
 from twisted.internet.defer import Deferred
@@ -186,5 +185,5 @@
 
 class PassportNexus(HTTPClient):
-    
+
     """
     Used to obtain the URL of a valid passport
@@ -331,5 +330,5 @@
                This is relevant for the return value of
                SwitchboardClient.sendMessage (which will return
-               a Deferred if ack is set to either MESSAGE_ACK or MESSAGE_NACK  
+               a Deferred if ack is set to either MESSAGE_ACK or MESSAGE_NACK
                and will fire when the respective ACK or NACK is received).
                If set to MESSAGE_ACK_NONE sendMessage will return None.
@@ -380,5 +379,5 @@
 
 class MSNContact:
-    
+
     """
     This class represents a contact (user).
@@ -402,5 +401,5 @@
                     (true=yes, false=no)
     """
-    
+
     def __init__(self, userHandle="", screenName="", lists=0, groups=[], status=None):
         self.userHandle = userHandle
@@ -857,5 +856,5 @@
         checkParamLen(len(params), 2, 'CHL')
         self.sendLine("QRY %s msmsgs@msnmsgr.com 32" % self._nextTransactionID())
-        self.transport.write(md5.md5(params[1] + MSN_CHALLENGE_STR).hexdigest())
+        self.transport.write(md5(params[1] + MSN_CHALLENGE_STR).hexdigest())
 
     def handle_QRY(self, params):
@@ -1254,5 +1253,5 @@
                  only element.
         """
-        
+
         id, d = self._createIDMapping()
         self.sendLine("CHG %s %s" % (id, status))
@@ -1305,5 +1304,5 @@
                           interprets as -> allow messages from all
                           users except those on the block list.
-                          
+
         @return: A Deferred, the callback of which will be fired when
                  the server replies with the new privacy setting.
@@ -1363,5 +1362,5 @@
     # should be. If someone has a specific justified need for this
     # then please contact me and i'll re-enable/fix support for it.
-                    
+
     #def requestListGroups(self):
     #    """
@@ -1374,5 +1373,5 @@
     #             current list version.
     #    """
-    #    
+    #
     #    # this doesn't need to be used if syncing of the lists takes place (which it SHOULD!)
     #    # i.e. please don't use it!
@@ -1474,5 +1473,5 @@
                  the new group name (str).
         """
-        
+
         id, d = self._createIDMapping()
         self.sendLine("REG %s %s %s 0" % (id, groupID, quote(newName)))
@@ -1510,5 +1509,5 @@
                  will be None)
         """
-        
+
         id, d = self._createIDMapping()
         listType = listIDToCode[listType].upper()
@@ -1555,5 +1554,5 @@
                  be None)
         """
-        
+
         id, d = self._createIDMapping()
         listType = listIDToCode[listType].upper()
@@ -1625,5 +1624,5 @@
         to close the connection.
         """
-        
+
         self.sendLine("OUT")
 
@@ -2118,5 +2117,5 @@
         self.segmentLength = 0
         self.buffer = ''
-        
+
         if isinstance(file, types.StringType):
             path = os.path.join(directory, file)
@@ -2238,5 +2237,5 @@
                 transfer invitation
     """
-    
+
     def __init__(self, file):
         """
--- twisted/words/protocols/jabber/sasl_mechanisms.py (revision 20070)
+++ twisted/words/protocols/jabber/sasl_mechanisms.py (revision 25457)
@@ -1,5 +1,5 @@
 # -*- test-case-name: twisted.words.test.test_jabbersaslmechanisms -*-
 #
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -8,7 +8,9 @@
 """
 
-import md5, binascii, random, time, os
+import binascii, random, time, os
 
 from zope.interface import Interface, Attribute, implements
+
+from twisted.python.hashlib import md5
 
 class ISASLMechanism(Interface):
@@ -179,5 +181,5 @@
 
         def H(s):
-            return md5.new(s).digest()
+            return md5(s).digest()
 
         def HEX(n):
@@ -222,3 +224,3 @@
 
     def _gen_nonce(self):
-        return md5.new("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
+        return md5("%s:%s:%s" % (str(random.random()) , str(time.gmtime()),str(os.getpid()))).hexdigest()
--- twisted/words/protocols/jabber/xmlstream.py (revision 25272)
+++ twisted/words/protocols/jabber/xmlstream.py (revision 25457)
@@ -43,6 +43,6 @@
     Create a SHA1-digest string of a session identifier and password.
     """
-    import sha
-    return sha.new("%s%s" % (sid, password)).hexdigest()
+    from twisted.python.hashlib import sha1
+    return sha1("%s%s" % (sid, password)).hexdigest()
 
 
--- twisted/words/protocols/oscar.py (revision 24441)
+++ twisted/words/protocols/oscar.py (revision 25457)
@@ -1,4 +1,4 @@
 # -*- test-case-name: twisted.words.test -*-
-# Copyright (c) 2001-2005 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -10,17 +10,14 @@
 """
 
-from __future__ import nested_scopes
-
-from twisted.internet import reactor, defer, protocol
-from twisted.python import log
-
 import struct
-import md5
 import string
 import socket
 import random
-import time
 import types
 import re
+
+from twisted.internet import reactor, defer, protocol
+from twisted.python import log
+from twisted.python.hashlib import md5
 
 def logPacketData(data):
@@ -63,7 +60,7 @@
 
 def encryptPasswordMD5(password,key):
-    m=md5.new()
+    m=md5()
     m.update(key)
-    m.update(md5.new(password).digest())
+    m.update(md5(password).digest())
     m.update("AOL Instant Messenger (SM)")
     return m.digest()
--- twisted/web2/test/test_httpauth.py (revision 19764)
+++ twisted/web2/test/test_httpauth.py (revision 25457)
@@ -1,3 +1,6 @@
-import md5
+# Copyright (c) 2006-2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+from twisted.python.hashlib import md5
 from twisted.internet import address
 from twisted.trial import unittest
@@ -264,8 +267,8 @@
 
         self.failUnless(creds.checkHash(
-                md5.md5('username:test realm:password').hexdigest()))
+                md5('username:test realm:password').hexdigest()))
 
         self.failIf(creds.checkHash(
-                md5.md5('username:test realm:bogus').hexdigest()))
+                md5('username:test realm:bogus').hexdigest()))
 
     def test_invalidOpaque(self):
@@ -365,5 +368,5 @@
                             clientAddress.host,
                             '-137876876')
-        digest = md5.new(key + credentialFactory.privateKey).hexdigest()
+        digest = md5(key + credentialFactory.privateKey).hexdigest()
         ekey = key.encode('base64')
 
@@ -391,5 +394,5 @@
                             '0')
 
-        digest = md5.new(key + 'this is not the right pkey').hexdigest()
+        digest = md5(key + 'this is not the right pkey').hexdigest()
 
         badChecksum = '%s-%s' % (digest,
--- twisted/web2/server.py (revision 21556)
+++ twisted/web2/server.py (revision 25457)
@@ -1,4 +1,4 @@
 # -*- test-case-name: twisted.web2.test.test_server -*-
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -523,5 +523,5 @@
         def filterit(response, f):
             if (hasattr(f, 'handleErrors') or
-                (response.code >= 200 and response.code < 300 and response.code != 204)):
+                (response.code >= 200 and response.code < 300)):
                 return f(self, response)
             else:
--- twisted/web2/auth/digest.py (revision 20346)
+++ twisted/web2/auth/digest.py (revision 25457)
@@ -1,3 +1,4 @@
 # -*- test-case-name: twisted.web2.test.test_httpauth -*-
+# Copyright (c) 2006-2008 Twisted Matrix Laboratories.
 
 """
@@ -6,5 +7,7 @@
 http://www.faqs.org/rfcs/rfc2617.html
 """
+import sys
 import time
+import random
 
 from twisted.cred import credentials, error
@@ -12,14 +15,12 @@
 
 from twisted.web2.auth.interfaces import ICredentialFactory
-
-import md5, sha
-import random, sys
+from twisted.python.hashlib import md5, sha1
 
 # The digest math
 
 algorithms = {
-    'md5': md5.new,
-    'md5-sess': md5.new,
-    'sha': sha.new,
+    'md5': md5,
+    'md5-sess': md5,
+    'sha': sha1,
 }
 
@@ -229,5 +230,5 @@
         # in the opaque value with a suitable digest
         key = "%s,%s,%s" % (nonce, clientip, str(int(self._getTime())))
-        digest = md5.new(key + self.privateKey).hexdigest()
+        digest = md5(key + self.privateKey).hexdigest()
         ekey = key.encode('base64')
         return "%s-%s" % (digest, ekey.strip('\n'))
@@ -276,5 +277,5 @@
 
         # Verify the digest
-        digest = md5.new(key + self.privateKey).hexdigest()
+        digest = md5(key + self.privateKey).hexdigest()
         if digest != opaqueParts[0]:
             raise error.LoginFailed('Invalid response, invalid opaque value')
--- twisted/web2/static.py (revision 20546)
+++ twisted/web2/static.py (revision 25457)
@@ -1,3 +1,3 @@
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -10,5 +10,4 @@
 import os, time, stat
 import tempfile
-import md5
 
 # Sibling Imports
--- twisted/persisted/sob.py (revision 24441)
+++ twisted/persisted/sob.py (revision 25457)
@@ -1,4 +1,4 @@
 # -*- test-case-name: twisted.test.test_sob -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -10,5 +10,5 @@
 """
 
-import os, md5, sys
+import os, sys
 try:
     import cPickle as pickle
@@ -20,4 +20,5 @@
     import StringIO
 from twisted.python import log, runtime
+from twisted.python.hashlib import md5
 from twisted.persisted import styles
 from zope.interface import implements, Interface
@@ -32,9 +33,9 @@
     if leftover:
         data += ' '*(cipher.block_size - leftover)
-    return cipher.new(md5.new(passphrase).digest()[:16]).encrypt(data)
+    return cipher.new(md5(passphrase).digest()[:16]).encrypt(data)
 
 def _decrypt(passphrase, data):
     from Crypto.Cipher import AES
-    return AES.new(md5.new(passphrase).digest()[:16]).decrypt(data)
+    return AES.new(md5(passphrase).digest()[:16]).decrypt(data)
 
 
--- twisted/news/database.py (revision 24441)
+++ twisted/news/database.py (revision 25457)
@@ -1,4 +1,4 @@
 # -*- test-case-name: twisted.news.test.test_news -*-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -14,5 +14,9 @@
 
 
-from __future__ import nested_scopes
+import getpass, pickle, time, socket
+import os
+import StringIO
+
+from zope.interface import implements, Interface
 
 from twisted.news.nntp import NNTPError
@@ -21,9 +25,6 @@
 from twisted.enterprise import adbapi
 from twisted.persisted import dirdbm
-
-import getpass, pickle, time, socket, md5
-import os
-import StringIO
-from zope.interface import implements, Interface
+from twisted.python.hashlib import md5
+
 
 
@@ -54,13 +55,13 @@
         if not self.getHeader('Message-ID'):
             s = str(time.time()) + self.body
-            id = hexdigest(md5.md5(s)) + '@' + socket.gethostname()
+            id = hexdigest(md5(s)) + '@' + socket.gethostname()
             self.putHeader('Message-ID', '<%s>' % id)
 
         if not self.getHeader('Bytes'):
             self.putHeader('Bytes', str(len(self.body)))
-        
+
         if not self.getHeader('Lines'):
             self.putHeader('Lines', str(self.body.count('\n')))
-        
+
         if not self.getHeader('Date'):
             self.putHeader('Date', time.ctime(time.time()))
@@ -84,5 +85,5 @@
             headers.append('%s: %s' % i)
         return '\r\n'.join(headers) + '\r\n'
-    
+
     def overview(self):
         xover = []
@@ -95,10 +96,10 @@
     pass
 
-    
+
 class INewsStorage(Interface):
     """
     An interface for storing and requesting news articles
     """
-    
+
     def listRequest():
         """
@@ -113,6 +114,6 @@
         recommended subscription groups for new server users
         """
-    
-    
+
+
     def postRequest(message):
         """
@@ -121,6 +122,6 @@
         whose errback will be invoked otherwise.
         """
-    
-    
+
+
     def overviewRequest():
         """
@@ -147,5 +148,5 @@
         """
 
-    
+
     def listGroupRequest(group):
         """
@@ -153,6 +154,6 @@
         (group name, [article indices])
         """
-    
-    
+
+
     def groupRequest(group):
         """
@@ -161,5 +162,5 @@
         """
 
-    
+
     def articleExistsRequest(id):
         """
@@ -171,5 +172,5 @@
 
     def articleRequest(group, index, id = None):
-        """ 
+        """
         Returns a deferred whose callback will be passed a file-like object
         containing the full article text (headers and body) for the article
@@ -181,5 +182,5 @@
         """
 
-    
+
     def headRequest(group, index):
         """
@@ -190,5 +191,5 @@
         """
 
-    
+
     def bodyRequest(group, index):
         """
@@ -232,5 +233,5 @@
 class PickleStorage:
     """A trivial NewsStorage implementation using pickles
-    
+
     Contains numerous flaws and is generally unsuitable for any
     real applications.  Consider yourself warned!
@@ -389,6 +390,6 @@
         else:
             return defer.fail(ERR_NOGROUP)
-                
-    
+
+
     def headRequest(self, group, index):
         if self.db.has_key(group):
@@ -442,5 +443,5 @@
     maxArticle = 0
     articles = None
-    
+
     def __init__(self, name, flags = 'y'):
         self.name = name
@@ -453,7 +454,7 @@
     A NewStorage implementation using Twisted's dirdbm persistence module.
     """
-    
-    implements(INewsStorage)    
-    
+
+    implements(INewsStorage)
+
     def __init__(self, mailhost, path):
         self.path = path
@@ -503,6 +504,6 @@
     def subscriptionRequest(self):
         return defer.succeed(self.dbm['subscriptions'])
-    
-    
+
+
     def getModerator(self, groups):
         # first see if any groups are moderated.  if so, nothing gets posted,
@@ -533,15 +534,15 @@
         cleave = message.find('\r\n\r\n')
         headers, article = message[:cleave], message[cleave + 4:]
-        
+
         article = Article(headers, article)
         groups = article.getHeader('Newsgroups').split()
         xref = []
-        
+
         # Check for moderated status
         moderator = self.getModerator(groups)
         if moderator and not article.getHeader('Approved'):
             return self.notifyModerator(moderator, article)
-        
-        
+
+
         for group in groups:
             try:
@@ -571,5 +572,5 @@
         if not self.dbm['groups'].has_key(group):
             return defer.succeed([])
-        
+
         if low is None:
             low = 0
@@ -586,5 +587,5 @@
         if group not in self.dbm['groups']:
             return defer.succeed([])
-        
+
         if low is None:
             low = 0
@@ -619,6 +620,6 @@
     def articleExistsRequest(self, id):
         return defer.succeed(id in self.dbm['Message-IDs'])
-    
-    
+
+
     def articleRequest(self, group, index, id = None):
         if id is not None:
@@ -630,5 +631,5 @@
                 group, index = xref[0]
                 index = int(index)
-        
+
         try:
             a = self.dbm['groups'][group].articles[index]
@@ -641,6 +642,6 @@
                 StringIO.StringIO(a.textHeaders() + '\r\n' + a.body)
             ))
-    
-    
+
+
     def headRequest(self, group, index, id = None):
         if id is not None:
@@ -652,5 +653,5 @@
                 group, index = xref[0]
                 index = int(index)
-        
+
         try:
             a = self.dbm['groups'][group].articles[index]
@@ -670,5 +671,5 @@
                 group, index = xref[0]
                 index = int(index)
-        
+
         try:
             a = self.dbm['groups'][group].articles[index]
@@ -691,5 +692,5 @@
         group_id      SERIAL,
         name          VARCHAR(80) NOT NULL,
-        
+
         flags         INTEGER DEFAULT 0 NOT NULL
     );
@@ -701,5 +702,5 @@
         article_id    SERIAL,
         message_id    TEXT,
-        
+
         header        TEXT,
         body          TEXT
@@ -720,14 +721,14 @@
         group_id    INTEGER
     );
-    
+
     CREATE TABLE overview (
         header      TEXT
     );
     """
-    
+
     def __init__(self, info):
         self.info = info
         self.dbpool = adbapi.ConnectionPool(**self.info)
-        
+
 
     def __setstate__(self, state):
@@ -779,12 +780,12 @@
             WHERE name IN (%s)
         """ % (', '.join([("'%s'" % (adbapi.safe(group),)) for group in groups]),)
-        
+
         transaction.execute(sql)
         result = transaction.fetchall()
-        
+
         # No relevant groups, bye bye!
         if not len(result):
             raise NNTPError('None of groups in Newsgroup header carried')
-        
+
         # Got some groups, now find the indices this article will have in each
         sql = """
@@ -801,18 +802,18 @@
         if not len(indices):
             raise NNTPError('Internal server error - no indices found')
-        
+
         # Associate indices with group names
         gidToName = dict([(b, a) for (a, b) in result])
         gidToIndex = dict(indices)
-        
+
         nameIndex = []
         for i in gidToName:
             nameIndex.append((gidToName[i], gidToIndex[i]))
-        
+
         # Build xrefs
         xrefs = socket.gethostname().split()[0]
         xrefs = xrefs + ' ' + ' '.join([('%s:%d' % (group, id)) for (group, id) in nameIndex])
         article.putHeader('Xref', xrefs)
-        
+
         # Hey!  The article is ready to be posted!  God damn f'in finally.
         sql = """
@@ -824,7 +825,7 @@
             adbapi.safe(article.body)
         )
-        
+
         transaction.execute(sql)
-        
+
         # Now update the posting to reflect the groups to which this belongs
         for gid in gidToName:
@@ -834,5 +835,5 @@
             """ % (gid, gidToIndex[gid])
             transaction.execute(sql)
-        
+
         return len(nameIndex)
 
@@ -889,5 +890,5 @@
             AND groups.name = '%s'
         """ % (adbapi.safe(group),)
-        
+
         return self.dbpool.runQuery(sql).addCallback(
             lambda results, group = group: (group, [res[0] for res in results])
@@ -895,5 +896,5 @@
 
 
-    def groupRequest(self, group): 
+    def groupRequest(self, group):
         sql = """
             SELECT groups.name,
@@ -907,5 +908,5 @@
             GROUP BY groups.name, groups.flags
         """ % (adbapi.safe(group),)
-        
+
         return self.dbpool.runQuery(sql).addCallback(
             lambda results: tuple(results[0])
@@ -918,5 +919,5 @@
             WHERE message_id = '%s'
         """ % (adbapi.safe(id),)
-        
+
         return self.dbpool.runQuery(sql).addCallback(
             lambda result: bool(result[0][0])
@@ -934,5 +935,5 @@
             """ % (adbapi.safe(id), adbapi.safe(group))
         else:
-            sql = """ 
+            sql = """
                 SELECT postings.article_index, articles.message_id, articles.header, articles.body
                 FROM groups,articles LEFT OUTER JOIN postings
@@ -961,5 +962,5 @@
             AND groups.name = '%s'
         """ % (index, adbapi.safe(group))
-        
+
         return self.dbpool.runQuery(sql).addCallback(lambda result: result[0])
 
@@ -974,5 +975,5 @@
             AND groups.name = '%s'
         """ % (index, adbapi.safe(group))
-        
+
         return self.dbpool.runQuery(sql).addCallback(
             lambda result: result[0]
--- twisted/web/server.py (revision 22056)
+++ twisted/web/server.py (revision 25457)
@@ -1,5 +1,5 @@
 # -*- test-case-name: twisted.web.test.test_web -*-
 
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -508,7 +508,8 @@
         (internal) Generate an opaque, unique ID for a user's session.
         """
-        import md5, random
+        from twisted.python.hashlib import md5
+        import random
         self.counter = self.counter + 1
-        return md5.new("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest()
+        return md5("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest()
 
     def makeSession(self):
--- twisted/web/test/test_httpauth.py (revision 23950)
+++ twisted/web/test/test_httpauth.py (revision 25457)
@@ -6,9 +6,9 @@
 """
 
-import md5, sha
 
 from zope.interface import implements
 from zope.interface.verify import verifyObject
 
+from twisted.python.hashlib import md5, sha1
 from twisted.trial import unittest
 from twisted.cred import error, portal
@@ -182,5 +182,5 @@
 
 
-    def test_MD5HashA1(self, _algorithm='md5', _hash=md5.md5):
+    def test_MD5HashA1(self, _algorithm='md5', _hash=md5):
         """
         L{calcHA1} accepts the C{'md5'} algorithm and returns an MD5 hash of
@@ -204,7 +204,7 @@
                          nonce, self.cnonce)
         a1 = '%s:%s:%s' % (self.username, self.realm, self.password)
-        ha1 = md5.md5(a1).digest()
+        ha1 = md5(a1).digest()
         a1 = '%s:%s:%s' % (ha1, nonce, self.cnonce)
-        expected = md5.md5(a1).hexdigest()
+        expected = md5(a1).hexdigest()
         self.assertEqual(hashA1, expected)
 
@@ -215,8 +215,8 @@
         parameters, excluding the nonce and cnonce.
         """
-        self.test_MD5HashA1('sha', sha.sha)
-
-
-    def test_MD5HashA2Auth(self, _algorithm='md5', _hash=md5.md5):
+        self.test_MD5HashA1('sha', sha1)
+
+
+    def test_MD5HashA2Auth(self, _algorithm='md5', _hash=md5):
         """
         L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of
@@ -231,5 +231,5 @@
 
 
-    def test_MD5HashA2AuthInt(self, _algorithm='md5', _hash=md5.md5):
+    def test_MD5HashA2AuthInt(self, _algorithm='md5', _hash=md5):
         """
         L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of
@@ -266,5 +266,5 @@
         C{'auth-int'}.
         """
-        self.test_MD5HashA2Auth('sha', sha.sha)
+        self.test_MD5HashA2Auth('sha', sha1)
 
 
@@ -274,8 +274,8 @@
         its arguments, including the entity hash for QOP of C{'auth-int'}.
         """
-        self.test_MD5HashA2AuthInt('sha', sha.sha)
-
-
-    def test_MD5HashResponse(self, _algorithm='md5', _hash=md5.md5):
+        self.test_MD5HashA2AuthInt('sha', sha1)
+
+
+    def test_MD5HashResponse(self, _algorithm='md5', _hash=md5):
         """
         L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash
@@ -309,8 +309,8 @@
         value if the nonce count and client nonce are C{None}
         """
-        self.test_MD5HashResponse('sha', sha.sha)
-
-
-    def test_MD5HashResponseExtra(self, _algorithm='md5', _hash=md5.md5):
+        self.test_MD5HashResponse('sha', sha1)
+
+
+    def test_MD5HashResponseExtra(self, _algorithm='md5', _hash=md5):
         """
         L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash
@@ -349,5 +349,5 @@
         value if they are specified.
         """
-        self.test_MD5HashResponseExtra('sha', sha.sha)
+        self.test_MD5HashResponseExtra('sha', sha1)
 
 
@@ -640,5 +640,5 @@
 
         cleartext = '%s:%s:%s' % (self.username, self.realm, self.password)
-        hash = md5.md5(cleartext)
+        hash = md5(cleartext)
         self.assertTrue(creds.checkHash(hash.hexdigest()))
         hash.update('wrong')
@@ -762,5 +762,5 @@
                             self.clientAddress.host,
                             '-137876876')
-        digest = md5.md5(key + credentialFactory.privateKey).hexdigest()
+        digest = md5(key + credentialFactory.privateKey).hexdigest()
         ekey = b64encode(key)
 
@@ -787,5 +787,5 @@
                             '0')
 
-        digest = md5.md5(key + 'this is not the right pkey').hexdigest()
+        digest = md5(key + 'this is not the right pkey').hexdigest()
         badChecksum = '%s-%s' % (digest, b64encode(key))
 
--- twisted/web/woven/guard.py (revision 17081)
+++ twisted/web/woven/guard.py (revision 25457)
@@ -1,5 +1,5 @@
 # -*- test-case-name: twisted.web.test.test_woven -*-
 
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -17,5 +17,4 @@
 import random
 import time
-import md5
 import urllib
 
@@ -23,4 +22,5 @@
 
 from twisted.python import log, components
+from twisted.python.hashlib import md5
 from twisted.web.resource import Resource, IResource
 from twisted.web.util import redirectTo, Redirect, DeferredResource
@@ -30,5 +30,5 @@
 
 def _sessionCookie():
-    return md5.new("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest()
+    return md5("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest()
 
 class GuardSession(components.Componentized):
--- twisted/web/_auth/digest.py (revision 23948)
+++ twisted/web/_auth/digest.py (revision 25457)
@@ -10,8 +10,8 @@
 
 import time
-import md5, sha
 
 from zope.interface import implements
 
+from twisted.python.hashlib import md5, sha1
 from twisted.python.randbytes import secureRandom
 from twisted.cred import credentials, error
@@ -22,5 +22,5 @@
 
 algorithms = {
-    'md5': md5.new,
+    'md5': md5,
 
     # md5-sess is more complicated than just another algorithm.  It requires
@@ -31,7 +31,7 @@
     # RFC 2617, section 3.2.2.2 and do not try to make DigestCredentialFactory
     # support this unless you completely understand it. -exarkun
-    'md5-sess': md5.new,
-
-    'sha': sha.new,
+    'md5-sess': md5,
+
+    'sha': sha1,
 }
 
@@ -258,5 +258,5 @@
             clientip = ''
         key = "%s,%s,%s" % (nonce, clientip, now)
-        digest = md5.new(key + self.privateKey).hexdigest()
+        digest = md5(key + self.privateKey).hexdigest()
         ekey = key.encode('base64')
         return "%s-%s" % (digest, ekey.strip('\n'))
@@ -316,5 +316,5 @@
 
         # Verify the digest
-        digest = md5.new(key + self.privateKey).hexdigest()
+        digest = md5(key + self.privateKey).hexdigest()
         if digest != opaqueParts[0]:
             raise error.LoginFailed('Invalid response, invalid opaque value')
--- twisted/web/monitor.py (revision 17451)
+++  (revision )
@@ -1,85 +1,0 @@
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-#
-from twisted.web import client
-from twisted.internet import reactor
-import md5
-from zope.interface import implements
-
-class IChangeNotified:
-    pass
-
-class BaseChangeNotified:
-
-    implements(IChangeNotified)
-
-    def reportChange(self, old, new):
-        pass
-
-    def reportNoChange(self):
-        pass
-
-class ChangeChecker:
-
-    working = 0
-    call = None
-
-    def __init__(self, notified, url, delay=60):
-        self.notified = notified
-        self.url = url
-        self.md5 = None
-        self.delay = delay
-
-    def start(self):
-        self.working = 1
-        self._getPage()
-
-    def stop(self):
-        if self.call:
-            self.call.cancel()
-            self.call = None
-        self.working = 0
-
-    def _getPage(self):
-        d = client.getPage(self.url)
-        d.addErrback(self.noPage)
-        d.addCallback(self.page)
-        self.call = None
-
-    def noPage(self, e):
-        self.gotMD5(None)
-
-    def page(self, p):
-        if p is None:
-            return self.gotMD5(None)
-        m = md5.new()
-        m.update(p)
-        self.gotMD5(m.digest())
-
-    def gotMD5(self, md5):
-        if not self.working:
-            return
-        if md5 != self.md5:
-            self.notified.reportChange(self.md5, md5)
-            self.md5 = md5
-        else:
-            self.notified.reportNoChange()
-        if not self.call:
-            self.call = reactor.callLater(self.delay, self._getPage)
-
-
-class ProxyChangeChecker(ChangeChecker):
-
-    def __init__(self, proxyHost, proxyPort, notified, url, delay=60):
-        self.proxyHost = proxyHost
-        self.proxyPort = proxyPort
-        ChangeChecker.__init__(self, notified, url, delay)
-
-    def _getPage(self):
-        factory = client.HTTPClientFactory(self.proxyHost, self.url)
-        factory.headers = {'pragma': 'no-cache'}
-        reactor.connectTCP(self.proxyHost, self.proxyPort, factory)
-        d = factory.deferred
-        d.addErrback(self.noPage)
-        d.addCallback(self.page)
--- twisted/cred/util.py (revision 24441)
+++ twisted/cred/util.py (revision 25457)
@@ -1,20 +1,18 @@
-
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# -*- test-case-name: twisted.test.test_newcred -*-
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
+"""
+Outdated, deprecated functionality related to challenge-based authentication.
 
-"""
-Utility functions for authorization.
-
-These are currently for challenge-response shared secret authentication.
-
-Maintainer: Glyph Lefkowitz
+Seek a solution to your problem elsewhere.  This module is deprecated.
 """
 
 # System Imports
-import md5
-import random
+import random, warnings
 
+from twisted.python.hashlib import md5
 from twisted.cred.error import Unauthorized
+
 
 def respond(challenge, password):
@@ -22,8 +20,12 @@
     This is useful for challenge/response authentication.
     """
-    m = md5.new()
+    warnings.warn(
+        "twisted.cred.util.respond is deprecated since Twisted 8.3.",
+        category=PendingDeprecationWarning,
+        stacklevel=2)
+    m = md5()
     m.update(password)
     hashedPassword = m.digest()
-    m = md5.new()
+    m = md5()
     m.update(hashedPassword)
     m.update(challenge)
@@ -34,7 +36,11 @@
     """I return some random data.
     """
+    warnings.warn(
+        "twisted.cred.util.challenge is deprecated since Twisted 8.3.",
+        category=PendingDeprecationWarning,
+        stacklevel=2)
     crap = ''
     for x in range(random.randrange(15,25)):
         crap = crap + chr(random.randint(65,90))
-    crap = md5.new(crap).digest()
+    crap = md5(crap).digest()
     return crap
--- twisted/test/test_newcred.py (revision 20857)
+++ twisted/test/test_newcred.py (revision 25457)
@@ -1,7 +1,7 @@
-# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
 """
-Now with 30% more starch.
+Tests for L{twisted.cred}, now with 30% more starch.
 """
 
@@ -11,5 +11,5 @@
 
 from twisted.trial import unittest
-from twisted.cred import portal, checkers, credentials, error
+from twisted.cred import portal, checkers, credentials, error, util
 from twisted.python import components
 from twisted.internet import defer
@@ -27,4 +27,47 @@
 else:
     from twisted.cred import pamauth
+
+
+class DeprecatedUtilTests(unittest.TestCase):
+    """
+    Tests for the deprecation of the functions in L{twisted.cred.util}.
+    """
+    def test_respond(self):
+        """
+        L{respond} applies a particular hashing to a challenge and a password
+        and returns the result.  It is deprecated and calling it emits a
+        deprecation warning.
+        """
+        # Use some values and test against the known correct output.
+        self.assertEqual(
+            util.respond('foo', 'bar').encode('hex'),
+            'ebe4a2902532198cafaa223fb5ac0f20')
+
+        warnings = self.flushWarnings(offendingFunctions=[self.test_respond])
+        self.assertEqual(
+            warnings[0]['message'],
+            'twisted.cred.util.respond is deprecated since Twisted 8.3.')
+        self.assertEqual(
+            warnings[0]['category'],
+            PendingDeprecationWarning)
+        self.assertEqual(len(warnings), 1)
+
+
+    def test_challenge(self):
+        """
+        L{challenge} returns a different string each time it is called.
+        """
+        self.assertNotEqual(util.challenge(), util.challenge())
+        warnings = self.flushWarnings(offendingFunctions=[self.test_challenge])
+        for w in warnings:
+            self.assertEqual(
+                w['message'],
+                'twisted.cred.util.challenge is deprecated since Twisted 8.3.')
+            self.assertEqual(
+                w['category'],
+                PendingDeprecationWarning)
+        self.assertEqual(len(warnings), 2)
+
+
 
 class ITestable(Interface):
--- twisted/mail/test/test_mail.py (revision 25447)
+++ twisted/mail/test/test_mail.py (revision 25457)
@@ -8,5 +8,4 @@
 import os
 import errno
-import md5
 import shutil
 import pickle
@@ -33,4 +32,5 @@
 from twisted.python import failure
 from twisted.python.filepath import FilePath
+from twisted.python.hashlib import md5
 
 from twisted import mail
@@ -670,5 +670,5 @@
 
     def testAuthenticateAPOP(self):
-        resp = md5.new(self.P.magic + 'password').hexdigest()
+        resp = md5(self.P.magic + 'password').hexdigest()
         return self.P.authenticateUserAPOP('user', resp
             ).addCallback(self._cbAuthenticateAPOP
@@ -682,5 +682,5 @@
 
     def testAuthenticateIncorrectUserAPOP(self):
-        resp = md5.new(self.P.magic + 'password').hexdigest()
+        resp = md5(self.P.magic + 'password').hexdigest()
         return self.assertFailure(
             self.P.authenticateUserAPOP('resu', resp),
@@ -688,5 +688,5 @@
 
     def testAuthenticateIncorrectResponseAPOP(self):
-        resp = md5.new('wrong digest').hexdigest()
+        resp = md5('wrong digest').hexdigest()
         return self.assertFailure(
             self.P.authenticateUserAPOP('user', resp),
--- twisted/mail/pop3client.py (revision 24441)
+++ twisted/mail/pop3client.py (revision 25457)
@@ -1,4 +1,5 @@
 # -*- test-case-name: twisted.mail.test.test_pop3client -*-
 # Copyright (c) 2001-2004 Divmod Inc.
+# Copyright (c) 2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -11,7 +12,8 @@
 """
 
-import re, md5
+import re
 
 from twisted.python import log
+from twisted.python.hashlib import md5
 from twisted.internet import defer
 from twisted.protocols import basic
@@ -486,5 +488,5 @@
         # Internal helper.  Computes and sends an APOP response.  Returns
         # a Deferred that fires when the server responds to the response.
-        digest = md5.new(challenge + password).hexdigest()
+        digest = md5(challenge + password).hexdigest()
         return self.apop(username, digest)
 
--- twisted/mail/pop3.py (revision 24441)
+++ twisted/mail/pop3.py (revision 25457)
@@ -1,5 +1,5 @@
 # -*- test-case-name: twisted.mail.test.test_pop3 -*-
 #
-# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
+# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
 # See LICENSE for details.
 
@@ -15,5 +15,4 @@
 import base64
 import binascii
-import md5
 import warnings
 
@@ -27,4 +26,5 @@
 from twisted.internet import interfaces
 from twisted.python import log
+from twisted.python.hashlib import md5
 
 from twisted import cred
@@ -45,5 +45,5 @@
     def checkPassword(self, password):
         seed = self.magic + password
-        myDigest = md5.new(seed).hexdigest()
+        myDigest = md5(seed).hexdigest()
         return myDigest == self.digest
 
@@ -1032,5 +1032,5 @@
 
     def apopAuthenticate(self, user, password, magic):
-        digest = md5.new(magic + password).hexdigest()
+        digest = md5(magic + password).hexdigest()
         self.apop(user, digest)
 
--- twisted/mail/maildir.py (revision 25447)
+++ twisted/mail/maildir.py (revision 25457)
@@ -12,5 +12,4 @@
 import socket
 import time
-import md5
 
 from zope.interface import implements
@@ -27,4 +26,5 @@
 from twisted.persisted import dirdbm
 from twisted.python import log, failure
+from twisted.python.hashlib import md5
 from twisted.mail import mail
 from twisted.internet import interfaces, defer, reactor
@@ -297,5 +297,5 @@
         # Returning the actual filename is a mistake.  Hash it.
         base = os.path.basename(self.list[i])
-        return md5.md5(base).hexdigest()
+        return md5(base).hexdigest()
 
     def deleteMessage(self, i):
@@ -380,5 +380,5 @@
         Return a hash of the contents of the message at the given offset.
         """
-        return md5.new(self.msgs[i]).hexdigest()
+        return md5(self.msgs[i]).hexdigest()
 
 
--- twisted/internet/_sslverify.py (revision 24403)
+++ twisted/internet/_sslverify.py (revision 25457)
@@ -1,9 +1,12 @@
 # -*- test-case-name: twisted.test.test_sslverify -*-
-# Copyright 2005 Divmod, Inc.  See LICENSE file for details
-
-import itertools, md5
+# Copyright (c) 2005 Divmod, Inc.
+# Copyright (c) 2008 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+import itertools
 from OpenSSL import SSL, crypto
 
 from twisted.python import reflect, util
+from twisted.python.hashlib import md5
 from twisted.internet.defer import Deferred
 from twisted.internet.error import VerifyError, CertificateError
@@ -452,5 +455,5 @@
         key.
         """
-        return md5.md5(self._emptyReq).hexdigest()
+        return md5(self._emptyReq).hexdigest()
 
 
@@ -726,5 +729,5 @@
 
         if self.enableSessions:
-            sessionName = md5.md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
+            sessionName = md5("%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest()
             ctx.set_session_id(sessionName)
 
--- twisted/trial/test/test_loader.py (revision 24671)
+++ twisted/trial/test/test_loader.py (revision 25457)
@@ -6,5 +6,4 @@
 """
 
-import md5
 import os
 import shutil
@@ -12,4 +11,5 @@
 
 from twisted.python import util
+from twisted.python.hashlib import md5
 from twisted.trial.test import packages
 from twisted.trial import runner, reporter, unittest
@@ -485,5 +485,5 @@
 #                 return s.__module__+'.'+s.__name__
             n = runner.name(s)
-            d = md5.new(n).hexdigest()
+            d = md5(n).hexdigest()
             return d
         self.loadSortedPackages(sillySorter)
--- twisted/spread/pb.py (revision 24441)
+++ twisted/spread/pb.py (revision 25457)
@@ -28,5 +28,4 @@
 """
 
-import md5
 import random
 import new
@@ -39,4 +38,5 @@
 from twisted.python.versions import Version
 from twisted.python.deprecate import deprecated
+from twisted.python.hashlib import md5
 from twisted.internet import defer, protocol
 from twisted.cred.portal import Portal
@@ -998,8 +998,8 @@
     This is useful for challenge/response authentication.
     """
-    m = md5.new()
+    m = md5()
     m.update(password)
     hashedPassword = m.digest()
-    m = md5.new()
+    m = md5()
     m.update(hashedPassword)
     m.update(challenge)
@@ -1012,5 +1012,5 @@
     for x in range(random.randrange(15,25)):
         crap = crap + chr(random.randint(65,90))
-    crap = md5.new(crap).digest()
+    crap = md5(crap).digest()
     return crap
 
@@ -1341,10 +1341,10 @@
     # IUsernameHashedPassword:
     def checkPassword(self, password):
-        return self.checkMD5Password(md5.md5(password).digest())
+        return self.checkMD5Password(md5(password).digest())
 
 
     # IUsernameMD5Password
     def checkMD5Password(self, md5Password):
-        md = md5.new()
+        md = md5()
         md.update(md5Password)
         md.update(self.challenge)
