first commit
This commit is contained in:
6
security/.settings/org.eclipse.core.resources.prefs
Normal file
6
security/.settings/org.eclipse.core.resources.prefs
Normal file
@ -0,0 +1,6 @@
|
||||
#Thu Jul 05 02:27:50 CEST 2012
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/main/resources=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
encoding/<project>=UTF-8
|
||||
6
security/.settings/org.eclipse.jdt.core.prefs
Normal file
6
security/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,6 @@
|
||||
#Thu Jul 05 02:27:50 CEST 2012
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.5
|
||||
5
security/.settings/org.eclipse.m2e.core.prefs
Normal file
5
security/.settings/org.eclipse.m2e.core.prefs
Normal file
@ -0,0 +1,5 @@
|
||||
#Thu Jul 05 02:27:48 CEST 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
40
security/pom.xml
Normal file
40
security/pom.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.muehlencord.shared</groupId>
|
||||
<artifactId>shared-security</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>shared-security</name>
|
||||
|
||||
<parent>
|
||||
<artifactId>shared</artifactId>
|
||||
<groupId>de.muehlencord</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<url>http://maven.apache.org</url>
|
||||
<ciManagement>
|
||||
<system>hudson</system>
|
||||
<url>http://sunrise.muehlencord.intra:8088/jenkins/job/shared-security/</url>
|
||||
</ciManagement>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.4</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package de.muehlencord.shared.security;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
*/
|
||||
public abstract class PasswordUtil {
|
||||
|
||||
/**
|
||||
* returns password (pos 0) and the salt (pos 1) of given plaintext password. Both strings are base64 encoded
|
||||
*
|
||||
* @param plainTextPassword he
|
||||
* @param saltLength the length of the salt to use
|
||||
* @return the password (pos 0) and the salt (pos 1) of given plaintext password. Both strings are base64 encoded
|
||||
*
|
||||
* @throws de.muehlencord.shared.security.SecurityException if any error occurs during the password generation
|
||||
*/
|
||||
public static String[] getMD5Password(final String plainTextPassword, final int saltLength) throws SecurityException {
|
||||
byte[] unHashedPassword = getBase64MD5HashedPassword(plainTextPassword);
|
||||
byte[] salt = createSalt(saltLength);
|
||||
byte[] hashedPassword = hashPasswordWithSalt(unHashedPassword, salt);
|
||||
|
||||
// test
|
||||
String saltStr = base64Encode(salt);
|
||||
byte[] salt2 = base64Decode(saltStr);
|
||||
if (!Arrays.equals(salt, salt2)) {
|
||||
throw new SecurityException("Salt conversion failed");
|
||||
}
|
||||
|
||||
|
||||
String[] returnValue = new String[2];
|
||||
returnValue[0] = base64Encode(hashedPassword);
|
||||
returnValue[1] = base64Encode(salt);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given password (plain text) matches the given crypted password. The crypted password is hashed with the given salt. Both strings, crypted
|
||||
* password and salt, have to be base64 encoded
|
||||
*
|
||||
* @param plainTextPassword the plaintext password to compare to
|
||||
* @param cryptedPasswordStr the crypted password to compare to
|
||||
* @param saltStr the salt needed to hash the plaintext password with to get the correct crypted password if both passwords match
|
||||
* @return true, if and only if the encryption of plainTextPassword (hashed with saltStr) equals to cryptedPasswordStr
|
||||
*
|
||||
* @throws de.muehlencord.shared.security.SecurityException if any error occures during the check
|
||||
*/
|
||||
public static boolean checkPassword(String plainTextPassword, String cryptedPasswordStr, String saltStr) throws SecurityException {
|
||||
byte[] salt = base64Decode(saltStr);
|
||||
byte[] newPassword = getBase64MD5HashedPassword(plainTextPassword);
|
||||
byte[] newHashedPassword = hashPasswordWithSalt(newPassword, salt);
|
||||
byte[] crytepdPassword = base64Decode(cryptedPasswordStr);
|
||||
return Arrays.equals(crytepdPassword, newHashedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a new salt as a string
|
||||
*
|
||||
* @param saltLength the length of the salt
|
||||
* @return a new salt as a string (base64 encoded)
|
||||
*
|
||||
* @throws SecurityException if the creation of the salt fails
|
||||
*/
|
||||
public static String createSaltString(int saltLength) throws SecurityException {
|
||||
byte[] salt = createSalt(saltLength);
|
||||
return base64Encode(salt);
|
||||
}
|
||||
|
||||
|
||||
/* *** private methods *** */
|
||||
/**
|
||||
* creates a salt and returns the value as byte[]
|
||||
*
|
||||
* @param saltLength the length the salt string should have
|
||||
* @return the generated salt as byte[]
|
||||
*
|
||||
* @throws SecurityException if the salt creation fails
|
||||
*/
|
||||
private static byte[] createSalt(int saltLength) throws SecurityException {
|
||||
try {
|
||||
SecureRandom sha1SecureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||
byte salt[] = new byte[saltLength];
|
||||
synchronized (sha1SecureRandom) {
|
||||
sha1SecureRandom.nextBytes(salt);
|
||||
}
|
||||
return salt;
|
||||
} catch (Exception ex) {
|
||||
throw new SecurityException("Cannot created salt", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hashes the given password (md5 hashed, base64 coded) with the given salt
|
||||
* @param text the text to salt
|
||||
* @param salt the salt to use
|
||||
* @return the input text salted with password
|
||||
* @throws SecurityException
|
||||
*/
|
||||
private static byte[] hashPasswordWithSalt(byte text[], byte salt[]) throws SecurityException {
|
||||
try {
|
||||
MessageDigest sha1Algorithm = MessageDigest.getInstance("SHA-1");
|
||||
byte[] digest;
|
||||
synchronized (sha1Algorithm) {
|
||||
sha1Algorithm.reset();
|
||||
sha1Algorithm.update(salt);
|
||||
digest = sha1Algorithm.digest(text);
|
||||
}
|
||||
return digest;
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new SecurityException("Cannot hash password with salt", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the given password as md5 without appliying salt
|
||||
*
|
||||
* @param plainTextPassword the password to convert
|
||||
* @return the given password as md5 without appliying salt
|
||||
*
|
||||
* @throws SecurityException if the passwor cannot be converted
|
||||
*/
|
||||
private static byte[] getBase64MD5HashedPassword(final String plainTextPassword) throws SecurityException {
|
||||
try {
|
||||
MessageDigest algorithm = MessageDigest.getInstance("MD5");
|
||||
algorithm.reset();
|
||||
algorithm.update(plainTextPassword.getBytes());
|
||||
byte[] messageDigest = algorithm.digest();
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (int i = 0; i < messageDigest.length; i++) {
|
||||
int halfbyte = (messageDigest[i] >>> 4) & 0x0F;
|
||||
int twoHalfs = 0;
|
||||
do {
|
||||
if ((0 <= halfbyte) && (halfbyte <= 9)) {
|
||||
buf.append((char) ('0' + halfbyte));
|
||||
} else {
|
||||
buf.append((char) ('a' + (halfbyte - 10)));
|
||||
}
|
||||
halfbyte = messageDigest[i] & 0x0F;
|
||||
} while (twoHalfs++ < 1);
|
||||
}
|
||||
|
||||
// take password and hash with salt
|
||||
byte[] unHashedPassword = base64Decode(buf.toString());
|
||||
|
||||
return unHashedPassword;
|
||||
} catch (Exception ex) {
|
||||
throw new SecurityException("Cannot created password", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the plain byte[] as base64 coded string
|
||||
*
|
||||
* @param data the data to convert
|
||||
* @return the plain byte[] as base64 coded string
|
||||
*/
|
||||
private static String base64Encode(final byte[] data) {
|
||||
Base64 encoder = new Base64();
|
||||
byte[] result = encoder.encode(data);
|
||||
return new String(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the given base64 coded string as decoded byte[]
|
||||
*
|
||||
* @param data the string to convert
|
||||
* @return the given base64 coded string as decoded byte[]
|
||||
*/
|
||||
private static byte[] base64Decode(final String data) {
|
||||
Base64 decoder = new Base64();
|
||||
return decoder.decode(data.getBytes());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
package de.muehlencord.shared.security;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
*/
|
||||
public class SecurityException extends Exception {
|
||||
|
||||
public SecurityException() {
|
||||
super ("An error occured during a security action");
|
||||
}
|
||||
|
||||
public SecurityException(String msg) {
|
||||
super (msg);
|
||||
}
|
||||
|
||||
public SecurityException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public SecurityException(Throwable cause) {
|
||||
super (cause);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package de.muehlencord.shared.security;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
*/
|
||||
public class PasswordUtilTest {
|
||||
|
||||
public PasswordUtilTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test of createSaltString method, of class PasswordUtil.
|
||||
*/
|
||||
@Test
|
||||
public void createSaltString() throws Exception {
|
||||
System.out.println("createSaltString");
|
||||
int saltLength = 40;
|
||||
String result = PasswordUtil.createSaltString(saltLength);
|
||||
assertNotNull(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getMD5Password method, of class PasswordUtil.
|
||||
*/
|
||||
@Test
|
||||
public void getMD5Password() throws Exception {
|
||||
System.out.println("getMD5Password");
|
||||
String plainTextPassword = "";
|
||||
int saltLength = 40;
|
||||
String[] result1 = PasswordUtil.getMD5Password(plainTextPassword, saltLength);
|
||||
String password1 = result1[0];
|
||||
String salt1 = result1[1];
|
||||
assertNotNull(result1);
|
||||
assertNotNull(password1);
|
||||
assertNotNull(salt1);
|
||||
|
||||
String[] result2 = PasswordUtil.getMD5Password(plainTextPassword, saltLength);
|
||||
String password2 = result2[0];
|
||||
String salt2 = result2[1];
|
||||
assertNotNull(result2);
|
||||
assertNotNull(password2);
|
||||
assertNotNull(salt2);
|
||||
|
||||
assertNotSame(result1, result2);
|
||||
assertNotSame(password1, password2);
|
||||
assertNotSame(salt1, salt2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test of checkPassword method, of class PasswordUtil.
|
||||
*/
|
||||
@Test
|
||||
public void checkPassword() throws Exception {
|
||||
System.out.println("checkPassword");
|
||||
String plainTextPassword = "welcome";
|
||||
String plainTextPassword2 = "this is not the correct password";
|
||||
|
||||
String[] data = PasswordUtil.getMD5Password(plainTextPassword, 40);
|
||||
String cryptedPassword = data[0];
|
||||
String salt = data[1];
|
||||
|
||||
String salt2 = PasswordUtil.createSaltString(40);
|
||||
String salt3 = PasswordUtil.createSaltString(10);
|
||||
|
||||
boolean expResult = true;
|
||||
boolean result = PasswordUtil.checkPassword(plainTextPassword, cryptedPassword, salt);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
expResult = false;
|
||||
result = PasswordUtil.checkPassword(plainTextPassword2, cryptedPassword, salt);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
expResult = false;
|
||||
result = PasswordUtil.checkPassword(plainTextPassword, cryptedPassword, salt2);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
expResult = false;
|
||||
result = PasswordUtil.checkPassword(plainTextPassword, cryptedPassword, salt3);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user