【Java】使用MD5进行加密解密(代码实现)

目录

为什么需要加密?

MD5加密测试

第一种加密方式

第二种加密方式

JUnit测试

为什么需要加密?

主要是保证网络传输数据的安全性。

  1. 我们的数据需要存储到前端,对于用户来说,不应该知道我们的敏感信息

  2. 在正式环境,我们的数据需要通过网络传输,必须要保证数据在网络传输的安全性,所以我们要采用加密的方式进行传输

明文:加密之前的内容,原始内容

暗文:加密之后的内容

公钥:可见的公共的钥匙

私钥:不可见的私有的钥匙

不可逆加密算法

特征:只能加密不能解密

技术:md5

作用:一般对登录密码处理,用于做密码比对

问题:只能加密,不能解密,不能用来对网络中传输的数据进行加密

可逆对称加密算法

特征:

1. 可以加密,也可以解密

2. 加密和解密的密钥是同一个

实现:DES,AES

作用:对数据库密码进行加密

算法:

密文为s,加解密算法为AES,秘钥为k,明文为c

加密:s = AES(k,c)

解密:c = AES(k,s)

问题:

1. 数据可能会被其他人解密

2. 数据可能会被篡改

RSA,RSA2:**可逆非对称加密算法【这个最好-用这个】**

特征:

1. 可以加密,也可以解密

2. 加密和解密的密钥不是同一个。但是是成对出现的。一个私钥就对应一个公钥如果使用私钥加密,

只能使用与之对应公钥来解决。反之如果使用公钥加密,只能使用与之对应私钥解密

作用:网络传输中对数据进行加解密

算法:

密文为s,加解密算法为RSA私钥为k1,公钥为k2,明文为c

第一组:私钥加密公钥解密

加密:s = rsa(k1,c)

解密:c = rsa(k2,s)

第二组:公钥加密私钥解决

加密:s = rsa(k2,c)

解密:c = rsa(k1,s)

注意:加密一次不安全,要加密两次,解密两次第一次加密和解密并不是真正的数据,而是数字签名和签名认证/确认身份【确认不成功会返回false】

权限控制需要使用到的技术

  1. JWT令牌[JSON web Token]

  2. RSA加密算法

  3. Router动态路由

  4. Vue自定义指令

MD5加密测试

        思路:当平时我们在注册的时候需要对密码进行加密,然后存储到数据库,当我们进行第一次登录的时候需要进行校验,使用同样的方式对用户输入的密码进行加密然后和数据库获取的密码进行equals比较,如果返回值是true说明密码正确,返回为false,说明密码错误。

第一种加密方式

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Utils {

    /**
     * MD5加密 通过将盐值和密码进行加密,进行混淆
     * 登录的时候就通过密码和数据库中的盐值进行拼接 进行MD5加密后的结果是否相同
     * @param context
     */
    public static String encrypByMd5(String context) {
    try {  
        // 获取一个MD5消息摘要实例
        MessageDigest md = MessageDigest.getInstance("MD5");
        
        // 更新消息摘要,将输入的文本内容转换为字节数组并进行处理
        md.update(context.getBytes());
        
        // 计算消息摘要,得到MD5散列值
        byte[] encryContext = md.digest();
  
        int i;  
        StringBuffer buf = new StringBuffer("");  
        for (int offset = 0; offset < encryContext.length; offset++) {
            // 将字节值转换为无符号整数
            i = encryContext[offset];  
            if (i < 0) i += 256;  // 处理负值
            if (i < 16) buf.append("0");  // 补充前导0,以保证每个字节都被表示为两位十六进制数
            buf.append(Integer.toHexString(i));  // 将字节值转换为十六进制字符串并追加到结果字符串
       }  
       
        // 返回MD5散列值的十六进制表示
        return buf.toString();
    } catch (NoSuchAlgorithmException e) {
        // 处理NoSuchAlgorithmException异常,通常是因为指定的MD5算法不可用
        e.printStackTrace();
        return  null;
    }  
}

    public static void main(String[] args) {
    //加密
    //1 生成随机盐值
    String pwd = "1";
    String salt = StrUtils.getComplexRandomString(32);
    //2 通过这个盐值加密
    String md5Pwd = MD5Utils.encrypByMd5(pwd +"yhp"+ salt+"xxxx");
    System.out.println(md5Pwd);

    //密码比对
    //1 查询盐值-就是salt
    String saltTmp = salt;
    //3 加密比对
    String pwdTmp = "1";
    String inputMd5Pwd = MD5Utils.encrypByMd5(pwdTmp +"yhp"+ saltTmp+"xxxx");
    if (inputMd5Pwd.equals(md5Pwd)){
        System.out.println("登录成功!");
    }else{
        System.out.println("密码错误");
    }
  }
}

