java 实现md5加密的三种方式与解密

一、解密

  说明:截止文章发布,Java没有实现解密,但是已有网站可以免费破解了!(本质应该是将加密结果与加密前的数据对应存储起来了)

  见文末相关推荐

二、加密的三种方式

  说明:都是返回长度为32位的16进制字符串(小写)。

  方法一:推荐使用

  所需jar包:commons-codec.jar

<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version>
</dependency>
       import org.apache.commons.codec.digest.DigestUtils;
       /**
 * MD5加密之方法一
 * @explain 借助apache工具类DigestUtils实现
 * @param str
 *            待加密字符串
 * @return 16进制加密字符串
 */
public static String encryptToMD5(String str) {
    return DigestUtils.md5Hex(str);
}  

  方法二

       /**
 * MD5加密之方法二
 * @explain java实现
 * @param str
 *            待加密字符串
 * @return 16进制加密字符串
 */
public static String encrypt2ToMD5(String str) {
    // 加密后的16进制字符串
    String hexStr =        "" ;
    try {
        // 此 MessageDigest 类为应用程序提供信息摘要算法的功能
        MessageDigest md5 = MessageDigest.getInstance(       "MD5" );
        // 转换为MD5码
        byte [] digest = md5.digest(str.getBytes(       "utf-8" ));
        hexStr = ByteUtils.toHexString(digest);
    }        catch (Exception e) {
        e.printStackTrace();
    }
    return hexStr;
}  

  方法三:SPRING核心包

import org.springframework.util.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
/**
 * MD5加密
 * @explain springboot自带MD5加密
 * @param str 待加密字符串
 * @return 16进制加密字符串(小写)
 */
public static String toMD5(String str) {
    log.debug(      "MD5待加密字符串:\n" + str);
    String md5 = md5 = DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8));
    log.debug(      "MD5加密结果:\n" + md5);
    return md5;
}

20200827

  spring-core.jar,只要有这个jar包,就能引入DigestUtils.class。

  这也是springboot能够引入该类的最终原因,比如说:我使用的是

  鼠标悬浮,同时按住Ctrl键,点击就可以打开该jar包的.pom文件,你会发现有这样一个依赖

  再次执行以上操作

 

  我们可以发现:springboot最终依赖的有spring-core.jar,所以,springboot也可以直接导入DigestUtils.class。

通过源码,我们可以看到:spring的DigestUtils.class对于md5的加密,最终依赖的还是:MessageDigest.class。

三、测试

public static void main(String[] args) {
    String str = "Marydon";
    System.out.println("MD5加密方法一:" + MD5Utils.encryptToMD5(str));
    System.out.println("MD5加密方法二:" + MD5Utils.encrypt2ToMD5(str));
    System.out.println("MD5加密方法三:" + MD5Utils.encrypt3ToMD5(str));
    // 结束都是:988218e7eefcd86d5d855a8947f37f43
}

四、关于md5自动补零

20201201

  我们知道,MD5加密结果通常返回的是32位的16进制字符串,加密结果之所以永远是32位,其实是进行了自动补零操作(也就是:当加密结果长度不够32位时,会在前面自动补零,直到满足长度=32位)

下面就来验证一下:

  如上图所示,两个加密结果都进行了补零操作。

  它们的真实加密结果就是:去掉前面的0,一起来验证一下。

  只所以讲这个问题,是因为在实际开发过程中,在对接接口的时候,我方用的是常用的MD5加密方案(自动补零),而接口提供方使用的是展示真实加密结果的MD5,在比对加密结果的时候肯定会经常出现加密结果不一致导致校验失败的问题。

  所以,我在这里添加能够显示真实加密结果的MD5代码,以供有这种特殊需求的园友使用。

/*
 * MD5加密(真实长度,不补零)
 * @attention:
 * @date: 2020年12月01日 0001 14:44
 * @param: str
 * @return: java.lang.String
 */
public static String toMD5_realLength_UpperCase(String str) {
    if (StringUtils.isEmpty(str))      return "" ;

    try {
        log.debug(     "MD5待加密字符串:\n" + str);
        MessageDigest md5 = MessageDigest.getInstance(    "MD5" );
        // 计算md5函数
        md5.update(str.getBytes(UTF8));
        //digest()最后确定返回md5 hash值,返回值为8位字符串。
        //因为md5hash值是16位的hex值,实际上就是8位的字符
        //BigInteger函数则将8位的字符串转换成16位hex值,
        //用字符串来表示;得到字符串形式的hash值
        String md5Str =      new BigInteger(    1 , md5.digest()).toString(     16 ).toUpperCase();
        log.debug(    "MD5加密结果(不补零):\n" + md5Str);
        return md5Str;
    }      catch (Exception e) {
        e.printStackTrace();
        return "" ;
    }
}

