Commit 9a8d8d05 by Tuomas Riihimäki

Added initial ldap management

1 parent 538ca73a
......@@ -34,7 +34,10 @@ public class BootstrapBean implements BootstrapBeanLocal {
dbUpdates.add(new String[] { "DELETE FROM application_permissions WHERE application = 'MAP' and permission = 'RELEASE_PLACE'" });
dbUpdates.add(new String[] { "ALTER TABLE site_page_content ADD COLUMN locale varchar(10)" });
dbUpdates.add(new String[] { "ALTER TABLE products ALTER COLUMN vat TYPE NUMERIC(4,3)" });
dbUpdates.add(new String[] { "ALTER TABLE roles ADD ldap_role boolean not null default false" });
dbUpdates.add(new String[] {
"ALTER TABLE organisation_roles ADD ldap_role boolean not null default false",
"ALTER TABLE organisation_roles add ldap_weight integer NOT NULL default 100"
});
}
@EJB
......
package fi.codecrew.moya.beans;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import fi.codecrew.moya.beanutil.LdapUserHandler;
import fi.codecrew.moya.model.LanEventPrivatePropertyKey;
/**
* Session Bean implementation class LdapBean
*/
@Stateless
@LocalBean
public class LdapBean implements LdapBeanLocal {
@EJB
private EventBean eventbean;
/**
* Default constructor.
*/
public LdapConnection getConnection() {
String ldapurl = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.LDAP_URL);
String userBase = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.LDAP_USER_OU);
String groupBase = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.LDAP_GROUP_OU);
LdapConnection conn = null;
if (ldapurl != null && !ldapurl.isEmpty() && userBase != null && !userBase.isEmpty() && groupBase != null && !groupBase.isEmpty()) {
String bindDn = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.LDAP_BIND_DN);
String bindPw = eventbean.getPrivatePropertyString(LanEventPrivatePropertyKey.LDAP_BIND_PW);
conn = new LdapConnection(ldapurl, userBase, groupBase, bindDn, bindPw);
}
return conn;
}
private static class LdapConnection extends LdapUserHandler
{
public LdapConnection(String ldapUri, String userBaseDn, String groupBaseDn, String mgmtUser, String mgmtPass) {
super(ldapUri, userBaseDn, groupBaseDn, mgmtUser, mgmtPass);
}
}
}
......@@ -55,6 +55,8 @@ public class RoleBean implements RoleBeanLocal {
@EJB
private EventUserFacade eventuserfacade;
private EventBeanLocal permbean;
// VIEW_ALL pitää olla että voidaan hakea roolien perusteella.
@Override
@RolesAllowed({ UserPermission.S_READ_ROLES, UserPermission.S_VIEW_ALL })
......@@ -165,6 +167,11 @@ public class RoleBean implements RoleBeanLocal {
return role;
}
private void checkRoleLdap()
{
}
@Override
@RolesAllowed(UserPermission.S_WRITE_ROLES)
public Role addRole(EventUser eventuser, Role role)
......
......@@ -167,6 +167,8 @@ public class UserBean implements UserBeanLocal {
// private EventUser currentEventuser;
// private ArrayList<Role> currentEventuserRoles;
// HUOMHUOM! Älä määrittele tätä UserBeanLocal interfacelle.
// Käytä Viewien puolelta findUsersRoles joka tarkistaa käyttäjän oikeudet ensin.
public Set<Role> localFindUsersRoles(EventUser u) {
// if (currentEventuser != null && u.equals(currentEventuser)) {
// logger.debug("Returnin cached eventuserroles for user {}: {}",
......
package fi.codecrew.moya.beanutil;
/**
* Copyright Iudex / Tuomas Riihimäki
*
*/
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import javax.naming.AuthenticationException;
import javax.naming.CommunicationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.OrgRole;
import fi.codecrew.moya.utilities.PasswordFunctions;
public class LdapUserHandler {
private final String ldapURI;
private final String userBaseDn;
//private final String roleBaseDn;
private final String mgmtPass;
private final String mgmtUser;
private final String roleBaseDn;
private String fallbackuser = null;
private String fallbackpass = null;
private static final String MEMBER_OF_FIELD = "memberOf";
private static final Logger logger = LoggerFactory.getLogger(LdapUserHandler.class);
private static final Charset LATIN1 = Charset.forName("ISO-8859-1");
private Integer gidBase = 20000;
private Integer uidBase = 20000;
public enum PasswordChangeStatus {
PWD_CHANGED, PWD_COMPLEXITY_NOT_MET, UNKNOWN_ERROR, WRONG_PASSWORD, UNKNOWN_USER,
}
public LdapUserHandler(String ldapUri, String userBaseDn, String roleBaseDn, String mgmtUser, String mgmtPass)
{
this.ldapURI = ldapUri;
this.userBaseDn = userBaseDn;
this.roleBaseDn = roleBaseDn;
this.mgmtUser = mgmtUser;
this.mgmtPass = mgmtPass;
}
protected InitialLdapContext getContext() throws NamingException {
return createInitialContext(mgmtUser, mgmtPass, true);
}
private InitialLdapContext createInitialContext(String userRDN, String password, boolean pool) throws NamingException {
Hashtable<String, String> authEnv = new Hashtable<String, String>(11);
authEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
authEnv.put(Context.PROVIDER_URL, ldapURI);
if (password != null && userRDN != null && !userRDN.isEmpty()) {
authEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
authEnv.put(Context.SECURITY_PRINCIPAL, userRDN);
authEnv.put(Context.SECURITY_CREDENTIALS, password);
authEnv.put(Context.REFERRAL, "follow");
if (ldapURI.startsWith("ldaps"))
{
authEnv.put("java.naming.ldap.factory.socket",
"fi.iudex.utils.ldap.NocheckSSLSocketFactory");
authEnv.put(Context.SECURITY_PROTOCOL, "ssl");
}
if (pool) {
// Default AD timeout value is 900..
authEnv.put("com.sun.jndi.ldap.connect.pool.timeout", "900");
authEnv.put("com.sun.jndi.ldap.connect.pool", "true");
}
// authEnv.put(Context.SECURITY_PROTOCOL, "ssl");
}
return new InitialLdapContext(authEnv, null);
}
protected List<String> createLdapAttrSingleAttrSearch(String baseDn, String filter, String field) {
Map<String, List<String>> retMap = createLdapAttrUniqueDnSearch(baseDn, filter, field);
List<String> ret = null;
if (retMap != null) {
ret = retMap.get(field);
}
return ret;
}
protected Map<String, List<String>> createLdapAttrUniqueDnSearch(String baseDn, String filter, String... fields)
{
Map<String, Map<String, List<String>>> retMap = createLdapAttrSearch(baseDn, filter, fields);
Map<String, List<String>> ret = null;
if (retMap != null) {
if (retMap.isEmpty()) {
ret = new HashMap<>();
} else if (retMap.size() != 1) {
throw new RuntimeException("Got multiple results for attribute search with filter: " + filter);
} else {
ret = retMap.values().iterator().next();
}
}
return ret;
}
protected Map<String, Map<String, List<String>>> createLdapAttrSearch(String baseDn, String filter, String... fields)
{
InitialLdapContext ctx = null;
Map<String, Map<String, List<String>>> ret = new HashMap<>();
try {
ctx = getContext();
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
ctls.setReturningAttributes(fields);
NamingEnumeration<SearchResult> results = ctx.search(baseDn, filter, ctls);
while (results.hasMore())
{
SearchResult result = results.next();
logger.info("Got dn:{}", result.getName());
Map<String, List<String>> resultAttrs = ret.get(result.getName());
if (resultAttrs == null) {
resultAttrs = new HashMap<>();
ret.put(result.getName(), resultAttrs);
}
NamingEnumeration<? extends Attribute> searchAttrs = result.getAttributes().getAll();
while (searchAttrs.hasMore()) {
Attribute next = searchAttrs.next();
logger.info("Got {}, {}, {}", next.getID(), next.get(), searchAttrs.hasMore());
if (next == null || next.get() == null)
continue;
List<String> resultList = resultAttrs.get(next.getID());
if (resultList == null) {
resultList = new ArrayList<>();
resultAttrs.put(next.getID(), resultList);
}
NamingEnumeration<?> searchField = next.getAll();
while (searchField.hasMore()) {
Object fieldResult = searchField.next();
if (fieldResult != null) {
resultList.add(fieldResult.toString());
}
}
}
}
} catch (NamingException e) {
logger.warn("Error searching parameters", e);
} finally {
close(ctx);
}
return ret;
}
// public Set<String> getMemberships(String user) {
// Set<String> rolenames = new HashSet<String>();
// InitialLdapContext ctx = null;
// try {
// ctx = getContext();
// NamingEnumeration<SearchResult> roleSearch = getLdapParameters(ctx, user, MEMBER_OF_FIELD);
// if (roleSearch.hasMore())
// {
// SearchResult result = roleSearch.next();
//
// if (roleSearch.hasMore()) {
// logger.warn("Found multiple users Clearing usergroups! {}", roleSearch.next());
// return null;
// }
// Attribute groupAttrs = result.getAttributes().get(MEMBER_OF_FIELD);
//
// if (groupAttrs != null) {
// NamingEnumeration<?> roleOUs = groupAttrs.getAll();
// while (roleOUs.hasMore()) {
// String roleObject = roleOUs.next().toString();
// Matcher roleFinder = GROUP_PATTERN.matcher(roleObject);
//
// if (roleFinder.find()) {
// String roleName = roleFinder.group(1);
// logger.info("Got group {} to user {}", roleName, user);
// rolenames.add(roleName);
// }
// else {
// logger.info("role pattern did not match {}", roleObject);
// }
// }
// }
//
// }
// } catch (CommunicationException ce) {
// rolenames = null;
// logger.info("Error connecting to server", ce);
//
// } catch (NamingException e) {
// logger.warn("Error while getting group names.", e);
// } finally {
// close(ctx);
// }
// return rolenames;
//
// }
protected NamingEnumeration<SearchResult> getLdapParameters(InitialLdapContext ctx, String user, String... attrs) throws NamingException {
StringBuilder filter = new StringBuilder("(&(objectClass=posixAccount)(uid=").append(user).append("))");
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
ctls.setReturningAttributes(attrs);
return ctx.search(this.userBaseDn, filter.toString(), ctls);
}
public String createUser(EventUser user, List<OrgRole> roles)
{
InitialLdapContext ctx = null;
OrgRole primary = null;
for (OrgRole role : roles) {
if (role.isLdapRole() && (primary == null || primary.getLdapWeight() < role.getLdapWeight())) {
primary = role;
}
}
String dnStr = null;
try {
StringBuilder dnBld = new StringBuilder();
dnBld.append("uid=").append(user.getLogin());
dnBld.append(",ou=").append(primary.getName());
dnBld.append(",").append(userBaseDn);
String dn = dnBld.toString();
ctx = getContext();
BasicAttributes entry = new BasicAttributes();
entry.put(new BasicAttribute("uid", user.getLogin()));
entry.put(new BasicAttribute("givenName", user.getFirstnames()));
entry.put(new BasicAttribute("sn", user.getLastname()));
entry.put(new BasicAttribute("cn", user.getWholeName()));
entry.put(new BasicAttribute("loginShell", "/bin/bash"));
entry.put(new BasicAttribute("homeDirectory", user.getLogin()));
entry.put(new BasicAttribute("uidNumber", uidBase + user.getId()));
entry.put(new BasicAttribute("gidNumber", gidBase + primary.getId()));
entry.put(new BasicAttribute("userPassword", user.getPassword()));
entry.put(new BasicAttribute("mail", user.getEmail()));
BasicAttribute oc = new BasicAttribute("objectClass");
oc.add("inetOrgPerson");
oc.add("posixAccount");
oc.add("shadowAccount");
oc.add("person");
oc.add("organizationalPerson");
entry.put(oc);
ctx.createSubcontext(dn, entry);
dnStr = dn;
} catch (NamingException e) {
logger.warn("Error while creating user to ldap");
} finally {
close(ctx);
}
return dnStr;
}
protected String buildUserRdn(String username) {
InitialLdapContext ctx = null;
String ret = null;
try {
ctx = getContext();
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
ctls.setReturningAttributes(new String[] { "dn" });
NamingEnumeration<SearchResult> result = ctx.search(this.userBaseDn, "uid=" + username, ctls);
if (result.hasMore()) {
SearchResult dn = result.next();
ret = dn.getNameInNamespace();
}
} catch (NamingException e) {
logger.warn("Error building RDN", e);
} finally {
close(ctx);
}
return ret;
}
public boolean authenticate(String username, char[] passwd) {
String pwd = new String(passwd);
if (username == null || passwd == null || username.isEmpty() || pwd.isEmpty()) {
return false;
}
InitialLdapContext userCtx = null;
try {
String userDn = buildUserRdn(username);
if (userDn == null || userDn.isEmpty()) {
logger.info("Username {}, not found when authenticating");
return false;
}
userCtx = createInitialContext(userDn, pwd, false);
return true;
} catch (AuthenticationException authEx) {
logger.info("Authentication failed!", authEx);
} catch (CommunicationException ce) {
// If ldap server can not be reached, check if we are trying to auth with fallback credentials
// WARNING!!!! THIS IS A BACKDOOR! DO NOT USE IN PRODUCTION!
if (username.equals(fallbackuser) && pwd.equals(fallbackpass)) {
logger.warn("Login successfull for backupuser. ");
return true;
} else {
logger.info("Error connecting to ldapserver", ce);
}
} catch (NamingException e) {
logger.warn("Error connecting to auth context", e);
} finally {
close(userCtx);
}
return false;
}
protected void close(InitialLdapContext userCtx) {
try {
if (userCtx != null) {
userCtx.close();
}
userCtx = null;
} catch (NamingException e) {
logger.warn("Error closing...", e);
}
}
public PasswordChangeStatus changePassword(String username, String oldPwd, String newPwd) {
InitialLdapContext userCtx = null;
try {
String newHash = PasswordFunctions.getEncryptedPassword(newPwd);
String userDn = buildUserRdn(username);
if (userDn == null || userDn.isEmpty()) {
return PasswordChangeStatus.UNKNOWN_USER;
}
logger.info("Chpass {} for user {} ", newHash, userDn);
userCtx = createInitialContext(userDn, oldPwd, false);
ModificationItem[] mods = new ModificationItem[1];
Attribute mod0 = new BasicAttribute("userpassword", newHash);
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, mod0);
userCtx.modifyAttributes(userDn, mods);
} catch (NamingException e) {
logger.warn("Error changing password", e);
return PasswordChangeStatus.UNKNOWN_ERROR;
} finally {
close(userCtx);
}
return PasswordChangeStatus.PWD_CHANGED;
}
protected void setFallbackpass(String fallbackpass) {
this.fallbackpass = fallbackpass;
}
protected void setFallbackuser(String fallbackuser) {
this.fallbackuser = fallbackuser;
}
}
package fi.codecrew.moya.beans;
import javax.ejb.Local;
@Local
public interface LdapBeanLocal {
}
......@@ -57,6 +57,28 @@ public class OrgRole extends GenericEntity {
@ManyToMany(mappedBy = "orgRoles")
private List<Role> eventRoles;
@Column(name = "ldap_role", nullable = false)
private boolean ldapRole = false;
@Column(name = "ldap_weight", nullable = false)
private int ldapWeight = 100;
public boolean isLdapRole() {
return ldapRole;
}
public void setLdapRole(boolean ldapRole) {
this.ldapRole = ldapRole;
}
public int getLdapWeight() {
return ldapWeight;
}
public void setLdapWeight(int ldapWeight) {
this.ldapWeight = ldapWeight;
}
public OrgRole() {
super();
}
......
......@@ -83,9 +83,6 @@ public class Role extends GenericEntity {
inverseJoinColumns = { @JoinColumn(name = "org_role_id", referencedColumnName = OrgRole.ID_COLUMN) })
private List<OrgRole> orgRoles;
@Column(name = "ldap_role", nullable = false)
private boolean ldapRole = false;
public Role() {
super();
}
......@@ -209,12 +206,4 @@ public class Role extends GenericEntity {
this.orgRoles = orgRoles;
}
public boolean isLdapRole() {
return ldapRole;
}
public void setLdapRole(boolean ldapRole) {
this.ldapRole = ldapRole;
}
}
......@@ -5,6 +5,6 @@
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
<property name="java-output-path" value="/MoyaEventMgmtWeb/build/classes"/>
<property name="context-root" value="moya-mgmt-web"/>
<property name="component.inclusion.patterns" value="WEB-INF/lib/javamelody-core*,WEB-INF/lib/primefaces*,**/*.xml,**/*.xhtml,**/*.properties,**/*.class,**/*.png,**/*.css,**/*.js,resources/*"/>
<property name="component.inclusion.patterns" value="WEB-INF/lib/prettyfaces-core*,WEB-INF/lib/javamelody-core*,WEB-INF/lib/primefaces*,**/*.xml,**/*.xhtml,**/*.properties,**/*.class,**/*.png,**/*.css,**/*.js,resources/*"/>
</wb-module>
</project-modules>
package fi.codecrew.moya.utilities;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Copyright Iudex / Tuomas Riihimäki
*
*/
public class ByteUtils {
public static int parseUnsigned(byte... b) {
if (b.length > 4) {
throw new RuntimeException("Integer should never have more than 4 bytes!");
}
return new BigInteger(1, b).intValue();
}
public static Long parseUnsignedLong(byte[] b) {
if (b.length > 8) {
throw new RuntimeException("Long should never have more than 4 bytes!");
}
return new BigInteger(1, b).longValue();
}
public static short parseSigned(byte b0, byte b1) {
return (short) (((b0 & 0xff) << 8) | (b1 & 0xff));
}
public static Integer parseSignedO(byte b, byte c) {
return Integer.valueOf(parseSigned(b, c));
}
public static Integer parseSigned(byte b1, byte b2, byte b3, byte b4) {
return (b1 & 0xff) << 24 | (b2 & 0xff) << 16 | (b3 & 0xff) << 8 | (b4 & 0xff);
}
public static void main(String[] ads)
{
System.out.println(parseUnsigned((byte) 0x31, (byte) 0x79));
// System.out.println(parseSignedDecimal("+5.123"));
// System.out.println(parseSignedDecimal("-5.123"));
// System.out.println(parseSignedDecimal(" - 5123"));
// System.out.println(parseSignedDecimal(null));
// System.out.println(parseSignedDecimal(""));
// System.out.println(parseSignedDecimal(" "));
}
public static BigDecimal parseSignedDecimal(String number) {
if (number == null || (number = number.trim()).isEmpty()) {
return null;
}
number = number.trim();
char firstChar = number.charAt(0);
boolean signPositive = true;
switch (firstChar) {
case '-':
signPositive = false;
case '+':
number = number.substring(1).trim();
}
BigDecimal ret = new BigDecimal(number);
if (!signPositive) {
ret = ret.negate();
}
return ret;
}
// public static int parseSignedInt(byte... b) {
// if (b.length > 4) {
// throw new
// RuntimeException("Integer should never have more than 4 bytes!");
// }
// // return new BigInteger(1, b).intValue();
//
// int value = (b[b.length - 1] & 0xff);
// if (b.length > 1) {
// value |= (b[b.length - 2] & 0xff) << 8;
// }
// if (b.length > 2) {
// value |= (b[b.length - 3] & 0xff) << 16;
// }
// if (b.length > 3) {
// value |= (b[b.length - 4] & 0xff) << 24;
// }
// return value;
// }
/**
* Copies the integer value to four bytes in the destination bytearray beginning from the offset
*
* Notice! This function handles signed integers: -1 -> 0xff 0xff 0xff 0xff
*
* @param dst
* @param offset
* @param value
*/
public static void intToBytearray(byte[] dst, int offset, int value) {
dst[offset++] = (byte) (value >>> 24);
dst[offset++] = (byte) (value >>> 16);
dst[offset++] = (byte) (value >>> 8);
dst[offset] = (byte) (value);
}
public static byte[] toArray(int... bytes) {
byte[] ret = new byte[bytes.length];
for (int i = 0; i < bytes.length; ++i) {
ret[i] = (byte) (bytes[i]);
}
return ret;
}
public static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
int val = ((int) b) & 0xff;
if (val < 0x10)
sb.append("0");
sb.append(Integer.toHexString(val));
}
return sb.toString();
}
}
......@@ -70,7 +70,6 @@ public class JpegReader {
JpegImageParser parser = new JpegImageParser();
ByteSource byteSource = new ByteSourceFile(file);
@SuppressWarnings("rawtypes")
List<Segment> segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
if (segments != null && segments.size() >= 1) {
UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
......
package fi.codecrew.moya.utilities;
import java.security.MessageDigest;
public class MD4Digest extends MessageDigest {
/**
* The size in bytes of the input block to the tranformation algorithm.
*/
private static final int BLOCK_LENGTH = 64; // = 512 / 8;
/**
* 4 32-bit words (interim result)
*/
private int[] context = new int[4];
/**
* Number of bytes processed so far mod. 2 power of 64.
*/
private long count;
/**
* 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.
*/
private byte[] buffer = new byte[BLOCK_LENGTH];
/**
* 512 bits work buffer = 16 x 32-bit words
*/
private int[] X = new int[16];
public MD4Digest() {
super("MD4");
engineReset();
}
@Override
public void engineUpdate(byte b) {
int i = (int) (count % BLOCK_LENGTH);
count++;
buffer[i] = b;
if (i == BLOCK_LENGTH - 1)
transform(buffer, 0);
}
@Override
protected void engineUpdate(byte[] input, int offset, int len) {
// make sure we don't exceed input's allocated size/length
if (offset < 0 || len < 0 || (long) offset + len > input.length)
throw new ArrayIndexOutOfBoundsException();
// compute number of bytes still unhashed; ie. present in buffer
int bufferNdx = (int) (count % BLOCK_LENGTH);
count += len; // update number of bytes
int partLen = BLOCK_LENGTH - bufferNdx;
int i = 0;
if (len >= partLen) {
System.arraycopy(input, offset, buffer, bufferNdx, partLen);
transform(buffer, 0);
for (i = partLen; i + BLOCK_LENGTH - 1 < len; i += BLOCK_LENGTH)
transform(input, offset + i);
bufferNdx = 0;
}
// buffer remaining input
if (i < len)
System.arraycopy(input, offset + i, buffer, bufferNdx, len - i);
}
@Override
protected byte[] engineDigest() {
// pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
int bufferNdx = (int) (count % BLOCK_LENGTH);
int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx);
// padding is alwas binary 1 followed by binary 0s
byte[] tail = new byte[padLen + 8];
tail[0] = (byte) 0x80;
// append length before final transform:
// save number of bits, casting the long to an array of 8 bytes
// save low-order byte first.
for (int i = 0; i < 8; i++)
tail[padLen + i] = (byte) ((count * 8) >>> (8 * i));
engineUpdate(tail, 0, tail.length);
byte[] result = new byte[16];
// cast this MD4's context (array of 4 ints) into an array of 16 bytes.
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
result[i * 4 + j] = (byte) (context[i] >>> (8 * j));
// reset the engine
engineReset();
return result;
}
@Override
protected void engineReset() {
// initial values of MD4 i.e. A, B, C, D
// as per rfc-1320; they are low-order byte first
context[0] = 0x67452301;
context[1] = 0xEFCDAB89;
context[2] = 0x98BADCFE;
context[3] = 0x10325476;
count = 0L;
for (int i = 0; i < BLOCK_LENGTH; i++)
buffer[i] = 0;
}
/**
* MD4 basic transformation.
* <p>
* Transforms context based on 512 bits from input block starting from the offset'th byte.
*
* @param block
* input sub-array.
* @param offset
* starting position of sub-array.
*/
private void transform(byte[] block, int offset) {
// encodes 64 bytes from input block into an array of 16 32-bit
// entities. Use A as a temp var.
for (int i = 0; i < 16; i++)
X[i] = (block[offset++] & 0xFF) |
(block[offset++] & 0xFF) << 8 |
(block[offset++] & 0xFF) << 16 |
(block[offset++] & 0xFF) << 24;
int A = context[0];
int B = context[1];
int C = context[2];
int D = context[3];
A = FF(A, B, C, D, X[0], 3);
D = FF(D, A, B, C, X[1], 7);
C = FF(C, D, A, B, X[2], 11);
B = FF(B, C, D, A, X[3], 19);
A = FF(A, B, C, D, X[4], 3);
D = FF(D, A, B, C, X[5], 7);
C = FF(C, D, A, B, X[6], 11);
B = FF(B, C, D, A, X[7], 19);
A = FF(A, B, C, D, X[8], 3);
D = FF(D, A, B, C, X[9], 7);
C = FF(C, D, A, B, X[10], 11);
B = FF(B, C, D, A, X[11], 19);
A = FF(A, B, C, D, X[12], 3);
D = FF(D, A, B, C, X[13], 7);
C = FF(C, D, A, B, X[14], 11);
B = FF(B, C, D, A, X[15], 19);
A = GG(A, B, C, D, X[0], 3);
D = GG(D, A, B, C, X[4], 5);
C = GG(C, D, A, B, X[8], 9);
B = GG(B, C, D, A, X[12], 13);
A = GG(A, B, C, D, X[1], 3);
D = GG(D, A, B, C, X[5], 5);
C = GG(C, D, A, B, X[9], 9);
B = GG(B, C, D, A, X[13], 13);
A = GG(A, B, C, D, X[2], 3);
D = GG(D, A, B, C, X[6], 5);
C = GG(C, D, A, B, X[10], 9);
B = GG(B, C, D, A, X[14], 13);
A = GG(A, B, C, D, X[3], 3);
D = GG(D, A, B, C, X[7], 5);
C = GG(C, D, A, B, X[11], 9);
B = GG(B, C, D, A, X[15], 13);
A = HH(A, B, C, D, X[0], 3);
D = HH(D, A, B, C, X[8], 9);
C = HH(C, D, A, B, X[4], 11);
B = HH(B, C, D, A, X[12], 15);
A = HH(A, B, C, D, X[2], 3);
D = HH(D, A, B, C, X[10], 9);
C = HH(C, D, A, B, X[6], 11);
B = HH(B, C, D, A, X[14], 15);
A = HH(A, B, C, D, X[1], 3);
D = HH(D, A, B, C, X[9], 9);
C = HH(C, D, A, B, X[5], 11);
B = HH(B, C, D, A, X[13], 15);
A = HH(A, B, C, D, X[3], 3);
D = HH(D, A, B, C, X[11], 9);
C = HH(C, D, A, B, X[7], 11);
B = HH(B, C, D, A, X[15], 15);
context[0] += A;
context[1] += B;
context[2] += C;
context[3] += D;
}
private int FF(int a, int b, int c, int d, int x, int s) {
int t = a + ((b & c) | (~b & d)) + x;
return t << s | t >>> (32 - s);
}
private int GG(int a, int b, int c, int d, int x, int s) {
int t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999;
return t << s | t >>> (32 - s);
}
private int HH(int a, int b, int c, int d, int x, int s) {
int t = a + (b ^ c ^ d) + x + 0x6ED9EBA1;
return t << s | t >>> (32 - s);
}
}
package fi.codecrew.moya.utilities;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Copyright Iudex / Tuomas Riihimäki
*
*/
public class NTLMFunctions {
private static final Charset UTF16LE_ENCODING = Charset.forName("UTF-16LE");
private static final Logger logger = LoggerFactory.getLogger(NTLMFunctions.class);
public static String getNTHash(String passAttr)
{
StringBuilder pwd = new StringBuilder();
// pwd.append('"');
pwd.append(passAttr);
// pwd.append('"');
String ret = null;
try {
byte pwdBytes[] = pwd.toString().getBytes(UTF16LE_ENCODING);
//MD4 algo = new MD4();
MessageDigest algo = new MD4Digest();
byte[] bytes = algo.digest(pwdBytes);
ret = ByteUtils.toHexString(bytes);
//logger.info("hex: {}", ret);
} finally {
}
return ret;
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!