StrUtils:

package com.review.api;

import java.util.Random;

public class StrUtils {

    private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+";

    /**
     * 生成指定长度的复杂随机字符串
     *
     * @param length 随机字符串长度
     * @return 随机字符串
     */
    public static String getComplexRandomString(int length) {
        if (length < 1) {
            throw new IllegalArgumentException("随机字符串长度必须大于等于1");
        }
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(CHARACTERS.length());
            sb.append(CHARACTERS.charAt(index));
        }
        return sb.toString();
    }

}

第二种加密方式

        注意:MD5 算法通常用于加密而不是解密,因为它是不可逆的哈希函数。这里所说的“解密”实际上是指破解 MD5 加密的哈希值。

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Util {

    // 加密方法:接收一个字符串明文,返回使用 MD5 加密后的哈希值
    public static String encrypt(String plaintext) throws NoSuchAlgorithmException {
        // 使用 MD5 算法创建 MessageDigest 对象
        MessageDigest md = MessageDigest.getInstance("MD5");
        // 更新 MessageDigest 对象中的字节数据
        md.update(plaintext.getBytes());
        // 对更新后的数据计算哈希值,存储在 byte 数组中
        byte[] digest = md.digest();
        // 将 byte 数组转换为十六进制字符串
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b & 0xff));
        }
        // 返回十六进制字符串
        return sb.toString();
    }

    // 解密方法:接收一个字符串明文和一个使用 MD5 加密后的哈希值,返回解密结果(true 表示匹配,false 表示不匹配)
    public static boolean decrypt(String plaintext, String encrypted) throws NoSuchAlgorithmException {
        // 调用加密方法计算出明文的哈希值
        String decrypted = encrypt(plaintext);
        // 比较计算得到的哈希值和输入的哈希值是否相同
        return decrypted.equals(encrypted);
    }
}

这个类实现了两个静态方法:encrypt() 和 decrypt()encrypt() 方法将输入的明文字符串使用 MD5 哈希算法加密,并返回其哈希值的十六进制表示形式。decrypt() 方法将输入的明文字符串和哈希值与使用 encrypt() 方法计算出的哈希值比较,如果相同则返回 true,否则返回 false。由于 MD5 哈希算法是不可逆的,所以它是无法直接进行解密的,decrypt() 方法的实际作用是通过试图暴力破解哈希值来验证一组明文和哈希值是否匹配。

在 encrypt() 方法中,我们使用 MessageDigest 类来创建一个 MD5 消息摘要对象。然后,我们在对象上调用 update() 方法来更新摘要数据,并在调用 digest() 方法时计算哈希值。digest() 方法返回一个 byte 数组,其中包含计算出的哈希值。我们使用 StringBuilder 对象将此数组转换为一个十六进制字符串,并返回结果。

在 decrypt() 方法中,我们只需要在内部调用 encrypt() 方法来计算明文的哈希值,并将其与输入的哈希值进行比较即可。我们使用 equals() 方法来比较字符串相等性,因为这是一种比较字符串内容的安全和可靠的方法。

JUnit测试

import java.security.NoSuchAlgorithmException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class MD5UtilTest {

    /**
     * 测试加密
     * */
    @Test
    public void testEncrypt() throws NoSuchAlgorithmException {
        String plaintext = "hello world";
        String expected = "5eb63bbbe01eeed093cb22bb8f5acdc3";
        //进行加密
        String actual = MD5Util.encrypt(plaintext);
        Assertions.assertEquals(expected, actual);
        System.out.println("加密是否成功:"+expected.equals(actual));
    }

    /**
     * 进行解密
     * */
    @Test
    public void testDecrypt() throws NoSuchAlgorithmException {
        String plaintext = "hello world";
        String encrypted = "5eb63bbbe01eeed093cb22bb8f5acdc3";
        boolean expected = true;
        boolean actual = MD5Util.decrypt(plaintext, encrypted);
        Assertions.assertEquals(expected, actual);
        System.out.println("解密是否成功:"+actual);
    }
}

  • 8
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mxin5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值