code: public String createChallenge(String request)
        throws IllegalArgumentException, ProtocolVersionException {
  
      String userName;
      userName = CrtAuthCodec.deserializeRequest(request);
  
      Fingerprint fingerprint;
      try {
        fingerprint = new Fingerprint(getKeyForUser(userName));
      } catch (KeyNotFoundException e) {
        log.info("No public key found for user {}, creating fake fingerprint", userName);
        fingerprint = createFakeFingerprint(userName);
      }
  
      byte[] uniqueData = new byte[Challenge.UNIQUE_DATA_LENGTH];
      UnsignedInteger timeNow = timeSupplier.getTime();
      random.nextBytes(uniqueData);
      Challenge challenge = Challenge.newBuilder()
          .setFingerprint(fingerprint)
          .setUniqueData(uniqueData)
          .setValidFromTimestamp(timeNow.minus(CLOCK_FUDGE))
          .setValidToTimestamp(timeNow.plus(RESPONSE_TIMEOUT))
          .setServerName(serverName)
          .setUserName(userName)
          .build();
  
      return encode(CrtAuthCodec.serialize(challenge, secret));
    }
docs: Create a challenge to authenticate a given user. The userName needs to be provided at this
  stage to encode a fingerprint of the public key stored in the server encoded in the challenge.
  This is required because a client can hold more than one private key and would need this
  information to pick the right key to sign the response. If the keyProvider fails to retrieve
  the public key, a fake Fingerprint is generated so that the presence of a challenge doesn't
  reveal whether a user key is present on the server or not.
  
  @param request The request message which contains an encoded username
  @return A challenge message.
  @throws IllegalArgumentException if the request format is invalid