目录

1.常见哈希算法总结:

1.1、概述

1.2、常见的哈希算法

1.2.1、MD5和SHA-1

1.2.2、RipeMD-160

2.对称加密算法与非对称加密算对比

2.1 概述:

2.1.1对称加密算法:

2.1.2非对称加密算法:


1.常见哈希算法总结:

1.1、概述

        哈希算法,又称摘要算法,它的作用是对任意一组数据进行计算,得到一组固定长度的输出摘要,可以用来验证原始数据是否被篡改。

 特点:相同的输入一定得到相同的输出,不同的输入大概率得到不同的输出

1.2、常见的哈希算法

        

哈希加密算法 是指_ci

 如上图所示,表中的哈希算法都是现在比较常见的,注意它们的输出长度不同且都是固定的,输出长度越长,越不容易产生碰撞,也就越安全。

其中最常用的是MD5算法和SHA-1算法下面介绍一下实现过程和方法:

1.2.1、MD5和SHA-1

以MD5为例:(SHA-1与之写法相同,只需修改参数中的算法名称)

        1.首先需要创建一个Message实例:使用MessageDigest.getInstance()方法,参数中传入所要用的的算法名称

哈希加密算法 是指_System_02

         2.使用update方法更新数据(注意:这个方法参数中需要传入数组)

哈希加密算法 是指_哈希加密算法 是指_03

         3.使用digest方法获取加密数组

      

哈希加密算法 是指_哈希加密算法 是指_04

        4.为了便于观察结果,使用16进制进行存储输出

 

哈希加密算法 是指_java_05

