def process(self, challenge=None): """ """ if challenge is None: if self.has_values(['username', 'realm', 'nonce', 'key_hash', 'nc', 'cnonce', 'qops']): self._qops = self.values['qops'] return self.response() else: return None d = parse_challenge(challenge) if b'rspauth' in d: self.mutual_auth(d[b'rspauth']) else: if b'realm' not in d: d[b'realm'] = self.sasl.def_realm for key in ['nonce', 'realm']: if bytes(key) in d: self.values[key] = d[bytes(key)] self.values['nc'] = 0 self._qops = [b'auth'] if b'qop' in d: self._qops = [x.strip() for x in d[b'qop'].split(b',')] self.values['qops'] = self._qops if b'maxbuf' in d: self._max_buffer = int(d[b'maxbuf']) return self.response()
def process_one(self, challenge): """ """ vitals = ['username'] if 'SaltedPassword' not in self.values: vitals.append('password') if 'Iterations' not in self.values: vitals.append('password') self.check_values(vitals) username = bytes(self.values['username']) self._step = 1 self._cnonce = bytes(('%s' % random.random())[2:]) self._soup = b'n=' + username + b',r=' + self._cnonce self._gs2header = b'' if not self.sasl.tls_active(): if self._cb: self._gs2header = b'p=tls-unique,,' else: self._gs2header = b'y,,' else: self._gs2header = b'n,,' return self._gs2header + self._soup
def process(self, challenge=None): """ Process a challenge request and return the response. :param challenge: A challenge issued by the server that must be answered for authentication. """ user = bytes(self.values['username']) password = bytes(self.values['password']) return b'\x00' + user + b'\x00' + password
def process(self, challenge): """ """ if challenge is None: return None self.check_values(['username', 'password']) username = bytes(self.values['username']) password = bytes(self.values['password']) mac = hmac.HMAC(key=password, digestmod=self.hash) mac.update(challenge) return username + b' ' + bytes(mac.hexdigest())
def gen_hash(self, a2): """ """ if not self.has_values(['key_hash']): key_hash = self.hash() user = bytes(self.values['username']) password = bytes(self.values['password']) realm = bytes(self.values['realm']) kh = user + b':' + realm + b':' + password key_hash.update(kh) self.values['key_hash'] = key_hash.digest() a1 = self.hash(self.values['key_hash']) a1h = b':' + self.values['nonce'] + b':' + self._cnonce a1.update(a1h) response = self.hash() self._a1 = a1.digest() rv = bytes(a1.hexdigest().lower()) rv += b':' + self.values['nonce'] rv += b':' + bytes('%08x' % self.values['nc']) rv += b':' + self._cnonce rv += b':' + self._qop rv += b':' + bytes(self.hash(a2).hexdigest().lower()) response.update(rv) return bytes(response.hexdigest().lower())
def Hi(self, text, salt, iterations): """ """ text = bytes(text) ui_1 = self.HMAC(text, salt + b'\0\0\0\01') ui = ui_1 for i in range(iterations - 1): ui_1 = self.HMAC(text, ui_1) ui = XOR(ui, ui_1) return ui
def parse_challenge(stuff): """ """ ret = {} var = b'' val = b'' in_var = True in_quotes = False new = False escaped = False for c in stuff: if sys.version_info >= (3, 0): c = bytes([c]) if in_var: if c.isspace(): continue if c == b'=': in_var = False new = True else: var += c else: if new: if c == b'"': in_quotes = True else: val += c new = False elif in_quotes: if escaped: escaped = False val += c else: if c == b'\\': escaped = True elif c == b'"': in_quotes = False else: val += c else: if c == b',': if var: ret[var] = val var = b'' val = b'' in_var = True else: val += c if var: ret[var] = val return ret
def process_two(self, challenge): """ """ data = parse_challenge(challenge) self._step = 2 self._soup += b',' + challenge + b',' self._nonce = data[b'r'] self._salt = b64decode(data[b's']) self._iter = int(data[b'i']) if self._nonce[:len(self._cnonce)] != self._cnonce: raise SASLCancelled(self.sasl, self) cbdata = self.sasl.tls_active() c = self._gs2header if not cbdata and self._cb: c += None r = b'c=' + b64encode(c).replace(b'\n', b'') r += b',r=' + self._nonce self._soup += r if 'Iterations' in self.values: if self.values['Iterations'] != self._iter: if 'SaltedPassword' in self.values: del self.values['SaltedPassword'] if 'Salt' in self.values: if self.values['Salt'] != self._salt: if 'SaltedPassword' in self.values: del self.values['SaltedPassword'] self.values['Iterations'] = self._iter self.values['Salt'] = self._salt if 'SaltedPassword' not in self.values: self.check_values(['password']) password = bytes(self.values['password']) salted_pass = self.Hi(password, self._salt, self._iter) self.values['SaltedPassword'] = salted_pass salted_pass = self.values['SaltedPassword'] client_key = self.HMAC(salted_pass, b'Client Key') stored_key = self.H(client_key) client_sig = self.HMAC(stored_key, self._soup) client_proof = XOR(client_key, client_sig) r += b',p=' + b64encode(client_proof).replace(b'\n', b'') server_key = self.HMAC(self.values['SaltedPassword'], b'Server Key') self.server_sig = self.HMAC(server_key, self._soup) return r
def process(self, challenge=None): if challenge is not None: values = {} for kv in challenge.split(b'&'): key, value = kv.split(b'=') values[key] = value resp_data = { b'method': values[b'method'], b'v': b'1.0', b'call_id': b'1.0', b'nonce': values[b'nonce'], b'access_token': self.values['access_token'], b'api_key': self.values['api_key'] } resp = '&'.join(['%s=%s' % (k, v) for k, v in resp_data.items()]) return bytes(resp) return b''
def response(self): """ """ vitals = ['username'] if not self.has_values(['key_hash']): vitals.append('password') self.check_values(vitals) resp = {} if 'auth-int' in self._qops: self._qop = b'auth-int' resp['qop'] = self._qop if 'realm' in self.values: resp['realm'] = quote(self.values['realm']) resp['username'] = quote(bytes(self.values['username'])) resp['nonce'] = quote(self.values['nonce']) if self.values['nc']: self._cnonce = self.values['cnonce'] else: self._cnonce = bytes('%s' % random.random())[2:] resp['cnonce'] = quote(self._cnonce) self.values['nc'] += 1 resp['nc'] = bytes('%08x' % self.values['nc']) service = bytes(self.sasl.service) host = bytes(self.sasl.host) self._digest_uri = service + b'/' + host resp['digest-uri'] = quote(self._digest_uri) a2 = b'AUTHENTICATE:' + self._digest_uri if self._qop != b'auth': a2 += b':00000000000000000000000000000000' resp['maxbuf'] = b'16777215' # 2**24-1 resp['response'] = self.gen_hash(a2) return b','.join([bytes(k) + b'=' + bytes(v) for k, v in resp.items()])
def process(self, challenge=None): return bytes(self.values['access_token'])
f.flush() # Loop until we're done. # IMAP SASL profile does base64 everywhere, like many protocols. # It's up to us to handle that, Suelta expects the real data. while True: stuff = f.readline() print(stuff) if stuff[0] == '.': break if stuff[0] == '+': gunk = base64.b64decode(bytes(stuff[2:])) print("Got: %s" % gunk) my_gunk = mech.process(gunk) print("Sending: %s" % my_gunk) if my_gunk is None: my_stuff = b'+' else: my_stuff =base64.b64encode(my_gunk).replace(b'\n', b'') my_stuff += b'\r\n' my_stuff = my_stuff.decode('utf-8') # Note the slightly hairy way you need to encode to avoid linebreaks. f.write(my_stuff) f.flush()