added more options to HashBuilder and added extractor method

This commit is contained in:
Sebastian Sdorra
2012-02-17 21:26:15 +01:00
parent fa759e8502
commit 694bbbd9f0
11 changed files with 521 additions and 16 deletions

View File

@@ -39,6 +39,14 @@ package sonia.scm.security;
public interface HashBuilder
{
/**
* Method description
*
*
* @return
*/
public HashBuilder appendSalt();
/**
* Method description
*
@@ -57,6 +65,14 @@ public interface HashBuilder
*/
public HashBuilder createSalt(int length);
/**
* Method description
*
*
* @return
*/
public HashBuilder enableLabel();
/**
* Method description
*

View File

@@ -49,7 +49,7 @@ public class MD5HashBuilder extends MessageDigestHashBuilder
*/
public MD5HashBuilder()
{
super(DIGEST, null, null, 0);
super(DIGEST, null, null, 0, false, false);
}
/**
@@ -60,7 +60,7 @@ public class MD5HashBuilder extends MessageDigestHashBuilder
*/
public MD5HashBuilder(String value)
{
super(DIGEST, value, null, 0);
super(DIGEST, value, null, 0, false, false);
}
/**
@@ -72,7 +72,7 @@ public class MD5HashBuilder extends MessageDigestHashBuilder
*/
public MD5HashBuilder(String value, byte[] salt)
{
super(DIGEST, value, salt, 0);
super(DIGEST, value, salt, 0, false, false);
}
/**
@@ -85,6 +85,37 @@ public class MD5HashBuilder extends MessageDigestHashBuilder
*/
public MD5HashBuilder(String value, byte[] salt, int iterations)
{
super(DIGEST, value, salt, iterations);
super(DIGEST, value, salt, iterations, false, false);
}
/**
* Constructs ...
*
*
* @param value
* @param salt
* @param iterations
* @param appendSalt
*/
public MD5HashBuilder(String value, byte[] salt, int iterations,
boolean appendSalt)
{
super(DIGEST, value, salt, iterations, appendSalt, false);
}
/**
* Constructs ...
*
*
* @param value
* @param salt
* @param iterations
* @param appendSalt
* @param enableLabel
*/
public MD5HashBuilder(String value, byte[] salt, int iterations,
boolean appendSalt, boolean enableLabel)
{
super(DIGEST, value, salt, iterations, appendSalt, enableLabel);
}
}

View File

