com.fluidbpm.ws.client.v1.user.AES256Local Maven / Gradle / Ivy
/*
* Koekiebox CONFIDENTIAL
*
* [2012] - [2017] Koekiebox (Pty) Ltd
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property
* of Koekiebox and its suppliers, if any. The intellectual and
* technical concepts contained herein are proprietary to Koekiebox
* and its suppliers and may be covered by South African and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material is strictly
* forbidden unless prior written permission is obtained from Koekiebox.
*/
package com.fluidbpm.ws.client.v1.user;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.fluidbpm.program.api.util.UtilGlobal;
import com.fluidbpm.ws.client.FluidClientException;
/**
* Utility class for AES-256 cryptography.
*
* @author jasonbruwer
* @since v1.0
*
* @see Mac
* @see Cipher
*/
public class AES256Local {
public static final int IV_SIZE_BYTES = 16;
public static final int SEED_SIZE_BYTES = 32;
private static final String HMAC_ALGO = "HmacSHA256";
private static final String ALGO_CBC = "AES/CBC/PKCS5Padding";
private static final String KEY_ALGO = "AES";
private static SecureRandom secureRandom;
/**
* Generate a new initialization vector with a {@code seedParam} byte
* count.
*
* @param seedParam Size of the random bytes.
* @return The software randomly generated bytes.
*/
public static byte[] generateRandom(int seedParam) {
if (AES256Local.secureRandom == null)
{
AES256Local.secureRandom = new SecureRandom();
}
return new IvParameterSpec(AES256Local.secureRandom.generateSeed(seedParam)).getIV();
}
/**
* Generates an HMAC from {@code encryptedDataParam}.
*
* @param hMacKeyParam The symmetric key to use.
* @param encryptedDataParam The encrypted data.
* @return The HMAC result.
*/
public static byte[] hmacSha256(byte[] hMacKeyParam, byte[] encryptedDataParam) {
try {
// hmac
Mac hmac = Mac.getInstance(HMAC_ALGO);
hmac.init(new SecretKeySpec(hMacKeyParam, HMAC_ALGO));
return hmac.doFinal(encryptedDataParam);
}
//Changed for Java 1.6 compatibility...
catch (NoSuchAlgorithmException except) {
throw new FluidClientException("Unable to create HMAC from key. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
}
catch (InvalidKeyException except) {
throw new FluidClientException("Unable to create HMAC from key. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
}
}
/**
* Generate a derived HMAC from {@code encryptedDataParam} using
* other params.
*
* @param encryptedDataParam The encrypted data to generate HMAC from.
* @param passwordParam Password (clear text) used to derive the key from.
* @param saltParam The password salt as passed by the Init request.
* @param seedParam Seed to be poisoned
* @return Derived HMAC.
*/
public static byte[] generateLocalHMAC(
byte[] encryptedDataParam, String passwordParam, String saltParam, byte[] seedParam){
byte[] poisonedSeed = poisonBytes(seedParam);
byte[] passwordSha256 = sha256(
passwordParam.concat(saltParam).getBytes());
//Add the seed to the password and SHA-256...
byte[] derivedKey = sha256(UtilGlobal.addAll(passwordSha256, poisonedSeed));
return hmacSha256(derivedKey, encryptedDataParam);
}
/**
* Generate a derived HMAC from {@code encryptedDataParam} using {@code keyParam}.
*
* @param encryptedDataParam The encrypted data to generate HMAC from.
* @param keyParam Key used to derive the key from.
* @param seedParam Seed to be poisoned
* @return The HMAC for {@code encryptedDataParam}.
*/
public static byte[] generateLocalHMACForReqToken(
byte[] encryptedDataParam, byte[] keyParam, byte[] seedParam){
byte[] poisonedSeed = poisonBytes(seedParam);
//Add the seed to the password and SHA-256...
byte[] derivedKey = sha256(UtilGlobal.addAll(keyParam, poisonedSeed));
return hmacSha256(derivedKey, encryptedDataParam);
}
/**
* Creates a derived version of {@code bytesToPoisonParam}.
*
* @param bytesToPoisonParam The bytes to poison.
* @return The poisoned bytes.
*/
private static byte[] poisonBytes(byte[] bytesToPoisonParam) {
if (bytesToPoisonParam == null) {
return null;
}
byte[] returnVal = new byte[bytesToPoisonParam.length];
for (int index = 0; index < bytesToPoisonParam.length; index++) {
byte poisoned = (byte) (bytesToPoisonParam[index] ^ 222);
returnVal[index] = poisoned;
}
return returnVal;
}
/**
* Decrypts the encrypted data.
*
* @param encryptedDataParam The Base64 data to decrypt.
* @param passwordParam Password in the clear.
* @param saltParam The password salt as passed by the Init request.
* @param ivParam IV value used during packet encryption
* @param seedParam The random seed.
* @return Decrypted bytes / Clear text.
*/
public static byte[] decryptInitPacket(
byte[] encryptedDataParam,
String passwordParam,
String saltParam,
byte[] ivParam,
byte[] seedParam){
//Stored like this in the database, so we have to get the password as stored in the database so that the
// SHa256 and SALT combination will be valid...
byte[] passwordSha256 = sha256(passwordParam.concat(saltParam).getBytes());
//Add the seed to the password and SHA-256...
byte[] derivedKey = sha256(UtilGlobal.addAll(passwordSha256, seedParam));
//Decrypt with the derived key.
return decrypt(derivedKey, encryptedDataParam, ivParam);
}
/**
* Decrypt {@code dataToDecryptParam} using the {@code keyParam} key.
*
* @param keyParam The symmetric key.
* @param dataToDecryptParam The encrypted data to decrypt.
* @param ivParam The random IV.
* @return Clear text.
*/
public static byte[] decrypt(byte[] keyParam, byte[] dataToDecryptParam, byte[] ivParam) {
Key key = new SecretKeySpec(keyParam, KEY_ALGO);
try {
Cipher cipher = Cipher.getInstance(ALGO_CBC);
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivParam));
return cipher.doFinal(dataToDecryptParam);
}
//Changed for Java 1.6 compatibility...
catch (InvalidKeyException except) {
throw new FluidClientException("Key: Unable to decrypt data. " +
except.getMessage(), except, FluidClientException.ErrorCode.AES_256);
} catch (InvalidAlgorithmParameterException except) {
throw new FluidClientException("Algo: Unable to decrypt data. " +
except.getMessage(), except, FluidClientException.ErrorCode.AES_256);
} catch (IllegalBlockSizeException except) {
throw new FluidClientException("Block: Unable to decrypt data. " +
except.getMessage(), except, FluidClientException.ErrorCode.AES_256);
} catch (NoSuchPaddingException except) {
throw new FluidClientException("NoPadding: Unable to decrypt data. " +
except.getMessage(), except, FluidClientException.ErrorCode.AES_256);
} catch (NoSuchAlgorithmException except) {
throw new FluidClientException("NoAlgo: Unable to decrypt data. " +
except.getMessage(), except, FluidClientException.ErrorCode.AES_256);
} catch (BadPaddingException except) {
throw new FluidClientException("BadPadding: Unable to decrypt data. " +
except.getMessage(), except, FluidClientException.ErrorCode.AES_256);
}
}
/**
* Encrypts the {@code dataToEncryptParam} data using key {@code keyParam}.
*
* @param keyParam Key to encrypt with.
* @param dataToEncryptParam Data to encrypt.
* @param ivParam - 16 bytes for AES-256.
* @return Cipher text.
*/
public static byte[] encrypt(byte[] keyParam, byte[] dataToEncryptParam, byte[] ivParam) {
if (dataToEncryptParam == null) {
throw new FluidClientException("No data to encrypt provided. ",
FluidClientException.ErrorCode.AES_256);
}
Key key = new SecretKeySpec(keyParam, KEY_ALGO);
try {
Cipher cipher = Cipher.getInstance(ALGO_CBC);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivParam));
return cipher.doFinal(dataToEncryptParam);
}
//Changed for Java 1.6 compatibility...
catch (InvalidKeyException except) {
throw new FluidClientException("Key: Unable to encrypt data. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
} catch (InvalidAlgorithmParameterException except) {
throw new FluidClientException("Algo: Unable to encrypt data. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
} catch (IllegalBlockSizeException except) {
throw new FluidClientException("Block: Unable to encrypt data. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
} catch (NoSuchPaddingException except) {
throw new FluidClientException("NoPadding: Unable to encrypt data. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
} catch (NoSuchAlgorithmException except) {
throw new FluidClientException("NoAlgo: Unable to encrypt data. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
} catch (BadPaddingException except) {
throw new FluidClientException("BadPadding: Unable to encrypt data. " + except.getMessage(), except,
FluidClientException.ErrorCode.AES_256);
}
}
/**
* Compute SHA256 digest from {@code dataParam}.
*
* @param dataParam The data to SHA-256.
* @return SHA256 digest.
*/
public static byte[] sha256(final byte[] dataParam) {
if (dataParam == null || dataParam.length == 0) {
return new byte[] {};
}
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
return digest.digest(dataParam);
}
//
catch (final NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy