算法

[ 加密 ] AES好是好 密钥长度却是固定 但我想任意位数可否

2021-09-04  本文已影响0人  一个好汉
用户想打架篇

用户输入的口令并不能直接作为AES的密钥进行加密
用户当场暴跳如雷...
比特长度恰好是128/192/256位或者说16/24/32字节
这可如何是好呀

再加上用户输入的口令一般都有规律,
安全性远远不如安全随机数产生的随机口令
极其容易被破解

用户输入的口令,通常还需要使用PBE算法,采用随机数杂凑计算出真正的密钥,再进行加密

来人 上代码
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;

/**
 * 口令加密
 * 记得引入 BouncyCastle jar包
 */
public class PBEEncrypt {
    public static void main(String[] args) throws Exception {
        // 把BouncyCastle作为Provider添加到java.security:
        Security.addProvider(new BouncyCastleProvider());
        // 原文:
        String message = "Hello, world!";
        // 加密口令:
        String password = "hello12345";
        // 16 bytes随机Salt:
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        System.out.printf("salt: %032x\n", new BigInteger(1, salt));
        // 加密:
        byte[] data = message.getBytes(StandardCharsets.UTF_8);
        byte[] encrypted = encrypt(password, salt, data);
        System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(password, salt, encrypted);
        System.out.println("decrypted: " + new String(decrypted, StandardCharsets.UTF_8));
    }

    /**
     * 加密
     */
    public static byte[] encrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
        // 通过 SecretKeyFactory 获取Key
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        // 通过加盐 获取 AlgorithmParameterSpec 指定了循环次数1000,循环次数越多 暴力破解难度越大
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        // Cipher 初始化
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        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("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);
        return cipher.doFinal(input);
    }
}

来人 上结果
salt: ee160bd84def30cbbd5feb04b60b7e41
encrypted: 5S8RWNzBLXRcUOiKB6e2vA==
decrypted: Hello, world!
来人 上结论

PBEwithSHA1and128bitAES-CBC-BC 算法通过用户口令和安全的随机salt计算出Key,然后底层使用AES再进行加密

Key通过口令和安全的随机salt计算得出,大大提高了安全性

上一篇下一篇

猜你喜欢

热点阅读