first commit

This commit is contained in:
jomu
2013-02-06 22:06:43 +00:00
parent 1a6d3e4c41
commit aef92c311d
84 changed files with 5334 additions and 0 deletions

30
jmpass/pom.xml Normal file
View File

@ -0,0 +1,30 @@
<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>jmpass</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jmpass</name>
<url>http://www.mühlencord.de/</url>
<issueManagement>
<system>Bugzilla</system>
<url>https://jomu.timelord.de/bugzilla/</url>
</issueManagement>
<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>
</dependencies>
</project>

View File

@ -0,0 +1,56 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.jmpass;
/**
*
* @author jomu
*/
public class Bcrypt {
// http://en.wikipedia.org/wiki/Bcrypt
public String bcrypt(long cost, byte[] salt, String input) {
String state = eksBlowfishSetup(cost, salt, input);
String cText = "OrpheanBeholderScryDoubt"; // FIXME - what is this string for, 3 64 bit blocks
for (int i=0; i<64; i++) { // FIXME - why 64?
cText = encryptECB(state, cText);
}
return concatenate(cost, salt, cText);
}
private String eksBlowfishSetup(long cost, String salt, String key) {
String state = initState();
state = expandKey (state, salt, key);
// TODO buffer overflow check, max size of cost
long rounds = Math.round(Math.pow(2, cost));
for (int i=0; i<rounds; i++) {
state = expandKey (state, 0, key);
state = expandKey (state, 0, salt);
}
}
private String initState() {
throw new UnsupportedOperationException("Not yet implemented");
}
private String expandKey(String state, String salt, String input) {
throw new UnsupportedOperationException("Not yet implemented");
}
private String encryptECB(String state, String cText) {
throw new UnsupportedOperationException("Not yet implemented");
}
private String concatenate(long cost, byte[] salt, String cText) {
throw new UnsupportedOperationException("Not yet implemented");
}
}

View File

@ -0,0 +1,82 @@
package de.muehlencord.shared.jmpass;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
*
* @author joern@muehlencord.de
*/
public class Password {
private final static int SALT_BYTES = 16;
private long rounds;
private byte[] hash;
private byte[] salt;
public Password(int iterations) {
rounds = Math.round(Math.pow(2, iterations));
}
public void hashPassword(String password) throws PasswordException {
try {
salt = createSalt();
hash = createHash(password, salt);
} catch (Exception ex) {
throw new PasswordException("Error while hashing password. Reason: " + ex.getMessage(), ex);
}
}
public String getPasswordHashString() {
StringBuilder sb = new StringBuilder();
sb.append("$");
sb.append(rounds);
sb.append("$");
sb.append(salt);
sb.append(hash);
return sb.toString();
}
private int getIterationsFromString(String hashedPassword) throws PasswordException {
if (hashedPassword.length() < 20) {
throw new PasswordException("Given string is not a valid hashed password");
}
String roundsString = hashedPassword.substring(0, 3);
if ((!roundsString.startsWith("$")) || (!roundsString.endsWith("$"))) {
throw new PasswordException("Cannot read iterations value from given string");
}
try {
int rounds = Integer.parseInt(roundsString.substring(1, 2));
return rounds;
} catch (Exception ex) {
throw new PasswordException("Cannot parse iterations value from given string", ex);
}
}
private byte[] createSalt() throws NoSuchAlgorithmException {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
// Salt generation 64 bits long
byte[] bSalt = new byte[SALT_BYTES];
random.nextBytes(bSalt);
return bSalt;
}
private byte[] createHash(String password, byte[] salt) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
digest.update(salt);
byte[] input = digest.digest(password.getBytes("UTF-8"));
for (int i = 0; i < rounds; i++) {
digest.reset();
input = digest.digest(input);
}
return input;
}
}

View File

@ -0,0 +1,26 @@
package de.muehlencord.shared.jmpass;
/**
*
* @author joern@muehlencord.de
*/
class PasswordException extends Exception {
/**
* creats an instance of PasswordException with the given message
* @param msg the msg of the exception
*/
public PasswordException(String msg) {
super (msg);
}
/**
* creats an instance of PasswordException with the given message
* @param msg the msg of the exception
* @param th the causing exception
*/
public PasswordException(String msg, Throwable th) {
super (msg);
}
}

View File

@ -0,0 +1,16 @@
package de.muehlencord.shared.jmpass;
/**
*
* @author joern@muehlencord.de
*/
public class PasswordValidator {
public static boolean validatePassword(String plainPassword, String hashedPassword) {
Password pw = new Password(8);
pw.hashPassword(plainPassword);
String hash = pw.getPasswordHashString();
return hashedPassword.equals(hash);
}
}

View File

@ -0,0 +1,38 @@
package de.muehlencord.shared.jmpass;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}