def test_base64(): allowed_s = string.ascii_letters + string.digits + '+/=' allowed_d = {} for c in allowed_s: allowed_d[ord(c)] = None isAllowed = allowed_d.__contains__ def checkEncoded(s): for c in s: assert isAllowed(c), s cases = [ '', 'x', '\x00', '\x01', '\x00' * 100, ''.join(map(chr, list(range(256)))), ] for s in cases: b64 = oidutil.toBase64(s) checkEncoded(b64) s_prime = oidutil.fromBase64(b64) assert str(s_prime, encoding="utf-8") == s, (s, b64, s_prime) # Randomized test for _ in range(50): n = random.randrange(2048) s = ''.join(map(chr, [random.randrange(256) for _ in range(n)])) b64 = oidutil.toBase64(s) checkEncoded(b64) s_prime = oidutil.fromBase64(b64) assert str(s_prime, encoding="utf-8") == s, (s, b64, s_prime)
def test_base64(): allowed_s = string.ascii_letters + string.digits + '+/=' allowed_d = {} for c in allowed_s: allowed_d[c] = None isAllowed = allowed_d.has_key def checkEncoded(s): for c in s: assert isAllowed(c), s cases = [ '', 'x', '\x00', '\x01', '\x00' * 100, ''.join(map(chr, range(256))), ] for s in cases: b64 = oidutil.toBase64(s) checkEncoded(b64) s_prime = oidutil.fromBase64(b64) assert s_prime == s, (s, b64, s_prime) # Randomized test for _ in xrange(50): n = random.randrange(2048) s = ''.join(map(chr, map(lambda _: random.randrange(256), range(n)))) b64 = oidutil.toBase64(s) checkEncoded(b64) s_prime = oidutil.fromBase64(b64) assert s_prime == s, (s, b64, s_prime)
def serialize(self): """ Convert an association to KV form. @return: String in KV form suitable for deserialization by deserialize. @rtype: str """ data = { 'version': '2', 'handle': self.handle, 'secret': oidutil.toBase64(self.secret), 'issued': str(int(self.issued)), 'lifetime': str(int(self.lifetime)), 'assoc_type': self.assoc_type } assert len(data) == len(self.assoc_keys) pairs = [] for field_name in self.assoc_keys: pairs.append((field_name, data[field_name])) return kvform.seqToKV(pairs, strict=True)
def serialize(self): """ Convert an association to KV form. @return: String in KV form suitable for deserialization by deserialize. @rtype: str """ data = { "version": "2", "handle": self.handle, "secret": oidutil.toBase64(self.secret), "issued": str(int(self.issued)), "lifetime": str(int(self.lifetime)), "assoc_type": self.assoc_type, } assert len(data) == len(self.assoc_keys) pairs = [] for field_name in self.assoc_keys: pairs.append((field_name, data[field_name])) return kvform.seqToKV(pairs, strict=True)
def verify(self, assoc_handle, sig, signed_pairs): """Verify that the signature for some data is valid. @param assoc_handle: The handle of the association used to sign the data. @type assoc_handle: str @param sig: The base-64 encoded signature to check. @type sig: str @param signed_pairs: The data to check, an ordered list of key-value pairs. The keys should be as they are in the request's C{signed} list, without any C{"openid."} prefix. @type signed_pairs: list of pairs @returns: C{True} if the signature is valid, C{False} if not. @returntype: bool """ assoc = self.getAssociation(assoc_handle, dumb=True) if not assoc: oidutil.log("failed to get assoc with handle %r to verify sig %r" % (assoc_handle, sig)) return False # Not using Association.checkSignature here is intentional; # Association should not know things like "the list of signed pairs is # in the request's 'signed' parameter and it is comma-separated." expected_sig = oidutil.toBase64(assoc.sign(signed_pairs)) return sig == expected_sig
def associate(services, url): '''Create an association (OpenID section 8) between RP and OP. Return response as a dictionary.''' req_data = { 'openid.ns':"http://specs.openid.net/auth/2.0", 'openid.mode':"associate", 'openid.assoc_type':"HMAC-SHA1", 'openid.session_type':"no-encryption", } if url.startswith('http:'): # Use DH exchange req_data['openid.session_type'] = "DH-SHA1" # Private key: random number between 1 and dh_prime-1 priv = random.SystemRandom().randrange(1, dh_prime - 1) # Public key: 2^priv mod prime pubkey = pow(2L, priv, dh_prime) dh_public_base64 = base64.b64encode(btwoc(pubkey)) # No need to send key and generator req_data['openid.dh_consumer_public'] = dh_public_base64 if is_compat_1x(services): # 14.2.1: clear session_type in 1.1 compatibility mode if req_data['openid.session_type'] == "no-encryption": req_data['openid.session_type'] = '' del req_data['openid.ns'] res = urllib.urlopen(url, b(urllib.urlencode(req_data))) try: if res.getcode() != 200: raise ValueError("OpenID provider refuses connection with status %s" % res.getcode()) data = parse_response(res.read()) except ValueError: endpoint = OpenIDServiceEndpoint.fromOPEndpointURL(url) store = MemoryStore() consumer = GenericConsumer(store) try: assoc = consumer._requestAssociation(endpoint, req_data['openid.assoc_type'], req_data['openid.session_type']) data = { 'assoc_handle': assoc.handle, 'expires_in': assoc.lifetime, 'mac_key': oidutil.toBase64(assoc.secret), } except ServerError: data = { 'error': 'Server %s refused its suggested association type: session_type=%s, assoc_type=%s' % (url, req_data['openid.assoc_type'], req_data['openid.session_type']), } if 'error' in data: raise ValueError, "associate failed: "+data['error'] if url.startswith('http:'): enc_mac_key = b(data.get('enc_mac_key')) if not enc_mac_key: raise ValueError, "Provider protocol error: not using DH-SHA1" enc_mac_key = base64.b64decode(enc_mac_key) dh_server_public = unbtwoc(base64.b64decode(b(data['dh_server_public']))) # shared secret: sha1(2^(server_priv*priv) mod prime) xor enc_mac_key shared_secret = btwoc(pow(dh_server_public, priv, dh_prime)) shared_secret = hashlib.sha1(shared_secret).digest() if len(shared_secret) != len(enc_mac_key): raise ValueError, "incorrect DH key size" # Fake mac_key result data['mac_key'] = b(base64.b64encode(string_xor(enc_mac_key, shared_secret))) return data
def createAssociation(self, dumb=True, assoc_type='HMAC-SHA1'): """Make a new association. @param dumb: Is this association for a dumb-mode transaction? @type dumb: bool @param assoc_type: The type of association to create. Currently there is only one type defined, C{HMAC-SHA1}. @type assoc_type: str @returns: the new association. @returntype: L{openid.association.Association} """ secret = cryptutil.getBytes(20) uniq = oidutil.toBase64(cryptutil.getBytes(4)) handle = '{%s}{%x}{%s}' % (assoc_type, int(time.time()), uniq) assoc = Association.fromExpiresIn(self.SECRET_LIFETIME, handle, secret, assoc_type) if dumb: key = self._dumb_key else: key = self._normal_key self.store.storeAssociation(key, assoc) return assoc
def createAssociation(self, dumb=True, assoc_type='HMAC-SHA1'): """Make a new association. @param dumb: Is this association for a dumb-mode transaction? @type dumb: bool @param assoc_type: The type of association to create. Currently there is only one type defined, C{HMAC-SHA1}. @type assoc_type: str @returns: the new association. @returntype: L{openid.association.Association} """ secret = cryptutil.getBytes(20) uniq = oidutil.toBase64(cryptutil.getBytes(4)) handle = '{%s}{%x}{%s}' % (assoc_type, int(time.time()), uniq) assoc = Association.fromExpiresIn( self.SECRET_LIFETIME, handle, secret, assoc_type) if dumb: key = self._dumb_key else: key = self._normal_key self.store.storeAssociation(key, assoc) return assoc
def _safe64(s): h64 = oidutil.toBase64(cryptutil.sha1(s)) # to be able to manipulate it, make it a bytearray h64 = bytearray(h64) h64 = h64.replace(b'+', b'_') h64 = h64.replace(b'/', b'.') h64 = h64.replace(b'=', b'') return bytes(h64)
def _safe64(s): h64 = oidutil.toBase64(cryptutil.sha1(s)) # to be able to manipulate it, make it a bytearray h64 = bytearray(h64) h64 = h64.replace(b"+", b"_") h64 = h64.replace(b"/", b".") h64 = h64.replace(b"=", b"") return bytes(h64)
def storeAssociation(self, server_url, assoc): iden = '%s-%s' % (server_url, assoc.handle) datum = {'secret': oidutil.toBase64(assoc.secret), 'issued': str(assoc.issued), 'lifetime': str(assoc.lifetime), 'assoc_type': assoc.assoc_type} data = {iden: datum} self.save_unique_data('association', data)
def storeAssociation(self, server_url, assoc): iden = '%s-%s' % (server_url, assoc.handle) datum = { 'secret': oidutil.toBase64(assoc.secret), 'issued': str(assoc.issued), 'lifetime': str(assoc.lifetime), 'assoc_type': assoc.assoc_type } data = {iden: datum} self.save_unique_data('association', data, ttl=assoc.lifetime)
def test_base64(self): allowed_s = string.ascii_letters + string.digits + '+/=' allowed_d = {} for c in allowed_s: allowed_d[c] = None def checkEncoded(s): for c in s: self.assertIn(c, allowed_d, msg=s) cases = [ b'', b'x', b'\x00', b'\x01', b'\x00' * 100, ] if six.PY2: cases.append(b''.join(chr(i) for i in range(256))) else: assert six.PY3 cases.append(bytes(i for i in range(256))) for s in cases: b64 = oidutil.toBase64(s) checkEncoded(b64) s_prime = oidutil.fromBase64(b64) assert s_prime == s, (s, b64, s_prime) # Randomized test for _ in range(50): n = random.randrange(2048) if six.PY2: s = b''.join(chr(random.randrange(256)) for i in range(n)) else: assert six.PY3 s = bytes(random.randrange(256) for i in range(n)) b64 = oidutil.toBase64(s) checkEncoded(b64) s_prime = oidutil.fromBase64(b64) assert s_prime == s, (s, b64, s_prime)
def test_exchange_dynamic(self): # Test complete key exchange with random values # Consumer part consumer_dh = DiffieHellman.fromDefaults() consumer_public_key = consumer_dh.public_key # Server part secret = toBase64(os.urandom(32)) server_dh = DiffieHellman.fromDefaults() mac_key = server_dh.xor_secret(consumer_public_key, secret, hashes.SHA256()) server_public_key = server_dh.public_key # Consumer part shared_secret = consumer_dh.xor_secret(server_public_key, mac_key, hashes.SHA256()) # Check secret was negotiated correctly self.assertEqual(secret, shared_secret)
def getMessageSignature(self, message): """Return the signature of a message. If I am not a sign-all association, the message must have a signed list. @return: the signature, base64 encoded @rtype: six.text_type @raises ValueError: If there is no signed list and I am not a sign-all type of association. """ pairs = self._makePairs(message) return oidutil.toBase64(self.sign(pairs))
def test_plaintext(self): response = self.request.answer(self.assoc) rfg = response.fields.get self.failUnlessEqual(rfg("assoc_type"), "HMAC-SHA1") self.failUnlessEqual(rfg("assoc_handle"), self.assoc.handle) self.failUnlessEqual( rfg("expires_in"), "%d" % (self.signatory.SECRET_LIFETIME,)) self.failUnlessEqual( rfg("mac_key"), oidutil.toBase64(self.assoc.secret)) self.failIf(rfg("session_type")) self.failIf(rfg("enc_mac_key")) self.failIf(rfg("dh_server_public"))
def test_plainFallback(self): sess = DiffieHellmanConsumerSession() server_resp = { 'assoc_type': 'HMAC-SHA1', 'assoc_handle': 'handle', 'expires_in': '1000', 'mac_key': oidutil.toBase64(self.secret), } ret = self.consumer._parseAssociation(server_resp, sess, 'server_url') self.failIf(ret is None) self.failUnlessEqual(ret.assoc_type, 'HMAC-SHA1') self.failUnlessEqual(ret.secret, self.secret) self.failUnlessEqual(ret.handle, 'handle') self.failUnlessEqual(ret.lifetime, 1000)
def storeAssociation(self, server_url, association): Association().save({ 'url': server_url, 'handle': association.handle, 'secret': oidutil.toBase64(association.secret), 'issued': association.issued, 'lifetime': association.lifetime, 'type': association.assoc_type, 'expires': datetime.datetime.utcnow() + datetime.timedelta(seconds=association.lifetime) })
def xor_secret(self, public_key, secret, algorithm): """Return a base64 encoded XOR of a secret key and hash of a DH exchanged secret. @param public_key: Base64 encoded public key of the other party. @type public_key: six.text_type @param secret: Base64 encoded secret @type secret: six.text_type @type algorithm: hashes.HashAlgorithm @rtype: six.text_type """ dh_shared = self._get_shared_secret(public_key) # The DH secret must be `btwoc` compatible. # See http://openid.net/specs/openid-authentication-2_0.html#rfc.section.8.2.3 for details. dh_shared = cryptutil.fix_btwoc(dh_shared) digest = hashes.Hash(algorithm, backend=default_backend()) digest.update(dh_shared) hashed_dh_shared = digest.finalize() return toBase64(strxor(base64.b64decode(secret), hashed_dh_shared))
def signDict(self, fields, data, prefix='openid.'): """ Generate a signature for some fields in a dictionary @param fields: The fields to sign, in order @type fields: sequence of str @param data: Dictionary of values to sign @type data: {str:str} @return: the signature, base64 encoded @rtype: str """ pairs = [] for field in fields: pairs.append((field, data.get(prefix + field, ''))) return oidutil.toBase64(self.sign(pairs))
def longToBase64(l): return toBase64(longToBinary(l))
def _safe64(s): h64 = oidutil.toBase64(sha1(s.encode('utf-8')).digest()) h64 = h64.replace('+', '_') h64 = h64.replace('/', '.') h64 = h64.replace('=', '') return h64
def longToBase64(l): return toBase64(int_to_bytes(l))
def _safe64(s): h64 = oidutil.toBase64(cryptutil.sha1(s)) h64 = h64.replace("+", "_") h64 = h64.replace("/", ".") h64 = h64.replace("=", "") return h64
class TestDiffieHellman(unittest.TestCase): """Test `DiffieHellman` class.""" def test_init(self): dh = DiffieHellman(DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR) self.assertTrue(dh.usingDefaultValues()) def test_init_int(self): dh = DiffieHellman(base64ToLong(DEFAULT_DH_MODULUS), base64ToLong(DEFAULT_DH_GENERATOR)) self.assertTrue(dh.usingDefaultValues()) def test_modulus(self): dh = DiffieHellman.fromDefaults() modulus = int( '155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698' '188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681' '476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848' '253359305585439638443') warning_msg = "Modulus property will return base64 encoded string." with ShouldWarn(DeprecationWarning(warning_msg)): warnings.simplefilter('always') self.assertEqual(dh.modulus, modulus) def test_generator(self): dh = DiffieHellman.fromDefaults() warning_msg = "Generator property will return base64 encoded string." with ShouldWarn(DeprecationWarning(warning_msg)): warnings.simplefilter('always') self.assertEqual(dh.generator, 2) def test_parameters(self): dh = DiffieHellman.fromDefaults() self.assertEqual(dh.parameters, (DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR)) consumer_private_key = ( 'bVQh4Z81F5e57JCT1pmxADRktpYwIwhNjWkiIjg450sfYZOJ9Ntf4YHBhcBpkPyehdq/XL+yEWbZFig4wh2MdqES0X' 'aOPRVl7ZzsjTNgztKUYE2mhiYQd4KMmB9uLExM72ntwcdZ3/vlb0Fq8DlIx3FhqeaYsKKTsdUW/KbJcS0=' ) consumer_public_key = ( 'ANMxIwAeRWw5mZD3+DkoX3G6n/tuBGsjfk6R+vBW2zwve0BSlh1F0EsXlQEUuXJ+s1DQ8nFQLPYOLO0mLexXH0bSscv' 'zhBldH+L+fxJfoL9xoTAxk7qqT659QqErhEMtQpBy7hK5L7Qb8R2NAUZ++MPxUNB71IBd6vMG6M6MueXp' ) server_private_key = ( 'ANxFaZXkCVNESkYKFclilsm7tVIO1CNYy621Y44w19OPk7xE7zEZdttX/KfRSImecPpn+AATLhRZMuXzaq3KDFFTu9Nu' 'hSINYml2f7xZd1+lYg6YhWiojfP3YPqLIV9sj/26O1A7pTcq6jajj/8E5P+qkr6+bSQhZ0UlZiBQUyDr' ) server_public_key = ( 'MSJTx7cMqUBAcpLCan75t+8OSf3SZUSwivlEUYxMaHbbueKp1u4/7Fdw9sTCN3gA0iFE2dTOJpRUT4TmFomHnyIfBExdc' 'wbkXiQIhsSnBJkGmPuAPkKFFHtB0pKET6bWZolwP5fp4lZOgM+7FIRte5OZd5XEJIN9vBYxo6NaoRc=' ) shared_secret = ( 'FHWhX2v2g/twI8mO1HFiI9zgRP6/CBbJ0+13cgpDJvIUypDNcqLHlkGJtjaOJ1ciX+qk2Jf3Zdt5YJDgilVH+Xg7x7WaHXVxX' 'Yxu5RTwEuPyFUjO62XT6u11qJ35PvveTDwwAsv6+OspK8FRbqMKIgNuEkmaFDVwr4dKyhZUtNg=' ) secret = toBase64(b'Rimmer ordered hot gazpacho soup') mac_key = 'hAYpHzbPvEHs0J2t8KYiqoxsLSmRzGfCQmwMg9taNf0=' def setup_keys(self, dh_object, public_key, private_key): """Set up private and public key into DiffieHellman object.""" public_numbers = DHPublicNumbers(base64ToLong(public_key), dh_object.parameter_numbers) private_numbers = DHPrivateNumbers(base64ToLong(private_key), public_numbers) dh_object.private_key = private_numbers.private_key(default_backend()) def test_public(self): dh = DiffieHellman.fromDefaults() self.setup_keys(dh, self.server_public_key, self.server_private_key) warning_msg = "Attribute 'public' is deprecated. Use 'public_key' instead." with ShouldWarn(DeprecationWarning(warning_msg)): warnings.simplefilter('always') self.assertEqual(dh.public, base64ToLong(self.server_public_key)) def test_public_key(self): dh = DiffieHellman.fromDefaults() self.setup_keys(dh, self.server_public_key, self.server_private_key) self.assertEqual(dh.public_key, self.server_public_key) def test_get_shared_secret_server(self): server_dh = DiffieHellman.fromDefaults() self.setup_keys(server_dh, self.server_public_key, self.server_private_key) self.assertEqual( server_dh._get_shared_secret(self.consumer_public_key), base64.b64decode(self.shared_secret)) def test_get_shared_secret_consumer(self): consumer_dh = DiffieHellman.fromDefaults() self.setup_keys(consumer_dh, self.consumer_public_key, self.consumer_private_key) self.assertEqual( consumer_dh._get_shared_secret(self.server_public_key), base64.b64decode(self.shared_secret)) def test_getSharedSecret(self): # Test the deprecated method consumer_dh = DiffieHellman.fromDefaults() self.setup_keys(consumer_dh, self.consumer_public_key, self.consumer_private_key) warning_msg = "Method 'getSharedSecret' is deprecated in favor of '_get_shared_secret'." with ShouldWarn(DeprecationWarning(warning_msg)): warnings.simplefilter('always') self.assertEqual( consumer_dh.getSharedSecret(self.server_public_key), base64ToLong(self.shared_secret)) def test_xorSecret(self): # Test key exchange - deprecated method server_dh = DiffieHellman.fromDefaults() self.setup_keys(server_dh, self.server_public_key, self.server_private_key) def sha256(value): digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(value) return digest.finalize() warning_msg = "Method 'xorSecret' is deprecated, use 'xor_secret' instead." with ShouldWarn(DeprecationWarning(warning_msg)): warnings.simplefilter('always') secret = server_dh.xorSecret( base64ToLong(self.consumer_public_key), base64.b64decode(self.secret), sha256) self.assertEqual(secret, base64.b64decode(self.mac_key)) def test_exchange_server_static(self): # Test key exchange - server part with static values server_dh = DiffieHellman.fromDefaults() self.setup_keys(server_dh, self.server_public_key, self.server_private_key) self.assertEqual( server_dh.xor_secret(self.consumer_public_key, self.secret, hashes.SHA256()), self.mac_key) self.assertEqual(server_dh.public_key, self.server_public_key) def test_exchange_consumer_static(self): # Test key exchange - consumer part with static values consumer_dh = DiffieHellman.fromDefaults() self.setup_keys(consumer_dh, self.consumer_public_key, self.consumer_private_key) shared_secret = consumer_dh.xor_secret(self.server_public_key, self.mac_key, hashes.SHA256()) # Check secret was negotiated correctly self.assertEqual(shared_secret, self.secret) def test_exchange_dynamic(self): # Test complete key exchange with random values # Consumer part consumer_dh = DiffieHellman.fromDefaults() consumer_public_key = consumer_dh.public_key # Server part secret = toBase64(os.urandom(32)) server_dh = DiffieHellman.fromDefaults() mac_key = server_dh.xor_secret(consumer_public_key, secret, hashes.SHA256()) server_public_key = server_dh.public_key # Consumer part shared_secret = consumer_dh.xor_secret(server_public_key, mac_key, hashes.SHA256()) # Check secret was negotiated correctly self.assertEqual(secret, shared_secret)
def longToBase64(value): return toBase64(int_to_bytes(value))
def _safe64(s): h64 = oidutil.toBase64(cryptutil.sha1(s)) h64 = h64.replace('+', '_') h64 = h64.replace('/', '.') h64 = h64.replace('=', '') return h64
def answer(self, secret): return {'mac_key': oidutil.toBase64(secret)}
def answer(self, secret): mac_key = self.dh.xorSecret(self.consumer_pubkey, secret) return { 'dh_server_public': cryptutil.longToBase64(self.dh.public), 'enc_mac_key': oidutil.toBase64(mac_key), }
def associate(services, url): '''Create an association (OpenID section 8) between RP and OP. Return response as a dictionary.''' req_data = { 'openid.ns': "http://specs.openid.net/auth/2.0", 'openid.mode': "associate", 'openid.assoc_type': "HMAC-SHA1", 'openid.session_type': "no-encryption", } if url.startswith('http:'): # Use DH exchange req_data['openid.session_type'] = "DH-SHA1" # Private key: random number between 1 and dh_prime-1 priv = random.SystemRandom().randrange(1, dh_prime - 1) # Public key: 2^priv mod prime pubkey = pow(2L, priv, dh_prime) dh_public_base64 = base64.b64encode(btwoc(pubkey)) # No need to send key and generator req_data['openid.dh_consumer_public'] = dh_public_base64 if is_compat_1x(services): # 14.2.1: clear session_type in 1.1 compatibility mode if req_data['openid.session_type'] == "no-encryption": req_data['openid.session_type'] = '' del req_data['openid.ns'] res = urllib.urlopen(url, b(urllib.urlencode(req_data))) try: if res.getcode() != 200: raise ValueError( "OpenID provider refuses connection with status %s" % res.getcode()) data = parse_response(res.read()) except ValueError: endpoint = OpenIDServiceEndpoint.fromOPEndpointURL(url) store = MemoryStore() consumer = GenericConsumer(store) try: assoc = consumer._requestAssociation( endpoint, req_data['openid.assoc_type'], req_data['openid.session_type']) data = { 'assoc_handle': assoc.handle, 'expires_in': assoc.lifetime, 'mac_key': oidutil.toBase64(assoc.secret), } except ServerError: data = { 'error': 'Server %s refused its suggested association type: session_type=%s, assoc_type=%s' % (url, req_data['openid.assoc_type'], req_data['openid.session_type']), } if 'error' in data: raise ValueError, "associate failed: " + data['error'] if url.startswith('http:'): enc_mac_key = b(data.get('enc_mac_key')) if not enc_mac_key: raise ValueError, "Provider protocol error: not using DH-SHA1" enc_mac_key = base64.b64decode(enc_mac_key) dh_server_public = unbtwoc( base64.b64decode(b(data['dh_server_public']))) # shared secret: sha1(2^(server_priv*priv) mod prime) xor enc_mac_key shared_secret = btwoc(pow(dh_server_public, priv, dh_prime)) shared_secret = hashlib.sha1(shared_secret).digest() if len(shared_secret) != len(enc_mac_key): raise ValueError, "incorrect DH key size" # Fake mac_key result data['mac_key'] = b( base64.b64encode(string_xor(enc_mac_key, shared_secret))) return data