可变MD5加密(Java实现)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可变MD5加密(Java实现)相关的知识,希望对你有一定的参考价值。
参考技术A可变在这里含义很简单 就是最终的加密结果是可变的 而非必需按标准MD 加密实现 Java类库security中的MessageDigest类就提供了MD 加密的支持 实现起来非常方便 为了实现更多效果 我们可以如下设计MD 工具类
Java代码
package ** ** util;
import java security MessageDigest;
/**
* 标准MD 加密方法 使用java类库的security包的MessageDigest类处理
* @author Sarin
*/
public class MD
/**
* 获得MD 加密密码的方法
*/
public static String getMD ofStr(String origString)
String origMD = null;
try
MessageDigest md = MessageDigest getInstance( MD );
byte[] result = md digest(origString getBytes());
origMD = byteArray HexStr(result);
catch (Exception e)
e printStackTrace();
return origMD ;
/**
* 处理字节数组得到MD 密码的方法
*/
private static String byteArray HexStr(byte[] bs)
StringBuffer *** = new StringBuffer();
for (byte b : bs)
*** append(byte HexStr(b));
return *** toString();
/**
* 字节标准移位转十六进制方法
*/
private static String byte HexStr(byte b)
String hexStr = null;
int n = b;
if (n < )
//若需要自定义加密 请修改这个移位算法即可
n = b & x F + ;
hexStr = Integer toHexString(n / ) + Integer toHexString(n % );
return hexStr toUpperCase();
/**
* 提供一个MD 多次加密方法
*/
public static String getMD ofStr(String origString int times)
String md = getMD ofStr(origString);
for (int i = ; i < times ; i++)
md = getMD ofStr(md );
return getMD ofStr(md );
/**
* 密码验证方法
*/
public static boolean verifyPassword(String inputStr String MD Code)
return getMD ofStr(inputStr) equals(MD Code);
/**
* 重载一个多次加密时的密码验证方法
*/
public static boolean verifyPassword(String inputStr String MD Code int times)
return getMD ofStr(inputStr times) equals(MD Code);
/**
* 提供一个测试的主函数
*/
public static void main(String[] args)
System out println( : + getMD ofStr( ));
System out println( : + getMD ofStr( ));
System out println( sarin: + getMD ofStr( sarin ));
System out println( : + getMD ofStr( ));
可以看出实现的过程非常简单 因为由java类库提供了处理支持 但是要清楚的是这种方式产生的密码不是标准的MD 码 它需要进行移位处理才能得到标准MD 码 这个程序的关键之处也在这了 怎么可变?调整移位算法不就可变了么!不进行移位 也能够得到 位的密码 这就不是标准加密了 只要加密和验证过程使用相同的算法就可以了
MD 加密还是很安全的 像CMD 那些穷举破解的只是针对标准MD 加密的结果进行的 如果自定义移位算法后 它还有效么?可以说是无解的了 所以MD 非常安全可靠
为了更可变 还提供了多次加密的方法 可以在MD 基础之上继续MD 就是对 位的第一次加密结果再MD 恩 这样去破解?没有任何意义
这样在MIS系统中使用 安全可靠 欢迎交流 希望对使用者有用
我们最后看看由MD 加密算法实现的类 那是非常庞大的
Java代码
import java lang reflect *;
/**
* **********************************************
* md 类实现了RSA Data Security Inc 在提交给IETF
* 的RFC 中的MD message digest 算法
* ***********************************************
*/
public class MD
/* 下面这些S S 实际上是一个 * 的矩阵 在原始的C实现中是用#define 实现的
这里把它们实现成为static final是表示了只读 切能在同一个进程空间内的多个
Instance间共享*/
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final int S = ;
static final byte[] PADDING =
;
/* 下面的三个成员是MD 计算过程中用到的 个核心数据 在原始的C实现中
被定义到MD _CTX结构中
*/
private long[] state = new long[ ]; // state (ABCD)
private long[] count = new long[ ]; // number of bits modulo ^ (l *** first)
private byte[] buffer = new byte[ ]; // input buffer
/* digestHexStr是MD 的唯一一个公共成员 是最新一次计算结果的
进制ASCII表示
*/
public String digestHexStr;
/* digest 是最新一次计算结果的 进制内部表示 表示 bit的MD 值
*/
private byte[] digest = new byte[ ];
/*
getMD ofStr是类MD 最主要的公共方法 入口参数是你想要进行MD 变换的字符串
返回的是变换完的结果 这个结果是从公共成员digestHexStr取得的.
*/
public String getMD ofStr(String inbuf)
md Init();
md Update(inbuf getBytes() inbuf length());
md Final();
digestHexStr = ;
for (int i = ; i < ; i++)
digestHexStr += byteHEX(digest[i]);
return digestHexStr;
// 这是MD 这个类的标准构造函数 JavaBean要求有一个public的并且没有参数的构造函数
public MD ()
md Init();
return;
/* md Init是一个初始化函数 初始化核心变量 装入标准的幻数 */
private void md Init()
count[ ] = L;
count[ ] = L;
///* Load magic initialization constants
state[ ] = x L;
state[ ] = xefcdab L;
state[ ] = x badcfeL;
state[ ] = x L;
return;
/* F G H I 是 个基本的MD 函数 在原始的MD 的C实现中 由于它们是
简单的位运算 可能出于效率的考虑把它们实现成了宏 在java中 我们把它们
实现成了private方法 名字保持了原来C中的 */
private long F(long x long y long z)
return (x & y) | ((~x) & z);
private long G(long x long y long z)
return (x & z) | (y & (~z));
private long H(long x long y long z)
return x ^ y ^ z;
private long I(long x long y long z)
return y ^ (x | (~z));
/*
FF GG HH和II将调用F G H I进行近一步变换
FF GG HH and II transformations for rounds and
Rotation is separate from addition to prevent reputation
*/
private long FF(long a long b long c long d long x long s long ac)
a += F(b c d) + x + ac;
a = ((int) a << s) | ((int) a >>> ( s));
a += b;
return a;
private long GG(long a long b long c long d long x long s long ac)
a += G(b c d) + x + ac;
a = ((int) a << s) | ((int) a >>> ( s));
a += b;
return a;
private long HH(long a long b long c long d long x long s long ac)
a += H(b c d) + x + ac;
a = ((int) a << s) | ((int) a >>> ( s));
a += b;
return a;
private long II(long a long b long c long d long x long s long ac)
a += I(b c d) + x + ac;
a = ((int) a << s) | ((int) a >>> ( s));
a += b;
return a;
/*
md Update是MD 的主计算过程 inbuf是要变换的字节串 inputlen是长度 这个
函数由getMD ofStr调用 调用之前需要调用md init 因此把它设计成private的
*/
private void md Update(byte[] inbuf int inputLen)
int i index partLen;
byte[] block = new byte[ ];
index = (int) (count[ ] >>> ) & x F;
// /* Update number of bits */
if ((count[ ] += (inputLen << )) < (inputLen << ))
count[ ]++;
count[ ] += (inputLen >>> );
partLen = index;
// Transform as many times as possible
if (inputLen >= partLen)
md Memcpy(buffer inbuf index partLen);
md Transform(buffer);
for (i = partLen; i + < inputLen; i += )
md Memcpy(block inbuf i );
md Transform(block);
index = ;
else
i = ;
///* Buffer remaining input */
md Memcpy(buffer inbuf index i inputLen i);
/*
md Final整理和填写输出结果
*/
private void md Final()
byte[] bits = new byte[ ];
int index padLen;
///* Save number of bits */
Encode(bits count );
///* Pad out to mod
index = (int) (count[ ] >>> ) & x f;
padLen = (index < ) ? ( index) : ( index);
md Update(PADDING padLen);
///* Append length (before padding) */
md Update(bits );
///* Store state in digest */
Encode(digest state );
/* md Memcpy是一个内部使用的byte数组的块拷贝函数 从input的inpos开始把len长度的
字节拷贝到output的outpos位置开始
*/
private void md Memcpy(byte[] output byte[] input int outpos int inpos int len)
int i;
for (i = ; i < len; i++)
output[outpos + i] = input[inpos + i];
/*
md Transform是MD 核心变换程序 有md Update调用 block是分块的原始字节
*/
private void md Transform(byte block[])
long a = state[ ] b = state[ ] c = state[ ] d = state[ ];
long[] x = new long[ ];
Decode(x block );
/* Round */
a = FF(a b c d x[ ] S xd aa L); /* */
d = FF(d a b c x[ ] S xe c b L); /* */
c = FF(c d a b x[ ] S x dbL); /* */
b = FF(b c d a x[ ] S xc bdceeeL); /* */
a = FF(a b c d x[ ] S xf c fafL); /* */
d = FF(d a b c x[ ] S x c aL); /* */
c = FF(c d a b x[ ] S xa L); /* */
b = FF(b c d a x[ ] S xfd L); /* */
a = FF(a b c d x[ ] S x d L); /* */
d = FF(d a b c x[ ] S x b f afL); /* */
c = FF(c d a b x[ ] S xffff bb L); /* */
b = FF(b c d a x[ ] S x cd beL); /* */
a = FF(a b c d x[ ] S x b L); /* */
d = FF(d a b c x[ ] S xfd L); /* */
c = FF(c d a b x[ ] S xa eL); /* */
b = FF(b c d a x[ ] S x b L); /* */
/* Round */
a = GG(a b c d x[ ] S xf e L); /* */
d = GG(d a b c x[ ] S xc b L); /* */
c = GG(c d a b x[ ] S x e a L); /* */
b = GG(b c d a x[ ] S xe b c aaL); /* */
a = GG(a b c d x[ ] S xd f dL); /* */
d = GG(d a b c x[ ] S x L); /* */
c = GG(c d a b x[ ] S xd a e L); /* */
b = GG(b c d a x[ ] S xe d fbc L); /* */
a = GG(a b c d x[ ] S x e cde L); /* */
d = GG(d a b c x[ ] S xc d L); /* */
c = GG(c d a b x[ ] S xf d d L); /* */
b = GG(b c d a x[ ] S x a edL); /* */
a = GG(a b c d x[ ] S xa e e L); /* */
d = GG(d a b c x[ ] S xfcefa f L); /* */
c = GG(c d a b x[ ] S x f d L); /* */
b = GG(b c d a x[ ] S x d a c aL); /* */
/* Round */
a = HH(a b c d x[ ] S xfffa L); /* */
d = HH(d a b c x[ ] S x f L); /* */
c = HH(c d a b x[ ] S x d d L); /* */
b = HH(b c d a x[ ] S xfde cL); /* */
a = HH(a b c d x[ ] S xa beea L); /* */
d = HH(d a b c x[ ] S x bdecfa L); /* */
c = HH(c d a b x[ ] S xf bb b L); /* */
b = HH(b c d a x[ ] S xbebfbc L); /* */
a = HH(a b c d x[ ] S x b ec L); /* */
d = HH(d a b c x[ ] S xeaa faL); /* */
c = HH(c d a b x[ ] S xd ef L); /* */
b = HH(b c d a x[ ] S x d L); /* */
a = HH(a b c d x[ ] S xd d d L); /* */
d = HH(d a b c x[ ] S xe db e L); /* */
c = HH(c d a b x[ ] S x fa cf L); /* */
b = HH(b c d a x[ ] S xc ac L); /* */
/* Round */
a = II(a b c d x[ ] S xf L); /* */
d = II(d a b c x[ ] S x aff L); /* */
c = II(c d a b x[ ] S xab a L); /* */
b = II(b c d a x[ ] S xfc a L); /* */
a = II(a b c d x[ ] S x b c L); /* */
d = II(d a b c x[ ] S x f ccc L); /* */
c = II(c d a b x[ ] S xffeff dL); /* */
b = II(b c d a x[ ] S x dd L); /* */
a = II(a b c d x[ ] S x fa e fL); /* */
d = II(d a b c x[ ] S xfe ce e L); /* */
c = II(c d a b x[ ] S xa L); /* */
b = II(b c d a x[ ] S x e a L); /* */
a = II(a b c d x[ ] S xf e L); /* */
d = II(d a b c x[ ] S xbd af L); /* */
c = II(c d a b x[ ] S x ad d bbL); /* */
b = II(b c d a x[ ] S xeb d L); /* */
state[ ] += a;
state[ ] += b;
state[ ] += c;
state[ ] += d;
/*Encode把long数组按顺序拆成byte数组 因为java的long类型是 bit的
只拆低 bit 以适应原始C实现的用途
*/
private void Encode(byte[] output long[] input int len)
int i j;
for (i = j = ; j < len; i++ j += )
output[j] = (byte) (input[i] & xffL);
output[j + ] = (byte) ((input[i] >>> ) & xffL);
output[j + ] = (byte) ((input[i] >>> ) & xffL);
output[j + ] = (byte) ((input[i] >>> ) & xffL);
/*Decode把byte数组按顺序合成成long数组 因为java的long类型是 bit的
只合成低 bit 高 bit清零 以适应原始C实现的用途
*/
private void Decode(long[] output byte[] input int len)
int i j;
for (i = j = ; j < len; i++ j += )
output[i] = b iu(input[j]) | (b iu(input[j + ]) << ) | (b iu(input[j + ]) << )
| (b iu(input[j + ]) << );
return;
/*
b iu是我写的一个把byte按照不考虑正负号的原则的"升位"程序 因为java没有unsigned运算
*/
public static long b iu(byte b)
return b < ? b & x F + : b;
/*byteHEX() 用来把一个byte类型的数转换成十六进制的ASCII表示
因为java中的byte的toString无法实现这一点 我们又没有C语言中的
sprintf(outbuf % X ib)
*/
public static String byteHEX(byte ib)
char[] Digit = A B C D E F ;
char[] ob = new char[ ];
ob[ ] = Digit[(ib >>> ) & X F];
ob[ ] = Digit[ib & X F];
String s = new String(ob);
return s;
public static void main(String args[])
MD m = new MD ();
if (Array getLength(args) == ) //如果没有参数 执行标准的Test Suite
System out println( MD Test suite: );
System out println( MD (\\ \\ ): + m getMD ofStr( ));
System out println( MD (\\ a\\ ): + m getMD ofStr( a ));
System out println( MD (\\ abc\\ ): + m getMD ofStr( abc ));
System out println( MD (\\ \\ ): + m getMD ofStr( ));
System out println( MD (\\ \\ ): + m getMD ofStr( ));
System out println( MD (\\ message digest\\ ): + m getMD ofStr( message digest ));
System out println( MD (\\ abcdefghijklmnopqrstuvwxyz\\ ): + m getMD ofStr( abcdefghijklmnopqrstuvwxyz ));
System out println( MD (\\ ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz \\ ):
+ m getMD ofStr( ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ));
else
System out println( MD ( + args[ ] + )= + m getMD ofStr(args[ ]));
lishixinzhi/Article/program/Java/hx/201311/26604
Java 语言实现 MD5 加密
Java 语言实现 MD5 加密
背景说明
在实际项目中,为了安全性考虑,经常要求账号密码是以加密后的密文形式,保存到数据库中。
这样,即使有人获取到了数据库中的密文密码,也不知道明文密码信息是什么,从而防止系统被恶意访问。
密码加密有很多种方式,比如:Base64,DSA,RSA,MD5,SHA128,SHA256,SHA512等加密方式。
本文主要讲述 MD5 加密方式。
MD5 简介
MD5 消息摘要算法(英文:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。
MD5应用
1、数据加密
利用它的单向加密性,即不可逆性,我们可以应用于数据和密码的加密。
由于MD5算法的单向性,由MD5码计算出原文几乎是不可能的。目前对于这种加密方法的破解方式是收集常用的密码形式,例如生日,身份证号,电话号码等。把这些收集到的秘密用MD5处理之后进行存储,然后与需要还原的MD5进行比对,当收集的数据达到一定的数目,用户密码被破解的可能性就会变得很大。
对于这种方法,一种加强安全性的方法就是在对用户密码进行MD5处理的时候在原密码上加一个附近值,例如原密码为“password”,处理的时候变为“passworddrowssap”,经过这样的处理之后可以有效降低密码被破解的可能性。
2、确认文件是否被篡改
每个文件都可以计算出一个特定的 MD5 值。
比如,我们上传一个文件到服务器上,可以同时计算出该文件对应的 MD5 值;
在文件下载的时候,通过再次计算该文件的 MD5 值。
如果两个MD5值相同,说明文件没有变化,否则,说明文件被修改过。
Java 语言实现 MD5 加密
通过Java编写程序,实现对任意字符串进行 MD5 加密。
1、第一版代码(初始版)
代码如下:
package com.miracle.luna.md5; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Miracle Luna on 2019/11/18 */ public class Md5UtilOriginal { /** * 将数据进行 MD5 加密,并以16进制字符串格式输出 * @param data * @return */ public static String md5(String data) { try { byte[] md5 = md5(data.getBytes("utf-8")); return toHexString(md5); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } /** * 将字节数组进行 MD5 加密 * @param data * @return */ public static byte[] md5(byte[] data) { try { MessageDigest md = MessageDigest.getInstance("md5"); return md.digest(data); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return new byte[]{}; } /** * 将加密后的字节数组,转换成16进制的字符串 * @param md5 * @return */ private static String toHexString(byte[] md5) { StringBuilder sb = new StringBuilder(); System.out.println("md5.length: " + md5.length); for (byte b : md5) { sb.append(Integer.toHexString(b & 0xff)); } return sb.toString(); } public static void main(String[] args) { String password = "password"; String md5HexStr = md5(password); System.out.println("==> MD5 加密前: " + password); System.out.println("==> MD5 加密后: " + md5HexStr); } }
运行结果如下:
md5.length: 16
==> MD5 加密前: password
==> MD5 加密后: 5f4dcc3b5aa765d61d8327deb882cf99
2、第二版代码(精简版)
代码如下:
package com.miracle.luna.md5; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Miracle Luna on 2019/11/18 */ public class Md5UtilSimple { /** * 将数据进行 MD5 加密,并以16进制字符串格式输出 * @param data * @return */ public static String md5(String data) { StringBuilder sb = new StringBuilder(); try { MessageDigest md = MessageDigest.getInstance("md5"); byte[] md5 = md.digest(data.getBytes(StandardCharsets.UTF_8)); // 将字节数据转换为十六进制 for (byte b : md5) { sb.append(Integer.toHexString(b & 0xff)); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return sb.toString(); } public static void main(String[] args) { String password = "password"; String md5HexStr = md5(password); System.out.println("==> MD5 加密前: " + password); System.out.println("==> MD5 加密后: " + md5HexStr); } }
运行结果如下:
==> MD5 加密前: password
==> MD5 加密后: 5f4dcc3b5aa765d61d8327deb882cf99
3、第三版代码(最终优化版)
代码如下:
package com.miracle.luna.md5; // 此处需要引入 commons-codec-1.13.jar import org.apache.commons.codec.binary.Hex; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Miracle Luna on 2019/11/18 */ public class Md5Util { /** * 将数据进行 MD5 加密,并以16进制字符串格式输出 * @param data * @return */ public static String md5(String data) { try { MessageDigest md = MessageDigest.getInstance("MD5"); return Hex.encodeHexString(md.digest(data.getBytes(StandardCharsets.UTF_8))); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } public static void main(String[] args) { String password = "password"; String md5HexStr = md5(password); System.out.println("==> MD5 加密前: " + password); System.out.println("==> MD5 加密后: " + md5HexStr); } }
运行结果如下:
==> MD5 加密前: password
==> MD5 加密后: 5f4dcc3b5aa765d61d8327deb882cf99
commons-codec-1.13.jar 的 pom 引用如下:
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.13</version> </dependency>
MD5 在线加密&解密工具
1、MD5 在线加密工具
http://www.bejson.com/enc/md5/ (不仅支持 MD5加密,还支持 Base64,SHA等)
效果如下(在“加密前”后的输入框中输入需要 MD5 加密的字符串 --> 点击“MD5加密” --> 即可在“加密后”的显示显示框中看到加密后的密文):
2、MD5 在线解密
效果如下(输入框中输入需要解密的 MD5 密文,点击解密即可解密 ):
2) https://www.cmd5.com/ (这是一款很强大的解密工具,不仅支持 MD5,还支持SHA的解密)
效果如下(在密文输入框中输入 MD5 密文,点击“解密”,即可看到 MD5 的明文):
解密种类众多,选择范围如下:
MD5 密码安全性优化
由于现在直接将密码用 MD5 算法加密存在一定的安全隐患(被暴力破解的可能性),我们可以根据实际的需要,对密码加密的过程做一些逻辑处理。
比如,如下逻辑处理:
1)password --> Base64 加密,得到加密后的密码A;
2)password --> 翻转得到drowssap --> MD5 加密,得到加密后的密码B;
3)密码A+密码B拼接 --> MD5 加密,得到加密后的密码C;
4)密码C --> 翻转操作,产生密码D,作为最终的密文密码存到数据库中。
这样可以增强密码的安全性,减少被破解的可能性。(此处具体的逻辑优化,可以根据个人喜好和实际需求,灵活定义其变换的复杂性)。
【额外补充】
当密码以 MD5 密文存入到数据库中,用户登录的时候,前端将用户输入的明文密码传输给后端。
后端程序用同样的处理逻辑对其进行 MD5 加密,用加密后的密码与数据库中该用户的密文密码比较。
如果二者相等,说明用户输入的密码正确,允许访问系统;否则,说明密码不正确,禁止访问。
另外,为了系统的安全性考虑,防止恶意暴力尝试破解密码,我们经常限制用户输入密码错误的次数。
比如,连续输入3次或者5次密码,将会自动锁定账号一段时间(根据实际场景,设置锁定时长)。
关于 Base64 加密&解密 的Java 语言实现,请参考博客:https://www.cnblogs.com/miracle-luna/p/11128734.html
希望能帮到大家,谢谢!
以上是关于可变MD5加密(Java实现)的主要内容,如果未能解决你的问题,请参考以下文章