java消息摘要算法加密

慕课网学习笔记
参考:Java加密算法



消息摘要算法加密

  •  消息摘要算法主要分为3类:MD(Message Digest)、SHA(Secure Hash Algorithm)、MAC(Message Authentication Code),以上3类算法的主要作用是验证数据的完整性——是数字签名的核心算法。

消息摘要算法——MD

  • MD算法家族有3类MD2、MD4、MD5,MD家族生成的都是128位的信息摘要。
算法摘要长度实现方
MD2128JDK
MD4128Bouncy
MD5128JDK
  • 信息摘要算法由于使用的是一种单向函数,所以理论上是不可破解的(山东大学的王晓云教授已经破解了MD5和SHA,所以消息摘要是可以伪造的,只不过难度比较大)。所有MD算法进行摘要的结果都是128为位(32位16进制的数字,因为1位16进制数代表4位二进制数)

以下是Java中实现的各种MD加密:

package md;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class JavaMD {

    private static String src = "object-oriented"; // 需要加密的原始字符串

    public static void main(String[] args) throws NoSuchAlgorithmException {
        System.out.println("原始字符串:" + src + "\n");

        jdkMD5();
        bouncyCastleMD5();
        commonsCodecMD5();
        System.out.println();

        jdkMD2();
        bouncyCastleMD2();
        commonsCodecMD2();
        System.out.println();

        bouncyCastleMD4();
    }

    /** jdk实现MD5加密 */
    public static void jdkMD5() throws NoSuchAlgorithmException {

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] md5Bytes = md.digest(src.getBytes());
        System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));//利用第三方包将byte数组转化为16进制字符串
    }

    /** jdk实现MD2加密 */
    public static void jdkMD2() throws NoSuchAlgorithmException {

        MessageDigest md = MessageDigest.getInstance("md2");
        byte[] md5Bytes = md.digest(src.getBytes());
        System.out.println("JDK MD2:" + Hex.encodeHexString(md5Bytes));
    }

    /** Bouncy Castle实现MD4加密 */
    public static void bouncyCastleMD4() throws NoSuchAlgorithmException{
        /*通过这种方式给JDK动态添加一个provider,就可以通过这种方式获得JDK本身不支持的MD4了*/
        Security.addProvider(new BouncyCastleProvider());

        MessageDigest md = MessageDigest.getInstance("md4");

        byte[] md4Bytes = md.digest(src.getBytes());
        System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
    }

    /** Bouncy Castle实现MD5加密 */
    public static void bouncyCastleMD5(){
        Digest digest = new MD5Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[]md5Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(md5Bytes, 0);
        System.out.println("bc MD5:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));
    }

    /** Bouncy Castle实现MD2加密 */
    public static void bouncyCastleMD2(){
        Digest digest = new MD2Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[]md2Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(md2Bytes, 0);
        System.out.println("bc MD2:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md2Bytes));

    }

    /** Commons Codec 实现MD5加密*/
    public static void commonsCodecMD5() {
        System.out.println("cc MD5:\t" + DigestUtils.md5Hex(src.getBytes()));
    }

    /** Commons Codec 实现MD2加密*/
    public static void commonsCodecMD2() {
        System.out.println("cc MD2:\t" + DigestUtils.md2Hex(src.getBytes()));
    }
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

以上程序的运行结果:
这里写图片描述

  • JDK本身提供了MD2和MD5的实现,apache的Commons Codec在JDK的基础上进行了改良,使用Commons Codec提供接口进行MD2和MD5加密将会简单很多。JDK本省并没有提供MD4算法的实现,但是我们可以通过动态添加provider的方式让jdk支持MD4,见以下代码:
/* 通过这种方式给JDK动态添加一个provider,就可以通过这种方式获得JDK本身不支持的MD4了 */
Security.addProvider(new BouncyCastleProvider());

MessageDigest md = MessageDigest.getInstance("md4");

byte[] md4Bytes = md.digest(src.getBytes());
System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • Bouncy Castle提供了MD2、MD4和MD5的实现,对消息摘要算法的支持比较完善,但是API还是没有Apache的Commons Codec友善。因此,如果我们要进行MD2和MD4实现,最好选用Commons Codec。

MD算法的应用

这里写图片描述

  • 注册时:
      应用程序服务器将用户提交的密码进行MD5即:数据库中存放的用户名是明文,而密码是密文(16进制字符串)摘要算法,得到32位的16进制字符串(密文)。把用户名(明文)和密码(密文)进行信息持久化存储到数据库中,返回注册结果。

  • 登录时:
      应用程序服务器同样对密码进行MD5摘要,然后将用户提交的用户名和密码的摘要信息和数据库中存储的信息进行比对,返回登录结果。


消息摘要算法——SHA

安全散列算法,固定长度的摘要信息。被认为是MD5的继承者。是一个系列,包括SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512),也就是除了SHA-1,其他的4种都被称为是SHA-2。每种算法的摘要长度和实现方如下:
这里写图片描述

  • SHA算法的实现和MD算法的实现大同小异,也是JDK提供了默认的几种实现,apache的Commons Codec在JDK的基础上进行了优化,使其更好用,而Bouncy Castle是JDK的拓展,提供了JDK和Commons Codec没有的SHA-224的实现。
package sha;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;

public class JavaSHA {

    private static String src = "object-oriente"; // 需要加密的原始字符串

    public static void main(String[] args) throws NoSuchAlgorithmException {

        System.out.println("原始字符串:" + src);

        jdkSHA1();
        bouncyCastleSHA1();
        commonsCodecSAH1();
        System.out.println();

        bouncyCastleSHA224();
        System.out.println();
        jdkSHA256();

        bouncyCastleSHA256();
    }

    /** JDK实现sha-1 */
    public static void jdkSHA1() throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("sha");// sha1算法传入参数为sha
        byte[] sha1Bytes = md.digest(src.getBytes());
        System.out.println("JDK SHA-1:\t" + Hex.encodeHexString(sha1Bytes));
    }

    /** JDK实现sha-256 */
    public static void jdkSHA256() throws NoSuchAlgorithmException{
        MessageDigest md = MessageDigest.getInstance("sha-256");
        md.update(src.getBytes());
        System.out.println("JDK SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md.digest()));
    }

    /** Bouncy Castle实现sha-1 */
    public static void bouncyCastleSHA1(){

        Digest digest = new SHA1Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[]sha1Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha1Bytes, 0);
        System.out.println("bc SHA-1:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));
    }

    /** Bouncy Castle实现sha-224 */
    public static void bouncyCastleSHA224(){

        Digest digest = new SHA224Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[]sha224Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha224Bytes, 0);
        System.out.println("bc SHA-224:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));
    }

    /** Bouncy Castle实现sha-256 */
    public static void bouncyCastleSHA256() {
        Digest digest = new SHA256Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[] sha256Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha256Bytes, 0);
        System.out.println("bc SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha256Bytes));
    }

    /** Commons Codec实现sha-1 */
    public static void commonsCodecSAH1(){

        System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src.getBytes()));

        /* 采用下面的方式更加方便 */
//        System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src));

    }
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

