def Authenticate(self, app_id, challenge, registered_keys):
    """Authenticates app_id with the security key.

    Executes the U2F authentication/signature flow with the security key.

    Args:
      app_id: The app_id to register the security key against.
      challenge: Server challenge passed to the security key as a bytes object.
      registered_keys: List of keys already registered for this app_id+user.

    Returns:
      SignResponse with client_data, key_handle, and signature_data.  The client
      data is an object, while the signature_data is encoded in FIDO U2F binary
      format.

    Raises:
      U2FError: There was some kind of problem with authentication (e.g.
        there was a timeout while waiting for the test of user presence.)
    """
    client_data = model.ClientData(model.ClientData.TYP_AUTHENTICATION,
                                   challenge, self.origin)
    app_param = self.InternalSHA256(app_id)
    challenge_param = self.InternalSHA256(client_data.GetJson())
    num_invalid_keys = 0
    for key in registered_keys:
      try:
        if key.version != u'U2F_V2':
          continue
        for _ in range(30):
          try:
            resp = self.security_key.CmdAuthenticate(challenge_param, app_param,
                                                     key.key_handle)
            return model.SignResponse(key.key_handle, resp, client_data)
          except errors.TUPRequiredError:
            self.security_key.CmdWink()
            time.sleep(0.5)
      except errors.InvalidKeyHandleError:
        num_invalid_keys += 1
        continue
      except errors.HardwareError as e:
        raise errors.U2FError(errors.U2FError.BAD_REQUEST, e)

    if num_invalid_keys == len(registered_keys):
      # In this case, all provided keys were invalid.
      raise errors.U2FError(errors.U2FError.DEVICE_INELIGIBLE)

    # In this case, the TUP was not pressed.
    raise errors.U2FError(errors.U2FError.TIMEOUT)
Authenticates app_id with the security key.

    Executes the U2F authentication/signature flow with the security key.

    Args:
      app_id: The app_id to register the security key against.
      challenge: Server challenge passed to the security key as a bytes object.
      registered_keys: List of keys already registered for this app_id+user.

    Returns:
      SignResponse with client_data, key_handle, and signature_data.  The client
      data is an object, while the signature_data is encoded in FIDO U2F binary
      format.

    Raises:
      U2FError: There was some kind of problem with authentication (e.g.
        there was a timeout while waiting for the test of user presence.)