`

java密码的加密与解密

阅读更多

 

package com.monitor.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class SHAEncrypt {

	/**
	 * 生成SALT的数组(86)
	 */
	private final String[] SALT_ARR = { "a", "b", "c", "d", "e", "f", "g", "h",
			"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
			"v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H",
			"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
			"V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8",
			"9", "0", ".", "-", "*", "/", "'", ":", ";", ">", "<", "~", "!",
			"@", "#", "$", "%", "^", "&", "(", ")", "{", "}", "[", "]", "|" };
	/**
	 * 循环加密次数
	 */
	private final int ENCODE_COUNT = 1000;
	/**
	 * 加密算法类型
	 */
	private final String ENCODE_TYPE = "SHA-256";
	/**
	 * SALT长度
	 */
	private final int SALT_LENGTH = 16;
	/**
	 * getBytes时指定使用的字符集
	 */
	private final String CHAR_SET = "UTF-8";

	/**
	 * 对明文密码进行SSHA-256加密,加密步骤如下: <br>
	 * 1. 生成随机salt值 <br>
	 * 2. 明文密码变形:前后各补4位0 <br>
	 * 3. 连接salt值: 将salt分成前8位temp1和剩余部分temp2,以temp2+transformedPwd+temp1的形式连接 <br>
	 * 4. 对连接后的字串进行多次SHA-256加密<br>
	 * 5. 对加密后的密文右移6位<br>
	 * 6. 将salt值转换成字节数组(utf-8)再转换成16进制字符串<br>
	 * 7. 将转换后的salt值作左移4位变形<br>
	 * 8. 连接移位后的密文和移位后的变形salt值字串<br>
	 * 9. 对连接字串右移8位作为最终加密结果<br>
	 * 
	 * @param pwd
	 *            密码明文
	 * @return 加密后的密码
	 */
	public String encryptPwd(String pwd) {
		String ret = "";
		String salt = this.genSalt();
		ret = this.encryptPwdWithSalt(pwd, salt);
		return ret;
	}

	/**
	 * 对明文密码进行SSHA-256加密,加密步骤如下: <br>
	 * 1. 明文密码变形:前后各补4位0 <br>
	 * 2. 连接salt值: 将salt分成前8位temp1和剩余部分temp2,以temp2+transformedPwd+temp1的形式连接 <br>
	 * 3. 对连接后的字串进行多次SHA-256加密<br>
	 * 4. 对加密后的密文右移6位<br>
	 * 5. 将salt值转换成字节数组(utf-8)再转换成16进制字符串<br>
	 * 6. 将转换后的salt值作左移4位变形<br>
	 * 7. 连接移位后的密文和移位后的变形salt值字串<br>
	 * 8. 对连接字串右移8位作为最终加密结果<br>
	 * 
	 * @param pwd
	 *            明文密码
	 * @param salt
	 *            用于加密的salt值
	 * @return
	 */
	private String encryptPwdWithSalt(String pwd, String salt) {
		String ret = "";
		try {
			String transformedPwd = this.transform(pwd, 4);
			// 将salt分成前8位temp1和剩余部分temp2
			// 以temp2+transformedPwd+temp1的形式连接
			String joinStr = this.joinSaltAndPwd(salt, transformedPwd);
			String encodePwd = this.encodeJoinStr(joinStr);
			String rightMovedPwd = this.rightMove(encodePwd, 6);
			String hexStrSalt = this.bytes2Hex(salt.getBytes(CHAR_SET));
			String leftMovedHexStrSalt = this.rightMove(hexStrSalt, -4);
			ret = this.rightMove(rightMovedPwd + leftMovedHexStrSalt, 8);
		} catch (Exception e) {
			ret = "";
			e.printStackTrace();
		}
		return ret;
	}

	/**
	 * 对明文/密文进行验证,检查是否一致 验证步骤如下: <br>
	 * 1. 从原密文中获取通过逆运算获取salt字串 <br>
	 * 2. 对明文密码使用salt字串再次进行加密 <br>
	 * 3. 两个密文是否一致 <br>
	 * 
	 * @param pwd
	 *            明文密码
	 * @param encPwd
	 *            密文密码
	 * @return 校验结果
	 */
	public boolean validatePwd(String pwd, String encPwd) {
		if (null == encPwd) {
			return false;
		}
		boolean ret = false;
		String salt = this.getSaltFromEncryptedPwd(encPwd);
		ret = encPwd.equals(encryptPwdWithSalt(pwd, salt));
		return ret;
	}

	/**
	 * 从密文密码中通过逆运算获取加密时使用到的salt字串 <br>
	 * 获取步骤如下: <br>
	 * 1. 对密文左移8位 <br>
	 * 2. 从尾部截取变形后的salt字串 <br>
	 * 长度为2倍原salt字串长度(因为转为16进制字节数组字串时长度会加倍) <br>
	 * 3. 对salt值的16进制字节数组字符串右移4位 <br>
	 * 4. 将变形后的salt值从16进制字节数组字符串还原成原来的字符串形式 <br>
	 * 
	 * @param encPwd
	 *            密文密码
	 * @return 加密时使用的salt字串,获取出错则返回""
	 */
	private String getSaltFromEncryptedPwd(String encPwd) {
		String ret = "";
		try {
			String leftMoved = this.rightMove(encPwd, -8);
			int hexSaltLength = SALT_LENGTH * 2;
			if(encPwd.length()<hexSaltLength){
				// 加密密码长度比16进制字节数组字串的salt值短,不可能获取得到正确的salt值
				return "";
			}
			String hexSalt = this.rightMove(leftMoved.substring(encPwd.length()
					- hexSaltLength, encPwd.length()), 4);
			ret = new String(this.hex2Bytes(hexSalt), CHAR_SET);
		} catch (Exception e) {
			ret = "";
			e.printStackTrace();
		}
		return ret;
	}

	/**
	 * 
	 * 获得随机SALT值
	 * 
	 * @return 返回一个包含字母、数字、特殊字符的16位随机数
	 */
	private String genSalt() {

		StringBuffer result = new StringBuffer();
		Random r = new Random();
		int temp = 0;
		for (int i = 0; i < this.SALT_LENGTH; i++) {
			temp = r.nextInt(this.SALT_ARR.length);
			result.append(this.SALT_ARR[temp]);
		}
		return result.toString();
	}

	/**
	 * 密码变形(前后补N位0)
	 * 
	 * @param pwd
	 *            密码原文
	 * @param n
	 *            补0的个数
	 * @return 返回一个密码前后补N位0的字符串
	 */
	private String transform(String pwd, int n) {
		String toTransform = null == pwd ? "" : pwd;
		StringBuffer temp = new StringBuffer();
		for (int i = 0; i < n; i++)
			temp.append("0");
		return temp.toString() + toTransform + temp.toString();
	}

	/**
	 * 
	 * 把指定字符串右移N位,若N<0则为左移
	 * 
	 * @param src
	 *            源字符串
	 * @param n
	 *            右移的位数
	 * @return 返回一个右移N位的字符串
	 */
	private String rightMove(String src, int n) {
		if (src == null || src.length() == 0) {
			return src;
		}
		boolean isRight = true;
		int absN = n;
		if (n < 0) {
			isRight = false;
			absN = -n;
		}
		int cnt = absN > src.length() ? absN % src.length() : absN;
		if (0 == cnt) {
			return src;
		}
		if (isRight) {
			// 右移cnt位
			String temp1 = src.substring(src.length() - cnt, src.length());
			String temp2 = src.substring(0, src.length() - cnt);
			return temp1 + temp2;
		} else {
			// 左移cnt位
			String temp1 = src.substring(0, cnt);
			String temp2 = src.substring(cnt, src.length());
			return temp2 + temp1;
		}
	}

	/**
	 * 
	 * 把对应的随机数分成2部分,前半部分8个字符,调换顺序后把变形密码加到中间
	 * 
	 * @param pwd
	 *            变形密码
	 * @param salt
	 *            对应的随机数
	 * @return 返回一个随机数与变形密码连接的字符串
	 */
	private String joinSaltAndPwd(String salt, String pwd) {
		if(salt.length()!=SALT_LENGTH){
			// salt值的长度与给定的不符(校验的时候可能会出现)
			// 返回pwd+salt
			return pwd+salt;
		}
		String temp1 = salt.substring(0, 8);
		String temp2 = salt.substring(8, salt.length());
		return temp2 + pwd + temp1;
	}

	/**
	 * 
	 * 使用加密算法进行多次加密
	 * 
	 * @param joinStr
	 *            连接字符串
	 * @return 返回一个多次加密后的字符串
	 */
	private String encodeJoinStr(String joinStr) {

		if (joinStr == null)
			return null;

		String temp = joinStr;

		for (int i = 0; i < this.ENCODE_COUNT; i++) {

			temp = this.encrypt(temp);
		}
		return temp;
	}

	/**
	 * 把字节数组输出成16进制字符串
	 * 
	 * @param bts
	 * @return
	 */
	private String bytes2Hex(byte[] bts) {
		StringBuffer des = new StringBuffer();
		String tmp = null;
		for (int i = 0; i < bts.length; i++) {
			tmp = (Integer.toHexString(bts[i] & 0xFF));
			if (tmp.length() == 1) {
				des.append("0");
			}
			des.append(tmp);
		}
		return des.toString();
	}

	/**
	 * 把16进制字符串输出成字节数组
	 * 
	 * @param hexStr
	 * @return
	 */
	private byte[] hex2Bytes(String hexStr) {
		if ((hexStr.length() % 2) != 0) {
			return new byte[] {};
		}
		byte[] ret = new byte[hexStr.length() / 2];
		for (int i = 0; i < hexStr.length() / 2; i++) {

			ret[i] = (byte) (Long.decode("0x"
					+ hexStr.substring(i * 2, i * 2 + 2)) & 0xFF);
		}
		return ret;
	}

	/**
	 * 
	 * 利用SHA-256对源字符串进行加密
	 * 
	 * @param src
	 * @return 返回加密串,注:本例中,空串表示加密失败
	 */
	private String encrypt(String src) {

		// 源字符串转换成byte数组
		try {
			byte[] btSource = src.getBytes(CHAR_SET);
			// 此处选择了SHA-256加密算法,实际可选的算法有"MD2、MD5、SHA-1、SHA-256、SHA-384、SHA-512"
			MessageDigest md = MessageDigest.getInstance(this.ENCODE_TYPE);
			md.reset();
			md.update(btSource);
			String result = bytes2Hex(md.digest()); // to HexString
			return result;
		} catch (NoSuchAlgorithmException e) {
			return "";
		} catch (UnsupportedEncodingException e) {
			return "";
		}
	}

	public static void main(String args[]) throws Exception {
		SHAEncrypt demo = new SHAEncrypt();
		String str = "12test中文濲騃";
		long startTime = System.currentTimeMillis();
		String encPwd = demo.encryptPwd(str);
		System.out.println("encrypt time costs:"
				+ (System.currentTimeMillis() - startTime));
		System.out.println("encrypted pwd:" + encPwd + ",length:"
				+ encPwd.length());
		System.out.println(demo.validatePwd(str, encPwd));
		System.out.println(new String(demo.hex2Bytes(encPwd), "UTF-8"));
	}
}
分享到:
评论

相关推荐

    java密码加密与解密

    对密码进行加密和验证的java程序,对字符串进行MD5编码加密,再进行解密

    Java加密与解密的艺术.mobi

    Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。《Java加密与解密的艺术》,它的...

    排列码java实现,密码加密解密

    排列码的一个java实现,呵呵。排列码的一个java实现,呵呵

    java字符串-用户名和密码-加密解密

    java 用户名 密码 加密解密 可以用来邮箱加密。密码加密。 试过了。 非常好用。还可以自定义加密类。 可以动态化,多元化

    JAVA加密与解密的艺术--第2版.rar

    全书包含3个部分,基础篇对Java企业级应用的安全知识、密码学核心知识、与Java加密相关的API和通过权限文件加强系统安全方面的知识进行了全面的介绍;实践篇不仅对电子邮件传输算法、消息摘要算法、对称加密算法、非...

    Java加密与解密的艺术

    Java安全领域的百科全书,密码..., Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。

    对密码进行加密解密

    实现对登录密码的加密解密,更加安全的控制项目安全。

    Java加密与解密的艺术 第二版(清晰+书签+完整版).pdf

    《Java加密与解密的艺术(第2版)》共12章,分为3个部分:基础篇(第1~4章)对Java企业级应用的安全知识、密码学核心知识、与Java加密相关的API和通过权限文件加强系统安全方面的知识进行了全面的介绍;实践篇(第5...

    Java加密与解密的艺术配书源代码

    Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。 第一部分基础篇 第1章企业应用...

    java实现MD5加密解密算法

    java实现MD5加密解密算法,java源代码~

    java实现md5 加密解密

    java实现md5 加密解密(在网络中MD5是著名的不可逆算法,但是如果知道MD5的加密的字符串 则可以通过自己的加密算法对明文进行加密,对加密后的密文与字符串匹配; 匹配成功,表示找到明文;但是此程序的时间耗费较高!仅...

    java密码加密解密算法代码实现

    例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码...

    Java编程实现同步序列密码的加密解密系统

    java编程实现一个同步序列密码(流密码)的加密/解密系统

    java维吉尼亚加密解密用户设计界面

    java维吉尼亚加密解密用户设计界面 java维吉尼亚加密解密用户设计界面

    java的DES加密解密

    java的DES加密解密:用于密码在数据库的加密,解码类

    Java换位密码加密解密

    用Java图形用户界面实现的“换位密码算法的加密和解密”算法

    java密码加密方法

    java密码加密,解密方法,一个好例子帮助大家学习!

    《Java加密与解密的艺术》源码

    Java开发者将通过本书掌握密码学和Java加密与解密技术的所有细节;系统架构师将通过本书领悟构建安全企业级应用的要义;其他领域的安全工作者也能通过本书一窥加密与解密技术的精髓。《Java加密与解密的艺术》,它的...

    Java Jct 加密解密工具包源码.rar

    Java Jct 加密解密工具包源码,WDSsoft免费源代码,java加密解密编程常用工具包 JCT 1.0,作者吴东升 常蕴秋,BlowfishTool.java封装同Blowfish对称加密算法有关的方法,包括了使用创建Blowfish密码,使用Blowfish加密...

Global site tag (gtag.js) - Google Analytics