常用加密算法的Java实现
——单向加密算法MD5和SHA
1、Java
的安全体系架构
1.1
Java
的安全体系架构介绍
Java
中为安全
框架
提供类和
接口
。
JDK
安全
API
是
Java
编程语言的核心
API
,位于
java
.security
包(及其子包),以及
sun.security
API
包(及其子包)中。设计用于帮助开发人员在程序中同时使用低级和高级安全功能。
JDK 1.1
中第一次发布的
JDK
安全中引入了“
Java
加密
体系结构
”
(
JCA
)
,指的是用于访问和开发
Java
平台密码功能的构架。在
JDK 1.1
中,
JCA
包括用于数字签名和
报文摘要
的
API
。
JDK 1.2
大大扩展了
Java
加密体系结构,它还对证书管理基础结构进行了升级以支持
X.509
v3
证书,并为划分细致、可配置性强、功能灵活、可扩展的访问控制引入了新的
Java
安全
体系结构
。
Java
加密体系结构包含
JDK 1.2
安全
API
中与密码有关的部分,以及本文档中提供的一组约定和规范。为实现多重、可互操作的密码,它还提供了“提供者”体系结构。
Java
密码扩展
(
JCE
)
)扩展了
JCA API
,包括用于加密、
密钥
交换和信息
认证码
(
MAC
)的
API
。
JCE
和
JDK
密码共同提供了一个与平台无关的完整密码
API
。
JCE
作为
JDK
的扩展将独立发布,以符合美国的出口控制约束。
1.2
在
Eclipse
中关联
JDK
的源码
为了更加深刻的理解单向加密算法
MD5
和
SHA
的在
Java
中的实现,可使用
Eclipse IDE
关联
JDK
的源码(笔者所用的是
JDK6.0
)。
JDK6.0
安装完成后在
JDK
的根目录(
eg. C:\Java\jdk1.6.0_21
)有
src.zip
目录。可将该目录解压到另一个目录(
eg. D:\amigo\study\
技术随笔
\201405
)。
src.zip
中并不包含所有的
JDK
源代码,例如
sun
下面的子包都是不存在
src.zip
中的(
eg.
本文使用的
sun.security
包及其子包就不在其中)。
要想下载这些子包,需要下载
OpenJDK
的源代码,
openjdk
是
jdk
的开放原始码版本,以
GPL
协议的形式放出。在
JDK7
的时候,
openjdk
已经成为
jdk7
的主干开
发,
sun jdk7
是在
openjdk7
的基础上发布的,其大部分原始码都相同,只有少部分原始码被替换掉。使用
JRL(JavaResearch License
,
Java
研究授权协议
)
发布。
OpenJDK
的下载地址:
http://download.java.net/openjdk/jdk6/
下载完毕后将解压后的
openjdk-6-src-b27-26_oct_2012\jdk\src\share\classes
目录下的所有的文件和文件夹拷贝到刚才解压的
src
目录下。
接下来在
Eclipse
配置关联源码:点击“
Windows
”
->
“
Preferences
”,在左侧菜单选择“
Java
”
->
“
Installed JREs
”,若已经配置本机的
JRE
,可以不用配置。若未配置,点击右侧的“
Add
”按钮,在弹出的“
Add JRE
”窗口选择安装的
JDK6.0
的路径(
eg. C:\Java\jdk1.6.0_21
)。点击“
OK
”按钮完成
JRE
的设置。
选中已设置的
JRE
,点击右侧的“
Edit…
”按钮,在弹出窗口中选择
rt.jar
包后,点击“
Source Attachment…
”按钮,在弹出的窗口中点击“
External Folder…
”按钮,将源码路径指向刚才
src
的路径(
eg. D:\amigo\study\
技术随笔
\201405
)。参见下图:
点击“
OK
”按钮设置完成后,在其后编写
MD5
和
SHA
的实现时,在调用
MessageDigest
的相关方法的地方,可使用调试模式
F5
单步调试查看
Java
中
MD5
和
SHA
单向加密算法实现主要涉及的类。
1.3 JDK
中
MD5
和
SHA
加密的主要类
在
JDK6.0
中,与
MD5
与
SHA
密切相关的几个类的类图如下:
其中“
MessageDigestSpi
”为顶层抽象类,同一个包下的“
MessageDigest
”和“
DigestBase
”为子抽象类。
在上面的类图中,使用了
Delegate
(委托)设计模式。这种模式的原理为类
B
(在此处为
Delegage
内部类)和类
A
(在此处为
MessageDigestSpi
类)是两个互相没有什么关系的类,
B
具有和
A
一模一样的方法和属性;并且调用
B
中的方法和属性就是调用
A
中同名的方法和属性。
B
好像就是一个受
A
授权委托的中介。第三方的代码不需要知道
A
及其子类的存在,也不需要和
A
及其子类发生直接的联系,通过
B
就可以直接使用
A
的功能,这样既能够使用到
A
的各种功能,又能够很好的将
A
及其子类保护起来了。
MD5
和
SHA
的相关代码都在
MD5
和
SHA
等类中,但是面向客户的
MessageDigest
抽象类不需要跟各个实现类打交道,只要通过委托类与其打交道即可。
2
、
MD5
加密
2.1
概述
Message Digest Algorithm MD5
(中文名为
消息摘要算法
第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。该
算法
的文件号为
RFC 1321
(
R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992
)
.
MD5
的全称是
Message-Digest Algorithm 5
(信息
-
摘要算法),在
90
年代初由
MIT Laboratory for Computer Science
和
RSA Data Security Inc
的
Ronald L. Rivest
开发出来,经
MD2
、
MD3
和
MD4
发展而来。
MD5
用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译
摘要算法
、
哈希算法
),主流编程语言普遍已有
MD5
实现。将
数据
(如
汉字
)运算为另一固定长度值,是杂凑算法的基础原理,
MD5
的前身有
MD2
、
MD3
和
MD4
。
MD5
的作用是让大容量信息在用
数字签名
软件签署私人
密钥
前被
"
压缩
"
成一种保密的格式(就是把一个任意长度的字节串变换成一定长的
十六进制
数字串)。
2.2
算法原理
对
MD5
算法简要的叙述可以为:
MD5
以
512
位分组来处理输入的信息,且每一分组又被划分为
16
个
32
位子分组,经过了一系列的处理后,算法的输出由四个
32
位分组组成,将这四个
32
位分组级联后将生成一个
128
位散列值。
在
MD5
算法中,首先需要对信息进行填充,使其位长对
512
求余的结果等于
448
。因此,信息的位长(
Bits Length
)将被扩展至
N*512+448
,
N
为一个非负整数,
N
可以是零。填充的方法如下,在信息的后面填充一个
1
和无数个
0
,直到满足上面的条件时才停止用
0
对信息的填充。然后,在这个结果后面附加一个以
64
位二进制表示的填充前信息长度。经过这两步的处理,信息的位长
=N*512+448+64=(N+1
)
*512
,即长度恰好是
512
的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
2.3 Java
中的
MD5
实现
MD5
加密算法的
Java
实现如下所示:
package
amigo.endecrypt;
import
java.security.MessageDigest;
/**
* 采用MD5加密
*
@author
Xingxing,Xie
* @datetime 2014-5-31
*/
public
class
MD5Util {
/***
* MD5加密 生成32位md5码
*
@param
待加密字符串
*
@return
返回32位md5码
*/
public
static
String md5Encode(String inStr)
throws
Exception {
MessageDigest md5 =
null
;
try
{
md5 = MessageDigest.getInstance("MD5");
}
catch
(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return
"";
}
byte
[] byteArray = inStr.getBytes("UTF-8");
byte
[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue =
new
StringBuffer();
for
(
int
i = 0; i < md5Bytes.length; i++) {
int
val = ((
int
) md5Bytes[i]) & 0xff;
if
(val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return
hexValue.toString();
}
/**
* 测试主函数
*
@param
args
*
@throws
Exception
*/
public
static
void
main(String args[])
throws
Exception {
String str =
new
String("amigoxiexiexingxing");
System.out.println("原始:" + str);
System.out.println("MD5后:" + md5Encode(str));
}
}
测试结果:
原始:
amigoxiexiexingxing
MD5
后:
e9ac094091b96b84cca48098bc21b1d6
3
、
SHA
加密
3.1
概述
SHA
是一种
数据加密算法
,该算法经过加密专家多年来的发展和改进已日益完善,现在已成为公认的最安全的散列算法之一,并被广泛使用。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种
“
指纹
”
或是
“
摘要
”
所以对散列值的
数字签名
就可以视为对此明文的数字签名。
安全散列算法
SHA
(
Secure Hash Algorithm
,
SHA)
是美国国家标准技术研究所发布的国家标准
FIPS PUB 180
,最新的标准已经于
2008
年更新到
FIPS PUB 180-3
。其中规定了
SHA-1
,
SHA-224
,
SHA-256
,
SHA-384
,和
SHA-512
这几种
单向散列算法
。
SHA-1
,
SHA-224
和
SHA-256
适用于长度不超过
2^64
二进制位的消息。
SHA-384
和
SHA-512
适用于长度不超过
2^128
二进制位的消息。
3.2
原理
SHA-1
是一种
数据加密算法
,该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。
单向散列函数
的安全性在于其产生散列值的操作过程具有较强的单向性。如果在输入序列中嵌入密码,那么任何人在不知道密码的情况下都不能产生正确的散列值,从而保证了其安全性。
SHA
将输入流按照每块
512
位(
64
个字节)进行分块,并产生
20
个字节的被称为信息认证代码或信息摘要的输出。
该算法输入
报文
的长度不限,产生的输出是一个
160
位的
报文摘要
。输入是按
512
位的分组进行处理的。
SHA-1
是不可逆的、防冲突,并具有良好的雪崩效应。
通过散列算法可实现
数字签名
实现,数字签名的原理是将要传送的明文通过一种函数运算(
Hash
)转换成
报文摘要
(不同的明文对应不同的报文摘要),报文摘要加密后与明文一起传送给接受方,接受方将接受的明文产生新的报文摘要与发送方的发来报文摘要解密比较,比较结果一致表示明文未被改动,如果不一致表示明文已被篡改。
MAC
(信息认证代码)就是一个散列结果,其中部分输入信息是密码,只有知道这个密码的参与者才能再次计算和验证
MAC
码的合法性。
3.3 Java
中的
SHA
实现
SHA
的在
Java
的实现与
MD5
类似,参考代码如下所示:
package
amigo.endecrypt;
import
java.security.MessageDigest;
/**
* 采用SHAA加密
*
@author
Xingxing,Xie
* @datetime 2014-6-1
*/
public
class
SHAUtil {
/***
* SHA加密 生成40位SHA码
*
@param
待加密字符串
*
@return
返回40位SHA码
*/
public
static
String shaEncode(String inStr)
throws
Exception {
MessageDigest sha =
null
;
try
{
sha = MessageDigest.getInstance("SHA");
}
catch
(Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return
"";
}
byte
[] byteArray = inStr.getBytes("UTF-8");
byte
[] md5Bytes = sha.digest(byteArray);
StringBuffer hexValue =
new
StringBuffer();
for
(
int
i = 0; i < md5Bytes.length; i++) {
int
val = ((
int
) md5Bytes[i]) & 0xff;
if
(val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return
hexValue.toString();
}
/**
* 测试主函数
*
@param
args
*
@throws
Exception
*/
public
static
void
main(String args[])
throws
Exception {
String str =
new
String("amigoxiexiexingxing");
System.out.println("原始:" + str);
System.out.println("SHA后:" + shaEncode(str));
}
}
测试结果如下所示:
原始:
amigoxiexiexingxing
SHA
后:
04f79f496dd6bdab3439511606528a4ad9caac5e
3
、
SHA-1
和
MD5
的比较
因为二者均由
MD4
导出,
SHA-1
和
MD5
彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:
1
)对强行攻击的安全性
:最显著和最重要的区别是
SHA-1
摘要比
MD5
摘要长
32
位。使用强行技术,产生任何一个
报文
使其摘要等于给定报摘要的难度对
MD5
是
2^128
数量级的操作,而对
SHA-1
则是
2^160
数量级的操作。这样,
SHA-1
对强行攻击有更大的强度。
2
)对密码分析的安全性
:由于
MD5
的设计,易受密码分析的攻击,
SHA-1
显得不易受这样的攻击。
3
)速度
:在相同的硬件上,
SHA-1
的运行速度比
MD5
慢。
4
、参考文档
《
MD5
加密
_
百度百科》:
http://baike.baidu.com/view/1039631.htm?fr=aladdin
《
MD5_
百度百科》:
http://baike.baidu.com/view/7636.htm?fr=aladdin
《
MD5
解密网站》:
http://www.cmd5.com/
《
SHA_
百度百科》:
http://baike.baidu.com/link?url=FmqSdqu1CxQXDnQPxCD3hTdepu0RWV6N5dec5ZNWSC_U4WWle4a1h0E6744FnCRI
《加密解密在线测试网站》:
http://tripledes.online-domain-tools.com/
Openjdk
下载地址:
http://download.java.net/openjdk/jdk6/
《
OpenJDK
和
JDK
的区别和联系》:
http://blog.csdn.net/kiyoki/article/details/8777744
http://www.blogjava.net/amigoxie/archive/2014/06/01/414299.html