private void getSaltedPasswordFromTwoWay(NameCallback nameCallback, ByteStringBuilder b)
      throws SaslException {
    CredentialCallback credentialCallback =
        new CredentialCallback(singletonMap(TwoWayPassword.class, emptySet()));
    final ParameterCallback parameterCallback =
        new ParameterCallback(IteratedSaltedPasswordAlgorithmSpec.class);
    try {
      tryHandleCallbacks(nameCallback, parameterCallback, credentialCallback);
      algorithmSpec = (IteratedSaltedPasswordAlgorithmSpec) parameterCallback.getParameterSpec();
      if (algorithmSpec == null) throw new FastUnsupportedCallbackException(parameterCallback);
    } catch (UnsupportedCallbackException e) {
      Callback callback = e.getCallback();
      if (callback == nameCallback) {
        throw log.saslCallbackHandlerDoesNotSupportUserName(getMechanismName(), e);
      } else if (callback == credentialCallback) {
        return; // credential acquisition not supported
      } else if (callback == parameterCallback) {
        // one more try, with default parameters
        salt = ScramUtil.generateSalt(16, getRandom());
        algorithmSpec = new IteratedSaltedPasswordAlgorithmSpec(minimumIterationCount, salt);
        try {
          tryHandleCallbacks(nameCallback, credentialCallback);
        } catch (UnsupportedCallbackException ex) {
          callback = ex.getCallback();
          if (callback == nameCallback) {
            throw log.saslCallbackHandlerDoesNotSupportUserName(getMechanismName(), ex);
          } else if (callback == credentialCallback) {
            return;
          } else {
            throw log.saslCallbackHandlerFailedForUnknownReason(getMechanismName(), ex);
          }
        }
      } else {
        throw log.saslCallbackHandlerDoesNotSupportCredentialAcquisition(getMechanismName(), e);
      }
    }

    // get the clear password
    TwoWayPassword password = (TwoWayPassword) credentialCallback.getCredential();
    char[] passwordChars = ScramUtil.getTwoWayPasswordChars(getMechanismName(), password);
    getSaltedPasswordFromPasswordChars(passwordChars, b);
  }
  private void getSaltedPasswordFromPasswordCallback(NameCallback nameCallback, ByteStringBuilder b)
      throws SaslException {
    final PasswordCallback passwordCallback = new PasswordCallback("User password", false);
    try {
      tryHandleCallbacks(nameCallback, passwordCallback);
    } catch (UnsupportedCallbackException e) {
      final Callback callback = e.getCallback();
      if (callback == nameCallback) {
        throw log.saslCallbackHandlerDoesNotSupportUserName(getMechanismName(), e);
      } else if (callback == passwordCallback) {
        return; // PasswordCallback not supported
      } else {
        throw log.saslCallbackHandlerFailedForUnknownReason(getMechanismName(), e);
      }
    }

    salt = ScramUtil.generateSalt(16, getRandom());
    algorithmSpec = new IteratedSaltedPasswordAlgorithmSpec(minimumIterationCount, salt);

    char[] passwordChars = passwordCallback.getPassword();
    passwordCallback.clearPassword();
    getSaltedPasswordFromPasswordChars(passwordChars, b);
  }