口令加密算法
上一节我们讲的AES加密,细心的童鞋可能会发现,密钥长度是固定的128/192/256位,而不是我们用WinZip/WinRAR那样,随便输入几位都可以。
这是因为对称加密算法决定了口令必须是固定长度,然后对明文进行分块加密。又因为安全需求,口令长度往往都是128位以上,即至少16个字符。
但是我们平时使用的加密软件,输入6位、8位都可以,难道加密方式不一样?
实际上用户输入的口令并不能直接作为AES的密钥进行加密(除非长度恰好是128/192/256位),并且用户输入的口令一般都有规律,安全性远远不如安全随机数产生的随机口令。因此,用户输入的口令,通常还需要使用PBE算法,采用随机数杂凑计算出真正的密钥,再进行加密。
PBE就是Password Based Encryption的缩写,它的作用如下:
key = generate(userPassword, secureRandomPassword);
PBE的作用就是把用户输入的口令和一个安全随机的口令采用杂凑后计算出真正的密钥。以AES密钥为例,我们让用户输入一个口令,然后生成一个随机数,通过PBE算法计算出真正的AES口令,再进行加密,代码如下:
public class Main {
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("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, "UTF-8"));
}
// 加密:
public static byte[] encrypt(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.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);
}
}
使用PBE时,我们还需要引入BouncyCastle,并指定算法是PBEwithSHA1and128bitAES-CBC-BC
。观察代码,实际上真正的AES密钥是调用Cipher
的init()
方法时同时传入SecretKey
和PBEParameterSpec
实现的。在创建PBEParameterSpec
的时候,我们还指定了循环次数1000
,循环次数越多,暴力破解需要的计算量就越大。
如果我们把salt和循环次数固定,就得到了一个通用的“口令”加密软件。如果我们把随机生成的salt存储在U盘,就得到了一个“口令”加USB Key的加密软件,它的好处在于,即使用户使用了一个非常弱的口令,没有USB Key仍然无法解密,因为USB Key存储的随机数密钥安全性非常高。
小结
PBE算法通过用户口令和安全的随机salt计算出Key,然后再进行加密;
Key通过口令和安全的随机salt计算得出,大大提高了安全性;
PBE算法内部使用的仍然是标准对称加密算法(例如AES)。
相关文章
- [IJCAI | 论文解读] AttExplainer:通过强化学习的注意力机制来解释 Transformer
- [Brief. Bioinformatics | 论文简读] 一种从生物序列中提取特征的工具
- [KDD 2022 | 论文简读] 避免由于节点嵌入中的相似性假设而导致的偏差
- [JCIM 2022 | 论文简读] 多任务深度神经网络在Ames致突变性预测中的应用
- VScode本地进行Jenkinsfile语法验证
- Apache Airflow-ETL 工作流的下一级CRON替代方案
- Protein science︱王舒禹团队:贝叶斯与图神经网络结合预测突变对蛋白质稳定性的影响
- 软件测试|测试方法论—边界值
- [AAAI 2022 | 论文简读] SpreadGNN: 分子数据上图神经网络的分散式多任务联邦学习
- [Brief. Bioinformatics | 论文简读] CReSIL:从长读序列中准确识别染色体外环状DNA
- [Nat. Biotechnol. | 论文简读] 利用大规模数据标注和深度学习对组织图像进行具有人类水平表现的全细胞分割
- Apache Airflow的组件和常用术语
- [IJCAI 2022 | 论文简读] 不仅仅是同质性:结构感知路径聚合图神经网络
- [Nucleic Acids Res. | 论文简读] 使用纳米孔进行长读长单分子 RNA 结构测序
- [Nat. Commun. | 论文简读] 一个连接分子结构和生物医学文本的深度学习系统,其理解力可与人类专业人士相媲美
- [Nature Chemistry | 论文简读] 对酪氨酸的深度学习研究表明漫游会导致光损伤
- [BIB | 论文简读] BioGPT:用于生物医学文本生成和挖掘的生成性预训练转化器
- [MICCAI 2022 | 论文简读] ASA:用于预训练脑核磁分割的注意力对称自动编码器开源
- Jenkins: 如何更新当前构建名称和描述
- [KDD 2022 | 论文简读] 用于实体对齐的多模态孪生神经网络