整体实现代码如下:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class Demo01 {
	public static void main(String[] args) {
		try {
			//获取基于MD5算法的工具对象
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			
			//更新原始数据
			md5.update("hello".getBytes());
			md5.update("world".getBytes());
			
			//获取加密后的结果
			byte[] resultArray = md5.digest();
			
			StringBuilder sb = new StringBuilder();
			for (byte bite : resultArray) {
				
				//自定义格式:采用十六进制输出,不足位数用0补齐
				sb.append(String.format("%02x", bite));
			}
			System.out.println(sb.toString());

			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

	}
}

        但就像前面所说那样,使用这种加密算法,只要输入内容相同,就会得到相同的加密结果,所以一些常见的明文内容的加密结果就很容易被推演出来,因此就有了彩虹表的产生。

        彩虹表就是黑客根据大量推演和数据的积累制作的常见明文的对照表。

        所以为了抵御彩虹表的攻击,在加密是可以加入随机的 "盐",即对每个口令添加随机数

哈希加密算法 是指_System_06

 添加完“盐”后的实现代码如下:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

public class Demo04 {
	public static void main(String[] args) {
		String str = "gbwztxws";
		String salt = UUID.randomUUID().toString().substring(0, 5);
		System.out.println(salt);
		
		try {
			MessageDigest digest1 = MessageDigest.getInstance("MD5");
			MessageDigest digest2 = MessageDigest.getInstance("SHA-1");
			
			digest1.update(str.getBytes());
			digest1.update(salt.getBytes());
			byte[] result1 = digest1.digest();
			
			digest2.update(str.getBytes());
			digest2.update(salt.getBytes());
			byte[] result2 = digest2.digest();
			
			StringBuilder sb1 = new StringBuilder();
			for(byte bite:result1) {
				sb1.append(String.format("%02x", bite));
			}
			
			System.out.println(sb1.length());
			System.out.println(sb1);
			
			StringBuilder sb2 = new StringBuilder();
			for(byte bite:result2) {
				sb2.append(String.format("%02x", bite));
			}

			System.out.println(sb2.length());
			System.out.println(sb2);

		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

	}
}

1.2.2、RipeMD-160

        除了上述常用的两种算法,还有一种特殊的算法RipeMD-160,它之所以特殊,是因为在使用之前,必须注册BouncyCastle提供的通知类对象BouncyCastleProvider

哈希加密算法 是指_ci_07

 除此之外,其他实现代码与前两者相同

2.对称加密算法与非对称加密算对比

2.1 概述:

        对称加密算法就是传统的用一个密码进行加密和解密,就是使用一个函数,即用来接收明文输出密文又用它接收密文输出明文

        非对称加密算法中,加密和解密使用不同的密钥,但是是同一对公钥--私钥

2.1.1对称加密算法:

        1.常用的对称加密算法:

哈希加密算法 是指_System_08

          密钥长度直接决定加密强度,而工作模式和填充模式可以看成是对称加密算法的参数和格式选择。Java标 准库提供的算法实现并不包括所有的工作模式和所有填充模式,但是通常我们只需要挑选常用的使用就可 以了。

          其中,由于DES算法密钥过于短,可以在短时间内暴力破解,所以现在基本不再使用

AES算法ECB工作模式代码实现如下:

import java.security.GeneralSecurityException;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

//AES对称加密
//ECB工作模式
public class Demo06 {
	public static void main(String[] args) throws GeneralSecurityException {

		String str = "HelloWorld";
		System.out.println("原文:" + str);

		// key必须为16个字节
		byte[] key = "qwertyuiop123456".getBytes();

		byte[] dataBytes = str.getBytes();
		byte[] encryptBytes = encrypt(key, dataBytes);
		System.out.println("加密结果:" + Base64.getEncoder().encodeToString(encryptBytes));

		byte[] decryptBytes = decrypt(key, encryptBytes);
		System.out.println("解密结果:" + new String(decryptBytes));

	}

	// 加密
	public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {

		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

		SecretKey keySpec = new SecretKeySpec(key, "AES");

		cipher.init(Cipher.ENCRYPT_MODE, keySpec);

		return cipher.doFinal(input);
	}

	// 解密
	public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {

		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

		SecretKey keySpec = new SecretKeySpec(key, "AES");

		cipher.init(Cipher.DECRYPT_MODE, keySpec);

		return cipher.doFinal(input);

	}

}

2.1.2非对称加密算法:

        例如a与b两人使用非对称加密算法进行数据传输,若a想传输数据给b,则必须先要拿到b的公钥对数据进行加密再进行传输,而加密后的内容之后b再收到数据后使用自己相对应的私钥才能进行解密,若b想传输数据给a则同理如此。

        这样加密传输的好处就是,即使在传输的过程中公钥和加密后传输的数据被截取,只要没有私钥,则仍然无法破解数据内容。但同时,它的运算速度比对称加密慢得多。

以RSA为例的非对称加密算法实现代码如下:

import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.Cipher;

// RSA
public class Main05 {
    public static void main(String[] args) throws Exception {
        // 明文:
        byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
        
        // 创建公钥/私钥对:
        Human alice = new Human("Alice");
        
        // 用Alice的公钥加密:
        // 获取Alice的公钥,并输出
        byte[] pk = alice.getPublicKey();
        System.out.println(String.format("public key(公钥): %x", new BigInteger(1, pk)));
        
        // 使用公钥加密
        byte[] encrypted = alice.encrypt(plain);
        System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypted)));
       
        // 用Alice的私钥解密:
        // 获取Alice的私钥,并输出
        byte[] sk = alice.getPrivateKey();
        System.out.println(String.format("private key: %x", new BigInteger(1, sk)));
        
        // 使用私钥解密
        byte[] decrypted = alice.decrypt(encrypted);
        System.out.println(new String(decrypted, "UTF-8"));
    }
}

// 用户类
class Human {
    String name;
    // 私钥:
    PrivateKey sk;
    // 公钥:
    PublicKey pk;

    // 构造方法
    public Human(String name) throws GeneralSecurityException {
    	// 初始化姓名
        this.name = name;
        
        // 生成公钥/私钥对:
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
        kpGen.initialize(1024);
        KeyPair kp = kpGen.generateKeyPair();
        
        this.sk = kp.getPrivate();
        this.pk = kp.getPublic();
    }

    // 把私钥导出为字节
    public byte[] getPrivateKey() {
        return this.sk.getEncoded();
    }

    // 把公钥导出为字节
    public byte[] getPublicKey() {
        return this.pk.getEncoded();
    }

    // 用公钥加密:
    public byte[] encrypt(byte[] message) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, this.pk); // 使用公钥进行初始化
        return cipher.doFinal(message);
    }

    // 用私钥解密:
    public byte[] decrypt(byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, this.sk); // 使用私钥进行初始化
        return cipher.doFinal(input);
    }
}