本篇内容简要介绍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代码实现如下:
- /**
- * 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通过碰撞法都被破解了, 但是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算法有一个密钥,增强了数据传输过程中的安全性,强化了算法外的不可控因素。
单向加密的用途主要是为了校验数据在传输过程中是否被修改。
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 引用
知道碰到行家了,之前的理解,的确有些想当然,认为有加便有解,不知学术上的事,见笑见笑.
虽然我已承认单项加密,并更新了自己的知识库,但我会叫他们散列,并刻意和对称/非对称加密加以区分.
殊途同归,呵呵!
密码学杂凑函数(有时称作消息摘要函数,杂凑函数又称散列函数或哈希函数),陷门函数。叫那个都无所谓!
9 楼 trydofor 2009-06-25 06:52 引用
知道碰到行家了,之前的理解,的确有些想当然,认为有加便有解,不知学术上的事,见笑见笑.
虽然我已承认单项加密,并更新了自己的知识库,但我会叫他们散列,并刻意和对称/非对称加密加以区分.
8 楼 snowolf 2009-06-24 12:33 引用
我比较同意 trydofor 的说法。
加密的东西是可以解密的。
散列是单向的,不能解密。
所以 MD5, SHA是散列。base64属于机密算法。
看来兴趣未减,搜搜密码学杂凑函数(有时称作消息摘要函数,杂凑函数又称散列函数或哈希函数)陷门函数,加密不一定有解密!
在现代密码学中,杂凑函数占据基础而又重要的地位。密码学杂凑函数也称Hash函数、哈希函数或单向散列函数,它可以将任意长度的消息压缩到固定长度的杂凑值。杂凑值也被称为杂凑码、杂凑结果、消息摘要或数字指纹。杂凑函数的重要之处就是能够赋予每个消息唯一的“数字指纹”。例如,杂凑值“72c067b50c90837c95186d019f686700”可以看作是使用MD5算法对字符串“Cryptanalysis of Hash Functions and HMAC/NMAC”生成的“数字指纹”,即使更动该消息串的一个字母,对应的杂凑值也会变为截然不同的“指纹”。 杂凑函数在现代密码学中有着极其重要的用途,它不仅在安全通信中起着重要的作用,而且是许多密码算法与密码协议安全的基本前提条件。杂凑函数的最重要用途之一是用在数字签名中,它是保证数字签名方案安全而有效的充分必要条件。通常用公钥密码算法进行数字签名时,一般不是对消息直接签名,而是对消息的杂凑值进行签名,这样既可以减少计算量、提高效率,也可以破坏数字签名算法的某些代数结构。因此,对杂凑函数的研究在密码分析领域具有重要意义。 除了数据压缩、易于计算...
Cryptographic hash functions play a fundamental role in modern cryptography. They are used to compress messages of arbitrary length to fixed length hash values which are also called hash codes, hash results, message digests or digital fingerprints. A primary motivation for cryptographic hash functions is that they serve as compact representative images of input messages, which they can uniquely identify. For example, the MD5 hash code "72c067b50c90837c95186d019f686700" can be looked on as the "fingerp...
文献名称 杂凑函数以及HMAC/NMAC的安全性分析
Article Name
英文(英语)翻译 Cryptanalysis of Hash Functions and HMAC/NMAC;
作者 于红波; 导师:王小云;
Author
作者单位
Author Agencies 山东大学;
文献出处
Article From 山东大学; 信息安全(专业) 博士论文 2007年度
关键词 输入您的搜索字词 提交搜索表单
杂凑函数; HMAC; NMAC; 碰撞攻击; 第二原根攻击; 多碰撞攻击;
Keywords hash function;HMAC;NMAC;collision attack;second-preimage attack;multi-collision attack;
先了解下王小云的专注吧!
7 楼 renchunli 2009-06-24 10:41 引用
我比较同意 trydofor 的说法。
加密的东西是可以解密的。
散列是单向的,不能解密。
所以 MD5, SHA是散列。base64属于机密算法。
6 楼 snowolf 2009-06-04 21:28 引用
如果没记错的话,(BASE64外)这叫散列,消息摘要,或hash 加密是另外一个概念,有对称加密,非对称加密. 加密是可以解密的.
从密钥学的角度讲,消息摘要算法属于单向加密算法。
5 楼 trydofor 2009-06-04 19:57 引用
加密是另外一个概念,有对称加密,非对称加密.
加密是可以解密的.
4 楼 snowolf 2009-06-03 22:50 引用
3 楼 kinkding 2009-06-03 22:33 引用
原文:
简单加密
BASE64加密后:
vPK1pbzTw9w=
BASE64解密后:
简单加密
Mac密钥:
QIdiQufh2AYOjOVW7TW++PzDFqYKogLzZqB9wxJLMS+JQSAffZeFLJ9TCH23yZwuqBh5aQdAWP7e
LpH/D99kSA==
MD5:
-12d1456f5d947be6eac80fc07900be99
SHA:
-bbbd559051qu2b5pl635l3jj8jrvodsn
HMAC:
358250966fbd6166b94b384105f6894b
可能是JVM的默认编码方式和博主的不一样。