private OutgoingMessage sendParameters(final IncomingMessage in) throws KeyAgreementException {
    final String I = in.readString();

    // get s and v for user identified by I
    // ----------------------------------------------------------------------
    final Map credentials;
    try {
      final Map userID = new HashMap();
      userID.put(Registry.SASL_USERNAME, I);
      userID.put(SRPRegistry.MD_NAME_FIELD, srp.getAlgorithm());
      credentials = passwordDB.lookup(userID);
    } catch (IOException x) {
      throw new KeyAgreementException("computeSharedSecret()", x);
    }

    final BigInteger s =
        new BigInteger(1, Util.fromBase64((String) credentials.get(SRPRegistry.SALT_FIELD)));
    final BigInteger v =
        new BigInteger(
            1, Util.fromBase64((String) credentials.get(SRPRegistry.USER_VERIFIER_FIELD)));

    final Map configuration;
    try {
      final String mode = (String) credentials.get(SRPRegistry.CONFIG_NDX_FIELD);
      configuration = passwordDB.getConfiguration(mode);
    } catch (IOException x) {
      throw new KeyAgreementException("computeSharedSecret()", x);
    }

    N = new BigInteger(1, Util.fromBase64((String) configuration.get(SRPRegistry.SHARED_MODULUS)));
    g = new BigInteger(1, Util.fromBase64((String) configuration.get(SRPRegistry.FIELD_GENERATOR)));
    // ----------------------------------------------------------------------

    // generate an ephemeral keypair
    final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
    final Map attributes = new HashMap();
    if (rnd != null) {
      attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
    }
    attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
    attributes.put(SRPKeyPairGenerator.GENERATOR, g);
    attributes.put(SRPKeyPairGenerator.USER_VERIFIER, v);
    kpg.setup(attributes);
    hostKeyPair = kpg.generate();

    final BigInteger B = ((SRPPublicKey) hostKeyPair.getPublic()).getY();

    final OutgoingMessage result = new OutgoingMessage();
    result.writeMPI(N);
    result.writeMPI(g);
    result.writeMPI(s);
    result.writeMPI(B);

    return result;
  }
  protected OutgoingMessage computeSharedSecret(final IncomingMessage in)
      throws KeyAgreementException {
    N = in.readMPI();
    g = in.readMPI();
    final BigInteger s = in.readMPI();
    final BigInteger B = in.readMPI();

    if (B.mod(N).equals(BigInteger.ZERO)) {
      throw new KeyAgreementException("illegal value for B");
    }

    // generate an ephemeral keypair
    final SRPKeyPairGenerator kpg = new SRPKeyPairGenerator();
    final Map attributes = new HashMap();
    if (rnd != null) {
      attributes.put(SRPKeyPairGenerator.SOURCE_OF_RANDOMNESS, rnd);
    }
    attributes.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
    attributes.put(SRPKeyPairGenerator.GENERATOR, g);
    kpg.setup(attributes);
    userKeyPair = kpg.generate();

    final BigInteger A = ((SRPPublicKey) userKeyPair.getPublic()).getY();
    final BigInteger u = uValue(A, B); // u = H(A | B)

    if (u.mod(N).equals(BigInteger.ZERO)) {
      throw new KeyAgreementException("u is zero");
    }

    final BigInteger x;
    try {
      x = new BigInteger(1, srp.computeX(Util.trim(s), I, p));
    } catch (Exception e) {
      throw new KeyAgreementException("computeSharedSecret()", e);
    }

    // compute S = (B - 3g^x) ^ (a + ux)
    final BigInteger a = ((SRPPrivateKey) userKeyPair.getPrivate()).getX();
    final BigInteger S = B.subtract(THREE.multiply(g.modPow(x, N))).modPow(a.add(u.multiply(x)), N);

    K = S;

    final OutgoingMessage result = new OutgoingMessage();
    result.writeMPI(A);

    complete = true;
    return result;
  }