• 廖雪峰Java10加密与安全-4加密算法-2口令加密算法


    对称加密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的对象keySpec
            PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
            //获取SecretKeyFactory对象skeyFactory
            SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance(CIPHER_NAME);
            //传入keySpec,获取密钥:SecretKey类型的示例skey
            SecretKey skey = skeyFactory.generateSecret(keySpec);
            //将salt和用户输入的口令做1000次循环,获取PBEParameterSpec类型示例pbesp
            PBEParameterSpec 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.security
            Security.addProvider(new BouncyCastleProvider());
            String message = "Hello world!encrypted using PBE!";
            String password = "hello12345";
            //16字节的salt
            byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
            System.out.printf("salt:%032x
    ",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)
  • 相关阅读:
    Delphi使用Indy、ICS组件读取网页
    用SendNotifyMessage代替PostMessage避免消息丢失
    LuaPlus的编译和引用
    如何转换和输出超大整数(64位)
    jQuery 源码:封装 Event
    jQuery 源码:操作样式
    jQuery 源码:元素位置
    模拟ES5 Array.prototype.reduce
    as 和 is 运算符以及安全的类型强制转换
    计算机编程基础
  • 原文地址:https://www.cnblogs.com/csj2018/p/10859098.html
Copyright © 2020-2023  润新知