1MD5暗号化の概要
- MD5は、プレーンテキスト文字列を暗号化して暗号文を取得できる暗号化アルゴリズムです。
- MD5の元のテキストと暗号文は1対1のキーと値のペアです。
例:元のテキスト:123暗号文:202cb962ac59075b964b07152d234b70
何度実行しても暗号化アルゴリズムは固定されており、取得した暗号文は変更されません。
比較的不安定で、割れやすい
- 会社の暗号化にMD5を使用する
例:元のパスワードは123で、開始と終了、および暗号化用のユーザー名を交換します
例:暗号化用の321meimei e5212215b8cbf493e04f4290cf7cecc8
これは比較的安全です
package com.itheima.travel.util;
import java.security.MessageDigest;
/**
* 写一个MD5算法,运行结果与MySQL的md5()函数相同
* 将明文密码转成MD5密码
* 123456->e10adc3949ba59abbe56e057f20f883e
*/
public final class Md5Util {
private Md5Util(){
}
/**
* 将明文密码转成MD5密码
*/
public static String encodeByMd5(String password) throws Exception{
//Java中MessageDigest类封装了MD5和SHA算法,今天我们只要MD5算法
MessageDigest md5 = MessageDigest.getInstance("MD5");
//调用MD5算法,即返回16个byte类型的值
byte[] byteArray = md5.digest(password.getBytes());
//注意:MessageDigest只能将String转成byte[],接下来的事情,由我们程序员来完成
return byteArrayToHexString(byteArray);
}
/**
* 将byte[]转在16进制字符串
*/
private static String byteArrayToHexString(byte[] byteArray) {
StringBuffer sb = new StringBuffer();
//遍历
for(byte b : byteArray){
//16次
//取出每一个byte类型,进行转换
String hex = byteToHexString(b);
//将转换后的值放入StringBuffer中
sb.append(hex);
}
return sb.toString();
}
/**
* 将byte转在16进制字符串
*/
private static String byteToHexString(byte b) {
//-31转成e1,10转成0a,。。。
//将byte类型赋给int类型
int n = b;
//如果n是负数
if(n < 0){
//转正数
//-31的16进制数,等价于求225的16进制数
n = 256 + n;
}
//商(14),数组的下标
int d1 = n / 16;
//余(1),数组的下标
int d2 = n % 16;
//通过下标取值
return hex[d1] + hex[d2];
}
private static String[] hex = {
"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
/**
* 测试
*/
public static void main(String[] args) throws Exception{
String password = "123456";
String passwordMD5 = Md5Util.encodeByMd5(password);
System.out.println(password);
System.out.println(passwordMD5);
}
}
2Md5Hash暗号化とソルト
暗号化にShiroフレームワークを使用して、以下を直接テストします。
最初のステップ:依存関係を追加する
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.3.2</version>
</dependency>
ステップ2:テストクラスを作成する
package com.itheima;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.junit.Test;
public class App {
// (1) md5 加密,生成32位加密字符串
@Test
public void md5_1(){
Md5Hash md5Hash = new Md5Hash("1234");
System.out.println("加密:" + md5Hash.toString());
}
// (2) 加密加盐
@Test
public void md5_2(){
String salt = "AAA";
Md5Hash md5Hash = new Md5Hash("1234",salt);
System.out.println(md5Hash);
}
// (3) 加密 加盐 随机盐
@Test
public void md5_3(){
// 随机盐
SecureRandomNumberGenerator srn = new SecureRandomNumberGenerator();
String salt = srn.nextBytes().toHex();
Md5Hash md5Hash = new Md5Hash("1234",salt);
System.out.println(md5Hash.toString());
}
// (4) 加密 加盐 随机盐 迭代次数
@Test
public void md5_4(){
// 随机盐
SecureRandomNumberGenerator srn = new SecureRandomNumberGenerator();
String salt = srn.nextBytes().toHex();
Md5Hash md5Hash = new Md5Hash("1234",salt,3);// 迭代3次
System.out.println(md5Hash.toString());
}
}
3Springが提供する高度な暗号化
BCryptPasswordEncoder暗号化のソースはSpringセキュリティの一部であるため、Springセキュリティの依存関係を導入する必要があります
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
package com.itheima;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* spring security中的BCryptPasswordEncoder方法采用SHA-256 +随机盐+密钥对密码进行加密。
* SHA系列是Hash算法,不是加密算法,使用加密算法意味着可以解密(这个与编码/解码一样),
* 但是采用Hash处理,其过程是不可逆的。
*
* (1)加密(encode):注册用户时,使用SHA-256+随机盐+密钥把用户输入的密码进行hash处理,
* 得到密码的hash值,然后将其存入数据库中。
*
* (2)密码匹配(matches):用户登录时,密码匹配阶段并没有进行密码解密(因为密码经过Hash处理,是不可逆的),
* 而是使用相同的算法把用户输入的密码进行hash处理,得到密码的hash值,
* 然后将其与从数据库中查询到的密码hash值进行比较。如果两者相同,说明用户输入的密码正确。
*/
public class App {
@Test
public void test(){
// 加密器
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String str = encoder.encode("123");
System.out.println(str);
// 加密的结果每次不一样
//r1 = $2a$10$I4XP9//KH5GsPt059YmikuZJl0FUR6HQYSRa/J4UrOwKWmnlEh97G
//r1 = $2a$10$l3ki2psVSi91CWPpYXQRm.J3156djwwCyGI.7YGnjscOcxeAwQS6C
//r1 = $2a$10$gpTfkWpAtmSQywBepw3XU.aPX.zWzeauUoU7s8FVg9xPIXPLJIQCi
// 对比:加密前的123,与加密后的r1分别对比,返回的结果都是true.说明是一样的
boolean flag =
encoder.matches("123","$2a$10$gpTfkWpAtmSQywBepw3XU.aPX.zWzeauUoU7s8FVg9xPIXPLJIQCi");
System.out.println(flag);
}
}