/***************************************************************************
* Copyright (c) 2012-2013 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.vmware.bdd.security;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.codec.binary.Base64;
import com.vmware.aurora.exception.CommonException;
import com.vmware.bdd.exception.EncryptionException;
import com.vmware.bdd.utils.AuAssert;
public class EncryptionGuard {
private static final String UTF8_ENCODING = "UTF8";
// explicitly declare algorithm, block mode, padding mode.
// once need to change them, change the internal methods if necessary.
private static final String ALGORITHM = "AES";
private static final String BLOCK_MODE = "CBC";
private static final String PADDING = "PKCS5Padding";
private static final String TRANSFORMATION = ALGORITHM + "/" + BLOCK_MODE
+ "/" + PADDING;
// initialization vector required for CBC
private static final byte[] IV_PARAMETER = { (byte) 0x51, (byte) 0x2c,
(byte) 0x3a, (byte) 0xb4, (byte) 0x87, (byte) 0xa0, (byte) 0xa1,
(byte) 0x79, (byte) 0x56, (byte) 0x73, (byte) 0x56, (byte) 0x7d,
(byte) 0xc2, (byte) 0x1f, (byte) 0xeb, (byte) 0x73 };
// fix salt size
private static final int SALT_SIZE = 16;
/**
* Encrypt the clear text against given secret key.
*
* @param clearText
* the clear string
* @return the encrypted string, or null if the clear string is null
* @throws CommonException
* if input arguments is null
*/
public static String encode(String clearText)
throws GeneralSecurityException, UnsupportedEncodingException {
if (clearText == null) {
return null;
}
Key key = GuardKeyStore.getEncryptionKey();
String salt = SaltGenerator.genRandomString(SALT_SIZE);
String inputText = salt + clearText; // add salt
byte[] clearBytes = inputText.getBytes(UTF8_ENCODING);
Cipher cipher = getCiperInternal(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(clearBytes);
Base64 base64 = new Base64(0); // 0 - no chunking
return salt + base64.encodeToString(encryptedBytes);
}
/**
* Decrypt the encrypted text against given secret key.
*
* @param encodedText
* the encrypted string
* @return the clear string, or null if encrypted string is null
* @throws CommonException
* if input arguments is null
*/
public static String decode(String encodedText)
throws GeneralSecurityException, UnsupportedEncodingException {
if (encodedText == null) {
return null;
}
if (encodedText.length() < SALT_SIZE) {
throw EncryptionException.SHORT_ENCRYPTED_STRING(encodedText);
}
Key key = GuardKeyStore.getEncryptionKey();
String salt = encodedText.substring(0, SALT_SIZE);
String encryptedText = encodedText.substring(SALT_SIZE);
Base64 base64 = new Base64(0); // 0 - no chunking
byte[] encryptedBytes = base64.decode(encryptedText);
Cipher cipher = getCiperInternal(Cipher.DECRYPT_MODE, key);
byte[] outputBytes = cipher.doFinal(encryptedBytes);
String outputText = new String(outputBytes, UTF8_ENCODING);
AuAssert.check(salt.equals(outputText.substring(0, SALT_SIZE))); // Assert salt
return outputText.substring(SALT_SIZE);
}
/**
* Get a cipher instance when need it, not share between multiple threads
* because cipher is not thread safe.
*
* @param opmode
* the operation mode
* @param key
* the key
* @return initialized cipher instance
*/
private static Cipher getCiperInternal(int opmode, Key key)
throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
IvParameterSpec ips = new IvParameterSpec(IV_PARAMETER, 0, 16);
cipher.init(opmode, key, ips);
return cipher;
}
}