可变在这里含义很简单 就是最终的加密结果是可变的 而非必需按标准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 = partLeni + <inputLeni += ) {
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 <leni++)
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 <leni++ 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 <leni++ 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散列函数,也称作哈希函数,消息摘要函数,单向函数或者杂凑函数。散列函数主要用于验证数据的完整性。通过散列函数,可以创建消息的“数字指纹”,消息接收方可以通过校验消息的哈希值来验证消息的完整性,防止消息被篡改。散列函数具有以下特性:
任何消息经过散列函数处理后,都会产生一个唯一的散列值,这个散列值可以用来验证消息的完整性。计算消息散列值的过程被称为“消息摘要”,计算消息散列值的算法被称为消息摘要算法。常使用的消息摘要算法有:MD—消息摘要算法,SHA—安全散列算法,MAC—消息认证码算法。本文主要来了解MD算法。
MD5算法是典型的消息摘要算法,它是由MD4,MD3和MD2算法演变而来。无论是哪一种MD算法,其原理都是接受一个任意长度的消息并产生一个128位的消息摘要。如果把得到的消息摘要转换成十六进制字符串,则会得到一个32字节长度的字符串,我们平常见到的大部分MD数字指纹就是一个长度为32的十六进制字符串。
假设原始消息长度是b(以bit为单位),注意这里b可以是任意长度,并不一定要是8的整数倍。计算该消息MD5值的过程如下:
在计算消息的MD5值之前,首先对原始信息进行填充,这里的信息填充分为两步。
第一步,对原始信息进行填充,填充之后,要求信息的长度对512取余等于448。填充的规则如下:假设原始信息长度为b bit,那么在信息的b+1 bit位填充1,剩余的位填充0,直到信息长度对512取余为448。这里有一点需要注意,如果原始信息长度对512取余正好等于448,这种情况仍然要进行填充,很明显,在这时我们要填充的信息长度是512位,直到信息长度对512取余再次等于448。所以,填充的位数最少为1,最大为512。
第二步,填充信息长度,我们需要把原始信息长度转换成以bit为单位,然后在第一步操作的结果后面填充64bit的数据表示原始信息长度。第一步对原始信息进行填充之后,信息长度对512取余结果为448,这里再填充64bit的长度信息,整个信息恰好可以被512整除。其实从后续过程可以看到,计算MD5时,是将信息分为若干个分组进行处理的,每个信息分组的长度是512bit。
在进行MD5值计算之前,我们先来做一些定义。
下面就是最核心的信息处理过程,计算MD5的过程实际上就是轮流处理每个信息分组的过程。
MD5算法实现如下所示。
这里也和Java提供的标准MD5算法进行了对比,通过测试可以看到该MD5计算的结果和Java标准MD5算法的计算结果是一样的。
这是我以前做的一个小项目时用到md5写的
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
//将用户密码进行md5加密 并返回加密后的32位十六进制密码
public class MD5Util {
public static String md5(String password) {
try {
// 获取md5对象
MessageDigest md = MessageDigest.getInstance("md5")
// 获取加密后的密码并返回十进制字节数组
byte[] bytes = md.digest(password.getBytes())
// 遍历数组得到每个十进制数并转换成十六进制
StringBuffer sb = new StringBuffer()
for (byte b : bytes) {
// 把每个数转成十六进制 存进字符中
sb.append(toHex(b))
}
String finish = sb.toString()
return finish
} catch (NoSuchAlgorithmException e) {
e.printStackTrace()
throw new RuntimeException(e)
}
}
// 十进制转十六进制方法
private static String toHex(byte b) {
int target = 0
if (b <0) {
target = 255 + b
} else {
target = b
}
int first = target / 16
int second = target % 16
return Hex[first] + Hex[second]
}
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) {
String a = MD5Util.md5("1234")
System.out.println(a)
}*/
}