对称加密key是一个byte数组,如AES256算法的key是一个32字节的数组,普通的加密软件由用户输入加密口令。如果由用户输入口令,进行加密/解密,需要用到PBE算法。
1.PBE:Password Based Encryption
- 由用户输入口令,采用随机数杂凑计算出密钥再进行加密
- Password:用户口令,例如“hello123”
- Salt:随机生成的byte[]
- Key:由随机的salt和password计算而成:generate(byte[] salt,String password)
2.AES和PBE的对比:
AES
byte[] message = ...;byte[] key = generated16Bytes();//算法随机生成16字节的数组byte[] encrypted = aes128_encrypt(key, message);
PBE
byte[] message = ...;String password = "hello123";byte[] salt = random16Bytes();//随机产生一个16字节的salt//为什么引入salt?因为用户输入的口令通常都很短,引入一个随机的salt,既可增加口令的长度,还可以让相同的口令生成不同的key,从而提高安全性。byte[] key = generated16BytesFrom(password, salt); byte[] encrypted = aes128_encrypt(key,message);
3.代码示例:salt不固定
package com.testList;import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;public class SplitString {static final String CIPHER_NAME = "PBEwithSHA1and128bitAES-CBC-BC";//加密public static byte[] encrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {//传入char数组,获取一个PBEKeySpec的对象keySpecPBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());//获取SecretKeyFactory对象skeyFactorySecretKeyFactory skeyFactory = SecretKeyFactory.getInstance(CIPHER_NAME);//传入keySpec,获取密钥:SecretKey类型的示例skeySecretKey skey = skeyFactory.generateSecret(keySpec);//将salt和用户输入的口令做1000次循环,获取PBEParameterSpec类型示例pbespPBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);Cipher cipher = Cipher.getInstance(CIPHER_NAME);//初始化:指定加密模式,传入skey,pbeps对象cipher.init(Cipher.ENCRYPT_MODE, skey, pbeps);return cipher.doFinal(input);}public static byte[] decrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {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);//初始化:指定解密模式,传入skey,pbeps对象cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);return cipher.doFinal(input);}public static void main(String[] args) throws Exception{//把BouncyCastle作为provider添加到java.securitySecurity.addProvider(new BouncyCastleProvider());String message = "Hello world!encrypted using PBE!";String password = "hello12345";//16字节的saltbyte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);System.out.printf("salt:%032x\n",new BigInteger(1,salt));byte[] data = message.getBytes(StandardCharsets.UTF_8);byte[] encryted = encrypt(password,salt,data);//打印Base64加密后的密文System.out.println("encrypted:"+Base64.getEncoder().encodeToString(encryted));byte[] decrypted = decrypt(password,salt,encryted);System.out.println("decrypted:"+new String(decrypted,"UTF-8"));}
}
由于每次的salt不一样,每次的密文也不一样。
4.salt固定
如果把salt固定,就得到了一个通用的口令加密软件。
只有同事破解了salt+口令,才能解密。而salt为128为随机数,很难被破解
5.总结:
- PBE算法通过用户口令和随机salt计算key然后再加密
- key通过口令和随机salt计算出,提高了安全性
- PBE算法内部使用的仍然是标准对称加密算法(例如AES)