Java | 加密技术 | 摘要加密算法(不含原理)

一、背景简介

1.1 含义

消息摘要采用单向Hash函数将需加密的明文"摘要"成一串密文,这一串密文亦称为数字指纹(Finger Print)。它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。这个加密算法就是摘要算法,也有叫hash算法/不可逆算法。(都是从不同角度(结果、实质、特点)的命名,可能有区别,这里没有深究)

1.2 消息摘要特点

也可以说是摘要算法的特点

  1. 唯一性:数据只要有一点改变,那么再通过消息摘要算法得到的摘要也会发生变化。虽然理论上有可能会发生碰撞,但是概率极其低。
  2. 不可逆(无法倒推):消息摘要算法的密文无法被解密,可以利用唯一性去穷举,但概率微乎其微,密码越复杂所需解密时间越长,没有破解不了的加密,只是时间成本太高。
  3. 不需要密钥(对比对称/非对称加密):可使用于分布式网络。
  4. 长度固定:无论输入的明文有多长,计算出来的消息摘要的长度总是固定的。

1.3 常用的摘要算法

消息摘要算法包括三个系列:

  1. MD(Message Digest,消息摘要算法);MD5MD4MD2
  2. SHA(Secure Hash Algorithm,安全散列算法);SHA1
  3. MAC(Message AuthenticationCode,消息认证码算法);

JDK中使用MD5和SHA这两种消息摘要的方式基本一致:

  • 初始化MessageDigest对象
  • 更新要计算的内容
  • 生成摘要

二、具体实现

1. MD系列

1.1 简介

主要包括:MD5MD4MD2;目前被广泛应用于数据完整性校验、数据(消息)摘要、数据密码加密等;MD2、MD4、MD5 都产生16字节(128位)的校验值,一般用32位十六进制数表示,实际实用中会编码成字符;MD2的算法较慢但相对安全,MD4速度很快,但安全性下降,MD5比MD4更安全、速度更快;目前主流是MD5,MD6已推出但还在测试阶段。

1.2 应用举例

电驴(点对点的下载工具)使用的是经过改良的MD4的算法,这种改良后的MD4算法主要是用于通过P2P下载的文件截成块,分块之后进行摘要,通过摘要来验证所文件的最终的完整性,如果不完整是解压不开的。

1.3 代码实现

MD5在JDK中已经实现,也有common codes、bouncy castle实现的,其中common codes只是对JDK中MD5的实现进行了简化,JDK提供的MD5,MD2的实现偏底层一些,缺少了相应的进制的转换。比如,将byte[]数组转换为十六进制。
common-codes maven坐标
bouncy castle maven坐标
代码参考:消息摘要算法

package com.timliu.security.message_digest;
 
import java.security.MessageDigest;
import java.security.Security;
 
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
public class MD5Test {
 
	public static final String src = "hello world";
 
	public static void main(String[] args) {
		jdkMD5();
		jdkMD2();
 
		bcMD4();
		bcMD5();
 
		bc2jdkMD4();
 
		ccMD5();
		ccMD2();
 
	}
 
