package org.ovirt.engine.core.uutils.crypto;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
public class EnvelopePBE {
private static final String ARTIFACT_KEY = "artifact";
private static final String VERSION_KEY = "version";
private static final String ALGORITHM_KEY = "algorithm";
private static final String SALT_KEY = "salt";
private static final String ITERATIONS_KEY = "iterations";
private static final String SECRET_KEY = "secret";
private static final String ARTIFACT = "EnvelopePBE";
private static final String VERSION = "1";
public static boolean check(String blob, String password) throws IOException, GeneralSecurityException {
final Map<String, String> map = new ObjectMapper().readValue(
Base64.decodeBase64(blob),
TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, String.class)
);
if (!ARTIFACT.equals(map.get(ARTIFACT_KEY))) {
throw new IllegalArgumentException(String.format("Invalid artifact '%s'", map.get(ARTIFACT_KEY)));
}
if (!VERSION.equals(map.get(VERSION_KEY))) {
throw new IllegalArgumentException(String.format("Invalid version '%s'", map.get(VERSION_KEY)));
}
byte[] salt = Base64.decodeBase64(map.get(SALT_KEY));
return Arrays.equals(
Base64.decodeBase64(map.get(SECRET_KEY)),
SecretKeyFactory.getInstance(map.get(ALGORITHM_KEY)).generateSecret(
new PBEKeySpec(
password.toCharArray(),
salt,
Integer.parseInt(map.get(ITERATIONS_KEY)),
salt.length * 8
)
).getEncoded()
);
}
public static String encode(String algorithm, int keySize, int iterations, String randomProvider, String password) throws IOException, GeneralSecurityException {
final Base64 base64 = new Base64(0);
final Map<String, String> map = new HashMap<>();
byte[] salt = new byte[keySize/8];
SecureRandom.getInstance(randomProvider == null ? "SHA1PRNG" : randomProvider).nextBytes(salt);
map.put(ARTIFACT_KEY, ARTIFACT);
map.put(VERSION_KEY, VERSION);
map.put(ALGORITHM_KEY, algorithm);
map.put(SALT_KEY, base64.encodeToString(salt));
map.put(ITERATIONS_KEY, Integer.toString(iterations));
map.put(
SECRET_KEY,
base64.encodeToString(
SecretKeyFactory.getInstance(algorithm).generateSecret(
new PBEKeySpec(
password.toCharArray(),
salt,
iterations,
salt.length*8
)
).getEncoded()
)
);
return base64.encodeToString(new ObjectMapper().writeValueAsString(map).getBytes(StandardCharsets.UTF_8));
}
}