一.陈述一下工作流程:

1.根据已有的密码字符串去生成一个密码+盐字符串,可以将盐的加密字符串也存放在数据库(看需求),

2.验证时将提交的密码字符串进行同样的加密再从数据库中取得已有的盐进行组合密码+盐的字符串和已有的进行验证

package com.mi.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays; public class Md5SaltTool { private static final String HEX_NUMS_STR="0123456789ABCDEF";
private static final Integer SALT_LENGTH = 12; /**
* 将16进制字符串转换成字节数组
* @param hex
* @return
*/
public static byte[] hexStringToByte(String hex) {
int len = (hex.length() / 2);
byte[] result = new byte[len];
char[] hexChars = hex.toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (HEX_NUMS_STR.indexOf(hexChars[pos]) << 4
| HEX_NUMS_STR.indexOf(hexChars[pos + 1]));
}
return result;
} /**
* 将指定byte数组转换成16进制字符串
* @param b
* @return
*/
public static String byteToHexString(byte[] b) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
hexString.append(hex.toUpperCase());
}
return hexString.toString();
} /**
* 验证口令是否合法
* @param password
* @param passwordInDb
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static boolean validPassword(String password, String passwordInDb)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
//将16进制字符串格式口令转换成字节数组
byte[] pwdInDb = hexStringToByte(passwordInDb);
//声明盐变量
byte[] salt = new byte[SALT_LENGTH];
//将盐从数据库中保存的口令字节数组中提取出来
System.arraycopy(pwdInDb, 0, salt, 0, SALT_LENGTH);
//创建消息摘要对象
MessageDigest md = MessageDigest.getInstance("MD5");
//将盐数据传入消息摘要对象
md.update(salt);
//将口令的数据传给消息摘要对象
md.update(password.getBytes("UTF-8"));
//生成输入口令的消息摘要
byte[] digest = md.digest();
//声明一个保存数据库中口令消息摘要的变量
byte[] digestInDb = new byte[pwdInDb.length - SALT_LENGTH];
//取得数据库中口令的消息摘要
System.arraycopy(pwdInDb, SALT_LENGTH, digestInDb, 0, digestInDb.length);
//比较根据输入口令生成的消息摘要和数据库中消息摘要是否相同
if (Arrays.equals(digest, digestInDb)) {
//口令正确返回口令匹配消息
return true;
} else {
//口令不正确返回口令不匹配消息
return false;
}
} /**
* 获得加密后的16进制形式口令
* @param password
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String getEncryptedPwd(String password)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
//声明加密后的口令数组变量
byte[] pwd = null;
//随机数生成器
SecureRandom random = new SecureRandom();
//声明盐数组变量 12
byte[] salt = new byte[SALT_LENGTH];
//将随机数放入盐变量中
random.nextBytes(salt); //声明消息摘要对象
MessageDigest md = null;
//创建消息摘要
md = MessageDigest.getInstance("MD5");
//将盐数据传入消息摘要对象
md.update(salt);
//将口令的数据传给消息摘要对象
md.update(password.getBytes("UTF-8"));
//获得消息摘要的字节数组
byte[] digest = md.digest(); //因为要在口令的字节数组中存放盐,所以加上盐的字节长度
pwd = new byte[digest.length + SALT_LENGTH];
//将盐的字节拷贝到生成的加密口令字节数组的前12个字节,以便在验证口令时取出盐
System.arraycopy(salt, 0, pwd, 0, SALT_LENGTH);
//将消息摘要拷贝到加密口令字节数组从第13个字节开始的字节
System.arraycopy(digest, 0, pwd, SALT_LENGTH, digest.length);
for(int i=0;i<pwd.length;i++){
System.out.print(pwd[i]);
}
//将字节数组格式加密后的口令转化为16进制字符串格式的口令
return byteToHexString(pwd);
}
}

测试类如下:

package com.mi.util;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map; public class Md5SaltTest { private static Map users = new HashMap(); public static void main(String[] args){
String userName = "zyg";
String password = "123";
registerUser(userName,password); userName = "changong";
password = "456";
registerUser(userName,password); String loginUserId = "zyg";
String pwd = "1232";
try {
if(loginValid(loginUserId,pwd)){
System.out.println("欢迎登陆!!!");
}else{
System.out.println("口令错误,请重新输入!!!");
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} /**
* 注册用户
*
* @param userName
* @param password
*/
public static void registerUser(String userName,String password){
String encryptedPwd = null;
try {
encryptedPwd = Md5SaltTool.getEncryptedPwd(password);
users.put(userName, encryptedPwd); } catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} /**
* 验证登陆
*
* @param userName
* @param password
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public static boolean loginValid(String userName,String password)
throws NoSuchAlgorithmException, UnsupportedEncodingException{
/*String loginUserId = "zyg";
String pwd = "1232";*/
String pwdInDb = (String)users.get(userName);
if(null!=pwdInDb){ // 该用户存在
return Md5SaltTool.validPassword(password, pwdInDb);
}else{
System.out.println("不存在该用户!!!");
return false;
}
}
}