	// 用jdk实现:MD5
	public static void jdkMD5() {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");// 得到MD5加密的对象
			byte[] md5Bytes = md.digest(src.getBytes());
			System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));// Hex.encodeHexString()将byte[]数组转换成十六进制
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	// 用jdk实现:MD2
	public static void jdkMD2() {
		try {
			MessageDigest md = MessageDigest.getInstance("MD2");
			byte[] md2Bytes = md.digest(src.getBytes());
			System.out.println("JDK MD2:" + Hex.encodeHexString(md2Bytes));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	// 用bouncy castle实现:MD5
	public static void bcMD5() {
		MD5Digest digest = new MD5Digest();
		digest.update(src.getBytes(), 0, src.getBytes().length);
		byte[] md5Bytes = new byte[digest.getDigestSize()];
		digest.doFinal(md5Bytes, 0);
		System.out.println("bouncy castle MD5:"
				+ org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));
 
	}
 
	// 用bouncy castle实现:MD4
	public static void bcMD4() {
		MD4Digest digest = new MD4Digest();
		digest.update(src.getBytes(), 0, src.getBytes().length);
		byte[] md4Bytes = new byte[digest.getDigestSize()];
		digest.doFinal(md4Bytes, 0);
		System.out.println("bouncy castle MD4:"
				+ org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
	}
 
	// 用bouncy castle与jdk结合实现:MD4
	public static void bc2jdkMD4() {
		try {
			Security.addProvider(new BouncyCastleProvider());
			MessageDigest md = MessageDigest.getInstance("MD4");
			byte[] md4Bytes = md.digest(src.getBytes());
			System.out.println("bc and JDK MD4:"
					+ Hex.encodeHexString(md4Bytes));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	// 用common codes实现实现:MD5
	public static void ccMD5() {
		System.out.println("common codes MD5:"
				+ DigestUtils.md5Hex(src.getBytes()));
	}
 
	// 用common codes实现实现:MD2
	public static void ccMD2() {
		System.out.println("common codes MD2:"
				+ DigestUtils.md2Hex(src.getBytes()));
	}
 
}

2 SHA系列

2.1 简介

SHA(Secure Hash Algorithm)是由美国专门制定密码算法的标准机构——美国国家标准技术研究院(NIST)制定的,SHA系列算法的摘要长度分别为:SHA为20字节(160位)、SHA256为32字节(256位)、 SHA384为48字节(384位)、SHA512为64字节(512位),由于它产生的数据摘要的长度更长,因此更难以发生碰撞,它是未来数据摘要算法的发展方向。由于SHA系列算法的数据摘要长度较长,因此其运算速度与MD5相比,也相对较慢。
  目前SHA1的应用较为广泛,主要应用于CA和数字证书中,另外在目前互联网中流行的BT软件中,也是使用SHA1来进行文件校验的。

2.2 代码实现

    /**
     * JDK原生实现 
     * @Comment SHA1实现
     */
    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();
    }

	/**
	* commons codec实现
	* @Comment SHA1加密密码
	* org.apache.commons.codec.digest.DigestUtils
	*/
	public static String encodePassword(String psw) {
	    if(StringUtils.isEmpty(psw)){
	        return null;
	    }else{
	        return DigestUtils.sha1Hex(psw);
	    }
	} 
 
 

非对称加密算法:RSA,DSA/DSS
对称加密算法:AES,RC4,3DES
HASH算法(不可逆):MD5,SHA1,SHA256,HMAC

3 MAC 系列

HMAC(keyed-Hash Message Authentication Code):含有密钥的散列函数算法,包含了MD和SHA两个系列的消息摘要算法,HMAC只是在原有的MD和SHA算法的基础上添加了密钥。
融合MD系列:HmacMD2、HmacMD4、HmacMD5
融合SHA系列:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA38、HmacSHA512
实现方有:JDK、bouncy castle

package com.timliu.security.message_digest;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
 
public class HMACTest {
	public static final String src = "hello world";
 
	public static void main(String[] args) {
		jdkHmacMD5();
		bcHmacMD5();
 
	}
 
	// 用jdk实现:
	public static void jdkHmacMD5() {
		try {
			// 初始化KeyGenerator
			KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
			// 产生密钥
			SecretKey secretKey = keyGenerator.generateKey();
			// 获取密钥
			// byte[] key = secretKey.getEncoded();
			byte[] key = Hex.decodeHex(new char[] { '1', '2', '3', '4', '5',
					'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e' });
 
			// 还原密钥,HmacMD5是算法的名字
			SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacMD5");
			// 实例化MAC
			Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());
			// 初始化MAC
			mac.init(restoreSecretKey);
			// 执行消息摘要
			byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());
			System.out.println("jdk hmacMD5:"
					+ Hex.encodeHexString(hmacMD5Bytes));
 
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	// 用bouncy castle实现:
	public static void bcHmacMD5() {
		HMac hmac = new HMac(new MD5Digest());
		// 必须是16进制的字符,长度必须是2的倍数
		hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex
				.decode("123456789abcde")));
		hmac.update(src.getBytes(), 0, src.getBytes().length);
 
		// 执行摘要
		byte[] hmacMD5Bytes = new byte[hmac.getMacSize()];
		hmac.doFinal(hmacMD5Bytes, 0);
		System.out.println("bc hmacMD5:"
				+ org.bouncycastle.util.encoders.Hex.toHexString(hmacMD5Bytes));
 
	}
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值