code: static byte[] hkdf(byte[] inputKeyingMaterial, byte[] salt, byte[] info, int outputLength) {
          if (outputLength > MAX_HKDF_OUTPUT_LENGTH) {
              throw new IllegalArgumentException("Output length too large " + outputLength);
          }
  
          byte[] prk = extract(salt, inputKeyingMaterial);
  
          int numRounds = (int) Math.ceil((double) outputLength / SHA256_OUTPUT_BYTES);
          byte[] outputData = new byte[outputLength];
  
          int idx = 0;
          byte[] current = EMPTY_BYTES;
          if (info == null) {
              info = EMPTY_BYTES;
          }
  
          for (int i = 0; i < numRounds; ++i) {
              current = expand(prk, current, info, (byte) (i + 1));
              System.arraycopy(current, 0, outputData, idx, Math.min(SHA256_OUTPUT_BYTES, outputLength - idx));
              idx += SHA256_OUTPUT_BYTES;
          }
          return outputData;
      }
docs: The HKDF key-derivation function, as defined in RFC 5869 (see https://tools.ietf.org/html/rfc5869).
  
  @param inputKeyingMaterial the input keying material to HKDF. May not be null.
  @param salt optional salt parameter, may be null. This value does not need to be secret and can be safely
  reused between different calls to hkdf(). See the RFC for recommended practices for salt
  selection.
  @param info optional application- and/or context-specific information used to bind the derived key material
  to a particular context or use case. See the RFC for recommended practices for info parameter
  selection.
  @param outputLength desired length of the output key, in bytes. May not exceed MAX_HKDF_OUTPUT_LENGTH.
  @return a pseudo-random key of outputLength bytes long.
  @throws IllegalArgumentException if outputLength > MAX_HKDF_OUTPUT_LENGTH.