java实现MD5的加密

来源:互联网 发布:淘宝卖家互刷平台 编辑:程序博客网 时间:2024/06/04 20:19

引入

MD5的来源

1.在各种应用系统中,如果需要设置账户,那么就会涉及到储存用户账户信息的问题,为了保证所储存账户信息的安全,一般就会使用到MD5进行加密储存。那么我们得的搞清楚什么是MD5。
2. MD5其全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2、MD3和MD4发展而来。是让大容量信息在用数字签名软件签署私人密匙前被”压缩”成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数)。不管是MD2、MD4还是MD5,它们都需要获得一个随机长度的信息并产生一个128位的信息摘要。虽然这些算法的结构或多或少有些相似,但MD2的设计与MD4和MD5完全不同,那是因为MD2是为8位机器做过设计优化的,而MD4和MD5却是面向32位的电脑。这三个算法的描述和C语言源代码在Internet RFCs 1321中有详细的描述,这是一份最权威的文档,由Ronald L. Rivest在1992年8月向IETF提交。
3. MD5 其实在我们生活中是很常用的,似乎你并没有注意到,当你下载了一个镜像之后,你会发现下载页面还提供了一组 MD5 值,那么这组 MD5 值是用来做什么的呢?了解了 MD5 的作用之后,你就不难想到,MD5 是用来验证文件的一致性的,当你下载好镜像之后,你需要对该镜像做一次 MD5 的校验,得到的 MD5 值与下载页面提供的 MD5 值进行对比,以此来验证该镜像是否被篡改。

MD5 算法具有很多特点:

  1. 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  2. 容易计算:从原数据计算出MD5值很容易。
  3. 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  4. 弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
  5. 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。

消息摘要简介

一个消息摘要就是一个数据块的数字指纹。即对一个任意长度的一个数据块进行计算,产生一个唯一指印(对于SHA1是产生一个20字节的二进制数组)。消息摘要是一种与消息认证码结合使用以确保消息完整性的技术。主要使用单向散列函数算法,可用于检验消息的完整性,和通过散列密码直接以文本形式保存等,目前广泛使用的算法有MD4、MD5、SHA-1。

对字符串进行MD5处理:

加密及验证过程:

package com.lh.MD;import java.io.UnsupportedEncodingException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.util.Arrays;/** * MD加密 * @author huan * */public class MD5 {    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();        // 声明盐数组变量        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);        // 将字节数组格式加密后的口令转化为16进制字符串格式的口令        return byteToHexString(pwd);    }}

测试代码:

package com.lh.MD;import java.io.UnsupportedEncodingException;import java.security.NoSuchAlgorithmException;import java.util.HashMap;import java.util.Map;/** * 测试 * @author huan * */public class Test {    private static Map<String, String> users = new HashMap<String, String>();    public static void main(String[] args) {        String userName = "lh";        String password = "123";        registerUser(userName, password);        userName = "ll";        password = "456";        registerUser(userName, password);        String loginUserId = "lh";        String pwd = "123";        try {            if (loginValid(loginUserId, pwd)) {                System.out.println("欢迎登陆!!!");            } else {                System.out.println("口令错误,请重新输入!!!");            }        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }    }    /**     * 注册用户     *      * @param userName     * @param password     */    public static void registerUser(String userName, String password) {        String encryptedPwd = null;        try {            encryptedPwd = MD5.getEncryptedPwd(password);            users.put(userName, encryptedPwd);        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        } catch (UnsupportedEncodingException e) {            e.printStackTrace();        }    }    /**     * 验证登陆     *      * @param userName     * @param password     * @return     * @throws UnsupportedEncodingException     * @throws NoSuchAlgorithmException     */    public static boolean loginValid(String userName, String password)            throws NoSuchAlgorithmException, UnsupportedEncodingException {        String pwdInDb = (String) users.get(userName);        if (null != pwdInDb) { // 该用户存在            return MD5.validPassword(password, pwdInDb);        } else {            System.out.println("不存在该用户!!!");            return false;        }    }}

结果:

这里写图片描述

原创粉丝点击