口令加密算法 - Java加密与安全

口令加密算法 - Java加密与安全_第1张图片

口令加密

我们在前面介绍了对称加密算法,他们的key其实一个byte数组,例如AES256算法,他的key实际上是一个32位的数组

口令加密算法 - Java加密与安全_第2张图片

我们普通的加入软件有所不同,我们在使用WinRAR这样的软件的时候,通常是用户输入的加密口令

口令加密算法 - Java加密与安全_第3张图片

如果我们要用户自己输入口令,我们就需要用到PBE算法,它是Password Based Encryption的缩写,PEB算法是由用户输入口令,

然后采用随机数杂凑计算,生成密钥然后再进行加密

1. 首先我们看password也就是用户口令,例如hello123

2. 随着salt是随机生成的一个byte数组

3. 最后的加密密钥key,它是由随机的salt和用户的password计算而成的

口令加密算法 - Java加密与安全_第4张图片

我们来比较一下标准的AES方法和PEB方法,在标准的AES算法中,用于加密的密钥key,他这个是随机产生的,在PBE算法

通过用户输入的密码password,以及随机产生的16个字节的salt,基于这两部分生成的key,进行加密,为什么要使用salt

呢,因为用户输入的口令通常都很短,引入一个随机的salt,既可以增加口令的长度,还可以让相同的口令生成相同的key,

从而提高了安全性
package com.learn.securl;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class PBECipher {
	/**
	 * 首先我们要Castle的jar包引入到项目中
	 */
	static final String CIPHER_NAME = "PBEwithSHA1and128bitAES-CBC-BC";
	/**
	 * 加密
	 */
	public static byte[] encrypt(String password, byte[] salt, byte[] input) throws Exception {
		/**
		 * 我们在加密的时候需要创建一个PBEKeySpec
		 * 还有传入的用户输入的password
		 * 得到一个PBEKeySpec对象
		 */
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		/**
		 * 然后我们通过SecretKeyFactory
		 * 通过getInstance方法
		 * 得到一个SecretKeyFactory对象
		 */
		SecretKeyFactory sKeyFactory = SecretKeyFactory
				.getInstance(CIPHER_NAME);
		/**
		 * 然后通过generateSecret传入keySpec
		 * 就可以得到一个SecretKey
		 * 这个SecretKey就是我们将来要加密的密钥
		 */
		SecretKey skey = sKeyFactory.generateSecret(keySpec);
		/**
		 * 紧接着我们要通过salt生成一个PBEParameterSpec
		 * 我们传入1000
		 * 表示用户的口令和salt会走1000次的循环
		 */
		PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
		/**
		 * 然后我们通过Cipher.getInstance得到一个Cipher对象
		 */
		Cipher cipher = Cipher.getInstance(CIPHER_NAME);
		/**
		 * init方法会传入ENCRYPT_MODE,SecretKey,
		 * 以及PBEParameterSpec这三个对象然后就可以加密
		 */
		cipher.init(Cipher.ENCRYPT_MODE, skey, pbeps);
		/**
		 * 得到密文
		 */
		return cipher.doFinal(input);
	}
	/**
	 * 解密
	 * 
	 * 在解密的时候我们需要传入用户需要的password,salt,以及密文
	 */
	public static byte[] decrypt(String password, byte[] salt, byte[] input) throws Exception {
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		SecretKeyFactory sKeyFactory = SecretKeyFactory
				.getInstance(CIPHER_NAME);
		SecretKey skey = sKeyFactory.generateSecret(keySpec);
		PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
		Cipher cipher = Cipher.getInstance(CIPHER_NAME);
		/**
		 * 然后我们把模式设置为DECRYPT_MODE
		 */
		cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);
		return cipher.doFinal(input);
	}
	
	/**
	 * 我们运行这个代码
	 * 由于我们每次运行的salt是不同的
	 * 所以每次我们得到密文也是不同的
	 * 通过用户口令和随机数
	 * 我们就保证了加密的强度
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// 把BouncyCastle作为Provider添加到java.security:
		Security.addProvider(new BouncyCastleProvider());
		// 原文:
		String message = "Hello, world! encrypted using PBE!";
		// 加密口令
		/**
		 * 我们设置一个加密口令password hello123456
		 */
		String password = "hello12345";
		// 16 bytes随机Salt:
		/**
		 * 我们通过SecureRandom.getInstanceStrong().generateSeed生成一个随机salt
		 */
		byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
		/**
		 * 我们打印这个salt
		 * salt: d4356ec3e5621a8f1f6a7be953b0c31e
		 * 我们生成的随机的salt
		 * 1个16字节的数组
		 */
		System.out.printf("salt: %032x\n", new BigInteger(1, salt));
		// 加密:
		byte[] data = message.getBytes(StandardCharsets.UTF_8);
		/**
		 * 然后调用encrypt方法进行加密
		 */
		byte[] encrypted = encrypt(password, salt, data);
		/**
		 * 加密以后的密文是用Base64表示的
		 * encrypted: 2MnA9wd1IL4n0W3d3nS5dqZ6dj1fcxZI2GJtKKIDYchw1EkodmJeOLIQpUBendR+
		 */
		System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
		// 解密:
		byte[] decrypted = decrypt(password, salt, encrypted);
		/**
		 * 解密以后得到与原文相同的信息
		 * Hello, world! encrypted using PBE!
		 */
		System.out.println(new String(decrypted, "UTF-8"));
	}
}

口令加密算法 - Java加密与安全_第5张图片

在PBE算法中,如果我们把salt固定下来,就得到了一个通用的口令加密软件

如果我们把salt存在一个U盘上,实际上就得到了一个口令+USB Key的软件,这样的好处是即使用户使用了一个非常弱的口令,

没有USB Key仍然无法解密,因为只有同时破解了口令和salt,才能计算出key,而salt一般都是128位的随机数,一般很难被

破解


最后我们总结一下:

1. PBE算法通过用户口令和随机salt计算key然后再加密

2. 用于加密的Key是通过口令和随机salt计算得出的,因此提高了安全性

3. 在PBE算法的内部,仍然是标准的对称加密算法,例如AES

 

你可能感兴趣的:(口令加密算法 - Java加密与安全)