You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2012/04/20 17:36:59 UTC
svn commit: r1328414 [1/2] - in /commons/proper/codec/trunk/src: changes/
main/java/org/apache/commons/codec/digest/ site/xdoc/
test/java/org/apache/commons/codec/digest/
Author: ggregory
Date: Fri Apr 20 15:36:58 2012
New Revision: 1328414
URL: http://svn.apache.org/viewvc?rev=1328414&view=rev
Log:
[CODEC-133] Add classes for MD5/SHA1/SHA-512-based Unix crypt(3) hash variants.
Added:
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java
commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/UnixCryptTest.java
Modified:
commons/proper/codec/trunk/src/changes/changes.xml
commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/package.html
commons/proper/codec/trunk/src/site/xdoc/userguide.xml
Modified: commons/proper/codec/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/changes/changes.xml?rev=1328414&r1=1328413&r2=1328414&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/changes/changes.xml (original)
+++ commons/proper/codec/trunk/src/changes/changes.xml Fri Apr 20 15:36:58 2012
@@ -51,6 +51,9 @@ The <action> type attribute can be add,u
</release>
-->
<release version="1.7" date="TBD" description="Feature and fix release.">
+ <action dev="ggregory" type="fix" issue="CODEC-133" due-to="lathspell">
+ Add classes for MD5/SHA1/SHA-512-based Unix crypt(3) hash variants.
+ </action>
<action dev="ggregory" type="fix" issue="CODEC-96" due-to="sebb">
Base64 encode() method is no longer thread-safe, breaking clients using it as a shared BinaryEncoder.
Note: the fix breaks binary compatibility, however the changes are to a class (BaseNCodec) which is
Added: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java (added)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import java.util.Random;
+
+/**
+ * Base64 like method to convert binary bytes into ASCII chars.
+ *
+ * TODO: Can Base64 be reused?
+ *
+ * @version $Id $
+ * @since 1.7
+ */
+class B64 {
+
+ /**
+ * Table with characters for Base64 transformation.
+ */
+ static final String B64T = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ /**
+ * Base64 like conversion of bytes to ASCII chars.
+ *
+ * @param b2
+ * A byte from the result.
+ * @param b1
+ * A byte from the result.
+ * @param b0
+ * A byte from the result.
+ * @param outLen
+ * The number of expected output chars.
+ * @param buffer
+ * Where the output chars is appended to.
+ */
+ static void b64from24bit(byte b2, byte b1, byte b0, int outLen, StringBuilder buffer) {
+ // The bit masking is necessary because the JVM byte type is signed!
+ int w = ((b2 << 16) & 0x00ffffff) | ((b1 << 8) & 0x00ffff) | (b0 & 0xff);
+ // It's effectively a "for" loop but kept to resemble the original C code.
+ int n = outLen;
+ while (n-- > 0) {
+ buffer.append(B64T.charAt(w & 0x3f));
+ w >>= 6;
+ }
+ }
+
+ /**
+ * Generates a string of random chars from the B64T set.
+ *
+ * @param num
+ * Number of chars to generate.
+ */
+ static String getRandomSalt(int num) {
+ StringBuilder saltString = new StringBuilder();
+ for (int i = 1; i <= num; i++) {
+ saltString.append(B64T.charAt(new Random().nextInt(B64T.length())));
+ }
+ return saltString.toString();
+ }
+}
Added: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java (added)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import org.apache.commons.codec.Charsets;
+
+/**
+ * GNU libc crypt(3) compatible hash method.
+ *
+ * See {@link #crypt(String, String)} for further details.
+ *
+ * @version $Id $
+ * @since 1.7
+ */
+public class Crypt {
+
+ /**
+ * Encrypts a password in a crypt(3) compatible way.
+ *
+ * A random salt and the default algorithm (currently SHA-512) are used. See
+ * {@link #crypt(String, String)} for details.
+ *
+ * @param keyBytes
+ * The plaintext password.
+ * @return The hash value.
+ */
+ public static String crypt(byte[] keyBytes) throws Exception {
+ return crypt(keyBytes, null);
+ }
+
+ /**
+ * Encrypts a password in a crypt(3) compatible way.
+ *
+ * A random salt and the default algorithm (currently SHA-512) are used. See
+ * {@link #crypt(String, String)} for details.
+ *
+ * @param keyBytes
+ * The plaintext password.
+ * @param salt
+ * The salt value
+ * @return The hash value.
+ */
+ public static String crypt(byte[] keyBytes, String salt) throws Exception {
+ if (salt == null) {
+ return Sha2Crypt.sha512Crypt(keyBytes);
+ } else if (salt.startsWith(Sha2Crypt.SHA512_PREFIX)) {
+ return Sha2Crypt.sha512Crypt(keyBytes, salt);
+ } else if (salt.startsWith(Sha2Crypt.SHA256_PREFIX)) {
+ return Sha2Crypt.sha256Crypt(keyBytes, salt);
+ } else if (salt.startsWith(Md5Crypt.MD5_PREFIX)) {
+ return Md5Crypt.md5Crypt(keyBytes, salt);
+ } else {
+ return UnixCrypt.crypt(keyBytes, salt);
+ }
+ }
+
+ /**
+ * Calculates the digest using the strongest crypt(3) algorithm.
+ *
+ * A random salt and the default algorithm (currently SHA-512) are used.
+ *
+ * @see #crypt(String, String)
+ * @param key
+ * The plaintext password.
+ * @return The hash value.
+ */
+ public static String crypt(String key) throws Exception {
+ return crypt(key, null);
+ }
+
+ /**
+ * Encrypts a password in a crypt(3) compatible way.
+ *
+ * <p>
+ * The exact algorithm depends on the format of the salt string:
+ * <ul>
+ * <li>SHA-512 salts start with $6$ and are up to 16 chars long.
+ * <li>SHA-256 salts start with $5$ and are up to 16 chars long
+ * <li>MD5 salts start with "$1$" and are up to 8 chars long
+ * <li>DES, the traditional UnixCrypt algorithm is used else with only 2 chars
+ * <li>Only the first 8 chars of the passwords are used in the DES algorithm!
+ * </ul>
+ * The magic strings "$apr1$" and "$2a$" are not recognised by this method as its output should be identical with
+ * that of the libc implementation.
+ *
+ * <p>
+ * The rest of the salt string is drawn from the set [a-zA-Z0-9./] and is cut at the maximum length of if a "$" sign
+ * is encountered. It is therefore valid to enter a complete hash value as salt to e.g. verify a password with:
+ * storedPwd.equals(crypt(enteredPwd, storedPwd))
+ *
+ * <p>
+ * The resulting string starts with the marker string ($6$), continues with the salt value and ends with a "$" sign
+ * followed by the actual hash value. For DES the string only contains the salt and actual hash. It's toal length is
+ * dependend on the algorithm used:
+ * <ul>
+ * <li>SHA-512: 106 chars
+ * <li>SHA-256: 63 chars
+ * <li>MD5: 34 chars
+ * <li>DES: 13 chars
+ * </ul>
+ *
+ * <p>
+ * Example:
+ *
+ * <pre>
+ * crypt("secret", "$1$xxxx") => "$1$xxxx$aMkevjfEIpa35Bh3G4bAc."
+ * crypt("secret", "xx") => "xxWAum7tHdIUw"
+ * </pre>
+ *
+ * This method comes in a variation that accepts a byte[] array to support input strings that are not encoded in
+ * UTF-8 but e.g. in ISO-8859-1 where equal characters result in different byte values.
+ *
+ * @see "The man page of the libc crypt (3) function."
+ * @param key
+ * The plaintext password as entered by the used.
+ * @param salt
+ * The salt value
+ * @return The hash value i.e. encrypted password including the salt string
+ */
+ public static String crypt(String key, String salt) throws Exception {
+ return crypt(key.getBytes(Charsets.UTF_8), salt);
+ }
+}
Added: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java (added)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.codec.Charsets;
+
+/**
+ * The libc crypt() "$1$" and Apache "$apr1$" MD5-based hash algorithm.
+ * <p>
+ * Based on the public domain ("beer-ware") C implementation from Poul-Henning Kamp which was found at:
+ * </p>
+ * <p>
+ * http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libcrypt/crypt-md5.c?rev=1.1;content-type=text%2Fplain</br>
+ * Source: $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.1 1999/01/21 13:50:09 brandon Exp $
+ * </p>
+ * <p>
+ * Conversion to Kotlin and from there to Java in 2012.
+ * </p>
+ * <p>
+ * The C style comments are from the original C code, the ones with "//" from me.
+ * </p>
+ *
+ * @version $Id $
+ * @since 1.7
+ */
+public class Md5Crypt {
+
+ /**
+ * The Identifier of the Apache variant.
+ */
+ static final String APR1_PREFIX = "$apr1$";
+
+ /**
+ * The number of bytes of the final hash.
+ */
+ private static final int BLOCKSIZE = 16;
+
+ /**
+ * The MessageDigest MD5_ALGORITHM.
+ */
+ private static final String MD5_ALGORITHM = "MD5";
+
+ /**
+ * The Identifier of this crypt() variant.
+ */
+ static final String MD5_PREFIX = "$1$";
+
+ /**
+ * The number of rounds of the big loop.
+ */
+ private static final int ROUNDS = 1000;
+
+ /** See {@link #apr1Crypt(String, String)} for details. */
+ public static String apr1Crypt(byte[] keyBytes) throws Exception {
+ return apr1Crypt(keyBytes, APR1_PREFIX + B64.getRandomSalt(8));
+ }
+
+ /** See {@link #apr1Crypt(String, String)} for details. */
+ public static String apr1Crypt(byte[] keyBytes, String salt) throws Exception {
+ // to make the md5Crypt regex happy
+ if (salt != null && !salt.startsWith(APR1_PREFIX)) {
+ salt = APR1_PREFIX + salt;
+ }
+ return Md5Crypt.md5Crypt(keyBytes, salt, APR1_PREFIX);
+ }
+
+ /** See {@link #apr1Crypt(String, String)} for details. */
+ public static String apr1Crypt(String keyBytes) throws Exception {
+ return apr1Crypt(keyBytes.getBytes(Charsets.UTF_8));
+ }
+
+ /**
+ * Generates an Apache htpasswd compatible "$apr1$" MD5 based hash value. *
+ *
+ * The algorithm is identical to the crypt(3) "$1$" one but produces different outputs due to the different salt
+ * prefix.
+ *
+ * @param keyBytes
+ * The plaintext string that should be hashed.
+ * @param salt
+ * Salt string including the prefix and optionally garbage at the end. Will be generated randomly if
+ * null.
+ */
+ public static String apr1Crypt(String keyBytes, String salt) throws Exception {
+ return apr1Crypt(keyBytes.getBytes(Charsets.UTF_8), salt);
+ }
+
+ /**
+ * Generates a libc6 crypt() compatible "$1$" hash value.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ */
+ public static String md5Crypt(final byte[] keyBytes) throws Exception {
+ return md5Crypt(keyBytes, MD5_PREFIX + B64.getRandomSalt(8));
+ }
+
+ /**
+ * Generates a libc crypt() compatible "$1$" MD5 based hash value.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ *
+ * @param keyBytes
+ * The plaintext string that should be hashed.
+ * @param salt
+ * Salt string including the prefix and optionally garbage at the end. Will be generated randomly if
+ * null.
+ */
+ public static String md5Crypt(byte[] keyBytes, String salt) throws Exception {
+ return md5Crypt(keyBytes, salt, MD5_PREFIX);
+ }
+
+ /**
+ * Generates a libc6 crypt() "$1$" or Apache htpasswd "$apr1$" hash value.
+ *
+ * See {@link Crypt#crypt(String, String)} or {@link #apr1Crypt(String, String)} for details.
+ */
+ public static String md5Crypt(final byte[] keyBytes, final String salt, final String prefix) throws Exception {
+ int keyLen = keyBytes.length;
+
+ // Extract the real salt from the given string which can be a complete hash string.
+ String saltString;
+ if (salt == null) {
+ saltString = B64.getRandomSalt(8);
+ } else {
+ Pattern p = Pattern.compile("^" + prefix.replace("$", "\\$") + "([\\.\\/a-zA-Z0-9]{1,8}).*");
+ Matcher m = p.matcher(salt);
+ if (m == null || !m.find()) {
+ throw new IllegalArgumentException("Invalid salt value: " + salt);
+ }
+ saltString = m.group(1);
+ }
+ byte[] saltBytes = saltString.getBytes(Charsets.UTF_8);
+
+ MessageDigest ctx = MessageDigest.getInstance(MD5_ALGORITHM);
+
+ /*
+ * The password first, since that is what is most unknown
+ */
+ ctx.update(keyBytes);
+
+ /*
+ * Then our magic string
+ */
+ ctx.update(prefix.getBytes(Charsets.UTF_8));
+
+ /*
+ * Then the raw salt
+ */
+ ctx.update(saltBytes);
+
+ /*
+ * Then just as many characters of the MD5(pw,salt,pw)
+ */
+ MessageDigest ctx1 = MessageDigest.getInstance(MD5_ALGORITHM);
+ ctx1.update(keyBytes);
+ ctx1.update(saltBytes);
+ ctx1.update(keyBytes);
+ byte[] finalb = ctx1.digest();
+ int ii = keyLen;
+ while (ii > 0) {
+ ctx.update(finalb, 0, ii > 16 ? 16 : ii);
+ ii -= 16;
+ }
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ Arrays.fill(finalb, (byte) 0);
+
+ /*
+ * Then something really weird...
+ */
+ ii = keyLen;
+ int j = 0;
+ while (ii > 0) {
+ if ((ii & 1) == 1) {
+ ctx.update(finalb[j]);
+ } else {
+ ctx.update(keyBytes[j]);
+ }
+ ii >>= 1;
+ }
+
+ /*
+ * Now make the output string
+ */
+ StringBuilder passwd = new StringBuilder(prefix + saltString + "$");
+ finalb = ctx.digest();
+
+ /*
+ * and now, just to make sure things don't run too fast On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (int i = 0; i < ROUNDS; i++) {
+ ctx1 = MessageDigest.getInstance(MD5_ALGORITHM);
+ if ((i & 1) != 0) {
+ ctx1.update(keyBytes);
+ } else {
+ ctx1.update(finalb, 0, BLOCKSIZE);
+ }
+
+ if (i % 3 != 0) {
+ ctx1.update(saltBytes);
+ }
+
+ if (i % 7 != 0) {
+ ctx1.update(keyBytes);
+ }
+
+ if ((i & 1) != 0) {
+ ctx1.update(finalb, 0, BLOCKSIZE);
+ } else {
+ ctx1.update(keyBytes);
+ }
+ finalb = ctx1.digest();
+ }
+
+ // The following was nearly identical to the Sha2Crypt code.
+ // Again, the buflen is not really needed.
+ // int buflen = MD5_PREFIX.length() - 1 + salt_string.length() + 1 + BLOCKSIZE + 1;
+ B64.b64from24bit(finalb[0], finalb[6], finalb[12], 4, passwd);
+ B64.b64from24bit(finalb[1], finalb[7], finalb[13], 4, passwd);
+ B64.b64from24bit(finalb[2], finalb[8], finalb[14], 4, passwd);
+ B64.b64from24bit(finalb[3], finalb[9], finalb[15], 4, passwd);
+ B64.b64from24bit(finalb[4], finalb[10], finalb[5], 4, passwd);
+ B64.b64from24bit((byte) 0, (byte) 0, finalb[11], 2, passwd);
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ // Is there a better way to do this with the JVM?
+ ctx.reset();
+ ctx1.reset();
+ Arrays.fill(keyBytes, (byte) 0);
+ Arrays.fill(saltBytes, (byte) 0);
+ Arrays.fill(finalb, (byte) 0);
+
+ return passwd.toString();
+ }
+}
Added: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java (added)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,513 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * SHA2-based Unix crypt implementation.
+ *
+ * <p>
+ * Based on the C implementation released into the Public Domain by Ulrich Drepper <drepper@redhat.com>
+ * http://www.akkadia.org/drepper/SHA-crypt.txt
+ * </p>
+ *
+ * <p>
+ * Conversion to Kotlin and from there to Java in 2012 by Christian Hammers <ch@lathspell.de> and likewise put
+ * into the Public Domain.
+ * </p>
+ *
+ * @version $Id $
+ * @since 1.7
+ */
+public class Sha2Crypt {
+
+ /**
+ * Default number of rounds if not explicitly specified.
+ */
+ private static final int ROUNDS_DEFAULT = 5000;
+
+ /**
+ * Maximum number of rounds.
+ */
+ private static final int ROUNDS_MAX = 999999999;
+
+ /**
+ * Minimum number of rounds.
+ */
+ private static final int ROUNDS_MIN = 1000;
+
+ /**
+ * Prefix for optional rounds specification.
+ */
+ private static final String ROUNDS_PREFIX = "rounds=";
+
+ /**
+ * The MessageDigest algorithm.
+ */
+ private static final String SHA256_ALGORITHM = "SHA-256";
+
+ /**
+ * The number of bytes the final hash value will have.
+ */
+ private static final int SHA256_BLOCKSIZE = 32;
+
+ /**
+ * The prefixes that can be used to identify this crypt() variant.
+ */
+ static final String SHA256_PREFIX = "$5$";
+
+ private static final String SHA512_ALGORITHM = "SHA-512";
+
+ private static final int SHA512_BLOCKSIZE = 64;
+
+ static final String SHA512_PREFIX = "$6$";
+
+ /**
+ * Generates a libc crypt() compatible "$5$" hash value with random salt.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ */
+ public static String sha256Crypt(byte[] keyBytes) throws Exception {
+ return sha256Crypt(keyBytes, null);
+ }
+
+ /**
+ * Generates a libc6 crypt() compatible "$5$" hash value.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ */
+ public static String sha256Crypt(byte[] keyBytes, String salt) throws Exception {
+ if (salt == null) {
+ salt = SHA256_PREFIX + B64.getRandomSalt(8);
+ }
+ return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, SHA256_ALGORITHM);
+ }
+
+ /**
+ * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value.
+ *
+ * This is a nearly line by line conversion of the original C function. The numbered comments are from the algorithm
+ * description, the short C-style ones from the original C code and the ones with "Remark" from me.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ *
+ * @param keyBytes
+ * The plaintext that should be hashed.
+ * @param salt_string
+ * The real salt value without prefix or "rounds=".
+ * @param saltPrefix
+ * Either $5$ or $6$.
+ * @param blocksize
+ * A value that differs between $5$ and $6$.
+ * @param algorithm
+ * The MessageDigest algorithm identifier string.
+ * @return The complete hash value including prefix and salt.
+ */
+ private static String sha2Crypt(byte[] keyBytes, String salt, String saltPrefix, int blocksize, String algorithm)
+ throws Exception {
+ int keyLen = keyBytes.length;
+
+ // Extracts effective salt and the number of rounds from the given salt.
+ int rounds = ROUNDS_DEFAULT;
+ boolean roundsCustom = false;
+ if (salt == null) {
+ throw new IllegalArgumentException("Invalid salt value: null");
+ }
+ Pattern p = Pattern.compile("^\\$([56])\\$(rounds=(\\d+)\\$)?([\\.\\/a-zA-Z0-9]{1,16}).*");
+ Matcher m = p.matcher(salt);
+ if (m == null || !m.find()) {
+ throw new IllegalArgumentException("Invalid salt value: " + salt);
+ }
+ if (m.group(3) != null) {
+ rounds = Integer.valueOf(m.group(3));
+ rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds));
+ roundsCustom = true;
+ }
+ String saltString = m.group(4);
+ byte[] saltBytes = saltString.getBytes("UTF-8");
+ int saltLen = saltBytes.length;
+
+ // 1. start digest A
+ // Prepare for the real work.
+ MessageDigest ctx = MessageDigest.getInstance(algorithm);
+
+ // 2. the password string is added to digest A
+ /*
+ * Add the key string.
+ */
+ ctx.update(keyBytes);
+
+ // 3. the salt string is added to digest A. This is just the salt string
+ // itself without the enclosing '$', without the magic salt_prefix $5$ and
+ // $6$ respectively and without the rounds=<N> specification.
+ //
+ // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed
+ // necessary since it is a constant string and does not add security
+ // and /possibly/ allows a plain text attack. Since the rounds=<N>
+ // specification should never be added this would also create an
+ // inconsistency.
+ /*
+ * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character
+ * (for compatibility with existing implementations).
+ */
+ ctx.update(saltBytes);
+
+ // 4. start digest B
+ /*
+ * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first
+ * context.
+ */
+ MessageDigest altCtx = MessageDigest.getInstance(algorithm);
+
+ // 5. add the password to digest B
+ /*
+ * Add key.
+ */
+ altCtx.update(keyBytes);
+
+ // 6. add the salt string to digest B
+ /*
+ * Add salt.
+ */
+ altCtx.update(saltBytes);
+
+ // 7. add the password again to digest B
+ /*
+ * Add key again.
+ */
+ altCtx.update(keyBytes);
+
+ // 8. finish digest B
+ /*
+ * Now get result of this (32 bytes) and add it to the other context.
+ */
+ byte[] altResult = altCtx.digest();
+
+ // 9. For each block of 32 or 64 bytes in the password string (excluding
+ // the terminating NUL in the C representation), add digest B to digest A
+ /*
+ * Add for any character in the key one byte of the alternate sum.
+ */
+ /*
+ * (Remark: the C code comment seems wrong for key length > 32!)
+ */
+ int cnt = keyBytes.length;
+ while (cnt > blocksize) {
+ ctx.update(altResult, 0, blocksize);
+ cnt -= blocksize;
+ }
+
+ // 10. For the remaining N bytes of the password string add the first
+ // N bytes of digest B to digest A
+ ctx.update(altResult, 0, cnt);
+
+ // 11. For each bit of the binary representation of the length of the
+ // password string up to and including the highest 1-digit, starting
+ // from to lowest bit position (numeric value 1):
+ //
+ // a) for a 1-digit add digest B to digest A
+ //
+ // b) for a 0-digit add the password string
+ //
+ // NB: this step differs significantly from the MD5 algorithm. It
+ // adds more randomness.
+ /*
+ * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0
+ * the key.
+ */
+ cnt = keyBytes.length;
+ while (cnt > 0) {
+ if ((cnt & 1) != 0) {
+ ctx.update(altResult, 0, blocksize);
+ } else {
+ ctx.update(keyBytes);
+ }
+ cnt >>= 1;
+ }
+
+ // 12. finish digest A
+ /*
+ * Create intermediate result.
+ */
+ altResult = ctx.digest();
+
+ // 13. start digest DP
+ /*
+ * Start computation of P byte sequence.
+ */
+ altCtx = MessageDigest.getInstance(algorithm);
+
+ // 14. for every byte in the password (excluding the terminating NUL byte
+ // in the C representation of the string)
+ //
+ // add the password to digest DP
+ /*
+ * For every character in the password add the entire password.
+ */
+ for (int i = 1; i <= keyLen; i++) {
+ altCtx.update(keyBytes);
+ }
+
+ // 15. finish digest DP
+ /*
+ * Finish the digest.
+ */
+ byte[] tempResult = altCtx.digest();
+
+ // 16. produce byte sequence P of the same length as the password where
+ //
+ // a) for each block of 32 or 64 bytes of length of the password string
+ // the entire digest DP is used
+ //
+ // b) for the remaining N (up to 31 or 63) bytes use the first N
+ // bytes of digest DP
+ /*
+ * Create byte sequence P.
+ */
+ byte[] pBytes = new byte[keyLen];
+ int cp = 0;
+ while (cp < keyLen - blocksize) {
+ System.arraycopy(tempResult, 0, pBytes, cp, blocksize);
+ cp += blocksize;
+ }
+ System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp);
+
+ // 17. start digest DS
+ /*
+ * Start computation of S byte sequence.
+ */
+ altCtx = MessageDigest.getInstance(algorithm);
+
+ // 18. repeast the following 16+A[0] times, where A[0] represents the first
+ // byte in digest A interpreted as an 8-bit unsigned value
+ //
+ // add the salt to digest DS
+ /*
+ * For every character in the password add the entire password.
+ */
+ for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) {
+ altCtx.update(saltBytes);
+ }
+
+ // 19. finish digest DS
+ /*
+ * Finish the digest.
+ */
+ tempResult = altCtx.digest();
+
+ // 20. produce byte sequence S of the same length as the salt string where
+ //
+ // a) for each block of 32 or 64 bytes of length of the salt string
+ // the entire digest DS is used
+ //
+ // b) for the remaining N (up to 31 or 63) bytes use the first N
+ // bytes of digest DS
+ /*
+ * Create byte sequence S.
+ */
+ // Remark: The salt is limited to 16 chars, how does this make sense?
+ byte[] sBytes = new byte[saltLen];
+ cp = 0;
+ while (cp < saltLen - blocksize) {
+ System.arraycopy(tempResult, 0, sBytes, cp, blocksize);
+ cp += blocksize;
+ }
+ System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp);
+
+ // 21. repeat a loop according to the number specified in the rounds=<N>
+ // specification in the salt (or the default value if none is
+ // present). Each round is numbered, starting with 0 and up to N-1.
+ //
+ // The loop uses a digest as input. In the first round it is the
+ // digest produced in step 12. In the latter steps it is the digest
+ // produced in step 21.h. The following text uses the notation
+ // "digest A/C" to desribe this behavior.
+ /*
+ * Repeatedly run the collected hash value through sha512 to burn CPU cycles.
+ */
+ for (int i = 0; i <= rounds - 1; i++) {
+ // a) start digest C
+ /*
+ * New context.
+ */
+ ctx = MessageDigest.getInstance(algorithm);
+
+ // b) for odd round numbers add the byte sequense P to digest C
+ // c) for even round numbers add digest A/C
+ /*
+ * Add key or last result.
+ */
+ if ((i & 1) != 0) {
+ ctx.update(pBytes, 0, keyLen);
+ } else {
+ ctx.update(altResult, 0, blocksize);
+ }
+
+ // d) for all round numbers not divisible by 3 add the byte sequence S
+ /*
+ * Add salt for numbers not divisible by 3.
+ */
+ if (i % 3 != 0) {
+ ctx.update(sBytes, 0, saltLen);
+ }
+
+ // e) for all round numbers not divisible by 7 add the byte sequence P
+ /*
+ * Add key for numbers not divisible by 7.
+ */
+ if (i % 7 != 0) {
+ ctx.update(pBytes, 0, keyLen);
+ }
+
+ // f) for odd round numbers add digest A/C
+ // g) for even round numbers add the byte sequence P
+ /*
+ * Add key or last result.
+ */
+ if ((i & 1) != 0) {
+ ctx.update(altResult, 0, blocksize);
+ } else {
+ ctx.update(pBytes, 0, keyLen);
+ }
+
+ // h) finish digest C.
+ /*
+ * Create intermediate result.
+ */
+ altResult = ctx.digest();
+ }
+
+ // 22. Produce the output string. This is an ASCII string of the maximum
+ // size specified above, consisting of multiple pieces:
+ //
+ // a) the salt salt_prefix, $5$ or $6$ respectively
+ //
+ // b) the rounds=<N> specification, if one was present in the input
+ // salt string. A trailing '$' is added in this case to separate
+ // the rounds specification from the following text.
+ //
+ // c) the salt string truncated to 16 characters
+ //
+ // d) a '$' character
+ /*
+ * Now we can construct the result string. It consists of three parts.
+ */
+ StringBuilder buffer = new StringBuilder(saltPrefix + (roundsCustom ? ROUNDS_PREFIX + rounds + "$" : "")
+ + saltString + "$");
+
+ // e) the base-64 encoded final C digest. The encoding used is as
+ // follows:
+ // [...]
+ //
+ // Each group of three bytes from the digest produces four
+ // characters as output:
+ //
+ // 1. character: the six low bits of the first byte
+ // 2. character: the two high bits of the first byte and the
+ // four low bytes from the second byte
+ // 3. character: the four high bytes from the second byte and
+ // the two low bits from the third byte
+ // 4. character: the six high bits from the third byte
+ //
+ // The groups of three bytes are as follows (in this sequence).
+ // These are the indices into the byte array containing the
+ // digest, starting with index 0. For the last group there are
+ // not enough bytes left in the digest and the value zero is used
+ // in its place. This group also produces only three or two
+ // characters as output for SHA-512 and SHA-512 respectively.
+
+ // This was just a safeguard in the C implementation:
+ // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1;
+
+ if (blocksize == 32) {
+ B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer);
+ B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer);
+ B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer);
+ B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer);
+ B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer);
+ B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer);
+ B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer);
+ B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer);
+ B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer);
+ B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer);
+ B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer);
+ } else {
+ B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer);
+ B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer);
+ B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer);
+ B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer);
+ B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer);
+ B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer);
+ B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer);
+ B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer);
+ B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer);
+ B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer);
+ B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer);
+ B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer);
+ B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer);
+ B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer);
+ B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer);
+ B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer);
+ B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer);
+ B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer);
+ B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer);
+ B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer);
+ B64.b64from24bit(altResult[62], altResult[20], altResult[41], 4, buffer);
+ B64.b64from24bit((byte) 0, (byte) 0, altResult[63], 2, buffer);
+ }
+
+ /*
+ * Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps
+ * cannot get any information.
+ */
+ // Is there a better way to do this with the JVM?
+ Arrays.fill(tempResult, (byte) 0);
+ Arrays.fill(pBytes, (byte) 0);
+ Arrays.fill(sBytes, (byte) 0);
+ ctx.reset();
+ altCtx.reset();
+ Arrays.fill(keyBytes, (byte) 0);
+ Arrays.fill(saltBytes, (byte) 0);
+
+ return buffer.toString();
+ }
+
+ /**
+ * Generates a libc crypt() compatible "$6$" hash value with random salt.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ */
+ public static String sha512Crypt(byte[] keyBytes) throws Exception {
+ return sha512Crypt(keyBytes, null);
+ }
+
+ /**
+ * Generates a libc6 crypt() compatible "$6$" hash value.
+ *
+ * See {@link Crypt#crypt(String, String)} for details.
+ */
+ public static String sha512Crypt(byte[] keyBytes, String salt) throws Exception {
+ if (salt == null) {
+ salt = SHA512_PREFIX + B64.getRandomSalt(8);
+ }
+ return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, SHA512_ALGORITHM);
+ }
+}
Added: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java (added)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,446 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.commons.codec.digest;
+
+import java.util.Random;
+
+import org.apache.commons.codec.Charsets;
+
+/**
+ * Unix crypt(3) algorithm implementation.
+ *
+ * This class only implements the traditional 56 bit DES based algorithm. Please
+ * use DigestUtils.crypt() for a method that distinguishes between all the
+ * algorithms supported in the current glibc's crypt().
+ *
+ * The Java implementation was taken from the JetSpeed Portal project (see
+ * org.apache.jetspeed.services.security.ldap.UnixCrypt).
+ *
+ * This class is slightly incompatible if the given salt contains characters
+ * that are not part of the allowed range [a-zA-Z0-9./].
+ *
+ * @version $Id $
+ * @since 1.7
+ */
+public class UnixCrypt {
+
+ private static final int CON_SALT[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 0, 0, 0, 0, 0
+ };
+
+ private static final int COV2CHAR[] = {
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 120, 121, 122
+ };
+
+ private static final char SALT_CHARS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./".toCharArray();
+
+ private static final boolean SHIFT2[] = {
+ false, false, true, true, true, true, true, true, false, true,
+ true, true, true, true, true, false
+ };
+
+ private static final int SKB[][] = {
+ {
+ 0, 16, 0x20000000, 0x20000010, 0x10000, 0x10010, 0x20010000, 0x20010010, 2048, 2064,
+ 0x20000800, 0x20000810, 0x10800, 0x10810, 0x20010800, 0x20010810, 32, 48, 0x20000020, 0x20000030,
+ 0x10020, 0x10030, 0x20010020, 0x20010030, 2080, 2096, 0x20000820, 0x20000830, 0x10820, 0x10830,
+ 0x20010820, 0x20010830, 0x80000, 0x80010, 0x20080000, 0x20080010, 0x90000, 0x90010, 0x20090000, 0x20090010,
+ 0x80800, 0x80810, 0x20080800, 0x20080810, 0x90800, 0x90810, 0x20090800, 0x20090810, 0x80020, 0x80030,
+ 0x20080020, 0x20080030, 0x90020, 0x90030, 0x20090020, 0x20090030, 0x80820, 0x80830, 0x20080820, 0x20080830,
+ 0x90820, 0x90830, 0x20090820, 0x20090830
+ }, {
+ 0, 0x2000000, 8192, 0x2002000, 0x200000, 0x2200000, 0x202000, 0x2202000, 4, 0x2000004,
+ 8196, 0x2002004, 0x200004, 0x2200004, 0x202004, 0x2202004, 1024, 0x2000400, 9216, 0x2002400,
+ 0x200400, 0x2200400, 0x202400, 0x2202400, 1028, 0x2000404, 9220, 0x2002404, 0x200404, 0x2200404,
+ 0x202404, 0x2202404, 0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000,
+ 0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004, 0x10000400, 0x12000400,
+ 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400, 0x10000404, 0x12000404, 0x10002404, 0x12002404,
+ 0x10200404, 0x12200404, 0x10202404, 0x12202404
+ }, {
+ 0, 1, 0x40000, 0x40001, 0x1000000, 0x1000001, 0x1040000, 0x1040001, 2, 3,
+ 0x40002, 0x40003, 0x1000002, 0x1000003, 0x1040002, 0x1040003, 512, 513, 0x40200, 0x40201,
+ 0x1000200, 0x1000201, 0x1040200, 0x1040201, 514, 515, 0x40202, 0x40203, 0x1000202, 0x1000203,
+ 0x1040202, 0x1040203, 0x8000000, 0x8000001, 0x8040000, 0x8040001, 0x9000000, 0x9000001, 0x9040000, 0x9040001,
+ 0x8000002, 0x8000003, 0x8040002, 0x8040003, 0x9000002, 0x9000003, 0x9040002, 0x9040003, 0x8000200, 0x8000201,
+ 0x8040200, 0x8040201, 0x9000200, 0x9000201, 0x9040200, 0x9040201, 0x8000202, 0x8000203, 0x8040202, 0x8040203,
+ 0x9000202, 0x9000203, 0x9040202, 0x9040203
+ }, {
+ 0, 0x100000, 256, 0x100100, 8, 0x100008, 264, 0x100108, 4096, 0x101000,
+ 4352, 0x101100, 4104, 0x101008, 4360, 0x101108, 0x4000000, 0x4100000, 0x4000100, 0x4100100,
+ 0x4000008, 0x4100008, 0x4000108, 0x4100108, 0x4001000, 0x4101000, 0x4001100, 0x4101100, 0x4001008, 0x4101008,
+ 0x4001108, 0x4101108, 0x20000, 0x120000, 0x20100, 0x120100, 0x20008, 0x120008, 0x20108, 0x120108,
+ 0x21000, 0x121000, 0x21100, 0x121100, 0x21008, 0x121008, 0x21108, 0x121108, 0x4020000, 0x4120000,
+ 0x4020100, 0x4120100, 0x4020008, 0x4120008, 0x4020108, 0x4120108, 0x4021000, 0x4121000, 0x4021100, 0x4121100,
+ 0x4021008, 0x4121008, 0x4021108, 0x4121108
+ }, {
+ 0, 0x10000000, 0x10000, 0x10010000, 4, 0x10000004, 0x10004, 0x10010004, 0x20000000, 0x30000000,
+ 0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x100000, 0x10100000, 0x110000, 0x10110000,
+ 0x100004, 0x10100004, 0x110004, 0x10110004, 0x20100000, 0x30100000, 0x20110000, 0x30110000, 0x20100004, 0x30100004,
+ 0x20110004, 0x30110004, 4096, 0x10001000, 0x11000, 0x10011000, 4100, 0x10001004, 0x11004, 0x10011004,
+ 0x20001000, 0x30001000, 0x20011000, 0x30011000, 0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x101000, 0x10101000,
+ 0x111000, 0x10111000, 0x101004, 0x10101004, 0x111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000,
+ 0x20101004, 0x30101004, 0x20111004, 0x30111004
+ }, {
+ 0, 0x8000000, 8, 0x8000008, 1024, 0x8000400, 1032, 0x8000408, 0x20000, 0x8020000,
+ 0x20008, 0x8020008, 0x20400, 0x8020400, 0x20408, 0x8020408, 1, 0x8000001, 9, 0x8000009,
+ 1025, 0x8000401, 1033, 0x8000409, 0x20001, 0x8020001, 0x20009, 0x8020009, 0x20401, 0x8020401,
+ 0x20409, 0x8020409, 0x2000000, 0xa000000, 0x2000008, 0xa000008, 0x2000400, 0xa000400, 0x2000408, 0xa000408,
+ 0x2020000, 0xa020000, 0x2020008, 0xa020008, 0x2020400, 0xa020400, 0x2020408, 0xa020408, 0x2000001, 0xa000001,
+ 0x2000009, 0xa000009, 0x2000401, 0xa000401, 0x2000409, 0xa000409, 0x2020001, 0xa020001, 0x2020009, 0xa020009,
+ 0x2020401, 0xa020401, 0x2020409, 0xa020409
+ }, {
+ 0, 256, 0x80000, 0x80100, 0x1000000, 0x1000100, 0x1080000, 0x1080100, 16, 272,
+ 0x80010, 0x80110, 0x1000010, 0x1000110, 0x1080010, 0x1080110, 0x200000, 0x200100, 0x280000, 0x280100,
+ 0x1200000, 0x1200100, 0x1280000, 0x1280100, 0x200010, 0x200110, 0x280010, 0x280110, 0x1200010, 0x1200110,
+ 0x1280010, 0x1280110, 512, 768, 0x80200, 0x80300, 0x1000200, 0x1000300, 0x1080200, 0x1080300,
+ 528, 784, 0x80210, 0x80310, 0x1000210, 0x1000310, 0x1080210, 0x1080310, 0x200200, 0x200300,
+ 0x280200, 0x280300, 0x1200200, 0x1200300, 0x1280200, 0x1280300, 0x200210, 0x200310, 0x280210, 0x280310,
+ 0x1200210, 0x1200310, 0x1280210, 0x1280310
+ }, {
+ 0, 0x4000000, 0x40000, 0x4040000, 2, 0x4000002, 0x40002, 0x4040002, 8192, 0x4002000,
+ 0x42000, 0x4042000, 8194, 0x4002002, 0x42002, 0x4042002, 32, 0x4000020, 0x40020, 0x4040020,
+ 34, 0x4000022, 0x40022, 0x4040022, 8224, 0x4002020, 0x42020, 0x4042020, 8226, 0x4002022,
+ 0x42022, 0x4042022, 2048, 0x4000800, 0x40800, 0x4040800, 2050, 0x4000802, 0x40802, 0x4040802,
+ 10240, 0x4002800, 0x42800, 0x4042800, 10242, 0x4002802, 0x42802, 0x4042802, 2080, 0x4000820,
+ 0x40820, 0x4040820, 2082, 0x4000822, 0x40822, 0x4040822, 10272, 0x4002820, 0x42820, 0x4042820,
+ 10274, 0x4002822, 0x42822, 0x4042822
+ }
+ };
+
+ private static final int SPTRANS[][] = {
+ {
+ 0x820200, 0x20000, 0x80800000, 0x80820200, 0x800000, 0x80020200, 0x80020000, 0x80800000, 0x80020200, 0x820200,
+ 0x820000, 0x80000200, 0x80800200, 0x800000, 0, 0x80020000, 0x20000, 0x80000000, 0x800200, 0x20200,
+ 0x80820200, 0x820000, 0x80000200, 0x800200, 0x80000000, 512, 0x20200, 0x80820000, 512, 0x80800200,
+ 0x80820000, 0, 0, 0x80820200, 0x800200, 0x80020000, 0x820200, 0x20000, 0x80000200, 0x800200,
+ 0x80820000, 512, 0x20200, 0x80800000, 0x80020200, 0x80000000, 0x80800000, 0x820000, 0x80820200, 0x20200,
+ 0x820000, 0x80800200, 0x800000, 0x80000200, 0x80020000, 0, 0x20000, 0x800000, 0x80800200, 0x820200,
+ 0x80000000, 0x80820000, 512, 0x80020200
+ }, {
+ 0x10042004, 0, 0x42000, 0x10040000, 0x10000004, 8196, 0x10002000, 0x42000, 8192, 0x10040004,
+ 4, 0x10002000, 0x40004, 0x10042000, 0x10040000, 4, 0x40000, 0x10002004, 0x10040004, 8192,
+ 0x42004, 0x10000000, 0, 0x40004, 0x10002004, 0x42004, 0x10042000, 0x10000004, 0x10000000, 0x40000,
+ 8196, 0x10042004, 0x40004, 0x10042000, 0x10002000, 0x42004, 0x10042004, 0x40004, 0x10000004, 0,
+ 0x10000000, 8196, 0x40000, 0x10040004, 8192, 0x10000000, 0x42004, 0x10002004, 0x10042000, 8192,
+ 0, 0x10000004, 4, 0x10042004, 0x42000, 0x10040000, 0x10040004, 0x40000, 8196, 0x10002000,
+ 0x10002004, 4, 0x10040000, 0x42000
+ }, {
+ 0x41000000, 0x1010040, 64, 0x41000040, 0x40010000, 0x1000000, 0x41000040, 0x10040, 0x1000040, 0x10000,
+ 0x1010000, 0x40000000, 0x41010040, 0x40000040, 0x40000000, 0x41010000, 0, 0x40010000, 0x1010040, 64,
+ 0x40000040, 0x41010040, 0x10000, 0x41000000, 0x41010000, 0x1000040, 0x40010040, 0x1010000, 0x10040, 0,
+ 0x1000000, 0x40010040, 0x1010040, 64, 0x40000000, 0x10000, 0x40000040, 0x40010000, 0x1010000, 0x41000040,
+ 0, 0x1010040, 0x10040, 0x41010000, 0x40010000, 0x1000000, 0x41010040, 0x40000000, 0x40010040, 0x41000000,
+ 0x1000000, 0x41010040, 0x10000, 0x1000040, 0x41000040, 0x10040, 0x1000040, 0, 0x41010000, 0x40000040,
+ 0x41000000, 0x40010040, 64, 0x1010000
+ }, {
+ 0x100402, 0x4000400, 2, 0x4100402, 0, 0x4100000, 0x4000402, 0x100002, 0x4100400, 0x4000002,
+ 0x4000000, 1026, 0x4000002, 0x100402, 0x100000, 0x4000000, 0x4100002, 0x100400, 1024, 2,
+ 0x100400, 0x4000402, 0x4100000, 1024, 1026, 0, 0x100002, 0x4100400, 0x4000400, 0x4100002,
+ 0x4100402, 0x100000, 0x4100002, 1026, 0x100000, 0x4000002, 0x100400, 0x4000400, 2, 0x4100000,
+ 0x4000402, 0, 1024, 0x100002, 0, 0x4100002, 0x4100400, 1024, 0x4000000, 0x4100402,
+ 0x100402, 0x100000, 0x4100402, 2, 0x4000400, 0x100402, 0x100002, 0x100400, 0x4100000, 0x4000402,
+ 1026, 0x4000000, 0x4000002, 0x4100400
+ }, {
+ 0x2000000, 16384, 256, 0x2004108, 0x2004008, 0x2000100, 16648, 0x2004000, 16384, 8,
+ 0x2000008, 16640, 0x2000108, 0x2004008, 0x2004100, 0, 16640, 0x2000000, 16392, 264,
+ 0x2000100, 16648, 0, 0x2000008, 8, 0x2000108, 0x2004108, 16392, 0x2004000, 256,
+ 264, 0x2004100, 0x2004100, 0x2000108, 16392, 0x2004000, 16384, 8, 0x2000008, 0x2000100,
+ 0x2000000, 16640, 0x2004108, 0, 16648, 0x2000000, 256, 16392, 0x2000108, 256,
+ 0, 0x2004108, 0x2004008, 0x2004100, 264, 16384, 16640, 0x2004008, 0x2000100, 264,
+ 8, 16648, 0x2004000, 0x2000008
+ }, {
+ 0x20000010, 0x80010, 0, 0x20080800, 0x80010, 2048, 0x20000810, 0x80000, 2064, 0x20080810,
+ 0x80800, 0x20000000, 0x20000800, 0x20000010, 0x20080000, 0x80810, 0x80000, 0x20000810, 0x20080010, 0,
+ 2048, 16, 0x20080800, 0x20080010, 0x20080810, 0x20080000, 0x20000000, 2064, 16, 0x80800,
+ 0x80810, 0x20000800, 2064, 0x20000000, 0x20000800, 0x80810, 0x20080800, 0x80010, 0, 0x20000800,
+ 0x20000000, 2048, 0x20080010, 0x80000, 0x80010, 0x20080810, 0x80800, 16, 0x20080810, 0x80800,
+ 0x80000, 0x20000810, 0x20000010, 0x20080000, 0x80810, 0, 2048, 0x20000010, 0x20000810, 0x20080800,
+ 0x20080000, 2064, 16, 0x20080010
+ }, {
+ 4096, 128, 0x400080, 0x400001, 0x401081, 4097, 4224, 0, 0x400000, 0x400081,
+ 129, 0x401000, 1, 0x401080, 0x401000, 129, 0x400081, 4096, 4097, 0x401081,
+ 0, 0x400080, 0x400001, 4224, 0x401001, 4225, 0x401080, 1, 4225, 0x401001,
+ 128, 0x400000, 4225, 0x401000, 0x401001, 129, 4096, 128, 0x400000, 0x401001,
+ 0x400081, 4225, 4224, 0, 128, 0x400001, 1, 0x400080, 0, 0x400081,
+ 0x400080, 4224, 129, 4096, 0x401081, 0x400000, 0x401080, 1, 4097, 0x401081,
+ 0x400001, 0x401080, 0x401000, 4097
+ }, {
+ 0x8200020, 0x8208000, 32800, 0, 0x8008000, 0x200020, 0x8200000, 0x8208020, 32, 0x8000000,
+ 0x208000, 32800, 0x208020, 0x8008020, 0x8000020, 0x8200000, 32768, 0x208020, 0x200020, 0x8008000,
+ 0x8208020, 0x8000020, 0, 0x208000, 0x8000000, 0x200000, 0x8008020, 0x8200020, 0x200000, 32768,
+ 0x8208000, 32, 0x200000, 32768, 0x8000020, 0x8208020, 32800, 0x8000000, 0, 0x208000,
+ 0x8200020, 0x8008020, 0x8008000, 0x200020, 0x8208000, 32, 0x200020, 0x8008000, 0x8208020, 0x200000,
+ 0x8200000, 0x8000020, 0x208000, 32800, 0x8008020, 0x8200000, 32, 0x8208000, 0x208020, 0,
+ 0x8000000, 0x8200020, 32768, 0x208020
+ }
+ };
+
+ private static int[] body(int schedule[], int eSwap0, int eSwap1) {
+ int left = 0;
+ int right = 0;
+ int t = 0;
+ for (int j = 0; j < 25; j++) {
+ for (int i = 0; i < 32; i += 4) {
+ left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
+ right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
+ }
+ t = left;
+ left = right;
+ right = t;
+ }
+
+ t = right;
+ right = left >>> 1 | left << 31;
+ left = t >>> 1 | t << 31;
+ left &= 0xffffffff;
+ right &= 0xffffffff;
+ int results[] = new int[2];
+ permOp(right, left, 1, 0x55555555, results);
+ right = results[0];
+ left = results[1];
+ permOp(left, right, 8, 0xff00ff, results);
+ left = results[0];
+ right = results[1];
+ permOp(right, left, 2, 0x33333333, results);
+ right = results[0];
+ left = results[1];
+ permOp(left, right, 16, 65535, results);
+ left = results[0];
+ right = results[1];
+ permOp(right, left, 4, 0xf0f0f0f, results);
+ right = results[0];
+ left = results[1];
+ int out[] = new int[2];
+ out[0] = left;
+ out[1] = right;
+ return out;
+ }
+
+ private static int byteToUnsigned(byte b) {
+ int value = b;
+ return value < 0 ? value + 256 : value;
+ }
+
+ private static int dEncrypt(int el, int r, int s, int e0, int e1, int sArr[]) {
+ int v = r ^ r >>> 16;
+ int u = v & e0;
+ v &= e1;
+ u = u ^ u << 16 ^ r ^ sArr[s];
+ int t = v ^ v << 16 ^ r ^ sArr[s + 1];
+ t = t >>> 4 | t << 28;
+ el ^= SPTRANS[1][t & 0x3f] | SPTRANS[3][t >>> 8 & 0x3f] | SPTRANS[5][t >>> 16 & 0x3f]
+ | SPTRANS[7][t >>> 24 & 0x3f] | SPTRANS[0][u & 0x3f] | SPTRANS[2][u >>> 8 & 0x3f]
+ | SPTRANS[4][u >>> 16 & 0x3f] | SPTRANS[6][u >>> 24 & 0x3f];
+ return el;
+ }
+
+ private static int[] desSetKey(byte key[]) {
+ int schedule[] = new int[32];
+ int c = fourBytesToInt(key, 0);
+ int d = fourBytesToInt(key, 4);
+ int results[] = new int[2];
+ permOp(d, c, 4, 0xf0f0f0f, results);
+ d = results[0];
+ c = results[1];
+ c = hPermOp(c, -2, 0xcccc0000);
+ d = hPermOp(d, -2, 0xcccc0000);
+ permOp(d, c, 1, 0x55555555, results);
+ d = results[0];
+ c = results[1];
+ permOp(c, d, 8, 0xff00ff, results);
+ c = results[0];
+ d = results[1];
+ permOp(d, c, 1, 0x55555555, results);
+ d = results[0];
+ c = results[1];
+ d = (d & 0xff) << 16 | d & 0xff00 | (d & 0xff0000) >>> 16 | (c & 0xf0000000) >>> 4;
+ c &= 0xfffffff;
+ int j = 0;
+ for (int i = 0; i < 16; i++) {
+ if (SHIFT2[i]) {
+ c = c >>> 2 | c << 26;
+ d = d >>> 2 | d << 26;
+ } else {
+ c = c >>> 1 | c << 27;
+ d = d >>> 1 | d << 27;
+ }
+ c &= 0xfffffff;
+ d &= 0xfffffff;
+ int s = SKB[0][c & 0x3f] | SKB[1][c >>> 6 & 0x3 | c >>> 7 & 0x3c] | SKB[2][c >>> 13 & 0xf | c >>> 14 & 0x30] | SKB[3][c >>> 20 & 0x1 | c >>> 21 & 0x6 | c >>> 22 & 0x38];
+ int t = SKB[4][d & 0x3f] | SKB[5][d >>> 7 & 0x3 | d >>> 8 & 0x3c] | SKB[6][d >>> 15 & 0x3f] | SKB[7][d >>> 21 & 0xf | d >>> 22 & 0x30];
+ schedule[j++] = (t << 16 | s & 0xffff) & 0xffffffff;
+ s = s >>> 16 | t & 0xffff0000;
+ s = s << 4 | s >>> 28;
+ schedule[j++] = s & 0xffffffff;
+ }
+
+ return schedule;
+ }
+
+ private static int fourBytesToInt(byte b[], int offset) {
+ int value = byteToUnsigned(b[offset++]);
+ value |= byteToUnsigned(b[offset++]) << 8;
+ value |= byteToUnsigned(b[offset++]) << 16;
+ value |= byteToUnsigned(b[offset++]) << 24;
+ return value;
+ }
+
+ private static int hPermOp(int a, int n, int m) {
+ int t = (a << 16 - n ^ a) & m;
+ a = a ^ t ^ t >>> 16 - n;
+ return a;
+ }
+
+ private static void intToFourBytes(int iValue, byte b[], int offset) {
+ b[offset++] = (byte) (iValue & 0xff);
+ b[offset++] = (byte) (iValue >>> 8 & 0xff);
+ b[offset++] = (byte) (iValue >>> 16 & 0xff);
+ b[offset++] = (byte) (iValue >>> 24 & 0xff);
+ }
+
+ private static void permOp(int a, int b, int n, int m, int results[]) {
+ int t = (a >>> n ^ b) & m;
+ a ^= t << n;
+ b ^= t;
+ results[0] = a;
+ results[1] = b;
+ }
+
+ /**
+ * Generates a crypt(3) compatible hash using the DES algorithm.
+ *
+ * As no salt is given, a random one will be used.
+ *
+ * @param original Plaintext password
+ *
+ * @return A 13 character string starting with the salt string.
+ */
+ public static String crypt(byte[] original) {
+ return crypt(original, null);
+ }
+
+ /**
+ * Generates a crypt(3) compatible hash using the DES algorithm.
+ *
+ * Using unspecified characters as salt results incompatible hash values.
+ *
+ * @param original Plaintext password
+ *
+ * @param salt A two character string drawn from [a-zA-Z0-9./] or null for a
+ * random one.
+ *
+ * @return A 13 character string starting with the salt string.
+ */
+ public static String crypt(byte[] original, String salt) {
+ if (salt == null) {
+ Random randomGenerator = new Random();
+ int numSaltChars = SALT_CHARS.length;
+ salt = "" + SALT_CHARS[Math.abs(randomGenerator.nextInt()) % numSaltChars] + SALT_CHARS[Math.abs(randomGenerator.nextInt()) % numSaltChars];
+ } else if (!salt.matches("^[" + B64.B64T + "]{2,}$")) {
+ throw new IllegalArgumentException("Invalid salt value: " + salt);
+ }
+
+ for (; salt.length() < 2; salt = salt + "A");
+ StringBuilder buffer = new StringBuilder(" ");
+ char charZero = salt.charAt(0);
+ char charOne = salt.charAt(1);
+ buffer.setCharAt(0, charZero);
+ buffer.setCharAt(1, charOne);
+ int eSwap0 = CON_SALT[charZero];
+ int eSwap1 = CON_SALT[charOne] << 4;
+ byte key[] = new byte[8];
+ for (int i = 0; i < key.length; i++) {
+ key[i] = 0;
+ }
+
+ for (int i = 0; i < key.length && i < original.length; i++) {
+ int iChar = original[i];
+ key[i] = (byte) (iChar << 1);
+ }
+
+ int schedule[] = desSetKey(key);
+ int out[] = body(schedule, eSwap0, eSwap1);
+ byte b[] = new byte[9];
+ intToFourBytes(out[0], b, 0);
+ intToFourBytes(out[1], b, 4);
+ b[8] = 0;
+ int i = 2;
+ int y = 0;
+ int u = 128;
+ for (; i < 13; i++) {
+ int j = 0;
+ int c = 0;
+ for (; j < 6; j++) {
+ c <<= 1;
+ if ((b[y] & u) != 0) {
+ c |= 0x1;
+ }
+ u >>>= 1;
+ if (u == 0) {
+ y++;
+ u = 128;
+ }
+ buffer.setCharAt(i, (char) COV2CHAR[c]);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Generates a crypt(3) compatible hash using the DES algorithm.
+ *
+ * As no salt is given, a random one is used.
+ *
+ * @param original Plaintext password
+ *
+ * @return A 13 character string starting with the salt string.
+ */
+ public static String crypt(String original) throws Exception {
+ return crypt(original.getBytes(Charsets.UTF_8));
+ }
+
+ /**
+ * Generates a crypt(3) compatible hash using the DES algorithm.
+ *
+ * @param original Plaintext password
+ * @param salt A two character string drawn from [a-zA-Z0-9./] or null for a
+ * random one.
+ * @return A 13 character string starting with the salt string.
+ */
+ public static String crypt(String original, String salt) throws Exception {
+ return crypt(original.getBytes(Charsets.UTF_8), salt);
+ }
+
+}
Modified: commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/package.html
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/package.html?rev=1328414&r1=1328413&r2=1328414&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/package.html (original)
+++ commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/package.html Fri Apr 20 15:36:58 2012
@@ -16,6 +16,9 @@ limitations under the License.
-->
<html>
<body>
- Simplifies common {@link java.security.MessageDigest} tasks.
+ Simplifies common {@link java.security.MessageDigest} tasks and
+ includes a libc crypt(3) compatible crypt method that supports DES,
+ MD5, SHA-256 and SHA-512 based algorithms as well as the Apache
+ specific "$apr1$" variant.
</body>
</html>
Modified: commons/proper/codec/trunk/src/site/xdoc/userguide.xml
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/site/xdoc/userguide.xml?rev=1328414&r1=1328413&r2=1328414&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/site/xdoc/userguide.xml (original)
+++ commons/proper/codec/trunk/src/site/xdoc/userguide.xml Fri Apr 20 15:36:58 2012
@@ -97,7 +97,7 @@
Simplifies common
<a
href="http://download.oracle.com/javase/6/docs/api/java/security/MessageDigest.html">MessageDigest</a>
- tasks.
+ tasks and provides GNU libc crypt(3) compatible password hashing functions.
</td>
</tr>
</table>
Added: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java (added)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class Apr1CryptTest {
+
+ @Test
+ public void testApr1CryptStrings() throws Exception {
+ // A random example using htpasswd
+ assertEquals("$apr1$TqI9WECO$LHZB2DqRlk9nObiB6vJG9.", Md5Crypt.apr1Crypt("secret", "$apr1$TqI9WECO"));
+ // empty data
+ assertEquals("$apr1$foo$P27KyD1htb4EllIPEYhqi0", Md5Crypt.apr1Crypt("", "$apr1$foo"));
+ // salt gets cut at dollar sign
+ assertEquals("$apr1$1234$mAlH7FRST6FiRZ.kcYL.j1", Md5Crypt.apr1Crypt("secret", "$apr1$1234"));
+ assertEquals("$apr1$1234$mAlH7FRST6FiRZ.kcYL.j1", Md5Crypt.apr1Crypt("secret", "$apr1$1234$567"));
+ assertEquals("$apr1$1234$mAlH7FRST6FiRZ.kcYL.j1", Md5Crypt.apr1Crypt("secret", "$apr1$1234$567$890"));
+ // salt gets cut at maximum length
+ assertEquals("$apr1$12345678$0lqb/6VUFP8JY/s/jTrIk0", Md5Crypt.apr1Crypt("secret", "$apr1$1234567890123456"));
+ assertEquals("$apr1$12345678$0lqb/6VUFP8JY/s/jTrIk0", Md5Crypt.apr1Crypt("secret", "$apr1$123456789012345678"));
+ }
+
+ @Test
+ public void testApr1CryptBytes() throws Exception {
+ // An empty Bytearray equals an empty String
+ assertEquals("$apr1$foo$P27KyD1htb4EllIPEYhqi0", Md5Crypt.apr1Crypt(new byte[0], "$apr1$foo"));
+ // UTF-8 stores \u00e4 "a with diaeresis" as two bytes 0xc3 0xa4.
+ assertEquals("$apr1$./$EeFrYzWWbmTyGdf4xULYc.", Md5Crypt.apr1Crypt("t\u00e4st", "$apr1$./$"));
+ // ISO-8859-1 stores "a with diaeresis" as single byte 0xe4.
+ assertEquals("$apr1$./$kCwT1pY9qXAJElYG9q1QE1", Md5Crypt.apr1Crypt("t\u00e4st".getBytes("ISO-8859-1"), "$apr1$./$"));
+ }
+
+ @Test
+ public void testApr1CryptExplicitCall() throws Exception {
+ // When explicitly called the prefix is optional
+ assertEquals("$apr1$1234$mAlH7FRST6FiRZ.kcYL.j1", Md5Crypt.apr1Crypt("secret", "1234"));
+ // When explicitly called without salt, a random one will be used.
+ assertTrue(Md5Crypt.apr1Crypt("secret".getBytes()).matches("^\\$apr1\\$[a-zA-Z0-9./]{0,8}\\$.{1,}$"));
+ assertTrue(Md5Crypt.apr1Crypt("secret".getBytes(), null).matches("^\\$apr1\\$[a-zA-Z0-9./]{0,8}\\$.{1,}$"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testApr1CryptNullData() throws Exception {
+ Md5Crypt.apr1Crypt((byte[]) null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testApr1CryptWithEmptySalt() throws Exception {
+ Md5Crypt.apr1Crypt("secret".getBytes(), "");
+ }
+}
Added: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java (added)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+public class B64Test {
+
+ @Test
+ public void testB64from24bit() {
+ StringBuilder buffer = new StringBuilder("");
+ B64.b64from24bit((byte) 8, (byte) 16, (byte) 64, 2, buffer);
+ B64.b64from24bit((byte) 7, (byte) 77, (byte) 120, 4, buffer);
+ assertEquals("./spo/", buffer.toString());
+ }
+}
Added: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java (added)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class CryptTest {
+
+ @Test
+ public void testDefaultCryptVariant() throws Exception {
+ // If salt is null or completely omitted, a random "$6$" is used.
+ assertTrue(Crypt.crypt("secret").startsWith("$6$"));
+ assertTrue(Crypt.crypt("secret", null).startsWith("$6$"));
+ }
+
+ /**
+ * An empty string as salt is invalid.
+ *
+ * The C and Perl implementations return an empty string, PHP threads it
+ * as NULL. Our implementation should throw an Exception as any resulting
+ * hash would not be verifyable with other implementations of crypt().
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testCryptWithEmptySalt() throws Exception {
+ Crypt.crypt("secret", "");
+ }
+
+}
Added: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java (added)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class Md5CryptTest {
+
+ @Test
+ public void testMd5CryptStrings() throws Exception {
+ // empty data
+ assertEquals("$1$foo$9mS5ExwgIECGE5YKlD5o91", Crypt.crypt("", "$1$foo"));
+ // salt gets cut at dollar sign
+ assertEquals("$1$1234$ImZYBLmYC.rbBKg9ERxX70", Crypt.crypt("secret", "$1$1234"));
+ assertEquals("$1$1234$ImZYBLmYC.rbBKg9ERxX70", Crypt.crypt("secret", "$1$1234$567"));
+ assertEquals("$1$1234$ImZYBLmYC.rbBKg9ERxX70", Crypt.crypt("secret", "$1$1234$567$890"));
+ // salt gets cut at maximum length
+ assertEquals("$1$12345678$hj0uLpdidjPhbMMZeno8X/", Crypt.crypt("secret", "$1$1234567890123456"));
+ assertEquals("$1$12345678$hj0uLpdidjPhbMMZeno8X/", Crypt.crypt("secret", "$1$123456789012345678"));
+ }
+
+ @Test
+ public void testMd5CryptBytes() throws Exception {
+ // An empty Bytearray equals an empty String
+ assertEquals("$1$foo$9mS5ExwgIECGE5YKlD5o91", Crypt.crypt(new byte[0], "$1$foo"));
+ // UTF-8 stores \u00e4 "a with diaeresis" as two bytes 0xc3 0xa4.
+ assertEquals("$1$./$52agTEQZs877L9jyJnCNZ1", Crypt.crypt("t\u00e4st", "$1$./$"));
+ // ISO-8859-1 stores "a with diaeresis" as single byte 0xe4.
+ assertEquals("$1$./$J2UbKzGe0Cpe63WZAt6p//", Crypt.crypt("t\u00e4st".getBytes("ISO-8859-1"), "$1$./$"));
+ }
+
+ @Test
+ public void testMd5CryptExplicitCall() throws Exception {
+ assertTrue(Md5Crypt.md5Crypt("secret".getBytes()).matches("^\\$1\\$[a-zA-Z0-9./]{0,8}\\$.{1,}$"));
+ assertTrue(Md5Crypt.md5Crypt("secret".getBytes(), null).matches("^\\$1\\$[a-zA-Z0-9./]{0,8}\\$.{1,}$"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testMd5CryptNullData() throws Exception {
+ Md5Crypt.md5Crypt((byte[]) null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testMd5CryptWithEmptySalt() throws Exception {
+ Md5Crypt.md5Crypt("secret".getBytes(), "");
+ }
+}
Added: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java (added)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class Sha256CryptTest {
+
+ @Test
+ public void testSha256CryptStrings() throws Exception {
+ // empty data
+ assertEquals("$5$foo$Fq9CX624QIfnCAmlGiPKLlAasdacKCRxZztPoeo7o0B", Crypt.crypt("", "$5$foo"));
+ // salt gets cut at dollar sign
+ assertEquals("$5$45678$LulJuUIJIn.1uU.KPV9x92umMYFopzVDD.o2ZqA1i2/", Crypt.crypt("secret", "$5$45678"));
+ assertEquals("$5$45678$LulJuUIJIn.1uU.KPV9x92umMYFopzVDD.o2ZqA1i2/", Crypt.crypt("secret", "$5$45678$012"));
+ assertEquals("$5$45678$LulJuUIJIn.1uU.KPV9x92umMYFopzVDD.o2ZqA1i2/", Crypt.crypt("secret", "$5$45678$012$456"));
+ // salt gets cut at maximum length
+ assertEquals("$5$1234567890123456$GUiFKBSTUAGvcK772ulTDPltkTOLtFvPOmp9o.9FNPB", Crypt.crypt("secret", "$5$1234567890123456"));
+ assertEquals("$5$1234567890123456$GUiFKBSTUAGvcK772ulTDPltkTOLtFvPOmp9o.9FNPB", Crypt.crypt("secret", "$5$1234567890123456789"));
+ }
+
+ @Test
+ public void testSha256CryptBytes() throws Exception {
+ // An empty Bytearray equals an empty String
+ assertEquals("$5$foo$Fq9CX624QIfnCAmlGiPKLlAasdacKCRxZztPoeo7o0B", Crypt.crypt(new byte[0], "$5$foo"));
+ // UTF-8 stores \u00e4 "a with diaeresis" as two bytes 0xc3 0xa4.
+ assertEquals("$5$./$iH66LwY5sTDTdHeOxq5nvNDVAxuoCcyH/y6Ptte82P8", Crypt.crypt("t\u00e4st", "$5$./$"));
+ // ISO-8859-1 stores "a with diaeresis" as single byte 0xe4.
+ assertEquals("$5$./$qx5gFfCzjuWUOvsDDy.5Nor3UULPIqLVBZhgGNS0c14", Crypt.crypt("t\u00e4st".getBytes("ISO-8859-1"), "$5$./$"));
+ }
+
+ @Test
+ public void testSha256CryptExplicitCall() throws Exception {
+ assertTrue(Sha2Crypt.sha256Crypt("secret".getBytes()).matches("^\\$5\\$[a-zA-Z0-9./]{0,16}\\$.{1,}$"));
+ assertTrue(Sha2Crypt.sha256Crypt("secret".getBytes(), null).matches("^\\$5\\$[a-zA-Z0-9./]{0,16}\\$.{1,}$"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testSha256CryptNullData() throws Exception {
+ Sha2Crypt.sha256Crypt((byte[]) null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSha256CryptWithEmptySalt() throws Exception {
+ Sha2Crypt.sha256Crypt("secret".getBytes(), "");
+ }
+}
Added: commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java?rev=1328414&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java (added)
+++ commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java Fri Apr 20 15:36:58 2012
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.codec.digest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+public class Sha512CryptTest {
+
+ @Test
+ public void testSha512CryptStrings() throws Exception {
+ // empty data
+ assertEquals("$6$foo$Nywkte7LPWjaJhWjNeGJN.dFdY3pN1wYlGifyRLYOVlGS9EMSiZaDDe/BGSOYQ327q9.32I4UqQ5odsqvsBLX/", Crypt.crypt("", "$6$foo"));
+ // salt gets cut at dollar sign
+ assertEquals("$6$45678$f2en/Y053Knir/wu/T8DQKSbiUGcPcbXKsmyVlP820dIpXoY0KlqgUqRVFfavdRXwDMUZYsxPOymA4zgX0qE5.", Crypt.crypt("secret", "$6$45678"));
+ assertEquals("$6$45678$f2en/Y053Knir/wu/T8DQKSbiUGcPcbXKsmyVlP820dIpXoY0KlqgUqRVFfavdRXwDMUZYsxPOymA4zgX0qE5.", Crypt.crypt("secret", "$6$45678$012"));
+ assertEquals("$6$45678$f2en/Y053Knir/wu/T8DQKSbiUGcPcbXKsmyVlP820dIpXoY0KlqgUqRVFfavdRXwDMUZYsxPOymA4zgX0qE5.", Crypt.crypt("secret", "$6$45678$012$456"));
+ // salt gets cut at maximum length
+ assertEquals("$6$1234567890123456$d2HCAnimIF5VMqUnwaZ/4JhNDJ.ttsjm0nbbmc9eE7xUYiw79GMvXUc5ZqG5BlqkXSbASZxrvR0QefAgdLbeH.", Crypt.crypt("secret", "$6$1234567890123456"));
+ assertEquals("$6$1234567890123456$d2HCAnimIF5VMqUnwaZ/4JhNDJ.ttsjm0nbbmc9eE7xUYiw79GMvXUc5ZqG5BlqkXSbASZxrvR0QefAgdLbeH.", Crypt.crypt("secret", "$6$1234567890123456789"));
+ }
+
+ @Test
+ public void testSha512CryptBytes() throws Exception {
+ // An empty Bytearray equals an empty String
+ assertEquals("$6$foo$Nywkte7LPWjaJhWjNeGJN.dFdY3pN1wYlGifyRLYOVlGS9EMSiZaDDe/BGSOYQ327q9.32I4UqQ5odsqvsBLX/", Crypt.crypt(new byte[0], "$6$foo"));
+ // UTF-8 stores \u00e4 "a with diaeresis" as two bytes 0xc3 0xa4.
+ assertEquals("$6$./$fKtWqslQkwI8ZxjdWoeS.jHHrte97bZxiwB5gwCRHX6LG62fUhT6Bb5MRrjWvieh0C/gxh8ItFuTsVy80VrED1", Crypt.crypt("t\u00e4st", "$6$./$"));
+ // ISO-8859-1 stores "a with diaeresis" as single byte 0xe4.
+ assertEquals("$6$./$L49DSK.d2df/LxGLJQMyS5A/Um.TdHqgc46j5FpScEPlqQHP5dEazltaDNDZ6UEs2mmNI6kPwtH/rsP9g5zBI.", Crypt.crypt("t\u00e4st".getBytes("ISO-8859-1"), "$6$./$"));
+ }
+
+ @Test
+ public void testSha512CryptExplicitCall() throws Exception {
+ assertTrue(Sha2Crypt.sha512Crypt("secret".getBytes()).matches("^\\$6\\$[a-zA-Z0-9./]{0,16}\\$.{1,}$"));
+ assertTrue(Sha2Crypt.sha512Crypt("secret".getBytes(), null).matches("^\\$6\\$[a-zA-Z0-9./]{0,16}\\$.{1,}$"));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testSha512CryptNullData() throws Exception {
+ Sha2Crypt.sha512Crypt((byte[]) null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSha512CryptWithEmptySalt() throws Exception {
+ Sha2Crypt.sha512Crypt("secret".getBytes(), "");
+ }
+}
Re: svn commit: r1328414 [1/2] - in /commons/proper/codec/trunk/src:
changes/ main/java/org/apache/commons/codec/digest/ site/xdoc/ test/java/org/apache/commons/codec/digest/
Posted by Gary Gregory <ga...@gmail.com>.
On Fri, Apr 20, 2012 at 12:14 PM, sebb <se...@gmail.com> wrote:
> On 20 April 2012 16:58, Gary Gregory <ga...@gmail.com> wrote:
> > On Fri, Apr 20, 2012 at 11:44 AM, sebb <se...@gmail.com> wrote:
> >
> >> On 20 April 2012 16:36, <gg...@apache.org> wrote:
> >> > Author: ggregory
> >> > Date: Fri Apr 20 15:36:58 2012
> >> > New Revision: 1328414
> >> >
> >> > URL: http://svn.apache.org/viewvc?rev=1328414&view=rev
> >> > Log:
> >> > [CODEC-133] Add classes for MD5/SHA1/SHA-512-based Unix crypt(3) hash
> >> variants.
> >> >
> >> > Added:
> >> >
> >>
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java
> >> >
> >>
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java
> >> >
> >>
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java
> >> >
> >>
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java
> >> >
> >>
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java
> >> >
> >>
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/UnixCryptTest.java
> >>
> >> SVN EOL properties?
> >>
> >
> > What should I set svn:eol-style to?
>
> native
>
Done, thank you for the pointer.
Gary
> See:
>
> http://www.apache.org/dev/version-control.html#https-svn-config
>
> > Gary
> >
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> >> For additional commands, e-mail: dev-help@commons.apache.org
> >>
> >>
> >
> >
> > --
> > E-Mail: garydgregory@gmail.com | ggregory@apache.org
> > JUnit in Action, 2nd Ed: <http://goog_1249600977>http://bit.ly/ECvg0
> > Spring Batch in Action: <http://s.apache.org/HOq>http://bit.ly/bqpbCK
> > Blog: http://garygregory.wordpress.com
> > Home: http://garygregory.com/
> > Tweet! http://twitter.com/GaryGregory
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
>
>
--
E-Mail: garydgregory@gmail.com | ggregory@apache.org
JUnit in Action, 2nd Ed: <http://goog_1249600977>http://bit.ly/ECvg0
Spring Batch in Action: <http://s.apache.org/HOq>http://bit.ly/bqpbCK
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory
Re: svn commit: r1328414 [1/2] - in /commons/proper/codec/trunk/src:
changes/ main/java/org/apache/commons/codec/digest/ site/xdoc/ test/java/org/apache/commons/codec/digest/
Posted by sebb <se...@gmail.com>.
On 20 April 2012 16:58, Gary Gregory <ga...@gmail.com> wrote:
> On Fri, Apr 20, 2012 at 11:44 AM, sebb <se...@gmail.com> wrote:
>
>> On 20 April 2012 16:36, <gg...@apache.org> wrote:
>> > Author: ggregory
>> > Date: Fri Apr 20 15:36:58 2012
>> > New Revision: 1328414
>> >
>> > URL: http://svn.apache.org/viewvc?rev=1328414&view=rev
>> > Log:
>> > [CODEC-133] Add classes for MD5/SHA1/SHA-512-based Unix crypt(3) hash
>> variants.
>> >
>> > Added:
>> >
>> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java
>> >
>> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java
>> >
>> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java
>> >
>> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java
>> >
>> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java
>> >
>> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/UnixCryptTest.java
>>
>> SVN EOL properties?
>>
>
> What should I set svn:eol-style to?
native
See:
http://www.apache.org/dev/version-control.html#https-svn-config
> Gary
>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@commons.apache.org
>>
>>
>
>
> --
> E-Mail: garydgregory@gmail.com | ggregory@apache.org
> JUnit in Action, 2nd Ed: <http://goog_1249600977>http://bit.ly/ECvg0
> Spring Batch in Action: <http://s.apache.org/HOq>http://bit.ly/bqpbCK
> Blog: http://garygregory.wordpress.com
> Home: http://garygregory.com/
> Tweet! http://twitter.com/GaryGregory
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org
Re: svn commit: r1328414 [1/2] - in /commons/proper/codec/trunk/src:
changes/ main/java/org/apache/commons/codec/digest/ site/xdoc/ test/java/org/apache/commons/codec/digest/
Posted by Gary Gregory <ga...@gmail.com>.
On Fri, Apr 20, 2012 at 11:44 AM, sebb <se...@gmail.com> wrote:
> On 20 April 2012 16:36, <gg...@apache.org> wrote:
> > Author: ggregory
> > Date: Fri Apr 20 15:36:58 2012
> > New Revision: 1328414
> >
> > URL: http://svn.apache.org/viewvc?rev=1328414&view=rev
> > Log:
> > [CODEC-133] Add classes for MD5/SHA1/SHA-512-based Unix crypt(3) hash
> variants.
> >
> > Added:
> >
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java
> >
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java
> >
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java
> >
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java
> >
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java
> >
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/UnixCryptTest.java
>
> SVN EOL properties?
>
What should I set svn:eol-style to?
Gary
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
>
>
--
E-Mail: garydgregory@gmail.com | ggregory@apache.org
JUnit in Action, 2nd Ed: <http://goog_1249600977>http://bit.ly/ECvg0
Spring Batch in Action: <http://s.apache.org/HOq>http://bit.ly/bqpbCK
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory
Re: svn commit: r1328414 [1/2] - in /commons/proper/codec/trunk/src:
changes/ main/java/org/apache/commons/codec/digest/ site/xdoc/ test/java/org/apache/commons/codec/digest/
Posted by sebb <se...@gmail.com>.
On 20 April 2012 16:36, <gg...@apache.org> wrote:
> Author: ggregory
> Date: Fri Apr 20 15:36:58 2012
> New Revision: 1328414
>
> URL: http://svn.apache.org/viewvc?rev=1328414&view=rev
> Log:
> [CODEC-133] Add classes for MD5/SHA1/SHA-512-based Unix crypt(3) hash variants.
>
> Added:
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/B64.java
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Crypt.java
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Md5Crypt.java
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/Sha2Crypt.java
> commons/proper/codec/trunk/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Apr1CryptTest.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/B64Test.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/CryptTest.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Md5CryptTest.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha256CryptTest.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/Sha512CryptTest.java
> commons/proper/codec/trunk/src/test/java/org/apache/commons/codec/digest/UnixCryptTest.java
SVN EOL properties?
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org