运行结果:
这里写图片描述

SHA算法的应用

 在浏览器的证书管理器中证书:WEB证书一般采用SHA算法。
 这里写图片描述

消息摘要算法是为了防止消息在传输过程中的篡改。
这里写图片描述

我们在很多网站上都可以用QQ账号一键登录,通常腾讯会给每一个接入方一个key,可能会约定一个消息传送的格式(例如:http://**?msg=12Hsad74mj&&timestamp=1309488734),其中msg=摘要信息+key+时间戳。

消息摘要算法——MAC

MAC(Message Authentication Code),兼容了MD和SHA的特性,并且在它们的基础上加入了密钥。因此MAC也称为HMAC(keyed-Hash Message Authentication Code)含有密钥的散列函数算法。

  • MD系列:HmacMD2、HmacMD4、HmacMD5
  • SHA系列:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512

例如:常用的Linux客户端SecurityCRT。MAC的算法的提供者如下:
这里写图片描述

Commons Codec中并没有提供Hmac算法的实现。

下面的程序以JDK本身和Bouncy Castle实现了HmacMD5,如果需要实现其他的加密只需要改变相关的参数即可:

package hmac;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.DecoderException;
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 JavaHmac {

    private static String src = "object-oriente"; // 需要加密的原始字符串

    public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, DecoderException {

        System.out.println("原始字符串:" + src + "\n");
        jdkHmacMD5();
        bouncyCastleHmacMD5();
    }

    public static void jdkHmacMD5() throws NoSuchAlgorithmException, InvalidKeyException, DecoderException{

        //1.得到密钥
        KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); 
        SecretKey secretKey = keyGenerator.generateKey();//生成密钥
//        byte[] key = secretKey.getEncoded();//获得密钥
        byte[] key = Hex.decodeHex("aabbccddee".toCharArray());

        //2.还原密钥
        SecretKey restoreSecretKey = new SecretKeySpec(key, "hmacMD5");

        //3.信息摘要
        Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());//实例化mac
        mac.init(restoreSecretKey);//初始化mac
        byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());//执行摘要

        System.out.println("jdkHmacMD5:\t" + Hex.encodeHexString(hmacMD5Bytes));
    }

    public static void bouncyCastleHmacMD5() {

        HMac hmac = new HMac(new MD5Digest());
        //生成密钥的时候以aabbccddee为基准
        hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("aabbccddee")));
        hmac.update(src.getBytes(), 0, src.getBytes().length);

        // 执行摘要
        byte[]hmacMDdBytes = new byte[hmac.getMacSize()];
        hmac.doFinal(hmacMDdBytes, 0);

        System.out.println("bcHmacMD5:\t"+org.bouncycastle.util.encoders.Hex.toHexString(hmacMDdBytes));
    }

}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

运行结果:
这里写图片描述

HMAC算法的应用:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值