Java关于md5+salt盐加密验证的更多相关文章

  1. 关于MD5+salt盐加密

    MD5+salt 最近浏览浏览一些帖子时,发现曾经引以为傲的md5加密算法,虽然是无法解密的算法,但是现在可以通过FELHELP(谷歌浏览器插件)或者一些字典可以套出来,.但是当md5+salt值时, ...

  2. Java使用MD5加盐进行加密

    Java使用MD5加盐进行加密    我使用的方法是导入了md5.jar包,就不需要再自己写MD5的加密算法了,直接调用方法即可 点击下载md5包 import com.ndktools.javamd ...

  3. md5加密,md5加盐加密和解密

    package com.java.test; import java.security.MessageDigest; import java.security.SecureRandom; import ...

  4. 一种简单的md5加盐加密的方法(防止彩虹表撞库)

    md5加密(或者说摘要算法)大家都很熟悉了 就不解释了 现在很多数据库设计都喜欢用单向加密的方式保存密码,验证时对提交的密码再次加密之后做密文对比 /// <summary> 使用MD5加 ...

  5. MD5 加盐加密

    一.概述 MD5(Message Digest  Algorithm 5),是一种散列算法,是不可逆的,即通过md5加密之后没办法得到原文,没有解密算法. 在一般的项目中都会有登录注册功能,最简单的, ...

  6. MD5加盐加密

    package com.chauvet.utils; import java.security.NoSuchAlgorithmException; import java.util.Random; / ...

  7. JAVA通过md5方法进行加密

    import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /* * MD5 算法 * */ ...

  8. shiro入门学习--使用MD5和salt进行加密|练气后期

    写在前面 在上一篇文章<Shiro入门学习---使用自定义Realm完成认证|练气中期>当中,我们学会了使用自定义Realm实现shiro数据源的切换,我们可以切换成从关系数据库如MySQ ...

  9. SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期

    写在前面 通过前几篇文章的学习,我们从大体上了解了shiro关于认证和授权方面的应用.在接下来的文章当中,我将通过一个demo,带领大家搭建一个SpringBoot整合Shiro的一个项目开发脚手架, ...

随机推荐

  1. 运行java的class文件方法详解

    一.运行class文件 执行带main方法的class文件,命令行为:java <CLASS文件名>注意:CLASS文件名不要带文件后缀.class 例如: 复制代码代码如下: java ...

  2. 处理海量数据的高级排序之——归并排序(C++)

    代码实现                                                                                                 ...

  3. css圆角边框

    一.CSS3圆角的优点 传统的圆角生成方案,必须使用多张图片作为背景图案.CSS3的出现,使得我们再也不必浪费时间去制作这些图片了,而且还有其他多个优点: * 减少维护的工作量.图片文件的生成.更新. ...

  4. 【java】[转]标记接口和标记注解注解

    Java中的标记接口和标记注解 http://blog.sina.com.cn/s/blog_7fdce91f0101d93m.html

  5. 重写(Override)与重载(Overload)

    重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的好处在于子类可以根据需要,定义特定于自己的行为. 也就是说子类 ...

  6. AOP 学习

    学习 Spring.Net 的AOP 的时候,在做一个简单的测试例子的时候,配置文件和代码逻辑都是没问题的,但始终报这样一个异常: 无法将类型为“CompositionAopProxy_1e76f37 ...

  7. SDWebImage笔记

    SDWebImage托管在github上.https://github.com/rs/SDWebImage 这个类库提供一个UIImageView类别以支持加载来自网络的远程图片.具有缓存管理.异步下 ...

  8. bzoj3594: [Scoi2014]方伯伯的玉米田--树状数组优化DP

    题目大意:对于一个序列,可以k次选任意一个区间权值+1,求最长不下降子序列最长能为多少 其实我根本没想到可以用DP做 f[i][j]表示前i棵,操作j次,最长子序列长度 p[x][y]表示操作x次后, ...

  9. 数组API

    1.数组的创建 var arrayObj = new Array();//创建一个默认数组,长度是0 var arrayObj = new Array(size);//创建一个size长度的数组,注意 ...

  10. Spring注解详解

    概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...