首页 > java > JAVA实现PHP的crypt函数

JAVA实现PHP的crypt函数

在使用Suitecrm的过程中,需要使用java代码实现注册登录功能,并且还得让java端注册的用户仍然可以登录php管理后台。阅读Suitecrm的登陆注册代码之后,找到了计算user_hash值的函数:

/modules/Users/User.php

/**
 * Generate a new hash from plaintext password
 * @param string $password
 */
public static function getPasswordHash($password)
{
	if(!defined('CRYPT_MD5') || !constant('CRYPT_MD5')) {
		// does not support MD5 crypt - leave as is
		if(defined('CRYPT_EXT_DES') && constant('CRYPT_EXT_DES')) {
			return crypt(strtolower(md5($password)),
				"_.012".substr(str_shuffle('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), -4));
		}
		// plain crypt cuts password to 8 chars, which is not enough
		// fall back to old md5
		return strtolower(md5($password));
	}
	return @crypt(strtolower(md5($password)));
}
/**
 * Check that password matches existing hash
 * @param string $password Plaintext password
 * @param string $user_hash DB hash
 */
public static function checkPassword($password, $user_hash)
{
	return self::checkPasswordMD5(md5($password), $user_hash);
}

/**
 * Check that md5-encoded password matches existing hash
 * @param string $password MD5-encoded password
 * @param string $user_hash DB hash
 * @return bool Match or not?
 */
public static function checkPasswordMD5($password_md5, $user_hash)
{
	if(empty($user_hash)) return false;
	if($user_hash[0] != '$' && strlen($user_hash) == 32) {
		// Old way - just md5 password
		return strtolower($password_md5) == $user_hash;
	}
	return crypt(strtolower($password_md5), $user_hash) == $user_hash;
}


可以看出注册的加密流程只有2步,第一步将用户提交的密码进行md5(小写值),第二步将md5后的值使用crypt计算出user_hash存到数据库中即可。


通过http://stackoverflow.com/questions/3292160/equivalent-of-phps-crypt-function-in-java得知Apache Commons Codec包中已经提供了和PHP的crypt一样的算法Md5Crypt.md5Crypt(byte[], salt)。

于是编写了下面的这个密码工具类实现了兼容:

package com.github.shuiguang.utils;

import java.security.MessageDigest;
import org.apache.commons.codec.digest.Md5Crypt;

/**
 * 与PHP兼容的crypt算法加密密码
 * 
 * @author Z
 *
 */
public class PasswordUtils {

	/**
	 * 推荐使用js将用户的密码字段进行加密后传输
	 * @param args
	 */
	public static void main(String[] args) {

		// 用户注册提交的密码
		String password = "123456";
		
		// 注册即可通过js得到md5值
		String passwordMd5 = md5(password, "UTF-8");

		// java后端通过getPasswordMd5Hash计算出密文并将passwordHash作为userHash存到数据库
		String passwordHash = getPasswordMd5Hash(passwordMd5);

		System.out.println(passwordHash);
		
		// 查询出数据库中指定用户名的userHash
		String userHash = "$1$ca/./n2.$aZZe.KhrFLJE6EAmlCuMa0";
		
		// 通过checkPasswordMD5进行加密比对passwordMd5和userHash运算后的值还是不是userHash
		boolean flag = checkPasswordMD5(passwordMd5, userHash);
		
		// 如果还是userHash说明登陆的密码正确,否则错误
		System.out.println(flag);
		
		noJsCrypt();
		
	}
	
	/**
	 * 如果在前端未经过js的md5加密传输
	 */
	public static void noJsCrypt() {
		// 用户注册提交的密码
		String password = "123456";
		
		// java后端通过getPasswordHash计算出密文并将passwordHash作为userHash存到数据库
		String passwordHash = getPasswordHash(password);

		System.out.println(passwordHash);
		
		// 查询出数据库中指定用户名的userHash
		String userHash = "$1$ca/./n2.$aZZe.KhrFLJE6EAmlCuMa0";
		
		// 通过checkPasswordMD5进行加密比对passwordMd5和userHash运算后的值还是不是userHash
		boolean flag = checkPassword(password, userHash);
		
		// 如果还是userHash说明登陆的密码正确,否则错误
		System.out.println(flag);
	}

	/**
	 * md5 加密算法
	 * 
	 * @author Z
	 * @param s
	 * @param charset
	 * @return String 加密后的32位长度的字符串
	 */
	public static String md5(String s, String charset) {
		try {
			byte[] btInput = s.getBytes(charset);
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			mdInst.update(btInput);
			byte[] md = mdInst.digest();
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < md.length; i++) {
				int val = ((int) md[i]) & 0xff;
				if (val < 16) {
					sb.append("0");
				}
				sb.append(Integer.toHexString(val));
			}
			return sb.toString();
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * 获取未md5后的密码加密密文
	 * @param password
	 * @return
	 */
	public static String getPasswordHash(String password) {
		return password == null ? null : Md5Crypt.md5Crypt(md5(password, "UTF-8").getBytes());
	}

	/**
	 * 获取md5后的密码加密密文
	 * @param password
	 * @return
	 */
	public static String getPasswordMd5Hash(String passwordMd5) {
		return passwordMd5 == null ? null : Md5Crypt.md5Crypt(passwordMd5.toLowerCase().getBytes());
	}

	/**
	 * 校验未md5后的密码password是不是和数据库中的userHash匹配
	 * @return
	 */
	public static boolean checkPassword(String password, String userHash) {
	    return password == null ? false : Md5Crypt.md5Crypt(md5(password, "UTF-8").toLowerCase().getBytes(), userHash).equals(userHash);
	}
	
	/**
	 * 校验md5后的密码passwordMd5是不是和数据库中的userHash匹配
	 * @return
	 */
	public static boolean checkPasswordMD5(String passwordMd5, String userHash) {
	    return passwordMd5 == null ? false : Md5Crypt.md5Crypt(passwordMd5.toLowerCase().getBytes(), userHash).equals(userHash);
	}

}


经过测试,在java中创建的用户可以在Suitecrm管理后台正常登陆。



本文地址:http://blog.zhengshuiguang.com/java/java-crypt.html

转载随意,但请附上文章地址:-)

标签:suitecrm crypt md5crypt

评论已关闭