Return-Path: X-Original-To: apmail-commons-commits-archive@minotaur.apache.org Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A3ABB10A7B for ; Tue, 24 Dec 2013 20:41:38 +0000 (UTC) Received: (qmail 84875 invoked by uid 500); 24 Dec 2013 20:41:38 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 84675 invoked by uid 500); 24 Dec 2013 20:41:38 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 84544 invoked by uid 99); 24 Dec 2013 20:41:37 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 24 Dec 2013 20:41:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 24 Dec 2013 20:41:22 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id CA4C32388A3B for ; Tue, 24 Dec 2013 20:40:59 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r891687 [5/12] - in /websites/production/commons/content/proper/commons-codec: ./ apidocs/ apidocs/org/apache/commons/codec/ apidocs/org/apache/commons/codec/binary/ apidocs/org/apache/commons/codec/binary/class-use/ apidocs/org/apache/comm... Date: Tue, 24 Dec 2013 20:40:32 -0000 To: commits@commons.apache.org From: ggregory@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20131224204059.CA4C32388A3B@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: websites/production/commons/content/proper/commons-codec/apidocs/src-html/org/apache/commons/codec/digest/Sha2Crypt.html ============================================================================== --- websites/production/commons/content/proper/commons-codec/apidocs/src-html/org/apache/commons/codec/digest/Sha2Crypt.html (original) +++ websites/production/commons/content/proper/commons-codec/apidocs/src-html/org/apache/commons/codec/digest/Sha2Crypt.html Tue Dec 24 20:40:26 2013 @@ -42,8 +42,8 @@ 034 * into the Public Domain. 035 * <p> 036 * This class is immutable and thread-safe. -037 * -038 * @version $Id: Sha2Crypt.java 1435550 2013-01-19 14:09:52Z tn $ +037 * +038 * @version $Id: Sha2Crypt.java 1552696 2013-12-20 15:01:34Z ggregory $ 039 * @since 1.7 040 */ 041public class Sha2Crypt { @@ -80,461 +80,477 @@ 072 * Generates a libc crypt() compatible "$5$" hash value with random salt. 073 * <p> 074 * See {@link Crypt#crypt(String, String)} for details. -075 * -076 * @throws RuntimeException -077 * when a {@link java.security.NoSuchAlgorithmException} is caught. -078 */ -079 public static String sha256Crypt(final byte[] keyBytes) { -080 return sha256Crypt(keyBytes, null); -081 } -082 -083 /** -084 * Generates a libc6 crypt() compatible "$5$" hash value. -085 * <p> -086 * See {@link Crypt#crypt(String, String)} for details. -087 * -088 * @throws IllegalArgumentException -089 * if the salt does not match the allowed pattern -090 * @throws RuntimeException -091 * when a {@link java.security.NoSuchAlgorithmException} is caught. -092 */ -093 public static String sha256Crypt(final byte[] keyBytes, String salt) { -094 if (salt == null) { -095 salt = SHA256_PREFIX + B64.getRandomSalt(8); -096 } -097 return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256); -098 } -099 -100 /** -101 * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value. -102 * <p> -103 * This is a nearly line by line conversion of the original C function. The numbered comments are from the -104 * algorithm description, the short C-style ones from the original C code and the ones with "Remark" from me. -105 * <p> -106 * See {@link Crypt#crypt(String, String)} for details. -107 * -108 * @param keyBytes -109 * plaintext that should be hashed -110 * @param salt -111 * real salt value without prefix or "rounds=" -112 * @param saltPrefix -113 * either $5$ or $6$ -114 * @param blocksize -115 * a value that differs between $5$ and $6$ -116 * @param algorithm -117 * {@link MessageDigest} algorithm identifier string -118 * @return complete hash value including prefix and salt -119 * @throws IllegalArgumentException -120 * if the given salt is {@code null} or does not match the allowed pattern -121 * @throws IllegalArgumentException -122 * when a {@link NoSuchAlgorithmException} is caught -123 * @see MessageDigestAlgorithms -124 */ -125 private static String sha2Crypt(final byte[] keyBytes, final String salt, final String saltPrefix, -126 final int blocksize, final String algorithm) { -127 -128 final int keyLen = keyBytes.length; -129 -130 // Extracts effective salt and the number of rounds from the given salt. -131 int rounds = ROUNDS_DEFAULT; -132 boolean roundsCustom = false; -133 if (salt == null) { -134 throw new IllegalArgumentException("Salt must not be null"); -135 } -136 -137 final Matcher m = SALT_PATTERN.matcher(salt); -138 if (m == null || !m.find()) { -139 throw new IllegalArgumentException("Invalid salt value: " + salt); -140 } -141 if (m.group(3) != null) { -142 rounds = Integer.parseInt(m.group(3)); -143 rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds)); -144 roundsCustom = true; -145 } -146 final String saltString = m.group(4); -147 final byte[] saltBytes = saltString.getBytes(Charsets.UTF_8); -148 final int saltLen = saltBytes.length; -149 -150 // 1. start digest A -151 // Prepare for the real work. -152 MessageDigest ctx = DigestUtils.getDigest(algorithm); -153 -154 // 2. the password string is added to digest A -155 /* -156 * Add the key string. -157 */ -158 ctx.update(keyBytes); -159 -160 // 3. the salt string is added to digest A. This is just the salt string -161 // itself without the enclosing '$', without the magic salt_prefix $5$ and -162 // $6$ respectively and without the rounds=<N> specification. -163 // -164 // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed -165 // necessary since it is a constant string and does not add security -166 // and /possibly/ allows a plain text attack. Since the rounds=<N> -167 // specification should never be added this would also create an -168 // inconsistency. -169 /* -170 * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character -171 * (for compatibility with existing implementations). -172 */ -173 ctx.update(saltBytes); -174 -175 // 4. start digest B -176 /* -177 * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first -178 * context. -179 */ -180 MessageDigest altCtx = DigestUtils.getDigest(algorithm); -181 -182 // 5. add the password to digest B -183 /* -184 * Add key. -185 */ -186 altCtx.update(keyBytes); -187 -188 // 6. add the salt string to digest B -189 /* -190 * Add salt. -191 */ -192 altCtx.update(saltBytes); -193 -194 // 7. add the password again to digest B -195 /* -196 * Add key again. -197 */ -198 altCtx.update(keyBytes); -199 -200 // 8. finish digest B -201 /* -202 * Now get result of this (32 bytes) and add it to the other context. -203 */ -204 byte[] altResult = altCtx.digest(); -205 -206 // 9. For each block of 32 or 64 bytes in the password string (excluding -207 // the terminating NUL in the C representation), add digest B to digest A -208 /* -209 * Add for any character in the key one byte of the alternate sum. -210 */ -211 /* -212 * (Remark: the C code comment seems wrong for key length > 32!) -213 */ -214 int cnt = keyBytes.length; -215 while (cnt > blocksize) { -216 ctx.update(altResult, 0, blocksize); -217 cnt -= blocksize; -218 } -219 -220 // 10. For the remaining N bytes of the password string add the first -221 // N bytes of digest B to digest A -222 ctx.update(altResult, 0, cnt); -223 -224 // 11. For each bit of the binary representation of the length of the -225 // password string up to and including the highest 1-digit, starting -226 // from to lowest bit position (numeric value 1): -227 // -228 // a) for a 1-digit add digest B to digest A -229 // -230 // b) for a 0-digit add the password string -231 // -232 // NB: this step differs significantly from the MD5 algorithm. It -233 // adds more randomness. -234 /* -235 * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0 -236 * the key. -237 */ -238 cnt = keyBytes.length; -239 while (cnt > 0) { -240 if ((cnt & 1) != 0) { -241 ctx.update(altResult, 0, blocksize); -242 } else { -243 ctx.update(keyBytes); -244 } -245 cnt >>= 1; -246 } -247 -248 // 12. finish digest A -249 /* -250 * Create intermediate result. -251 */ -252 altResult = ctx.digest(); -253 -254 // 13. start digest DP -255 /* -256 * Start computation of P byte sequence. -257 */ -258 altCtx = DigestUtils.getDigest(algorithm); -259 -260 // 14. for every byte in the password (excluding the terminating NUL byte -261 // in the C representation of the string) -262 // -263 // add the password to digest DP -264 /* -265 * For every character in the password add the entire password. -266 */ -267 for (int i = 1; i <= keyLen; i++) { -268 altCtx.update(keyBytes); -269 } -270 -271 // 15. finish digest DP +075 * +076 * @param keyBytes +077 * plaintext to hash +078 * @return complete hash value +079 * @throws RuntimeException +080 * when a {@link java.security.NoSuchAlgorithmException} is caught. +081 */ +082 public static String sha256Crypt(final byte[] keyBytes) { +083 return sha256Crypt(keyBytes, null); +084 } +085 +086 /** +087 * Generates a libc6 crypt() compatible "$5$" hash value. +088 * <p> +089 * See {@link Crypt#crypt(String, String)} for details. +090 * +091 * @param keyBytes +092 * plaintext to hash +093 * @param salt +094 * real salt value without prefix or "rounds=" +095 * @return complete hash value including salt +096 * @throws IllegalArgumentException +097 * if the salt does not match the allowed pattern +098 * @throws RuntimeException +099 * when a {@link java.security.NoSuchAlgorithmException} is caught. +100 */ +101 public static String sha256Crypt(final byte[] keyBytes, String salt) { +102 if (salt == null) { +103 salt = SHA256_PREFIX + B64.getRandomSalt(8); +104 } +105 return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256); +106 } +107 +108 /** +109 * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value. +110 * <p> +111 * This is a nearly line by line conversion of the original C function. The numbered comments are from the algorithm +112 * description, the short C-style ones from the original C code and the ones with "Remark" from me. +113 * <p> +114 * See {@link Crypt#crypt(String, String)} for details. +115 * +116 * @param keyBytes +117 * plaintext to hash +118 * @param salt +119 * real salt value without prefix or "rounds=" +120 * @param saltPrefix +121 * either $5$ or $6$ +122 * @param blocksize +123 * a value that differs between $5$ and $6$ +124 * @param algorithm +125 * {@link MessageDigest} algorithm identifier string +126 * @return complete hash value including prefix and salt +127 * @throws IllegalArgumentException +128 * if the given salt is {@code null} or does not match the allowed pattern +129 * @throws IllegalArgumentException +130 * when a {@link NoSuchAlgorithmException} is caught +131 * @see MessageDigestAlgorithms +132 */ +133 private static String sha2Crypt(final byte[] keyBytes, final String salt, final String saltPrefix, +134 final int blocksize, final String algorithm) { +135 +136 final int keyLen = keyBytes.length; +137 +138 // Extracts effective salt and the number of rounds from the given salt. +139 int rounds = ROUNDS_DEFAULT; +140 boolean roundsCustom = false; +141 if (salt == null) { +142 throw new IllegalArgumentException("Salt must not be null"); +143 } +144 +145 final Matcher m = SALT_PATTERN.matcher(salt); +146 if (m == null || !m.find()) { +147 throw new IllegalArgumentException("Invalid salt value: " + salt); +148 } +149 if (m.group(3) != null) { +150 rounds = Integer.parseInt(m.group(3)); +151 rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds)); +152 roundsCustom = true; +153 } +154 final String saltString = m.group(4); +155 final byte[] saltBytes = saltString.getBytes(Charsets.UTF_8); +156 final int saltLen = saltBytes.length; +157 +158 // 1. start digest A +159 // Prepare for the real work. +160 MessageDigest ctx = DigestUtils.getDigest(algorithm); +161 +162 // 2. the password string is added to digest A +163 /* +164 * Add the key string. +165 */ +166 ctx.update(keyBytes); +167 +168 // 3. the salt string is added to digest A. This is just the salt string +169 // itself without the enclosing '$', without the magic salt_prefix $5$ and +170 // $6$ respectively and without the rounds=<N> specification. +171 // +172 // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed +173 // necessary since it is a constant string and does not add security +174 // and /possibly/ allows a plain text attack. Since the rounds=<N> +175 // specification should never be added this would also create an +176 // inconsistency. +177 /* +178 * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character +179 * (for compatibility with existing implementations). +180 */ +181 ctx.update(saltBytes); +182 +183 // 4. start digest B +184 /* +185 * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first +186 * context. +187 */ +188 MessageDigest altCtx = DigestUtils.getDigest(algorithm); +189 +190 // 5. add the password to digest B +191 /* +192 * Add key. +193 */ +194 altCtx.update(keyBytes); +195 +196 // 6. add the salt string to digest B +197 /* +198 * Add salt. +199 */ +200 altCtx.update(saltBytes); +201 +202 // 7. add the password again to digest B +203 /* +204 * Add key again. +205 */ +206 altCtx.update(keyBytes); +207 +208 // 8. finish digest B +209 /* +210 * Now get result of this (32 bytes) and add it to the other context. +211 */ +212 byte[] altResult = altCtx.digest(); +213 +214 // 9. For each block of 32 or 64 bytes in the password string (excluding +215 // the terminating NUL in the C representation), add digest B to digest A +216 /* +217 * Add for any character in the key one byte of the alternate sum. +218 */ +219 /* +220 * (Remark: the C code comment seems wrong for key length > 32!) +221 */ +222 int cnt = keyBytes.length; +223 while (cnt > blocksize) { +224 ctx.update(altResult, 0, blocksize); +225 cnt -= blocksize; +226 } +227 +228 // 10. For the remaining N bytes of the password string add the first +229 // N bytes of digest B to digest A +230 ctx.update(altResult, 0, cnt); +231 +232 // 11. For each bit of the binary representation of the length of the +233 // password string up to and including the highest 1-digit, starting +234 // from to lowest bit position (numeric value 1): +235 // +236 // a) for a 1-digit add digest B to digest A +237 // +238 // b) for a 0-digit add the password string +239 // +240 // NB: this step differs significantly from the MD5 algorithm. It +241 // adds more randomness. +242 /* +243 * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0 +244 * the key. +245 */ +246 cnt = keyBytes.length; +247 while (cnt > 0) { +248 if ((cnt & 1) != 0) { +249 ctx.update(altResult, 0, blocksize); +250 } else { +251 ctx.update(keyBytes); +252 } +253 cnt >>= 1; +254 } +255 +256 // 12. finish digest A +257 /* +258 * Create intermediate result. +259 */ +260 altResult = ctx.digest(); +261 +262 // 13. start digest DP +263 /* +264 * Start computation of P byte sequence. +265 */ +266 altCtx = DigestUtils.getDigest(algorithm); +267 +268 // 14. for every byte in the password (excluding the terminating NUL byte +269 // in the C representation of the string) +270 // +271 // add the password to digest DP 272 /* -273 * Finish the digest. +273 * For every character in the password add the entire password. 274 */ -275 byte[] tempResult = altCtx.digest(); -276 -277 // 16. produce byte sequence P of the same length as the password where -278 // -279 // a) for each block of 32 or 64 bytes of length of the password string -280 // the entire digest DP is used -281 // -282 // b) for the remaining N (up to 31 or 63) bytes use the first N -283 // bytes of digest DP -284 /* -285 * Create byte sequence P. -286 */ -287 final byte[] pBytes = new byte[keyLen]; -288 int cp = 0; -289 while (cp < keyLen - blocksize) { -290 System.arraycopy(tempResult, 0, pBytes, cp, blocksize); -291 cp += blocksize; -292 } -293 System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp); -294 -295 // 17. start digest DS -296 /* -297 * Start computation of S byte sequence. -298 */ -299 altCtx = DigestUtils.getDigest(algorithm); -300 -301 // 18. repeast the following 16+A[0] times, where A[0] represents the first -302 // byte in digest A interpreted as an 8-bit unsigned value -303 // -304 // add the salt to digest DS -305 /* -306 * For every character in the password add the entire password. -307 */ -308 for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) { -309 altCtx.update(saltBytes); -310 } -311 -312 // 19. finish digest DS +275 for (int i = 1; i <= keyLen; i++) { +276 altCtx.update(keyBytes); +277 } +278 +279 // 15. finish digest DP +280 /* +281 * Finish the digest. +282 */ +283 byte[] tempResult = altCtx.digest(); +284 +285 // 16. produce byte sequence P of the same length as the password where +286 // +287 // a) for each block of 32 or 64 bytes of length of the password string +288 // the entire digest DP is used +289 // +290 // b) for the remaining N (up to 31 or 63) bytes use the first N +291 // bytes of digest DP +292 /* +293 * Create byte sequence P. +294 */ +295 final byte[] pBytes = new byte[keyLen]; +296 int cp = 0; +297 while (cp < keyLen - blocksize) { +298 System.arraycopy(tempResult, 0, pBytes, cp, blocksize); +299 cp += blocksize; +300 } +301 System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp); +302 +303 // 17. start digest DS +304 /* +305 * Start computation of S byte sequence. +306 */ +307 altCtx = DigestUtils.getDigest(algorithm); +308 +309 // 18. repeast the following 16+A[0] times, where A[0] represents the first +310 // byte in digest A interpreted as an 8-bit unsigned value +311 // +312 // add the salt to digest DS 313 /* -314 * Finish the digest. +314 * For every character in the password add the entire password. 315 */ -316 tempResult = altCtx.digest(); -317 -318 // 20. produce byte sequence S of the same length as the salt string where -319 // -320 // a) for each block of 32 or 64 bytes of length of the salt string -321 // the entire digest DS is used -322 // -323 // b) for the remaining N (up to 31 or 63) bytes use the first N -324 // bytes of digest DS -325 /* -326 * Create byte sequence S. -327 */ -328 // Remark: The salt is limited to 16 chars, how does this make sense? -329 final byte[] sBytes = new byte[saltLen]; -330 cp = 0; -331 while (cp < saltLen - blocksize) { -332 System.arraycopy(tempResult, 0, sBytes, cp, blocksize); -333 cp += blocksize; -334 } -335 System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp); -336 -337 // 21. repeat a loop according to the number specified in the rounds=<N> -338 // specification in the salt (or the default value if none is -339 // present). Each round is numbered, starting with 0 and up to N-1. -340 // -341 // The loop uses a digest as input. In the first round it is the -342 // digest produced in step 12. In the latter steps it is the digest -343 // produced in step 21.h. The following text uses the notation -344 // "digest A/C" to describe this behavior. -345 /* -346 * Repeatedly run the collected hash value through sha512 to burn CPU cycles. -347 */ -348 for (int i = 0; i <= rounds - 1; i++) { -349 // a) start digest C -350 /* -351 * New context. -352 */ -353 ctx = DigestUtils.getDigest(algorithm); -354 -355 // b) for odd round numbers add the byte sequense P to digest C -356 // c) for even round numbers add digest A/C -357 /* -358 * Add key or last result. -359 */ -360 if ((i & 1) != 0) { -361 ctx.update(pBytes, 0, keyLen); -362 } else { -363 ctx.update(altResult, 0, blocksize); -364 } -365 -366 // d) for all round numbers not divisible by 3 add the byte sequence S -367 /* -368 * Add salt for numbers not divisible by 3. -369 */ -370 if (i % 3 != 0) { -371 ctx.update(sBytes, 0, saltLen); +316 for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) { +317 altCtx.update(saltBytes); +318 } +319 +320 // 19. finish digest DS +321 /* +322 * Finish the digest. +323 */ +324 tempResult = altCtx.digest(); +325 +326 // 20. produce byte sequence S of the same length as the salt string where +327 // +328 // a) for each block of 32 or 64 bytes of length of the salt string +329 // the entire digest DS is used +330 // +331 // b) for the remaining N (up to 31 or 63) bytes use the first N +332 // bytes of digest DS +333 /* +334 * Create byte sequence S. +335 */ +336 // Remark: The salt is limited to 16 chars, how does this make sense? +337 final byte[] sBytes = new byte[saltLen]; +338 cp = 0; +339 while (cp < saltLen - blocksize) { +340 System.arraycopy(tempResult, 0, sBytes, cp, blocksize); +341 cp += blocksize; +342 } +343 System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp); +344 +345 // 21. repeat a loop according to the number specified in the rounds=<N> +346 // specification in the salt (or the default value if none is +347 // present). Each round is numbered, starting with 0 and up to N-1. +348 // +349 // The loop uses a digest as input. In the first round it is the +350 // digest produced in step 12. In the latter steps it is the digest +351 // produced in step 21.h. The following text uses the notation +352 // "digest A/C" to describe this behavior. +353 /* +354 * Repeatedly run the collected hash value through sha512 to burn CPU cycles. +355 */ +356 for (int i = 0; i <= rounds - 1; i++) { +357 // a) start digest C +358 /* +359 * New context. +360 */ +361 ctx = DigestUtils.getDigest(algorithm); +362 +363 // b) for odd round numbers add the byte sequense P to digest C +364 // c) for even round numbers add digest A/C +365 /* +366 * Add key or last result. +367 */ +368 if ((i & 1) != 0) { +369 ctx.update(pBytes, 0, keyLen); +370 } else { +371 ctx.update(altResult, 0, blocksize); 372 } 373 -374 // e) for all round numbers not divisible by 7 add the byte sequence P +374 // d) for all round numbers not divisible by 3 add the byte sequence S 375 /* -376 * Add key for numbers not divisible by 7. +376 * Add salt for numbers not divisible by 3. 377 */ -378 if (i % 7 != 0) { -379 ctx.update(pBytes, 0, keyLen); +378 if (i % 3 != 0) { +379 ctx.update(sBytes, 0, saltLen); 380 } 381 -382 // f) for odd round numbers add digest A/C -383 // g) for even round numbers add the byte sequence P -384 /* -385 * Add key or last result. -386 */ -387 if ((i & 1) != 0) { -388 ctx.update(altResult, 0, blocksize); -389 } else { -390 ctx.update(pBytes, 0, keyLen); -391 } -392 -393 // h) finish digest C. -394 /* -395 * Create intermediate result. -396 */ -397 altResult = ctx.digest(); -398 } -399 -400 // 22. Produce the output string. This is an ASCII string of the maximum -401 // size specified above, consisting of multiple pieces: -402 // -403 // a) the salt salt_prefix, $5$ or $6$ respectively -404 // -405 // b) the rounds=<N> specification, if one was present in the input -406 // salt string. A trailing '$' is added in this case to separate -407 // the rounds specification from the following text. -408 // -409 // c) the salt string truncated to 16 characters +382 // e) for all round numbers not divisible by 7 add the byte sequence P +383 /* +384 * Add key for numbers not divisible by 7. +385 */ +386 if (i % 7 != 0) { +387 ctx.update(pBytes, 0, keyLen); +388 } +389 +390 // f) for odd round numbers add digest A/C +391 // g) for even round numbers add the byte sequence P +392 /* +393 * Add key or last result. +394 */ +395 if ((i & 1) != 0) { +396 ctx.update(altResult, 0, blocksize); +397 } else { +398 ctx.update(pBytes, 0, keyLen); +399 } +400 +401 // h) finish digest C. +402 /* +403 * Create intermediate result. +404 */ +405 altResult = ctx.digest(); +406 } +407 +408 // 22. Produce the output string. This is an ASCII string of the maximum +409 // size specified above, consisting of multiple pieces: 410 // -411 // d) a '$' character -412 /* -413 * Now we can construct the result string. It consists of three parts. -414 */ -415 final StringBuilder buffer = new StringBuilder(saltPrefix); -416 if (roundsCustom) { -417 buffer.append(ROUNDS_PREFIX); -418 buffer.append(rounds); -419 buffer.append("$"); -420 } -421 buffer.append(saltString); -422 buffer.append("$"); -423 -424 // e) the base-64 encoded final C digest. The encoding used is as -425 // follows: -426 // [...] -427 // -428 // Each group of three bytes from the digest produces four -429 // characters as output: -430 // -431 // 1. character: the six low bits of the first byte -432 // 2. character: the two high bits of the first byte and the -433 // four low bytes from the second byte -434 // 3. character: the four high bytes from the second byte and -435 // the two low bits from the third byte -436 // 4. character: the six high bits from the third byte -437 // -438 // The groups of three bytes are as follows (in this sequence). -439 // These are the indices into the byte array containing the -440 // digest, starting with index 0. For the last group there are -441 // not enough bytes left in the digest and the value zero is used -442 // in its place. This group also produces only three or two -443 // characters as output for SHA-512 and SHA-512 respectively. -444 -445 // This was just a safeguard in the C implementation: -446 // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1; -447 -448 if (blocksize == 32) { -449 B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer); -450 B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer); -451 B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer); -452 B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer); -453 B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer); -454 B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer); -455 B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer); -456 B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer); -457 B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer); -458 B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer); -459 B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer); -460 } else { -461 B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer); -462 B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer); -463 B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer); -464 B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer); -465 B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer); -466 B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer); -467 B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer); -468 B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer); -469 B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer); -470 B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer); -471 B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer); -472 B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer); -473 B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer); -474 B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer); -475 B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer); -476 B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer); -477 B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer); -478 B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer); -479 B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer); -480 B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer); -481 B64.b64from24bit(altResult[62], altResult[20], altResult[41], 4, buffer); -482 B64.b64from24bit((byte) 0, (byte) 0, altResult[63], 2, buffer); -483 } -484 -485 /* -486 * Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps -487 * cannot get any information. -488 */ -489 // Is there a better way to do this with the JVM? -490 Arrays.fill(tempResult, (byte) 0); -491 Arrays.fill(pBytes, (byte) 0); -492 Arrays.fill(sBytes, (byte) 0); -493 ctx.reset(); -494 altCtx.reset(); -495 Arrays.fill(keyBytes, (byte) 0); -496 Arrays.fill(saltBytes, (byte) 0); -497 -498 return buffer.toString(); -499 } -500 -501 /** -502 * Generates a libc crypt() compatible "$6$" hash value with random salt. -503 * <p> -504 * See {@link Crypt#crypt(String, String)} for details. -505 * -506 * @throws RuntimeException -507 * when a {@link java.security.NoSuchAlgorithmException} is caught. -508 */ -509 public static String sha512Crypt(final byte[] keyBytes) { -510 return sha512Crypt(keyBytes, null); -511 } -512 -513 /** -514 * Generates a libc6 crypt() compatible "$6$" hash value. -515 * <p> -516 * See {@link Crypt#crypt(String, String)} for details. -517 * -518 * @throws IllegalArgumentException -519 * if the salt does not match the allowed pattern -520 * @throws RuntimeException -521 * when a {@link java.security.NoSuchAlgorithmException} is caught. -522 */ -523 public static String sha512Crypt(final byte[] keyBytes, String salt) { -524 if (salt == null) { -525 salt = SHA512_PREFIX + B64.getRandomSalt(8); -526 } -527 return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, MessageDigestAlgorithms.SHA_512); -528 } -529} +411 // a) the salt salt_prefix, $5$ or $6$ respectively +412 // +413 // b) the rounds=<N> specification, if one was present in the input +414 // salt string. A trailing '$' is added in this case to separate +415 // the rounds specification from the following text. +416 // +417 // c) the salt string truncated to 16 characters +418 // +419 // d) a '$' character +420 /* +421 * Now we can construct the result string. It consists of three parts. +422 */ +423 final StringBuilder buffer = new StringBuilder(saltPrefix); +424 if (roundsCustom) { +425 buffer.append(ROUNDS_PREFIX); +426 buffer.append(rounds); +427 buffer.append("$"); +428 } +429 buffer.append(saltString); +430 buffer.append("$"); +431 +432 // e) the base-64 encoded final C digest. The encoding used is as +433 // follows: +434 // [...] +435 // +436 // Each group of three bytes from the digest produces four +437 // characters as output: +438 // +439 // 1. character: the six low bits of the first byte +440 // 2. character: the two high bits of the first byte and the +441 // four low bytes from the second byte +442 // 3. character: the four high bytes from the second byte and +443 // the two low bits from the third byte +444 // 4. character: the six high bits from the third byte +445 // +446 // The groups of three bytes are as follows (in this sequence). +447 // These are the indices into the byte array containing the +448 // digest, starting with index 0. For the last group there are +449 // not enough bytes left in the digest and the value zero is used +450 // in its place. This group also produces only three or two +451 // characters as output for SHA-512 and SHA-512 respectively. +452 +453 // This was just a safeguard in the C implementation: +454 // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1; +455 +456 if (blocksize == 32) { +457 B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer); +458 B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer); +459 B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer); +460 B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer); +461 B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer); +462 B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer); +463 B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer); +464 B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer); +465 B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer); +466 B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer); +467 B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer); +468 } else { +469 B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer); +470 B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer); +471 B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer); +472 B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer); +473 B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer); +474 B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer); +475 B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer); +476 B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer); +477 B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer); +478 B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer); +479 B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer); +480 B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer); +481 B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer); +482 B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer); +483 B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer); +484 B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer); +485 B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer); +486 B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer); +487 B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer); +488 B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer); [... 61 lines stripped ...]