package org.ovirt.engine.core.engineencryptutils;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.util.Enumeration;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import org.ovirt.engine.core.compat.Encoding;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.RefObject;
import org.ovirt.engine.core.compat.StringHelper;
public class EncryptionUtils {
private static String algo = "RSA";
private static String certType = "JKS";
/**
* Encrypts the specified source.
*
* @param source
* The source.
* @param cert
* The cert.
* @return base64 encoded result.
*/
private static String encrypt(String source, Certificate cert) throws GeneralSecurityException {
String result = null;
byte[] cipherbytes = Encoding.UTF8.getBytes(source.trim());
Cipher rsa = Cipher.getInstance(algo);
rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
byte[] cipher = rsa.doFinal(cipherbytes);
result = Encoding.Base64.getString(cipher);
return result;
}
/**
* Decrypts the specified source given a Private Key
*
* @param source
* The source.
* @param key
* The private key.
* @param error
* The error.
* @return
*/
private static String Decrypt(String source, Key key, RefObject<String> error) {
error.argvalue = "";
String result = "";
try {
{
byte[] cipherbytes = Encoding.Base64.getBytes(source);
{
Cipher rsa = Cipher.getInstance(algo);
rsa.init(Cipher.DECRYPT_MODE, key);
{
byte[] plainbytes = rsa.doFinal(cipherbytes);
result = Encoding.ASCII.getString(plainbytes);
}
}
}
} catch (Exception e) {
log.error("Error in the Decryption", e);
error.argvalue = e.getMessage();
}
return result;
}
/**
* Encrypts the specified source using certification file.
*
* @param source
* The source.
* @param certificateFile
* The certificate file.
* @param passwd
* The passwd.
* @param alis
* The certificate alias.
* @return
*
* Loads a private key from a JKS file using the supplied password and encrypts the value. The string which
* is returned is first base64 encoded The keyfile is loaded first off of the classpath, then from the file
* system.
*/
public final static String encrypt(String source, String certificateFile, String passwd, String alias)
throws Exception {
String result = "";
if (!StringHelper.isNullOrEmpty(source.trim())) {
try {
KeyStore store = EncryptionUtils.getKeyStore(certificateFile, passwd, certType);
Certificate cert = store.getCertificate(alias);
result = encrypt(source, cert);
} catch (Exception e) {
log.error("Error doing the encryption", e);
throw e;
}
}
return result;
}
/**
* Decrypts the specified source using certification file.
*
* @param source
* The source.
* @param keyFile
* The key file.
* @param passwd
* The passwd.
* @param alias
* The certificate alias.
* @return
*
* Loads a private key from a JKS file using the supplied password and decrypts the value. The string to be
* decrypted is assumed to have been base64 encoded. The keyfile is loaded from the file system
*/
public static String decrypt(String source, String keyFile, String passwd, String alias)
throws Exception {
String result = source;
try {
if (!StringHelper.isNullOrEmpty(source.trim())) {
KeyStore store = EncryptionUtils.getKeyStore(keyFile, passwd, certType);
Key key = store.getKey(alias, passwd.toCharArray());
result = decrypt(source, key);
}
} catch (Exception e) {
log.errorFormat("Failed to decrypt", e.getMessage());
log.debug("Failed to decrypt", e);
throw e;
}
return result;
}
private static String decrypt(String source, Key key) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String result = "";
byte[] cipherbytes = Encoding.Base64.getBytes(source);
Cipher rsa = Cipher.getInstance(algo);
rsa.init(Cipher.DECRYPT_MODE, key);
byte[] plainbytes = rsa.doFinal(cipherbytes);
result = Encoding.UTF8.getString(plainbytes);
return result;
}
/**
* Decrypts the specified source using Store.
*
* @param source
* The source.
* @param certificateFingerPrint
* The certification finger print.
* @param error
* The error.
* @return
*/
public static final String Decrypt(String source, String keyFile, String passwd,
RefObject<String> error) {
error.argvalue = "";
String result = source;
if (!StringHelper.isNullOrEmpty(source.trim())) {
try {
KeyStore store = EncryptionUtils.getKeyStore(keyFile, passwd, certType);
// Get the first one.
String alias = "None";
Enumeration<String> aliases = store.aliases();
while (aliases.hasMoreElements()) {
alias = aliases.nextElement();
break;
}
Key key = store.getKey(alias, passwd.toCharArray());
result = Decrypt(source, key, error);
} catch (Exception e) {
log.error("Error doing the decryption", e);
error.argvalue = e.getMessage();
}
}
return result;
}
/**
* Determines whether the specified name is a password holder.
*
* @param name
* The name.
* @return <c>true</c> if the specified name is password; otherwise, <c>false</c>.
*/
public static boolean IsPassword(String name) {
final String PASSWORD = "NoSoup4U";
return (name.toLowerCase().endsWith(PASSWORD));
}
public static KeyStore getKeyStore(String path, String passwd, String storeType) {
try {
InputStream fis = new FileInputStream(path);
KeyStore store = KeyStore.getInstance(storeType);
store.load(fis, passwd.toCharArray());
return store;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Encodes a given secret by specified key material and algorithm<BR>
* If not supplying any key material and algorithm using defaults:<BR>
* keyMaterial - <i>"jaas is the way"</i> <BR>
* algorithm - <i>"Blowfish"<i>
*
* @param secret
* the encrypted object
* @param keyMaterial
* the material for the encryption
* @param algorithm
* defines which algorithm to use
* @return the encrypted secret or null if encryption fails
*/
public static String encode(String secret, String keyMaterial, String algorithm) {
Cipher cipher;
byte[] encoding = null;
try {
EncryptUtilParams params = new EncryptUtilParams(keyMaterial, algorithm);
cipher = Cipher.getInstance(params.algorithm);
cipher.init(Cipher.ENCRYPT_MODE, params.secretKey);
encoding = cipher.doFinal(secret.getBytes());
} catch (Exception e) {
log.error("Error in encrypting the secret", e);
}
return encoding != null ? (new BigInteger(encoding)).toString(16) : null;
}
/**
* Decodes a given secret by specified key material and algorithm.<BR>
* If no key material and algorithm are supplied, using defaults:<BR>
* keyMaterial - <i>"jaas is the way"</i> <BR>
* algorithm - <i>"Blowfish"<i>
*
* @param secret
* the object to decode
* @param keyMaterial
* the material for the decoding action
* @param algorithm
* defines which algorithm to use
* @return the decoded secret or null if decode fails
*/
public static String decode(String secret, String keyMaterial, String algorithm) {
BigInteger n = new BigInteger(secret, 16);
byte[] encoding = n.toByteArray();
byte[] decode = null;
try {
EncryptUtilParams params = new EncryptUtilParams(keyMaterial, algorithm);
Cipher cipher = Cipher.getInstance(params.algorithm);
cipher.init(Cipher.DECRYPT_MODE, params.secretKey);
decode = cipher.doFinal(encoding);
} catch (Exception e) {
log.error("Error in decrypting the secret", e);
}
return decode != null ? new String(decode) : null;
}
/**
* Class use to holds and defines defaults values for encryption/decryption <BR>
* based on. Targeted to set defaults values as used in JBoss security login module:<BR>
* keyMaterial - <i>"jaas is the way"</i> <BR>
* algorithm - <i>"Blowfish"<i>
*/
private static class EncryptUtilParams {
private String algorithm = null;
private SecretKeySpec secretKey = null;
public EncryptUtilParams(String keyMaterial, String algorithm) {
if (algorithm == null || "".equals(algorithm)) {
this.algorithm = "Blowfish";
} else {
this.algorithm = algorithm;
}
if (keyMaterial == null || "".equals(keyMaterial)) {
secretKey = new SecretKeySpec("jaas is the way".getBytes(), this.algorithm);
} else {
secretKey = new SecretKeySpec(keyMaterial.getBytes(), this.algorithm);
}
}
}
private static LogCompat log = LogFactoryCompat.getLog(EncryptionUtils.class);
}