/*
 * MD5加密(真实长度,不补零)
 * @attention:
 * @date: 2020年12月01日 0001 14:44
 * @param: str
 * @return: java.lang.String
 */
public static String toMD5_realLength_LowerCase(String str) {
    if (StringUtils.isEmpty(str))      return "" ;

    try {
        log.debug(     "MD5待加密字符串:\n" + str);
        MessageDigest md5 = MessageDigest.getInstance(    "MD5" );
        // 计算md5函数
        md5.update(str.getBytes(UTF8));
        String md5Str =      new BigInteger(    1 , md5.digest()).toString(    16 ).toLowerCase();
        log.debug(     "MD5加密结果(不补零):\n" + md5Str);
        return md5Str;
    }      catch (Exception e) {
        e.printStackTrace();
        return "" ;
    }
}

2022年3月3日10:39:29

五、代码优化

查看代码

import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5加密工具类
 * @description
 * 不可逆算法(非对称算法)
 * md5加密会将数据加密成16进制字符串,其加密结果有且只有两种情况:
 * 1.默认情况
 * HexString.Length=32,当md5进行加密时,其加密后的长度不够32位时,会在前面自动补0;
 * 2.自定义
 * HexString.Length<32,我们可以手动来控制不让其在前面自动补0。
 * 3.虽然md5默认加密结果是16进制,但是,我们可以自定义加密结果的形式;
 * 但是,约定俗成的MD5加密结果是16进制。
 * @author: Marydon
 * @date: 2020年07月13日 0013 15:01
 */
@Slf4j
public final class Md5Utils extends EncodeDecodeTemplate{

    private Md5Utils() {
    }

    private static final String ALGORITHM_NAME = "MD5";

    /*
     * md5加密(32位)
     * @description:
     * @date: 2022/3/3 9:51
     * @param: plainText 明文
     * @return: java.lang.String 密文
     * 16进制加密字符串(大写)
     * 固定长度:32位
     */
    @NotNull
    public static String encrypt32ToHexString(@NotNull String plainText) {
        log.info("MD5待加密字符串:" + plainText);
        String hexString = encodeToHexString(core32(plainText.getBytes(StandardCharsets.UTF_8)));
        log.info("MD5加密结果(Length=32):" + hexString);
        return hexString;
    }

    /*
     * md5加密核心实现(自动补零,32位)
     * @description: 当加密解过不够32位时,自动在最前面补0,直到补够32位
     * @date: 2022/3/2 17:58
     * @param: plainBytes 待加密二进制数据
     * @return: byte[] 加密结果
     */
    @Nullable
    private static byte[] core32(byte[] plainBytes) {
        try {
            return MessageDigest.getInstance(ALGORITHM_NAME).digest(plainBytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.error("MD5加密失败:{}", e.getMessage());
            return null;
        }
    }

    /*
     * md5加密(<=32位)
     * @description: 当长度不够32位时,不用补0
     * @date: 2022/3/3 10:12
     * @param: plainText 明文
     * @return: java.lang.String 密文
     */
    @NotNull
    public static String encryptToHexString(@NotNull String plainText) {
        log.info("MD5待加密字符串:" + plainText);
        try {
            MessageDigest md5 = MessageDigest.getInstance(ALGORITHM_NAME);
            // 计算md5函数
            md5.update(plainText.getBytes(StandardCharsets.UTF_8));
            //digest()最后确定返回md5 hash值,返回值为8位字符串。
            //因为md5hash值是16位的hex值,实际上就是8位的字符
            //BigInteger函数则将8位的字符串转换成16位hex值,
            //用字符串来表示;得到字符串形式的hash值
            String hexString = new BigInteger(1, md5.digest()).toString(16).toUpperCase();
            log.info("MD5加密结果(Length<=32):" + hexString);
            return hexString;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log.error("MD5加密失败:{}", e.getMessage());
            return "";
        }
    }

    public static void main(String[] args) {
        String str = "++iNr+/=.0.瞾肇";
        encryptToHexString(str);
        str = "zhang三11111111";
        encrypt32ToHexString(str);

    }
}

 

posted @ 2018-05-31 15:20  Marydon  阅读(86107)  评论(4编辑  收藏  举报