static String makeShadowLine()

in compute/src/main/java/org/jclouds/compute/functions/Sha512Crypt.java [141:320]


   static String makeShadowLine(String password, @Nullable String shadowPrefix) {
      MessageDigest ctx = sha512();
      MessageDigest alt_ctx = sha512();

      byte[] alt_result;
      byte[] temp_result;
      byte[] p_bytes = null;
      byte[] s_bytes = null;
      int cnt;
      int cnt2;
      int rounds = ROUNDS_DEFAULT; // Default number of rounds.
      StringBuilder buffer;

      /* -- */

      if (shadowPrefix != null) {
         if (shadowPrefix.startsWith(sha512_salt_prefix)) {
            shadowPrefix = shadowPrefix.substring(sha512_salt_prefix.length());
         }

         if (shadowPrefix.startsWith(sha512_rounds_prefix)) {
            String num = shadowPrefix.substring(sha512_rounds_prefix.length(), shadowPrefix.indexOf('$'));
            int srounds = Integer.parseInt(num);
            shadowPrefix = shadowPrefix.substring(shadowPrefix.indexOf('$') + 1);
            rounds = Math.max(ROUNDS_MIN, Math.min(srounds, ROUNDS_MAX));
         }

         if (shadowPrefix.length() > SALT_LEN_MAX) {
            shadowPrefix = shadowPrefix.substring(0, SALT_LEN_MAX);
         }
      } else {
         java.util.Random randgen = new java.security.SecureRandom();
         StringBuilder saltBuf = new StringBuilder();

         while (saltBuf.length() < 16) {
            int index = (int) (randgen.nextFloat() * SALTCHARS.length());
            saltBuf.append(SALTCHARS, index, index + 1);
         }

         shadowPrefix = saltBuf.toString();
      }

      byte[] key = password.getBytes();
      byte[] salts = shadowPrefix.getBytes();

      ctx.reset();
      ctx.update(key, 0, key.length);
      ctx.update(salts, 0, salts.length);

      alt_ctx.reset();
      alt_ctx.update(key, 0, key.length);
      alt_ctx.update(salts, 0, salts.length);
      alt_ctx.update(key, 0, key.length);

      alt_result = alt_ctx.digest();

      for (cnt = key.length; cnt > 64; cnt -= 64) {
         ctx.update(alt_result, 0, 64);
      }

      ctx.update(alt_result, 0, cnt);

      for (cnt = key.length; cnt > 0; cnt >>= 1) {
         if ((cnt & 1) != 0) {
            ctx.update(alt_result, 0, 64);
         } else {
            ctx.update(key, 0, key.length);
         }
      }

      alt_result = ctx.digest();

      alt_ctx.reset();

      for (cnt = 0; cnt < key.length; ++cnt) {
         alt_ctx.update(key, 0, key.length);
      }

      temp_result = alt_ctx.digest();

      p_bytes = new byte[key.length];

      for (cnt2 = 0, cnt = p_bytes.length; cnt >= 64; cnt -= 64) {
         System.arraycopy(temp_result, 0, p_bytes, cnt2, 64);
         cnt2 += 64;
      }

      System.arraycopy(temp_result, 0, p_bytes, cnt2, cnt);

      alt_ctx.reset();

      for (cnt = 0; cnt < 16 + (alt_result[0] & 0xFF); ++cnt) {
         alt_ctx.update(salts, 0, salts.length);
      }

      temp_result = alt_ctx.digest();

      s_bytes = new byte[salts.length];

      for (cnt2 = 0, cnt = s_bytes.length; cnt >= 64; cnt -= 64) {
         System.arraycopy(temp_result, 0, s_bytes, cnt2, 64);
         cnt2 += 64;
      }

      System.arraycopy(temp_result, 0, s_bytes, cnt2, cnt);

      /*
       * Repeatedly run the collected hash value through SHA512 to burn CPU
       * cycles.
       */

      for (cnt = 0; cnt < rounds; ++cnt) {
         ctx.reset();

         if ((cnt & 1) != 0) {
            ctx.update(p_bytes, 0, key.length);
         } else {
            ctx.update(alt_result, 0, 64);
         }

         if (cnt % 3 != 0) {
            ctx.update(s_bytes, 0, salts.length);
         }

         if (cnt % 7 != 0) {
            ctx.update(p_bytes, 0, key.length);
         }

         if ((cnt & 1) != 0) {
            ctx.update(alt_result, 0, 64);
         } else {
            ctx.update(p_bytes, 0, key.length);
         }

         alt_result = ctx.digest();
      }

      buffer = new StringBuilder(sha512_salt_prefix);

      if (rounds != 5000) {
         buffer.append(sha512_rounds_prefix);
         buffer.append(rounds);
         buffer.append("$");
      }

      buffer.append(shadowPrefix);
      buffer.append("$");

      buffer.append(b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4));
      buffer.append(b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4));
      buffer.append(b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4));
      buffer.append(b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4));
      buffer.append(b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4));
      buffer.append(b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4));
      buffer.append(b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4));
      buffer.append(b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4));
      buffer.append(b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4));
      buffer.append(b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4));
      buffer.append(b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4));
      buffer.append(b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4));
      buffer.append(b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4));
      buffer.append(b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4));
      buffer.append(b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4));
      buffer.append(b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4));
      buffer.append(b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4));
      buffer.append(b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4));
      buffer.append(b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4));
      buffer.append(b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4));
      buffer.append(b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4));
      buffer.append(b64_from_24bit((byte) 0x00, (byte) 0x00, alt_result[63], 2));

      /*
       * Clear the buffer for the intermediate result so that people attaching
       * to processes or reading core dumps cannot get any information.
       */

      ctx.reset();

      return buffer.toString();
   }