def DigestCalcResponse( HA1, pszNonce, pszNonceCount, pszCNonce, pszQop, pszMethod, pszDigestUri, pszHEntity, ): m = md5() m.update(pszMethod) m.update(":") m.update(pszDigestUri) if pszQop == "auth-int": m.update(":") m.update(pszHEntity) HA2 = m.digest().encode('hex') m = md5() m.update(HA1) m.update(":") m.update(pszNonce) m.update(":") if pszNonceCount and pszCNonce: # pszQop: m.update(pszNonceCount) m.update(":") m.update(pszCNonce) m.update(":") m.update(pszQop) m.update(":") m.update(HA2) hash = m.digest().encode('hex') return hash
def _unzipIterChunkyTest(self, compression, chunksize, lower, upper): """ unzipIterChunky should unzip the given number of bytes per iteration. """ junk = ' '.join([str(random.random()) for n in xrange(1000)]) junkmd5 = md5(junk).hexdigest() tempdir = filepath.FilePath(self.mktemp()) tempdir.makedirs() zfpath = tempdir.child('bigfile.zip').path self._makebigfile(zfpath, compression, junk) uziter = zipstream.unzipIterChunky(zfpath, tempdir.path, chunksize=chunksize) r = uziter.next() # test that the number of chunks is in the right ballpark; # this could theoretically be any number but statistically it # should always be in this range approx = lower < r < upper self.failUnless(approx) for r in uziter: pass self.assertEqual(r, 0) newmd5 = md5(tempdir.child("zipstreamjunk").open().read()).hexdigest() self.assertEqual(newmd5, junkmd5)
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 respond(challenge, password): """Respond to a challenge. This is useful for challenge/response authentication. """ m = md5() m.update(password) hashedPassword = m.digest() m = md5() m.update(hashedPassword) m.update(challenge) doubleHashedPassword = m.digest() return doubleHashedPassword
def test_MD5SessionHashA1(self): """ L{calcHA1} accepts the C{'md5-sess'} algorithm and returns an MD5 hash of its parameters, including the nonce and cnonce. """ nonce = 'xyz321abc' hashA1 = calcHA1('md5-sess', self.username, self.realm, self.password, nonce, self.cnonce) a1 = '%s:%s:%s' % (self.username, self.realm, self.password) ha1 = md5(a1).digest() a1 = '%s:%s:%s' % (ha1, nonce, self.cnonce) expected = md5(a1).hexdigest() self.assertEqual(hashA1, expected)
def _fromString_PRIVATE_OPENSSH(Class, data, passphrase): """ Return a private key object corresponding to this OpenSSH private key string. If the key is encrypted, passphrase MUST be provided. Providing a passphrase for an unencrypted key is an error. The format of an OpenSSH private key string is:: -----BEGIN <key type> PRIVATE KEY----- [Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,<initialization value>] <base64-encoded ASN.1 structure> ------END <key type> PRIVATE KEY------ The ASN.1 structure of a RSA key is:: (0, n, e, d, p, q) The ASN.1 structure of a DSA key is:: (0, p, q, g, y, x) @type data: C{str} @type passphrase: C{str} @return: a C{Crypto.PublicKey.pubkey.pubkey} object @raises BadKeyError: if * a passphrase is provided for an unencrypted key * a passphrase is not provided for an encrypted key * the ASN.1 encoding is incorrect """ lines = [x + '\n' for x in data.split('\n')] kind = lines[0][11:14] if lines[1].startswith('Proc-Type: 4,ENCRYPTED'): # encrypted key ivdata = lines[2].split(',')[1][:-1] iv = ''.join([ chr(int(ivdata[i:i + 2], 16)) for i in range(0, len(ivdata), 2) ]) if not passphrase: raise EncryptedKeyError('encrypted key with no passphrase') ba = md5(passphrase + iv).digest() bb = md5(ba + passphrase + iv).digest() decKey = (ba + bb)[:24] b64Data = base64.decodestring(''.join(lines[3:-1])) keyData = DES3.new(decKey, DES3.MODE_CBC, iv).decrypt(b64Data) removeLen = ord(keyData[-1]) keyData = keyData[:-removeLen] else: b64Data = ''.join(lines[1:-1]) keyData = base64.decodestring(b64Data) try: decodedKey = berDecoder.decode(keyData)[0] except Exception, e: raise BadKeyError, 'something wrong with decode'
def respond(challenge, password): """Respond to a challenge. This is useful for challenge/response authentication. """ 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() m.update(hashedPassword) m.update(challenge) doubleHashedPassword = m.digest() return doubleHashedPassword
def __init__(self, head, body): self.body = body self.headers = {} header = None for line in head.split('\r\n'): if line[0] in ' \t': i = list(self.headers[header]) i[1] += '\r\n' + line else: i = line.split(': ', 1) header = i[0].lower() self.headers[header] = tuple(i) if not self.getHeader('Message-ID'): s = str(time.time()) + self.body 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()))
def do(): # Mark all properties as dirty, so they can be added back # to the newly updated file. self.properties().update(self.properties()) backup = None if self._path.exists(): backup = hidden(self._path.temporarySibling()) self._path.moveTo(backup) fh = self._path.open("w") try: # FIXME: concurrency problem; if this write is interrupted # halfway through, the underlying file will be corrupt. fh.write(componentText) finally: fh.close() md5 = hashlib.md5(componentText).hexdigest() self.properties()[md5key] = TwistedGETContentMD5.fromString(md5) # Now re-write the original properties on the updated file self.properties().flush() def undo(): if backup: backup.moveTo(self._path) else: self._path.remove() return undo
def challenge(): """I return some random data.""" crap = '' for x in range(random.randrange(15, 25)): crap = crap + chr(random.randint(65, 90)) crap = md5(crap).digest() return crap
def _mkuid(self): """ (internal) Generate an opaque, unique ID for a user's session. """ from twisted.python.hashlib import md5 import random self.counter = self.counter + 1 return md5("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest()
def sillySorter(s): # This has to work on fully-qualified class names and class # objects, which is silly, but it's the "spec", such as it is. # if isinstance(s, type) or isinstance(s, types.ClassType): # return s.__module__+'.'+s.__name__ n = runner.name(s) d = md5(n).hexdigest() return d
def _verifyOpaque(self, opaque, nonce, clientip): """ Given the opaque and nonce from the request, as well as the client IP that made the request, verify that the opaque was generated by us. And that it's not too old. @param opaque: The opaque value from the Digest response @param nonce: The nonce value from the Digest response @param clientip: The remote IP address of the client making the request or C{None} if the request was submitted over a channel where this does not make sense. @return: C{True} if the opaque was successfully verified. @raise error.LoginFailed: if C{opaque} could not be parsed or contained the wrong values. """ # First split the digest from the key opaqueParts = opaque.split('-') if len(opaqueParts) != 2: raise error.LoginFailed('Invalid response, invalid opaque value') if clientip is None: clientip = '' # Verify the key key = opaqueParts[1].decode('base64') keyParts = key.split(',') if len(keyParts) != 3: raise error.LoginFailed('Invalid response, invalid opaque value') if keyParts[0] != nonce: raise error.LoginFailed( 'Invalid response, incompatible opaque/nonce values') if keyParts[1] != clientip: raise error.LoginFailed( 'Invalid response, incompatible opaque/client values') try: when = int(keyParts[2]) except ValueError: raise error.LoginFailed( 'Invalid response, invalid opaque/time values') if (int(self._getTime()) - when > DigestCredentialFactory.CHALLENGE_LIFETIME_SECS): raise error.LoginFailed( 'Invalid response, incompatible opaque/nonce too old') # Verify the digest digest = md5(key + self.privateKey).hexdigest() if digest != opaqueParts[0]: raise error.LoginFailed('Invalid response, invalid opaque value') return True
def _toString_OPENSSH(self, extra): """ Return a public or private OpenSSH string. See _fromString_PUBLIC_OPENSSH and _fromString_PRIVATE_OPENSSH for the string formats. If extra is present, it represents a comment for a public key, or a passphrase for a private key. @type extra: C{str} @rtype: C{str} """ data = self.data() if self.isPublic(): b64Data = base64.encodestring(self.blob()).replace('\n', '') if not extra: extra = '' return ('%s %s %s' % (self.sshType(), b64Data, extra)).strip() else: lines = ['-----BEGIN %s PRIVATE KEY-----' % self.type()] if self.type() == 'RSA': p, q = data['p'], data['q'] objData = (0, data['n'], data['e'], data['d'], q, p, data['d'] % (q - 1), data['d'] % (p - 1), data['u']) else: objData = (0, data['p'], data['q'], data['g'], data['y'], data['x']) asn1Sequence = univ.Sequence() for index, value in itertools.izip(itertools.count(), objData): asn1Sequence.setComponentByPosition(index, univ.Integer(value)) asn1Data = berEncoder.encode(asn1Sequence) if extra: iv = randbytes.secureRandom(8) hexiv = ''.join(['%02X' % ord(x) for x in iv]) lines.append('Proc-Type: 4,ENCRYPTED') lines.append('DEK-Info: DES-EDE3-CBC,%s\n' % hexiv) ba = md5(extra + iv).digest() bb = md5(ba + extra + iv).digest() encKey = (ba + bb)[:24] padLen = 8 - (len(asn1Data) % 8) asn1Data += (chr(padLen) * padLen) asn1Data = DES3.new(encKey, DES3.MODE_CBC, iv).encrypt(asn1Data) b64Data = base64.encodestring(asn1Data).replace('\n', '') lines += [b64Data[i:i + 64] for i in range(0, len(b64Data), 64)] lines.append('-----END %s PRIVATE KEY-----' % self.type()) return '\n'.join(lines)
def getUidl(self, i): """Return a unique identifier for a message This is done using the basename of the filename. It is globally unique because this is how Maildirs are designed. """ # Returning the actual filename is a mistake. Hash it. base = os.path.basename(self.list[i]) return md5(base).hexdigest()
def _test(challenge): key = '%s,%s,%s' % (challenge['nonce'], clientAddress.host, '0') digest = md5(key + 'this is not the right pkey').hexdigest() badChecksum = '%s-%s' % (digest, key.encode('base64').strip('\n')) self.assertRaises(error.LoginFailed, credentialFactory.verifyOpaque, badChecksum, challenge['nonce'], clientAddress.host)
def generateOpaque(self, nonce, clientip): """ Generate an opaque to be returned to the client. This should be a unique string that can be returned to us and verified. """ # Now, what we do is encode the nonce, client ip and a timestamp # in the opaque value with a suitable digest key = "%s,%s,%s" % (nonce, clientip, str(int(self._getTime()))) digest = md5(key + self.privateKey).hexdigest() ekey = key.encode('base64') return "%s-%s" % (digest, ekey.strip('\n'))
def challenge(): """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(crap).digest() return crap
def _test(challenge): key = '%s,%s,%s' % (challenge['nonce'], clientAddress.host, '-137876876') digest = (md5(key + credentialFactory._fakeStaticPrivateKey).hexdigest()) ekey = key.encode('base64') oldNonceOpaque = '%s-%s' % (digest, ekey.strip('\n')) self.assertRaises(error.LoginFailed, credentialFactory.verifyOpaque, oldNonceOpaque, challenge['nonce'], clientAddress.host)
def _generateOpaque(self, nonce, clientip): """ Generate an opaque to be returned to the client. This is a unique string that can be returned to us and verified. """ # Now, what we do is encode the nonce, client ip and a timestamp in the # opaque value with a suitable digest. now = str(int(self._getTime())) if clientip is None: clientip = '' key = "%s,%s,%s" % (nonce, clientip, now) digest = md5(key + self.privateKey).hexdigest() ekey = key.encode('base64') return "%s-%s" % (digest, ekey.replace('\n', ''))
def DigestCalcHA1( pszAlg, pszUserName, pszRealm, pszPassword, pszNonce, pszCNonce, ): m = md5() m.update(pszUserName) m.update(":") m.update(pszRealm) m.update(":") m.update(pszPassword) HA1 = m.digest() if pszAlg == "md5-sess": m = md5() m.update(HA1) m.update(":") m.update(pszNonce) m.update(":") m.update(pszCNonce) HA1 = m.digest() return HA1.encode('hex')
def _makeContext(self): ctx = SSL.Context(self.method) if self.certificate is not None and self.privateKey is not None: ctx.use_certificate(self.certificate) ctx.use_privatekey(self.privateKey) # Sanity check ctx.check_privatekey() verifyFlags = SSL.VERIFY_NONE if self.verify: verifyFlags = SSL.VERIFY_PEER if self.requireCertificate: verifyFlags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT if self.verifyOnce: verifyFlags |= SSL.VERIFY_CLIENT_ONCE if self.caCerts: store = ctx.get_cert_store() for cert in self.caCerts: store.add_cert(cert) # It'd be nice if pyOpenSSL let us pass None here for this behavior (as # the underlying OpenSSL API call allows NULL to be passed). It # doesn't, so we'll supply a function which does the same thing. def _verifyCallback(conn, cert, errno, depth, preverify_ok): return preverify_ok ctx.set_verify(verifyFlags, _verifyCallback) if self.verifyDepth is not None: ctx.set_verify_depth(self.verifyDepth) if self.enableSingleUseKeys: ctx.set_options(SSL.OP_SINGLE_DH_USE) if self.fixBrokenPeers: ctx.set_options(self._OP_ALL) if self.enableSessions: sessionName = md5( "%s-%d" % (reflect.qual(self.__class__), _sessionCounter())).hexdigest() ctx.set_session_id(sessionName) if not self.enableSessionTickets: ctx.set_options(self._OP_NO_TICKET) return ctx
def test_mismatchedOpaqueChecksum(self): """ L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque checksum fails verification. """ credentialFactory = FakeDigestCredentialFactory( self.algorithm, self.realm) challenge = credentialFactory.getChallenge(self.clientAddress.host) key = '%s,%s,%s' % (challenge['nonce'], self.clientAddress.host, '0') digest = md5(key + 'this is not the right pkey').hexdigest() badChecksum = '%s-%s' % (digest, b64encode(key)) self.assertRaises(LoginFailed, credentialFactory._verifyOpaque, badChecksum, challenge['nonce'], self.clientAddress.host)
def md5(self): """ The MD5 hex digest of this object's content. @rtype: C{str} """ try: return str(self.properties()[PropertyName.fromElement( TwistedGETContentMD5)]) except KeyError: # FIXME: Strictly speaking we should not need to read the data as the md5 property should always be # present. However, our unit tests use static files for their data store and those currently # do not include the md5 xattr. try: data = self._path.open().read() except IOError: return None md5 = hashlib.md5(data).hexdigest() return md5
def test_oldNonce(self): """ L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given opaque is older than C{DigestCredentialFactory.CHALLENGE_LIFETIME_SECS} """ credentialFactory = FakeDigestCredentialFactory( self.algorithm, self.realm) challenge = credentialFactory.getChallenge(self.clientAddress.host) key = '%s,%s,%s' % (challenge['nonce'], self.clientAddress.host, '-137876876') digest = md5(key + credentialFactory.privateKey).hexdigest() ekey = b64encode(key) oldNonceOpaque = '%s-%s' % (digest, ekey.strip('\n')) self.assertRaises(LoginFailed, credentialFactory._verifyOpaque, oldNonceOpaque, challenge['nonce'], self.clientAddress.host)
def ssh_KEX_DH_GEX_REPLY(self, packet): """ Called when we receieve a MSG_KEX_DH_GEX_REPLY message. Payload:: string server host key integer f (server DH public key) We verify the host key by calling verifyHostKey, then continue in _continueGEX_REPLY. """ pubKey, packet = getNS(packet) f, packet = getMP(packet) signature, packet = getNS(packet) fingerprint = ':'.join( map(lambda c: '%02x' % ord(c), md5(pubKey).digest())) d = self.verifyHostKey(pubKey, fingerprint) d.addCallback(self._continueGEX_REPLY, pubKey, f, signature) d.addErrback(lambda unused: self.sendDisconnect( DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) return d
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 = StringTransport() self.client.makeConnection(transport) transport.clear() 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.assertEquals( response, md5(challenge + "Q1P7W2E4J9R8U3S5").hexdigest()) self.assertEquals( transport.value(), # 2 is the next transaction identifier. 32 is the length of the # response. "QRY 2 [email protected] 32\r\n" + response)
def fingerprint(self): """ Get the user presentation of the fingerprint of this L{Key}. As described by U{RFC 4716 section 4<http://tools.ietf.org/html/rfc4716#section-4>}:: The fingerprint of a public key consists of the output of the MD5 message-digest algorithm [RFC1321]. The input to the algorithm is the public key data as specified by [RFC4253]. (...) The output of the (MD5) algorithm is presented to the user as a sequence of 16 octets printed as hexadecimal with lowercase letters and separated by colons. @since: 8.2 @return: the user presentation of this L{Key}'s fingerprint, as a string. @rtype: L{str} """ return ':'.join([x.encode('hex') for x in md5(self.blob()).digest()])
def ssh_KEX_DH_GEX_GROUP(self, packet): """ This handles two different message which share an integer value. If the key exchange is diffie-hellman-group1-sha1, this is MSG_KEXDH_REPLY. Payload:: string serverHostKey integer f (server Diffie-Hellman public key) string signature We verify the host key by calling verifyHostKey, then continue in _continueKEXDH_REPLY. If the key exchange is diffie-hellman-group-exchange-sha1, this is MSG_KEX_DH_GEX_GROUP. Payload:: string g (group generator) string p (group prime) We generate a Diffie-Hellman public key and send it in a MSG_KEX_DH_GEX_INIT message. """ if self.kexAlg == 'diffie-hellman-group1-sha1': # actually MSG_KEXDH_REPLY pubKey, packet = getNS(packet) f, packet = getMP(packet) signature, packet = getNS(packet) fingerprint = ':'.join( [ch.encode('hex') for ch in md5(pubKey).digest()]) d = self.verifyHostKey(pubKey, fingerprint) d.addCallback(self._continueKEXDH_REPLY, pubKey, f, signature) d.addErrback(lambda unused: self.sendDisconnect( DISCONNECT_HOST_KEY_NOT_VERIFIABLE, 'bad host key')) return d else: self.p, rest = getMP(packet) self.g, rest = getMP(rest) self.x = Util.number.getRandomNumber(320, randbytes.secureRandom) self.e = _MPpow(self.g, self.x, self.p) self.sendPacket(MSG_KEX_DH_GEX_INIT, self.e)
def test_checkHash(self): """ L{DigestCredentialFactory.decode} returns an L{IUsernameDigestHash} provider which can verify a hash of the form 'username:realm:password'. """ challenge = self.credentialFactory.getChallenge( self.clientAddress.host) nc = "00000001" clientResponse = self.formatResponse(nonce=challenge['nonce'], response=self.getDigestResponse( challenge, nc), nc=nc, opaque=challenge['opaque']) creds = self.credentialFactory.decode(clientResponse, self.method, self.clientAddress.host) self.assertTrue(verifyObject(IUsernameDigestHash, creds)) cleartext = '%s:%s:%s' % (self.username, self.realm, self.password) hash = md5(cleartext) self.assertTrue(creds.checkHash(hash.hexdigest())) hash.update('wrong') self.assertFalse(creds.checkHash(hash.hexdigest()))