@@ -43,6 +43,9 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author Sebastian Sdorra
@@ -60,6 +63,9 @@ public class MessageDigestHashBuilder implements HashBuilder
/** Field description */
public static final String RANDOM_INSTANCE = "SHA1PRNG";
/** Field description */
private static Pattern PATTERN = Pattern.compile("\\{([^\\}]+)\\}(.*)");
//~--- constructors ---------------------------------------------------------
/**
@@ -70,18 +76,50 @@ public class MessageDigestHashBuilder implements HashBuilder
* @param value
* @param salt
* @param iterations
* @param appendSalt
* @param enableLabel
*/
public MessageDigestHashBuilder(String digest, String value, byte[] salt,
int iterations)
int iterations, boolean appendSalt,
boolean enableLabel)
{
this.digest = digest;
this.value = value;
this.salt = salt;
this.iterations = iterations;
this.appendSalt = appendSalt;
this.enableLable = enableLabel;
}
//~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param hash
*
* @return
*/
public static Extractor createExtractor(String hash)
{
return new Extractor(hash);
}
/**
* Method description
*
*
* @return
*/
@Override
public HashBuilder appendSalt()
{
this.appendSalt = true;
return this;
}
/**
* Method description
*
@@ -120,6 +158,20 @@ public class MessageDigestHashBuilder implements HashBuilder
return this;
}
/**
* Method description
*
*
* @return
*/
@Override
public HashBuilder enableLabel()
{
this.enableLable = true;
return this;
}
/**
* Method description
*
@@ -152,6 +204,15 @@ public class MessageDigestHashBuilder implements HashBuilder
input = md.digest(input);
}
}
if ((salt != null) && appendSalt)
{
byte[] content = new byte[input.length + salt.length];
System.arraycopy(input, 0, content, 0, input.length);
System.arraycopy(salt, 0, content, input.length, salt.length);
input = content;
}
}
catch (UnsupportedEncodingException ex)
{
@@ -174,7 +235,22 @@ public class MessageDigestHashBuilder implements HashBuilder
@Override
public String toHexString()
{
return Util.toString(toByteArray());
String hexString = null;
if (enableLable)
{
StringBuilder buffer = new StringBuilder();
buffer.append("{").append(digest).append("}");
buffer.append(Util.toString(toByteArray()));
hexString = buffer.toString();
}
else
{
hexString = Util.toString(toByteArray());
}
return hexString;
}
//~--- get methods ----------------------------------------------------------
@@ -260,11 +336,155 @@ public class MessageDigestHashBuilder implements HashBuilder
return this;
}
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 12/02/17
* @author Enter your name here...
*/
public static class Extractor
{
/**
* Constructs ...
*
*
* @param hash
*/
public Extractor(String hash)
{
this.hash = hash;
}
//~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public MessageDigestHashBuilder getHashBuilder()
{
return getHashBuilder(-1);
}
/**
* Method description
*
*
* @param saltLength
*
* @return
*/
public MessageDigestHashBuilder getHashBuilder(int saltLength)
{
MessageDigestHashBuilder hashBuilder = null;
Matcher m = PATTERN.matcher(hash);
if (m.matches())
{
String digest = m.group(1);
if (digest != null)
{
byte[] salt = null;
if (saltLength > 0)
{
String hashWithoutPrefix = m.group(2);
salt = getSalt(hashWithoutPrefix, saltLength);
}
hashBuilder = new MessageDigestHashBuilder(digest, null, salt, 0,
salt != null, true);
}
}
return hashBuilder;
}
/**
* Method description
*
*
* @return
*/
public String getLabel()
{
String label = null;
Matcher m = PATTERN.matcher(hash);
if (m.matches())
{
label = m.group(1);
}
return label;
}
/**
* Method description
*
*
* @param length
*
* @return
*/
public byte[] getSalt(int length)
{
Matcher m = PATTERN.matcher(hash);
String hashWithoutPrefix = hash;
if (m.matches())
{
hashWithoutPrefix = m.group(2);
}
return getSalt(hashWithoutPrefix, length);
}
/**
* Method description
*
*
* @param hashWithoutPrefix
* @param length
*
* @return
*/
private byte[] getSalt(String hashWithoutPrefix, int length)
{
byte[] content = Util.fromHexString(hashWithoutPrefix);
byte[] salt = new byte[length];
System.arraycopy(content, content.length - length, salt, 0, length);
return salt;
}
//~--- fields -------------------------------------------------------------
/** Field description */
private String hash;
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private boolean appendSalt;
/** Field description */
private String digest;
/** Field description */
private boolean enableLable;
/** Field description */
private int iterations;

View File

@@ -50,7 +50,7 @@ public class SHA1HashBuilder extends MessageDigestHashBuilder
*/
public SHA1HashBuilder()
{
super(DIGEST, null, null, 0);
super(DIGEST, null, null, 0, false, false);
}
/**
@@ -61,7 +61,7 @@ public class SHA1HashBuilder extends MessageDigestHashBuilder
*/
public SHA1HashBuilder(String value)
{
super(DIGEST, value, null, 0);
super(DIGEST, value, null, 0, false, false);
}
/**
@@ -73,7 +73,7 @@ public class SHA1HashBuilder extends MessageDigestHashBuilder
*/
public SHA1HashBuilder(String value, byte[] salt)
{
super(DIGEST, value, salt, 0);
super(DIGEST, value, salt, 0, false, false);
}
/**
@@ -86,6 +86,37 @@ public class SHA1HashBuilder extends MessageDigestHashBuilder
*/
public SHA1HashBuilder(String value, byte[] salt, int iterations)
{
super(DIGEST, value, salt, iterations);
super(DIGEST, value, salt, iterations, false, false);
}
/**
* Constructs ...
*
*
* @param value
* @param salt
* @param iterations
* @param appendSalt
*/
public SHA1HashBuilder(String value, byte[] salt, int iterations,
boolean appendSalt)
{
super(DIGEST, value, salt, iterations, appendSalt, false);
}
/**
* Constructs ...
*
*
* @param value
* @param salt
* @param iterations
* @param appendSalt
* @param enableLable
*/
public SHA1HashBuilder(String value, byte[] salt, int iterations,
boolean appendSalt, boolean enableLabel)
{
super(DIGEST, value, salt, iterations, appendSalt, enableLabel);
}
}

View File

