def __new__(cls, ffdh_name, bases, dct): the_class = super(_FFDHParamsMetaclass, cls).__new__(cls, ffdh_name, bases, dct) if conf.crypto_valid and ffdh_name != "_FFDHParams": pn = DHParameterNumbers(the_class.m, the_class.g) params = pn.parameters(default_backend()) _ffdh_groups[ffdh_name] = [params, the_class.mLen] return the_class
class DiffieHellman(object): """Utility for Diffie-Hellman key exchange.""" def __init__(self, modulus, generator): """Create a new instance. @type modulus: Union[six.integer_types] @type generator: Union[six.integer_types] """ self.parameter_numbers = DHParameterNumbers(modulus, generator) parameters = self.parameter_numbers.parameters(default_backend()) self.private_key = parameters.generate_private_key() @classmethod def fromDefaults(cls): """Create Diffie-Hellman with the default modulus and generator.""" return cls(DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR) @property def modulus(self): """Return the prime modulus value. @rtype: Union[six.integer_types] """ return self.parameter_numbers.p @property def generator(self): """Return the generator value. @rtype: Union[six.integer_types] """ return self.parameter_numbers.g @property def public(self): """Return the public key. @rtype: Union[six.integer_types] """ warnings.warn( "Attribute 'public' is deprecated. Use 'public_key' instead.", DeprecationWarning) return self.private_key.public_key().public_numbers().y @property def public_key(self): """Return base64 encoded public key. @rtype: six.text_type """ return cryptutil.longToBase64( self.private_key.public_key().public_numbers().y) def usingDefaultValues(self): return (self.modulus == DEFAULT_DH_MODULUS and self.generator == DEFAULT_DH_GENERATOR) def getSharedSecret(self, composite): """Return a shared secret. @param composite: Public key of the other party. @type composite: Union[six.integer_types] @rtype: Union[six.integer_types] """ warnings.warn( "Method 'getSharedSecret' is deprecated in favor of 'get_shared_secret'.", DeprecationWarning) return cryptutil.bytes_to_int(self.get_shared_secret(composite)) def get_shared_secret(self, public_key): """Return a shared secret. @param public_key: Public key of the other party. @type public_key: Union[six.integer_types] @rtype: six.binary_type """ public_numbers = DHPublicNumbers(public_key, self.parameter_numbers) return self.private_key.exchange( public_numbers.public_key(default_backend())) def xorSecret(self, composite, secret, hash_func): dh_shared = self.get_shared_secret(composite) hashed_dh_shared = hash_func(dh_shared) return strxor(secret, hashed_dh_shared)
class DiffieHellman(object): """Utility for Diffie-Hellman key exchange.""" def __init__(self, modulus, generator): """Create a new instance. @type modulus: six.text_type, Union[six.integer_types] are deprecated @type generator: six.text_type, Union[six.integer_types] are deprecated """ if isinstance(modulus, six.integer_types): warnings.warn("Modulus should be passed as base64 encoded string.") else: modulus = cryptutil.base64ToLong(modulus) if isinstance(generator, six.integer_types): warnings.warn("Generator should be passed as base64 encoded string.") else: generator = cryptutil.base64ToLong(generator) self.parameter_numbers = DHParameterNumbers(modulus, generator) parameters = self.parameter_numbers.parameters(default_backend()) self.private_key = parameters.generate_private_key() @classmethod def fromDefaults(cls): """Create Diffie-Hellman with the default modulus and generator.""" return cls(DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR) @property def modulus(self): """Return the prime modulus value. @rtype: Union[six.integer_types] """ warnings.warn("Modulus property will return base64 encoded string.", DeprecationWarning) return self.parameter_numbers.p @property def generator(self): """Return the generator value. @rtype: Union[six.integer_types] """ warnings.warn("Generator property will return base64 encoded string.", DeprecationWarning) return self.parameter_numbers.g @property def parameters(self): """Return base64 encoded modulus and generator. @return: Tuple with modulus and generator @rtype: Tuple[six.text_type, six.text_type] """ modulus = self.parameter_numbers.p generator = self.parameter_numbers.g return cryptutil.longToBase64(modulus), cryptutil.longToBase64(generator) @property def public(self): """Return the public key. @rtype: Union[six.integer_types] """ warnings.warn("Attribute 'public' is deprecated. Use 'public_key' instead.", DeprecationWarning) return self.private_key.public_key().public_numbers().y @property def public_key(self): """Return base64 encoded public key. @rtype: six.text_type """ return cryptutil.longToBase64(self.private_key.public_key().public_numbers().y) def usingDefaultValues(self): return self.parameters == (DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR) def getSharedSecret(self, composite): """Return a shared secret. @param composite: Public key of the other party. @type composite: Union[six.integer_types] @rtype: Union[six.integer_types] """ warnings.warn("Method 'getSharedSecret' is deprecated in favor of '_get_shared_secret'.", DeprecationWarning) return cryptutil.bytes_to_int(self._get_shared_secret(composite)) def _get_shared_secret(self, public_key): """Return a shared secret. @param public_key: Base64 encoded public key of the other party. @type public_key: six.text_type @rtype: six.binary_type """ public_numbers = DHPublicNumbers(cryptutil.base64ToLong(public_key), self.parameter_numbers) return self.private_key.exchange(public_numbers.public_key(default_backend())) def xorSecret(self, composite, secret, hash_func): warnings.warn("Method 'xorSecret' is deprecated, use 'xor_secret' instead.", DeprecationWarning) dh_shared = self._get_shared_secret(cryptutil.longToBase64(composite)) # 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) hashed_dh_shared = hash_func(dh_shared) return strxor(secret, hashed_dh_shared) 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))
class DiffieHellman(object): """Utility for Diffie-Hellman key exchange.""" def __init__(self, modulus, generator): """Create a new instance. @type modulus: six.text_type, Union[six.integer_types] are deprecated @type generator: six.text_type, Union[six.integer_types] are deprecated """ if isinstance(modulus, six.integer_types): warnings.warn("Modulus should be passed as base64 encoded string.") else: modulus = cryptutil.base64ToLong(modulus) if isinstance(generator, six.integer_types): warnings.warn( "Generator should be passed as base64 encoded string.") else: generator = cryptutil.base64ToLong(generator) self.parameter_numbers = DHParameterNumbers(modulus, generator) parameters = self.parameter_numbers.parameters(default_backend()) self.private_key = parameters.generate_private_key() @classmethod def fromDefaults(cls): """Create Diffie-Hellman with the default modulus and generator.""" return cls(DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR) @property def modulus(self): """Return the prime modulus value. @rtype: Union[six.integer_types] """ warnings.warn("Modulus property will return base64 encoded string.", DeprecationWarning) return self.parameter_numbers.p @property def generator(self): """Return the generator value. @rtype: Union[six.integer_types] """ warnings.warn("Generator property will return base64 encoded string.", DeprecationWarning) return self.parameter_numbers.g @property def parameters(self): """Return base64 encoded modulus and generator. @return: Tuple with modulus and generator @rtype: Tuple[six.text_type, six.text_type] """ modulus = self.parameter_numbers.p generator = self.parameter_numbers.g return cryptutil.longToBase64(modulus), cryptutil.longToBase64( generator) @property def public(self): """Return the public key. @rtype: Union[six.integer_types] """ warnings.warn( "Attribute 'public' is deprecated. Use 'public_key' instead.", DeprecationWarning) return self.private_key.public_key().public_numbers().y @property def public_key(self): """Return base64 encoded public key. @rtype: six.text_type """ return cryptutil.longToBase64( self.private_key.public_key().public_numbers().y) def usingDefaultValues(self): return self.parameters == (DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR) def getSharedSecret(self, composite): """Return a shared secret. @param composite: Public key of the other party. @type composite: Union[six.integer_types] @rtype: Union[six.integer_types] """ warnings.warn( "Method 'getSharedSecret' is deprecated in favor of '_get_shared_secret'.", DeprecationWarning) return cryptutil.bytes_to_int(self._get_shared_secret(composite)) def _get_shared_secret(self, public_key): """Return a shared secret. @param public_key: Base64 encoded public key of the other party. @type public_key: six.text_type @rtype: six.binary_type """ public_numbers = DHPublicNumbers(cryptutil.base64ToLong(public_key), self.parameter_numbers) return self.private_key.exchange( public_numbers.public_key(default_backend())) def xorSecret(self, composite, secret, hash_func): warnings.warn( "Method 'xorSecret' is deprecated, use 'xor_secret' instead.", DeprecationWarning) dh_shared = self._get_shared_secret(cryptutil.longToBase64(composite)) # 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) hashed_dh_shared = hash_func(dh_shared) return strxor(secret, hashed_dh_shared) 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 establish_association(endpoint, assoc_type, session_type, generator, generate_modulus): """Actually establish the association.""" generator = int(generator) if generate_modulus: parameters = generate_parameters(generator=generator, key_size=2048, backend=default_backend()) parameter_numbers = parameters.parameter_numbers() else: parameter_numbers = DHParameterNumbers(DEFAULT_DH_MODULUS, generator) parameters = parameter_numbers.parameters(default_backend()) private_key = parameters.generate_private_key() public_key = int_to_base64(private_key.public_key().public_numbers().y) logging.debug("Private key: %s", private_key.private_numbers().x) logging.debug("Public key: %s", private_key.public_key().public_numbers().y) data = {'openid.ns': OPENID2_NS, 'openid.mode': 'associate', 'openid.assoc_type': assoc_type, 'openid.session_type': session_type, 'openid.dh_consumer_public': public_key} if parameter_numbers != DHParameterNumbers(DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR): data['openid.dh_modulus'] = int_to_base64(parameter_numbers.p) data['openid.dh_gen'] = int_to_base64(parameter_numbers.g) logging.info("Query arguments: %s", data) response = requests.post(endpoint, data=data) if response.status_code != 200: if response.status_code == 400: # Is it an error response? error_data = parse_kv_response(response) if error_data.get('mode') == 'error': # It's an error response raise ValueError("Server responded with error: {}".format(error_data.get('error'))) raise ValueError("Response returned incorrect status code: {}".format(response.status_code)) association_data = parse_association_response(response) logging.debug("Association data: %s", association_data) if association_data['assoc_type'] != assoc_type: raise ValueError( "Unexpected assoc_type returned {}, expected {}".format(association_data['assoc_type'], assoc_type)) if association_data['session_type'] != session_type: raise ValueError( "Unexpected session_type returned {}, expected {}".format(association_data['session_type'], session_type)) server_public_key = base64_to_int(association_data['dh_server_public']) shared_secret = private_key.exchange( DHPublicNumbers(server_public_key, parameter_numbers).public_key(default_backend())) # Not an ordinary DH secret is used here. # According to http://openid.net/specs/openid-authentication-2_0.html#rfc.section.8.2.3, the first bit of # the DH secret must be zero. If it isn't, the bytes must be prepended by zero byte before they're hashed. shared_secret = bytearray(shared_secret) if shared_secret[0] > 127: shared_secret = bytearray([0]) + shared_secret shared_secret = bytes(shared_secret) logging.debug("DH shared secret: %s", base64.b64encode(shared_secret)) algorithm = getattr(hashes, assoc_type[5:]) digest = hashes.Hash(algorithm(), backend=default_backend()) digest.update(shared_secret) hashed_dh_shared = digest.finalize() mac_key = strxor(base64.b64decode(association_data['enc_mac_key']), hashed_dh_shared) return {'assoc_type': association_data['assoc_type'], 'session_type': association_data['session_type'], 'assoc_handle': association_data['assoc_handle'], 'expires_in': association_data['expires_in'], 'mac_key': base64.b64encode(mac_key).decode('utf-8')}
def establish_association(endpoint, assoc_type, session_type, generator, generate_modulus): """Actually establish the association.""" generator = int(generator) if generate_modulus: parameters = generate_parameters(generator=generator, key_size=2048, backend=default_backend()) parameter_numbers = parameters.parameter_numbers() else: parameter_numbers = DHParameterNumbers(DEFAULT_DH_MODULUS, generator) parameters = parameter_numbers.parameters(default_backend()) private_key = parameters.generate_private_key() public_key = int_to_base64(private_key.public_key().public_numbers().y) logging.debug("Private key: %s", private_key.private_numbers().x) logging.debug("Public key: %s", private_key.public_key().public_numbers().y) data = { 'openid.ns': OPENID2_NS, 'openid.mode': 'associate', 'openid.assoc_type': assoc_type, 'openid.session_type': session_type, 'openid.dh_consumer_public': public_key } if parameter_numbers != DHParameterNumbers(DEFAULT_DH_MODULUS, DEFAULT_DH_GENERATOR): data['openid.dh_modulus'] = int_to_base64(parameter_numbers.p) data['openid.dh_gen'] = int_to_base64(parameter_numbers.g) logging.info("Query arguments: %s", data) response = requests.post(endpoint, data=data) if response.status_code != 200: if response.status_code == 400: # Is it an error response? error_data = parse_kv_response(response) if error_data.get('mode') == 'error': # It's an error response raise ValueError("Server responded with error: {}".format( error_data.get('error'))) raise ValueError("Response returned incorrect status code: {}".format( response.status_code)) association_data = parse_association_response(response) logging.debug("Association data: %s", association_data) if association_data['assoc_type'] != assoc_type: raise ValueError( "Unexpected assoc_type returned {}, expected {}".format( association_data['assoc_type'], assoc_type)) if association_data['session_type'] != session_type: raise ValueError( "Unexpected session_type returned {}, expected {}".format( association_data['session_type'], session_type)) server_public_key = base64_to_int(association_data['dh_server_public']) shared_secret = private_key.exchange( DHPublicNumbers(server_public_key, parameter_numbers).public_key(default_backend())) # Not an ordinary DH secret is used here. # According to http://openid.net/specs/openid-authentication-2_0.html#rfc.section.8.2.3, the first bit of # the DH secret must be zero. If it isn't, the bytes must be prepended by zero byte before they're hashed. shared_secret = bytearray(shared_secret) if shared_secret[0] > 127: shared_secret = bytearray([0]) + shared_secret shared_secret = bytes(shared_secret) logging.debug("DH shared secret: %s", base64.b64encode(shared_secret)) algorithm = getattr(hashes, assoc_type[5:]) digest = hashes.Hash(algorithm(), backend=default_backend()) digest.update(shared_secret) hashed_dh_shared = digest.finalize() mac_key = strxor(base64.b64decode(association_data['enc_mac_key']), hashed_dh_shared) return { 'assoc_type': association_data['assoc_type'], 'session_type': association_data['session_type'], 'assoc_handle': association_data['assoc_handle'], 'expires_in': association_data['expires_in'], 'mac_key': base64.b64encode(mac_key).decode('utf-8') }