在Java 8中使用PBKDF2WithHmacSHA1生成派生密钥在高并发性下是不确定的
在Java 8(Linux)中使用在Java 8中使用PBKDF2WithHmacSHA1生成派生密钥在高并发性下是不确定的,java,Java,在Java 8(Linux)中使用PBKDF2WithHmacSHA1生成Java密码派生的密钥,在高并发性下调用时,似乎会随机返回归零的byte[]密钥。我无法用Java7重现这一点。由于我已经为我的用例找到了一个解决方案,并且我不能再进一步研究这个问题,所以我询问那里的Java专家是否可以: 请检查下面的代码 验证再现性 解释可能的原因 下面的示例将以一种非常不确定的方式在Linux x64上使用Java 8(可能需要执行几次才能失败): 导入java.security.Key; 导入j
PBKDF2WithHmacSHA1
生成Java密码派生的密钥,在高并发性下调用时,似乎会随机返回归零的byte[]
密钥。我无法用Java7重现这一点。由于我已经为我的用例找到了一个解决方案,并且我不能再进一步研究这个问题,所以我询问那里的Java专家是否可以:
- 请检查下面的代码
- 验证再现性
- 解释可能的原因
导入java.security.Key;
导入java.security.NoSuchAlgorithmException;
导入java.security.spec.InvalidKeySpecException;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
导入javax.crypto.SecretKey;
导入javax.crypto.SecretKeyFactory;
导入javax.crypto.spec.PBEKeySpec;
导入javax.crypto.spec.SecretKeySpec;
导入javax.xml.bind.DatatypeConverter;
公共班机{
私有静态最终字符串PASSWORD=“swordfish”;
private static final Callable CONCURRENT=new Callable(){
@凌驾
公共布尔调用()引发异常{
final Key key1=deriveKeyFromPassword(PASSWORD.toCharArray());
最后一个字节[]key1bytes=key1.getEncoded();
对于(int i=0;i<10000;i++){
final Key key2=deriveKeyFromPassword(PASSWORD.toCharArray());
最后一个字节[]key2bytes=key2.getEncoded();
如果(!array.equals(key1bytes,key2bytes)){
抛出新异常(“键不匹配!\n”
+key1:“+DatatypeConverter.printHexBinary(key1.getEncoded())+”\n
+“key2:”+DatatypeConverter.printHexBinary(key2.getEncoded())+“\n”);
}
}
返回true;
}
};
公共静态密钥deriveKeyFromPassword(最终字符[]密码){
试一试{
最终SecretKeyFactory=SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA1”);
最终PBEKeySpec spec=新的PBEKeySpec(密码,新字节[8],5256);
最终保密密钥机密=工厂生成密钥(规范);
返回新的SecretKeySpec(secret.getEncoded(),“AES”);
}捕获(NoSuchAlgorithmException | InvalidKeySpece异常){
抛出新的运行时异常(e);
}
}
公共静态void main(最终字符串[]args)引发异常{
final ExecutorService executor=Executors.newCachedThreadPool();
试一试{
int迭代次数=1;
while(true){
最终ArrayList结果=新建ArrayList();
对于(int i=0;i<10;i++){
结果.添加(执行者.提交(并发));
}
对于(最终未来结果:结果){
result.get();
}
System.out.println((迭代次数*10*10000*2)+“派生键”);
迭代++;
}
}捕获(最终异常e){
e、 printStackTrace();
系统出口(1);
}
}
}
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class Main {
private static final String PASSWORD = "swordfish";
private static final Callable<Boolean> CONCURRENT = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
final Key key1 = deriveKeyFromPassword(PASSWORD.toCharArray());
final byte[] key1bytes = key1.getEncoded();
for (int i = 0; i < 10000; i++) {
final Key key2 = deriveKeyFromPassword(PASSWORD.toCharArray());
final byte[] key2bytes = key2.getEncoded();
if (!Arrays.equals(key1bytes, key2bytes)) {
throw new Exception("Keys do not match!\n"
+ "key1: " + DatatypeConverter.printHexBinary(key1.getEncoded()) + "\n"
+ "key2: " + DatatypeConverter.printHexBinary(key2.getEncoded()) + "\n");
}
}
return true;
}
};
public static Key deriveKeyFromPassword(final char[] password) {
try {
final SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
final PBEKeySpec spec = new PBEKeySpec(password, new byte[8], 5, 256);
final SecretKey secret = factory.generateSecret(spec);
return new SecretKeySpec(secret.getEncoded(), "AES");
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
public static void main(final String[] args) throws Exception {
final ExecutorService executor = Executors.newCachedThreadPool();
try {
int iterations = 1;
while (true) {
final ArrayList<Future<Boolean>> results = new ArrayList<Future<Boolean>>();
for (int i = 0; i < 10; i++) {
results.add(executor.submit(CONCURRENT));
}
for (final Future<Boolean> result : results) {
result.get();
}
System.out.println((iterations * 10 * 10000 * 2) + " keys derived");
iterations++;
}
} catch (final Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}