Guest - 2018/09/21 20:44 - Views : 4435 -
Java -
Clone -
RAW -
Download -
import android.support.annotation.Nullable;
import android.util.Base64;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AesCipher
* <p>Encode/Decode text by password using AES-128-CBC algorithm</p>
*/
public class AesCipher {
public static final int INIT_VECTOR_LENGTH = 16;
/**
* @see <a href="https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-hex-string-in-java">how-to-convert-a-byte-array-to-a-hex-string</a>
*/
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
/**
* Encoded/Decoded data
*/
protected String data;
/**
* Initialization vector value
*/
protected String initVector;
/**
* Error message if operation failed
*/
protected String errorMessage;
private AesCipher() {
super();
}
/**
* AesCipher constructor.
*
* @param initVector Initialization vector value
* @param data Encoded/Decoded data
* @param errorMessage Error message if operation failed
*/
private AesCipher(@Nullable String initVector, @Nullable String data, @Nullable String errorMessage) {
super();
this.initVector = initVector;
this.data = data;
this.errorMessage = errorMessage;
}
/**
* Encrypt input text by AES-128-CBC algorithm
*
* @param secretKey 16/24/32 -characters secret password
* @param plainText Text for encryption
* @return Encoded string or NULL if error
*/
public static AesCipher encrypt(String secretKey, String plainText) {
String initVector = null;
try {
// Check secret length
if (!isKeyLengthValid(secretKey)) {
throw new Exception("Secret key's length must be 128, 192 or 256 bits");
}
// Get random initialization vector
SecureRandom secureRandom = new SecureRandom();
byte[] initVectorBytes = new byte[INIT_VECTOR_LENGTH / 2];
secureRandom.nextBytes(initVectorBytes);
initVector = bytesToHex(initVectorBytes);
initVectorBytes = initVector.getBytes("UTF-8");
IvParameterSpec ivParameterSpec = new IvParameterSpec(initVectorBytes);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// Encrypt input text
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
ByteBuffer byteBuffer = ByteBuffer.allocate(initVectorBytes.length + encrypted.length);
byteBuffer.put(initVectorBytes);
byteBuffer.put(encrypted);
// Result is base64-encoded string: initVector + encrypted result
String result = Base64.encodeToString(byteBuffer.array(), Base64.DEFAULT);
// Return successful encoded object
return new AesCipher(initVector, result, null);
} catch (Throwable t) {
t.printStackTrace();
// Operation failed
return new AesCipher(initVector, null, t.getMessage());
}
}
/**
* Decrypt encoded text by AES-128-CBC algorithm
*
* @param secretKey 16/24/32 -characters secret password
* @param cipherText Encrypted text
* @return Self object instance with data or error message
*/
public static AesCipher decrypt(String secretKey, String cipherText) {
try {
// Check secret length
if (!isKeyLengthValid(secretKey)) {
throw new Exception("Secret key's length must be 128, 192 or 256 bits");
}
// Get raw encoded data
byte[] encrypted = Base64.decode(cipherText, Base64.DEFAULT);
// Slice initialization vector
IvParameterSpec ivParameterSpec = new IvParameterSpec(encrypted, 0, INIT_VECTOR_LENGTH);
// Set secret password
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// Trying to get decrypted text
String result = new String(cipher.doFinal(encrypted, INIT_VECTOR_LENGTH, encrypted.length - INIT_VECTOR_LENGTH));
// Return successful decoded object
return new AesCipher(bytesToHex(ivParameterSpec.getIV()), result, null);
} catch (Throwable t) {
t.printStackTrace();
// Operation failed
return new AesCipher(null, null, t.getMessage());
}
}
/**
* Check that secret password length is valid
*
* @param key 16/24/32 -characters secret password
* @return TRUE if valid, FALSE otherwise
*/
public static boolean isKeyLengthValid(String key) {
return key.length() == 16 || key.length() == 24 || key.length() == 32;
}
/**
* Convert Bytes to HEX
*
* @param bytes Bytes array
* @return String with bytes values
*/
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
/**
* Get encoded/decoded data
*/
public String getData() {
return data;
}
/**
* Get initialization vector value
*/
public String getInitVector() {
return initVector;
}
/**
* Get error message
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* Check that operation failed
*
* @return TRUE if failed, FALSE otherwise
*/
public boolean hasError() {
return this.errorMessage != null;
}
/**
* To string return resulting data
*
* @return Encoded/decoded data
*/
public String toString() {
return getData();
}
}
// USAGE
String secretKey = "26kozQaKwRuNJ24t";
String text = "Some text";
AesCipher encrypted = AesCipher.encrypt(secretKey, text);
AesCipher decrypted = AesCipher.decrypt(secretKey, encrypted);
encrypted.hasError(); // TRUE if operation failed, FALSE otherwise
encrypted.getData(); // Encoded/Decoded result
encrypted.getInitVector(); // Get used (random if encode) init vector
// decrypted.* has identical methods