/**
   * Calculates the hash of password (and salt bytes, if supplied) and returns a base64 encoded
   * concatenation of the hash and salt, prefixed with {SHA} (or {SSHA} if salt was used).
   *
   * @param rawPass the password to be encoded.
   * @param salt the salt. Must be a byte array or null.
   * @return the encoded password in the specified format
   */
  public String encodePassword(String rawPass, Object salt) {
    MessageDigest sha;

    try {
      sha = MessageDigest.getInstance("SHA");
      sha.update(rawPass.getBytes("UTF-8"));
    } catch (java.security.NoSuchAlgorithmException e) {
      throw new IllegalStateException("No SHA implementation available!");
    } catch (UnsupportedEncodingException ue) {
      throw new IllegalStateException("UTF-8 not supported!");
    }

    if (salt != null) {
      Assert.isInstanceOf(byte[].class, salt, "Salt value must be a byte array");
      sha.update((byte[]) salt);
    }

    byte[] hash = combineHashAndSalt(sha.digest(), (byte[]) salt);

    String prefix;

    if (salt == null) {
      prefix = forceLowerCasePrefix ? SHA_PREFIX_LC : SHA_PREFIX;
    } else {
      prefix = forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX;
    }

    return prefix + new String(Base64.encode(hash));
  }
  private byte[] extractSalt(String encPass) {
    String encPassNoLabel = encPass.substring(6);

    byte[] hashAndSalt = Base64.decode(encPassNoLabel.getBytes());
    int saltLength = hashAndSalt.length - SHA_LENGTH;
    byte[] salt = new byte[saltLength];
    System.arraycopy(hashAndSalt, SHA_LENGTH, salt, 0, saltLength);

    return salt;
  }
 private static void appendCertificate(X509Certificate x509Certificate, StringBuilder sb) {
   sb.append("-----BEGIN CERTIFICATE-----\n");
   try {
     String certificate = new String(Base64.encode(x509Certificate.getEncoded()));
     int i = 0;
     while (true) {
       int j = i + 76;
       if (j < certificate.length()) {
         sb.append(certificate.substring(i, j)).append("\n");
         i = j;
       } else {
         sb.append(certificate.substring(i)).append("\n");
         break;
       }
     }
   } catch (CertificateEncodingException e) {
     sb.append("Cannot encode: ").append(e.getMessage());
   }
   sb.append("-----END CERTIFICATE-----\n");
 }
  /**
   * Encodes the rawPass using a MessageDigest. If a salt is specified it will be merged with the
   * password before encoding.
   *
   * @param rawPass The plain text password
   * @param salt The salt to sprinkle
   * @return Hex string of password digest (or base64 encoded string if encodeHashAsBase64 is
   *     enabled.
   */
  public String encodePassword(String rawPass, Object salt) {
    String saltedPass = mergePasswordAndSalt(rawPass, salt, false);

    MessageDigest messageDigest = getMessageDigest();

    byte[] digest;

    try {
      digest = messageDigest.digest(saltedPass.getBytes("UTF-8"));
    } catch (UnsupportedEncodingException e) {
      throw new IllegalStateException("UTF-8 not supported!");
    }

    // "stretch" the encoded value if configured to do so
    for (int i = 1; i < iterations; i++) {
      digest = messageDigest.digest(digest);
    }

    if (getEncodeHashAsBase64()) {
      return new String(Base64.encode(digest));
    } else {
      return new String(Hex.encode(digest));
    }
  }