基于口令的密码算法—PBE实现
PBE介绍
PBE(Password-Based Encryption)是一种基于密码的加密算法,主要用于加密密钥的生成。在Java中,我们可以使用JCE(Java Cryptography Extension)提供的javax.crypto
包来实现PBE加密。
考虑一个问题:
我们想要保障重要信息的机密性,用密钥进行加密,那么怎样保证密钥的机密性,用另一个密钥加密,另一个密钥的机密性如何保障呢?
和我们密码口令一样,密码口令要保护网站资产的安全,密码口令如何保管呢,所有网站都是用同一个密码,更不安全,用一个密码保护所有的密码,这个密码我记在脑子里,可以了,这就是keepass、onepass的实现原理。
PBE实现原理
口令做为密钥的一部分,同时增加salt值保护,盐值根据不同的用户可以产生不同的值,这样可以防止适用口令一样产生的加密串是一样的。这样即使一样的加密口令,一样的密钥值,落库时候的加密值也是不一样的。
代码实现
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;
public class PBEEncryptionExample {
private static final char[] PASSWORD = "mySecretPassword".toCharArray();
private static final byte[] SALT = {
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
(byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
}; //未进行随机化处理
private static final int ITERATION_COUNT = 1000;
public static void main(String[] args) throws Exception {
String plainText = "This is a test message";
// Encrypt
byte[] encryptedBytes = encrypt(plainText.getBytes(), PASSWORD, SALT, ITERATION_COUNT);
System.out.println(Base64.getEncoder().encodeToString(encryptedBytes));
// Decrypt
byte[] decryptedBytes = decrypt(encryptedBytes, PASSWORD, SALT, ITERATION_COUNT);
System.out.println(new String(decryptedBytes));
}
private static byte[] encrypt(byte[] plainText, char[] password, byte[] salt, int iterationCount)
throws Exception {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
pbeCipher.init(Cipher.ENCRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
return pbeCipher.doFinal(plainText);
}
private static byte[] decrypt(byte[] cipherText, char[] password, byte[] salt, int iterationCount)
throws Exception {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
pbeCipher.init(Cipher.DECRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
return pbeCipher.doFinal(cipherText);
}
}eturn pbeCipher.doFinal(cipherText);
}
}
输出:
pSqiAUt7url7b7oahPKZOblYOw9UEJna
This is a test message
口令不变,加密出来的数据也是不变的
稍微改改就能实现一个简单版的keepass,比如将明文密码、适用网址生成密文保存起来。适用的时候适用自己的口令完成解密
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;
public class PBEEncryptionExample {
// private static final char[] PASSWORD = "Secbh123".toCharArray();
private static final byte[] SALT = {
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
(byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
};
private static final int ITERATION_COUNT = 1000;
public static void main(String[] args) throws Exception {
// String plainText = "This is a test message";
char[] PASSWORD = args[1].toCharArray();
String plainText = args[0];
String keyType = args[2];
// Encrypt
if (keyType.equals("en")) {
byte[] encryptedBytes = encrypt(plainText.getBytes(), PASSWORD, SALT, ITERATION_COUNT);
System.out.println(Base64.getEncoder().encodeToString(encryptedBytes));
}
if (keyType.equals("de")) {
// Decrypt
byte[] encryptedBytes= Base64.getDecoder().decode(plainText.getBytes());
byte[] decryptedBytes = decrypt(encryptedBytes, PASSWORD, SALT, ITERATION_COUNT);
System.out.println(new String(decryptedBytes));
}
}
private static byte[] encrypt(byte[] plainText, char[] password, byte[] salt, int iterationCount)
throws Exception {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
pbeCipher.init(Cipher.ENCRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
return pbeCipher.doFinal(plainText);
}
private static byte[] decrypt(byte[] cipherText, char[] password, byte[] salt, int iterationCount)
throws Exception {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
KeySpec keySpec = new PBEKeySpec(password, salt, iterationCount);
Cipher pbeCipher = Cipher.getInstance(keyFactory.getAlgorithm());
pbeCipher.init(Cipher.DECRYPT_MODE, keyFactory.generateSecret(keySpec), new PBEParameterSpec(salt, iterationCount));
return pbeCipher.doFinal(cipherText);
}
}
我只要记住自己的口令123,其他密码可以随意落盘了
输出参考:
java PBEEncryptionExample sec 123 en
lQXapDYahhg=
java PBEEncryptionExample lQXapDYahhg= 123 de
sec
原文始发于微信公众号(YY的黑板报):密码算法知识也很有意思——聊聊PBE
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论