summaryrefslogtreecommitdiff
path: root/sleekxmpp/thirdparty/suelta/mechanisms
diff options
context:
space:
mode:
authorLance Stout <lancestout@gmail.com>2012-07-31 21:33:19 -0700
committerLance Stout <lancestout@gmail.com>2012-07-31 21:33:19 -0700
commit06a9d9fc3075df8e07960716c25d1eca2eb47f05 (patch)
tree94adfe3467fb50e3710548d6c97f1a6b36ed57a8 /sleekxmpp/thirdparty/suelta/mechanisms
parent44ce01a70b7926a1e1f4af6692be3bdc671f7318 (diff)
parent1383ca19b50ae7463a1f310f007ed120f811b574 (diff)
downloadslixmpp-06a9d9fc3075df8e07960716c25d1eca2eb47f05.tar.gz
slixmpp-06a9d9fc3075df8e07960716c25d1eca2eb47f05.tar.bz2
slixmpp-06a9d9fc3075df8e07960716c25d1eca2eb47f05.tar.xz
slixmpp-06a9d9fc3075df8e07960716c25d1eca2eb47f05.zip
Merge branch 'master' into develop
Conflicts: sleekxmpp/thirdparty/__init__.py
Diffstat (limited to 'sleekxmpp/thirdparty/suelta/mechanisms')
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/__init__.py8
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/anonymous.py36
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/cram_md5.py63
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/digest_md5.py275
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/facebook_platform.py43
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/google_token.py22
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/messenger_oauth2.py17
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/plain.py61
-rw-r--r--sleekxmpp/thirdparty/suelta/mechanisms/scram_hmac.py176
9 files changed, 0 insertions, 701 deletions
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/__init__.py b/sleekxmpp/thirdparty/suelta/mechanisms/__init__.py
deleted file mode 100644
index 2044ff80..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from sleekxmpp.thirdparty.suelta.mechanisms.anonymous import ANONYMOUS
-from sleekxmpp.thirdparty.suelta.mechanisms.plain import PLAIN
-from sleekxmpp.thirdparty.suelta.mechanisms.cram_md5 import CRAM_MD5
-from sleekxmpp.thirdparty.suelta.mechanisms.digest_md5 import DIGEST_MD5
-from sleekxmpp.thirdparty.suelta.mechanisms.scram_hmac import SCRAM_HMAC
-from sleekxmpp.thirdparty.suelta.mechanisms.messenger_oauth2 import X_MESSENGER_OAUTH2
-from sleekxmpp.thirdparty.suelta.mechanisms.facebook_platform import X_FACEBOOK_PLATFORM
-from sleekxmpp.thirdparty.suelta.mechanisms.google_token import X_GOOGLE_TOKEN
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/anonymous.py b/sleekxmpp/thirdparty/suelta/mechanisms/anonymous.py
deleted file mode 100644
index e44e91a2..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/anonymous.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-from sleekxmpp.thirdparty.suelta.exceptions import SASLError, SASLCancelled
-
-
-class ANONYMOUS(Mechanism):
-
- """
- """
-
- def __init__(self, sasl, name):
- """
- """
- super(ANONYMOUS, self).__init__(sasl, name, 0)
-
- def get_values(self):
- """
- """
- return {}
-
- def process(self, challenge=None):
- """
- """
- return b'Anonymous, Suelta'
-
- def okay(self):
- """
- """
- return True
-
- def get_user(self):
- """
- """
- return 'anonymous'
-
-
-register_mechanism('ANONYMOUS', 0, ANONYMOUS, use_hashes=False)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/cram_md5.py b/sleekxmpp/thirdparty/suelta/mechanisms/cram_md5.py
deleted file mode 100644
index e07bb883..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/cram_md5.py
+++ /dev/null
@@ -1,63 +0,0 @@
-import sys
-import hmac
-
-from sleekxmpp.thirdparty.suelta.util import hash, bytes
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-from sleekxmpp.thirdparty.suelta.exceptions import SASLError, SASLCancelled
-
-
-class CRAM_MD5(Mechanism):
-
- """
- """
-
- def __init__(self, sasl, name):
- """
- """
- super(CRAM_MD5, self).__init__(sasl, name, 2)
-
- self.hash = hash(name[5:])
- if self.hash is None:
- raise SASLCancelled(self.sasl, self)
- if not self.sasl.tls_active():
- if not self.sasl.sec_query(self, 'CRAM-MD5'):
- raise SASLCancelled(self.sasl, self)
-
- def prep(self):
- """
- """
- if 'savepass' not in self.values:
- if self.sasl.sec_query(self, 'CLEAR-PASSWORD'):
- self.values['savepass'] = True
-
- if 'savepass' not in self.values:
- del self.values['password']
-
- def process(self, challenge=None):
- """
- """
- 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 okay(self):
- """
- """
- return True
-
- def get_user(self):
- """
- """
- return self.values['username']
-
-
-register_mechanism('CRAM-', 20, CRAM_MD5)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/digest_md5.py b/sleekxmpp/thirdparty/suelta/mechanisms/digest_md5.py
deleted file mode 100644
index 890f3e24..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/digest_md5.py
+++ /dev/null
@@ -1,275 +0,0 @@
-import sys
-
-import random
-import hmac
-
-from sleekxmpp.thirdparty.suelta.util import hash, bytes, quote
-from sleekxmpp.thirdparty.suelta.util import num_to_bytes, bytes_to_num
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-from sleekxmpp.thirdparty.suelta.exceptions import SASLError, SASLCancelled
-
-
-
-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
-
-
-class DIGEST_MD5(Mechanism):
-
- """
- """
-
- enc_magic = 'Digest session key to client-to-server signing key magic'
- dec_magic = 'Digest session key to server-to-client signing key magic'
-
- def __init__(self, sasl, name):
- """
- """
- super(DIGEST_MD5, self).__init__(sasl, name, 3)
-
- self.hash = hash(name[7:])
- if self.hash is None:
- raise SASLCancelled(self.sasl, self)
-
- if not self.sasl.tls_active():
- if not self.sasl.sec_query(self, '-ENCRYPTION, DIGEST-MD5'):
- raise SASLCancelled(self.sasl, self)
-
- self._rspauth_okay = False
- self._digest_uri = None
- self._a1 = None
- self._enc_buf = b''
- self._enc_key = None
- self._enc_seq = 0
- self._max_buffer = 65536
- self._dec_buf = b''
- self._dec_key = None
- self._dec_seq = 0
- self._qops = [b'auth']
- self._qop = b'auth'
-
- def MAC(self, seq, msg, key):
- """
- """
- mac = hmac.HMAC(key=key, digestmod=self.hash)
- seqnum = num_to_bytes(seq)
- mac.update(seqnum)
- mac.update(msg)
- return mac.digest()[:10] + b'\x00\x01' + seqnum
-
-
- def encode(self, text):
- """
- """
- self._enc_buf += text
-
- def flush(self):
- """
- """
- result = b''
- # Leave buffer space for the MAC
- mbuf = self._max_buffer - 10 - 2 - 4
-
- while self._enc_buf:
- msg = self._encbuf[:mbuf]
- mac = self.MAC(self._enc_seq, msg, self._enc_key, self.hash)
- self._enc_seq += 1
- msg += mac
- result += num_to_bytes(len(msg)) + msg
- self._enc_buf = self._enc_buf[mbuf:]
-
- return result
-
- def decode(self, text):
- """
- """
- self._dec_buf += text
- result = b''
-
- while len(self._dec_buf) > 4:
- num = bytes_to_num(self._dec_buf)
- if len(self._dec_buf) < (num + 4):
- return result
-
- mac = self._dec_buf[4:4 + num]
- self._dec_buf = self._dec_buf[4 + num:]
- msg = mac[:-16]
-
- mac_conf = self.MAC(self._dec_mac, msg, self._dec_key)
- if mac[-16:] != mac_conf:
- self._desc_sec = None
- return result
-
- self._dec_seq += 1
- result += msg
-
- return result
-
- 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 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 mutual_auth(self, cmp_hash):
- """
- """
- a2 = b':' + self._digest_uri
- if self._qop != b'auth':
- a2 += b':00000000000000000000000000000000'
- if self.gen_hash(a2) == cmp_hash:
- self._rspauth_okay = True
-
- def prep(self):
- """
- """
- if 'password' in self.values:
- del self.values['password']
- self.values['cnonce'] = self._cnonce
-
- 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 okay(self):
- """
- """
- if self._rspauth_okay and self._qop == b'auth-int':
- self._enc_key = self.hash(self._a1 + self.enc_magic).digest()
- self._dec_key = self.hash(self._a1 + self.dec_magic).digest()
- self.encoding = True
- return self._rspauth_okay
-
-
-register_mechanism('DIGEST-', 30, DIGEST_MD5)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/facebook_platform.py b/sleekxmpp/thirdparty/suelta/mechanisms/facebook_platform.py
deleted file mode 100644
index af6a78eb..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/facebook_platform.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from sleekxmpp.thirdparty.suelta.util import bytes
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-
-try:
- import urlparse
-except ImportError:
- import urllib.parse as urlparse
-
-
-
-class X_FACEBOOK_PLATFORM(Mechanism):
-
- def __init__(self, sasl, name):
- super(X_FACEBOOK_PLATFORM, self).__init__(sasl, name)
- self.check_values(['access_token', 'api_key'])
-
- 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 = {
- 'method': values[b'method'],
- 'v': '1.0',
- 'call_id': '1.0',
- 'nonce': values[b'nonce'],
- 'access_token': self.values['access_token'],
- 'api_key': self.values['api_key']
- }
-
- for k, v in resp_data.items():
- resp_data[k] = bytes(v).decode('utf-8')
-
- resp = '&'.join(['%s=%s' % (k, v) for k, v in resp_data.items()])
- return bytes(resp)
- return b''
-
- def okay(self):
- return True
-
-register_mechanism('X-FACEBOOK-PLATFORM', 40, X_FACEBOOK_PLATFORM, use_hashes=False)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/google_token.py b/sleekxmpp/thirdparty/suelta/mechanisms/google_token.py
deleted file mode 100644
index e641bb91..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/google_token.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from sleekxmpp.thirdparty.suelta.util import bytes
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-from sleekxmpp.thirdparty.suelta.exceptions import SASLError, SASLCancelled
-
-
-
-class X_GOOGLE_TOKEN(Mechanism):
-
- def __init__(self, sasl, name):
- super(X_GOOGLE_TOKEN, self).__init__(sasl, name)
- self.check_values(['email', 'access_token'])
-
- def process(self, challenge=None):
- email = bytes(self.values['email'])
- token = bytes(self.values['access_token'])
- return b'\x00' + email + b'\x00' + token
-
- def okay(self):
- return True
-
-
-register_mechanism('X-GOOGLE-TOKEN', 3, X_GOOGLE_TOKEN, use_hashes=False)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/messenger_oauth2.py b/sleekxmpp/thirdparty/suelta/mechanisms/messenger_oauth2.py
deleted file mode 100644
index f5b0ddec..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/messenger_oauth2.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from sleekxmpp.thirdparty.suelta.util import bytes
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-
-
-class X_MESSENGER_OAUTH2(Mechanism):
-
- def __init__(self, sasl, name):
- super(X_MESSENGER_OAUTH2, self).__init__(sasl, name)
- self.check_values(['access_token'])
-
- def process(self, challenge=None):
- return bytes(self.values['access_token'])
-
- def okay(self):
- return True
-
-register_mechanism('X-MESSENGER-OAUTH2', 10, X_MESSENGER_OAUTH2, use_hashes=False)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/plain.py b/sleekxmpp/thirdparty/suelta/mechanisms/plain.py
deleted file mode 100644
index accae54a..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/plain.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import sys
-
-from sleekxmpp.thirdparty.suelta.util import bytes
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-from sleekxmpp.thirdparty.suelta.exceptions import SASLError, SASLCancelled
-
-
-class PLAIN(Mechanism):
-
- """
- """
-
- def __init__(self, sasl, name):
- """
- """
- super(PLAIN, self).__init__(sasl, name)
-
- if not self.sasl.tls_active():
- if not self.sasl.sec_query(self, '-ENCRYPTION, PLAIN'):
- raise SASLCancelled(self.sasl, self)
- else:
- if not self.sasl.sec_query(self, '+ENCRYPTION, PLAIN'):
- raise SASLCancelled(self.sasl, self)
-
- self.check_values(['username', 'password'])
-
- def prep(self):
- """
- Prepare for processing by deleting the password if
- the user has not approved storing it in the clear.
- """
- if 'savepass' not in self.values:
- if self.sasl.sec_query(self, 'CLEAR-PASSWORD'):
- self.values['savepass'] = True
-
- if 'savepass' not in self.values:
- del self.values['password']
-
- return True
-
- 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 okay(self):
- """
- Mutual authentication is not supported by PLAIN.
-
- :returns: ``True``
- """
- return True
-
-
-register_mechanism('PLAIN', 5, PLAIN, use_hashes=False)
diff --git a/sleekxmpp/thirdparty/suelta/mechanisms/scram_hmac.py b/sleekxmpp/thirdparty/suelta/mechanisms/scram_hmac.py
deleted file mode 100644
index b70ac9a4..00000000
--- a/sleekxmpp/thirdparty/suelta/mechanisms/scram_hmac.py
+++ /dev/null
@@ -1,176 +0,0 @@
-import sys
-import hmac
-import random
-from base64 import b64encode, b64decode
-
-from sleekxmpp.thirdparty.suelta.util import hash, bytes, num_to_bytes, bytes_to_num, XOR
-from sleekxmpp.thirdparty.suelta.sasl import Mechanism, register_mechanism
-from sleekxmpp.thirdparty.suelta.exceptions import SASLError, SASLCancelled
-
-
-def parse_challenge(challenge):
- """
- """
- items = {}
- for key, value in [item.split(b'=', 1) for item in challenge.split(b',')]:
- items[key] = value
- return items
-
-
-class SCRAM_HMAC(Mechanism):
-
- """
- """
-
- def __init__(self, sasl, name):
- """
- """
- super(SCRAM_HMAC, self).__init__(sasl, name, 0)
-
- self._cb = False
- if name[-5:] == '-PLUS':
- name = name[:-5]
- self._cb = True
-
- self.hash = hash(name[6:])
- if self.hash is None:
- raise SASLCancelled(self.sasl, self)
- if not self.sasl.tls_active():
- if not self.sasl.sec_query(self, '-ENCRYPTION, SCRAM'):
- raise SASLCancelled(self.sasl, self)
-
- self._step = 0
- self._rspauth = False
-
- def HMAC(self, key, msg):
- """
- """
- return hmac.HMAC(key=key, msg=msg, digestmod=self.hash).digest()
-
- 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 H(self, text):
- """
- """
- return self.hash(text).digest()
-
- def prep(self):
- if 'password' in self.values:
- del self.values['password']
-
- def process(self, challenge=None):
- """
- """
- steps = {
- 0: self.process_one,
- 1: self.process_two,
- 2: self.process_three
- }
- return steps[self._step](challenge)
-
- 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_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_three(self, challenge=None):
- """
- """
- data = parse_challenge(challenge)
- if b64decode(data[b'v']) == self.server_sig:
- self._rspauth = True
-
- def okay(self):
- """
- """
- return self._rspauth
-
- def get_user(self):
- return self.values['username']
-
-
-register_mechanism('SCRAM-', 60, SCRAM_HMAC)
-register_mechanism('SCRAM-', 70, SCRAM_HMAC, extra='-PLUS')