原创作者: snowolf
阅读:85103次
评论:39条
更新时间:2011-05-26
本篇内容简要介绍BASE64、MD5、SHA、HMAC几种加密算法。
BASE64编码算法不算是真正的加密算法。
MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密的基础。单纯的以上三种的加密并不可靠。
BASE64
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
常见于邮件、http加密,截取http信息,你就会发现登录操作的用户名、密码字段通过BASE64加密的。
通过java代码实现如下:
主要就是BASE64Encoder、BASE64Decoder两个类,我们只需要知道使用对应的方法即可。另,BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充。
MD5
MD5 -- message-digest algorithm 5 (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都是MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友都见过下载链接旁边放着MD5的串。就是用来验证文件是否一致的。
通过java代码实现如下:
通常我们不直接使用上述MD5加密。通常将MD5产生的字节数组交给BASE64再加密一把,得到相应的字符串。
SHA
SHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了,
但是SHA仍然是公认的安全加密算法,较之MD5更为安全。
通过java代码实现如下:
HMAC
HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。
通过java代码实现如下:
给出一个完整类,如下:
再给出一个测试类:
控制台输出:
BASE64的加密解密是双向的,可以求反解。
MD5、SHA以及HMAC是单向加密,任何数据加密后只会产生唯一的一个加密串,通常用来校验数据在传输过程中是否被修改。其中HMAC算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。
单向加密的用途主要是为了校验数据在传输过程中是否被修改。
BASE64编码算法不算是真正的加密算法。
MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密的基础。单纯的以上三种的加密并不可靠。
BASE64
按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
常见于邮件、http加密,截取http信息,你就会发现登录操作的用户名、密码字段通过BASE64加密的。

通过java代码实现如下:
/** * BASE64解密 * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64加密 * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); }
主要就是BASE64Encoder、BASE64Decoder两个类,我们只需要知道使用对应的方法即可。另,BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充。
MD5
MD5 -- message-digest algorithm 5 (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都是MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友都见过下载链接旁边放着MD5的串。就是用来验证文件是否一致的。

通过java代码实现如下:
/** * MD5加密 * * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data) throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); }
通常我们不直接使用上述MD5加密。通常将MD5产生的字节数组交给BASE64再加密一把,得到相应的字符串。
SHA
SHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,被广泛地应用于电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了,



通过java代码实现如下:
/** * SHA加密 * * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data) throws Exception { MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } }
HMAC
HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。

通过java代码实现如下:
/** * 初始化HMAC密钥 * * @return * @throws Exception */ public static String initMacKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); SecretKey secretKey = keyGenerator.generateKey(); return encryptBASE64(secretKey.getEncoded()); } /** * HMAC加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptHMAC(byte[] data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); return mac.doFinal(data); }
给出一个完整类,如下:
import java.security.MessageDigest; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * 基础加密组件 * * @author 梁栋 * @version 1.0 * @since 1.0 */ public abstract class Coder { public static final String KEY_SHA = "SHA"; public static final String KEY_MD5 = "MD5"; /** * MAC算法可选以下多种算法 * * <pre> * HmacMD5 * HmacSHA1 * HmacSHA256 * HmacSHA384 * HmacSHA512 * </pre> */ public static final String KEY_MAC = "HmacMD5"; /** * BASE64解密 * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64加密 * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } /** * MD5加密 * * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data) throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); } /** * SHA加密 * * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data) throws Exception { MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } /** * 初始化HMAC密钥 * * @return * @throws Exception */ public static String initMacKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); SecretKey secretKey = keyGenerator.generateKey(); return encryptBASE64(secretKey.getEncoded()); } /** * HMAC加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptHMAC(byte[] data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); return mac.doFinal(data); } }
再给出一个测试类:
import static org.junit.Assert.*; import org.junit.Test; /** * * @author 梁栋 * @version 1.0 * @since 1.0 */ public class CoderTest { @Test public void test() throws Exception { String inputStr = "简单加密"; System.err.println("原文:\n" + inputStr); byte[] inputData = inputStr.getBytes(); String code = Coder.encryptBASE64(inputData); System.err.println("BASE64加密后:\n" + code); byte[] output = Coder.decryptBASE64(code); String outputStr = new String(output); System.err.println("BASE64解密后:\n" + outputStr); // 验证BASE64加密解密一致性 assertEquals(inputStr, outputStr); // 验证MD5对于同一内容加密是否一致 assertArrayEquals(Coder.encryptMD5(inputData), Coder .encryptMD5(inputData)); // 验证SHA对于同一内容加密是否一致 assertArrayEquals(Coder.encryptSHA(inputData), Coder .encryptSHA(inputData)); String key = Coder.initMacKey(); System.err.println("Mac密钥:\n" + key); // 验证HMAC对于同一内容,同一密钥加密是否一致 assertArrayEquals(Coder.encryptHMAC(inputData, key), Coder.encryptHMAC( inputData, key)); BigInteger md5 = new BigInteger(Coder.encryptMD5(inputData)); System.err.println("MD5:\n" + md5.toString(16)); BigInteger sha = new BigInteger(Coder.encryptSHA(inputData)); System.err.println("SHA:\n" + sha.toString(32)); BigInteger mac = new BigInteger(Coder.encryptHMAC(inputData, inputStr)); System.err.println("HMAC:\n" + mac.toString(16)); } }
控制台输出:
原文: 简单加密 BASE64加密后: 566A5Y2V5Yqg5a+G BASE64解密后: 简单加密 Mac密钥: uGxdHC+6ylRDaik++leFtGwiMbuYUJ6mqHWyhSgF4trVkVBBSQvY/a22xU8XT1RUemdCWW155Bke pBIpkd7QHg== MD5: -550b4d90349ad4629462113e7934de56 SHA: 91k9vo7p400cjkgfhjh0ia9qthsjagfn HMAC: 2287d192387e95694bdbba2fa941009a
BASE64的加密解密是双向的,可以求反解。
MD5、SHA以及HMAC是单向加密,任何数据加密后只会产生唯一的一个加密串,通常用来校验数据在传输过程中是否被修改。其中HMAC算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。

单向加密的用途主要是为了校验数据在传输过程中是否被修改。
39 楼 huiyuanlujun 2013-08-25 16:47
38 楼 xiebo1983 2012-04-16 17:20
从《JAVA加密与解密艺术》中,MD5,SHA属于单向加密算法,你把摘要跟加密分的太清了
如果是MD5是单向加密算法,那如何解密?单向加密算法会有一个可倒推的解密算法。
MD5 SHA 没有。他们只是做摘要。
37 楼 hualang 2012-04-16 11:36
从《JAVA加密与解密艺术》中,MD5,SHA属于单向加密算法,你把摘要跟加密分的太清了
36 楼 xiebo1983 2012-03-25 22:03
35 楼 dushanggaolou 2012-01-05 11:14
34 楼 qin_eye 2011-11-27 12:58
33 楼 marquis 2011-10-09 18:06
32 楼 zhanghh321 2011-08-09 17:46
31 楼 tan4836128 2011-08-08 15:53
30 楼 zssggg 2011-07-11 16:29
29 楼 enternalttyy 2011-06-22 13:51
28 楼 yunnysunny 2011-03-22 16:14
名称无所谓,叫哈希 或者 单向加密 都无所谓。
只是提醒一下:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
sun.*里面的类不是标准java的一部分,慎用啊。
呵呵,你提到的东西我明白,同时我在我的书中《Java加密与解密的艺术》中给出了相应的替代方案。
您的书我看了,本来想深入研究一下,后来发现,还是当手册用比较好。
27 楼 frankiegao123 2010-12-11 13:16
Why Developers Should Not Write Programs That Call 'sun' Packages
http://java.sun.com/products/jdk/faq/faq-sun-packages.html
Sun 已被 Oracle 收购,作为一家很强势的公司是极有可能将 sun.* 和 com.sun.* 改为 oracle.* 和 com.oracle.* 的。
26 楼 frankiegao123 2010-12-11 13:12
不过我认为,把 MD5、SHA、HMAC 等认为是加密算法欠妥,因为有加密就得有解密。这些算法都归于散列函数之类,在应用上主要是用于验证数据的完整性或者有效性。
25 楼 snowolf 2010-05-06 17:59
名称无所谓,叫哈希 或者 单向加密 都无所谓。
只是提醒一下:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
sun.*里面的类不是标准java的一部分,慎用啊。
呵呵,你提到的东西我明白,同时我在我的书中《Java加密与解密的艺术》中给出了相应的替代方案。
Bouncy Castle 很好的代替方案,而且是Apache licence,功能更强大,使用也很方便,可以代替sun提供的方案
个人认为,单说Base64,Commons Codec更具优势!
24 楼 littleJava 2010-05-06 17:30
名称无所谓,叫哈希 或者 单向加密 都无所谓。
只是提醒一下:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
sun.*里面的类不是标准java的一部分,慎用啊。
呵呵,你提到的东西我明白,同时我在我的书中《Java加密与解密的艺术》中给出了相应的替代方案。
Bouncy Castle 很好的代替方案,而且是Apache licence,功能更强大,使用也很方便,可以代替sun提供的方案
23 楼 snowolf 2010-04-11 14:28
名称无所谓,叫哈希 或者 单向加密 都无所谓。
只是提醒一下:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
sun.*里面的类不是标准java的一部分,慎用啊。
呵呵,你提到的东西我明白,同时我在我的书中《Java加密与解密的艺术》中给出了相应的替代方案。
22 楼 lanxiazhi 2010-04-10 21:50
名称无所谓,叫哈希 或者 单向加密 都无所谓。
只是提醒一下:
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
sun.*里面的类不是标准java的一部分,慎用啊。
21 楼 tjgamejx2 2010-04-01 10:45
20 楼 huang4953 2010-02-08 15:43
19 楼 shrpcn 2010-01-27 12:45
18 楼 weihairui 2010-01-12 09:42
17 楼 snowolf 2009-08-20 14:42
简单加密
BASE64加密后:
vPK1pbzTw9w=
BASE64解密后:
简单加密
Mac密钥:
34e4yyZ5u5eSFp/ACJthtOcFXlKFNy4aczXRAY6DZA72FhwsyfwgI4efhFuWFbd6WWXKnlG5Q0rA
PPka5PKIoQ==
MD5:
-12d1456f5d947be6eac80fc07900be99
SHA:
-bbbd559051qu2b5pl635l3jj8jrvodsn
HMAC:
358250966fbd6166b94b384105f6894b
一样的结果~~~奇怪
这是中文编码问题!楼上几位使用的是GBK编码,我使用的是UTF-8编码。用GBK编码1个汉字就是2个字节,用UTF-8编码则1个汉字3个字节。转换为二进制再经过base64编码后当然会有所不同了!
16 楼 lfrick 2009-08-14 10:17
15 楼 onray 2009-08-10 14:02
简单加密
BASE64加密后:
vPK1pbzTw9w=
BASE64解密后:
简单加密
Mac密钥:
34e4yyZ5u5eSFp/ACJthtOcFXlKFNy4aczXRAY6DZA72FhwsyfwgI4efhFuWFbd6WWXKnlG5Q0rA
PPka5PKIoQ==
MD5:
-12d1456f5d947be6eac80fc07900be99
SHA:
-bbbd559051qu2b5pl635l3jj8jrvodsn
HMAC:
358250966fbd6166b94b384105f6894b
一样的结果~~~奇怪
14 楼 lingangw 2009-06-29 22:06
我是第一次使用JUnit,是因为JUnit的原因吗?
13 楼 snowolf 2009-06-28 21:03
另外在我的机器上运行的结果中只显示到MAC密钥结果一行,后面的都没有显示出来。
还有运行后:JUnit前面有个错号,test前面也有个错号,也没有什么提示。
不知道是什么原因?
和环境有关吗?我使用的是jdk1.6
12 楼 lingangw 2009-06-28 02:59
另外在我的机器上运行的结果中只显示到MAC密钥结果一行,后面的都没有显示出来。
还有运行后:JUnit前面有个错号,test前面也有个错号,也没有什么提示。
不知道是什么原因?
11 楼 chenlixun 2009-06-26 11:54
原文:
简单加密
BASE64加密后:
vPK1pbzTw9w=
BASE64解密后:
简单加密
Mac密钥:
QIdiQufh2AYOjOVW7TW++PzDFqYKogLzZqB9wxJLMS+JQSAffZeFLJ9TCH23yZwuqBh5aQdAWP7e
LpH/D99kSA==
MD5:
-12d1456f5d947be6eac80fc07900be99
SHA:
-bbbd559051qu2b5pl635l3jj8jrvodsn
HMAC:
358250966fbd6166b94b384105f6894b
可能是JVM的默认编码方式和博主的不一样。
我也有同样的问题,目前没找到原因.
10 楼 snowolf 2009-06-25 22:55
知道碰到行家了,之前的理解,的确有些想当然,认为有加便有解,不知学术上的事,见笑见笑.
虽然我已承认单项加密,并更新了自己的知识库,但我会叫他们散列,并刻意和对称/非对称加密加以区分.
殊途同归,呵呵!
密码学杂凑函数(有时称作消息摘要函数,杂凑函数又称散列函数或哈希函数),陷门函数。叫那个都无所谓!