@@ -50,7 +50,7 @@ public class SHA512HashBuilder extends MessageDigestHashBuilder
*/
public SHA512HashBuilder()
{
super(DIGEST, null, null, 0);
super(DIGEST, null, null, 0, false, false);
}
/**
@@ -61,7 +61,7 @@ public class SHA512HashBuilder extends MessageDigestHashBuilder
*/
public SHA512HashBuilder(String value)
{
super(DIGEST, value, null, 0);
super(DIGEST, value, null, 0, false, false);
}
/**
@@ -73,7 +73,7 @@ public class SHA512HashBuilder extends MessageDigestHashBuilder
*/
public SHA512HashBuilder(String value, byte[] salt)
{
super(DIGEST, value, salt, 0);
super(DIGEST, value, salt, 0, false, false);
}
/**
@@ -86,6 +86,37 @@ public class SHA512HashBuilder extends MessageDigestHashBuilder
*/
public SHA512HashBuilder(String value, byte[] salt, int iterations)
{
super(DIGEST, value, salt, iterations);
super(DIGEST, value, salt, iterations, false, false);
}
/**
* Constructs ...
*
*
* @param value
* @param salt
* @param iterations
* @param appendSalt
*/
public SHA512HashBuilder(String value, byte[] salt, int iterations,
boolean appendSalt)
{
super(DIGEST, value, salt, iterations, appendSalt, false);
}
/**
* Constructs ...
*
*
* @param value
* @param salt
* @param iterations
* @param appendSalt
* @param enableLabel
*/
public SHA512HashBuilder(String value, byte[] salt, int iterations,
boolean appendSalt, boolean enableLabel)
{
super(DIGEST, value, salt, iterations, appendSalt, enableLabel);
}
}

View File

@@ -35,6 +35,8 @@ package sonia.scm.util;
//~--- JDK imports ------------------------------------------------------------
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -334,6 +336,22 @@ public class Util
*
* @return
*/
public static byte[] fromHexString(String value)
{
return new BigInteger(value, 16).toByteArray();
}
/**
* Method description
*
*
* @param value
*
*
* @since 1.13
*
* @return
*/
public static String nonNull(Object value)
{
return (value != null)

View File

@@ -39,6 +39,11 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* @author Sebastian Sdorra
@@ -54,6 +59,18 @@ public abstract class HashBuilderTestBase
*/
public abstract HashBuilder createHashBuilder();
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
protected abstract String getLable();
//~--- methods --------------------------------------------------------------
/**
* Method description
*
@@ -74,6 +91,30 @@ public abstract class HashBuilderTestBase
checkHash("hitcheker", hash, otherHash);
}
/**
* Method description
*
*/
@Test
public void testCreateLabledHash()
{
HashBuilder hashBuilder = createHashBuilder();
String hash = hashBuilder.enableLabel().setValue("hitcheker").toHexString();
System.out.println(hash);
checkHash("hitcheker", hash);
Pattern p = Pattern.compile("\\{([^\\}]+)\\}.*");
Matcher m = p.matcher(hash);
assertTrue(m.matches());
String lable = m.group(1);
assertNotNull(lable);
assertEquals(getLable(), lable);
}
/**
* Method description
*
@@ -134,6 +175,19 @@ public abstract class HashBuilderTestBase
checkHash("hitcheker", hash, otherHash);
}
/**
* Method description
*
*
* @param plain
* @param hash
*/
private void checkHash(String plain, String hash)
{
assertNotNull(hash);
assertThat(hash, not(equalTo(plain)));
}
/**
* Method description
*
@@ -144,8 +198,7 @@ public abstract class HashBuilderTestBase
*/
private void checkHash(String plain, String hash, String otherHash)
{
assertNotNull(hash);
assertThat(hash, not(equalTo("hitcheker")));
checkHash(plain, hash);
assertNotNull(otherHash);
assertThat(otherHash, not(equalTo("hitcheker")));
assertEquals(hash, otherHash);

View File

@@ -49,4 +49,18 @@ public class MD5HashBuilderTest extends HashBuilderTestBase
{
return new MD5HashBuilder();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected String getLable()
{
return MD5HashBuilder.DIGEST;
}
}

View File

@@ -0,0 +1,63 @@
/**
* Copyright (c) 2010, Sebastian Sdorra All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of SCM-Manager;
* nor the names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* http://bitbucket.org/sdorra/scm-manager
*
*/
package sonia.scm.security;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import static org.junit.Assert.*;
/**
*
* @author Sebastian Sdorra
*/
public class MessageDigestHashBuilderTest
{
/**
* Method description
*
*/
@Test
public void testExtractor()
{
MessageDigestHashBuilder hashBuilder = new SHA1HashBuilder("hitcheker");
String hash =
hashBuilder.enableLabel().createSalt().appendSalt().toHexString();
assertNotNull(hash);
hashBuilder =
MessageDigestHashBuilder.createExtractor(hash).getHashBuilder(8);
assertEquals(hash, hashBuilder.setValue("hitcheker").toHexString());
}
}

View File

@@ -69,4 +69,18 @@ public class SHA1HashBuilderTest extends HashBuilderTestBase
assertEquals(hash, newHash);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected String getLable()
{
return SHA1HashBuilder.DIGEST;
}
}

View File

@@ -49,4 +49,18 @@ public class SHA512HashBuilderTest extends HashBuilderTestBase
{
return new SHA512HashBuilder();
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
protected String getLable()
{
return SHA512HashBuilder.DIGEST;
}
}