dorkbox.util.crypto.CryptoAES Maven / Gradle / Ivy
Show all versions of Utilities Show documentation
/*
* Copyright 2010 dorkbox, llc
*
* 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 dorkbox.util.crypto;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.slf4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* AES crypto functions
*/
@SuppressWarnings({"Duplicates"})
public final
class CryptoAES {
private static final int ivSize = 16;
/**
* AES encrypts data with a specified key.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
public static
byte[] encryptWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data, Logger logger) {
byte[] encryptAES = encrypt(aesEngine, aesKey, aesIV, data, logger);
int length = encryptAES.length;
byte[] out = new byte[length + ivSize];
System.arraycopy(aesIV, 0, out, 0, ivSize);
System.arraycopy(encryptAES, 0, out, ivSize, length);
return out;
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES encrypts data with a specified key.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
@Deprecated
public static
byte[] encryptWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data, Logger logger) {
byte[] encryptAES = encrypt(aesEngine, aesKey, aesIV, data, logger);
int length = encryptAES.length;
byte[] out = new byte[length + ivSize];
System.arraycopy(aesIV, 0, out, 0, ivSize);
System.arraycopy(encryptAES, 0, out, ivSize, length);
return out;
}
/**
* AES encrypts data with a specified key.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
public static
boolean encryptStreamWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out, Logger logger) {
try {
out.write(aesIV);
} catch (IOException e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return encryptStream(aesEngine, aesKey, aesIV, in, out, logger);
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES encrypts data with a specified key.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
@Deprecated
public static
boolean encryptStreamWithIV(BufferedBlockCipher aesEngine,
byte[] aesKey,
byte[] aesIV,
InputStream in,
OutputStream out,
Logger logger) {
try {
out.write(aesIV);
} catch (IOException e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return encryptStream(aesEngine, aesKey, aesIV, in, out, logger);
}
/**
* AES encrypts data with a specified key.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
public static
byte[] encrypt(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data, Logger logger) {
int length = data.length;
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
return encrypt(aesEngine, aesIVAndKey, data, length, logger);
}
/**
* AES encrypts data with a specified key.
*
* @param logger
* may be null, if no log output is necessary
*
* @return length of encrypted data, -1 if there was an error.
*/
public static
byte[] encrypt(GCMBlockCipher aesEngine, CipherParameters aesIVAndKey, byte[] data, int length, Logger logger) {
aesEngine.reset();
aesEngine.init(true, aesIVAndKey);
int minSize = aesEngine.getOutputSize(length);
byte[] outArray = new byte[minSize];
int actualLength = aesEngine.processBytes(data, 0, length, outArray, 0);
try {
actualLength += aesEngine.doFinal(outArray, actualLength);
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return new byte[0];
}
if (outArray.length == actualLength) {
return outArray;
}
else {
byte[] result = new byte[actualLength];
System.arraycopy(outArray, 0, result, 0, result.length);
return result;
}
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES encrypts data with a specified key.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
@Deprecated
public static
byte[] encrypt(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data, Logger logger) {
int length = data.length;
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(true, aesIVAndKey);
int minSize = aesEngine.getOutputSize(length);
byte[] outBuf = new byte[minSize];
int actualLength = aesEngine.processBytes(data, 0, length, outBuf, 0);
try {
actualLength += aesEngine.doFinal(outBuf, actualLength);
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return new byte[0];
}
if (outBuf.length == actualLength) {
return outBuf;
}
else {
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES encrypt from one stream to another.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
@Deprecated
public static
boolean encryptStream(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out, Logger logger) {
byte[] buf = new byte[ivSize];
byte[] outbuf = new byte[512];
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(true, aesIVAndKey);
try {
int bytesRead;
int bytesProcessed;
while ((bytesRead = in.read(buf)) >= 0) {
bytesProcessed = aesEngine.processBytes(buf, 0, bytesRead, outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
}
bytesProcessed = aesEngine.doFinal(outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
out.flush();
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return true;
}
/**
* AES encrypt from one stream to another.
*
* @param logger
* may be null, if no log output is necessary
* @param aesIV
* must be a nonce (unique value) !!
*
* @return true if successful
*/
public static
boolean encryptStream(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out, Logger logger) {
byte[] buf = new byte[ivSize];
byte[] outbuf = new byte[512];
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(true, aesIVAndKey);
try {
int bytesRead;
int bytesProcessed;
while ((bytesRead = in.read(buf)) >= 0) {
bytesProcessed = aesEngine.processBytes(buf, 0, bytesRead, outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
}
bytesProcessed = aesEngine.doFinal(outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
out.flush();
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return true;
}
/**
* AES decrypt (if the aes IV is included in the data). IV must be a nonce (unique value) !!
*
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
public static
byte[] decryptWithIV(GCMBlockCipher aesEngine, byte[] aesKey, byte[] data, Logger logger) {
byte[] aesIV = new byte[ivSize];
System.arraycopy(data, 0, aesIV, 0, ivSize);
byte[] in = new byte[data.length - ivSize];
System.arraycopy(data, ivSize, in, 0, in.length);
return decrypt(aesEngine, aesKey, aesIV, in, logger);
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES decrypt (if the aes IV is included in the data). IV must be a nonce (unique value)
*
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
@Deprecated
public static
byte[] decryptWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] data, Logger logger) {
byte[] aesIV = new byte[ivSize];
System.arraycopy(data, 0, aesIV, 0, ivSize);
byte[] in = new byte[data.length - ivSize];
System.arraycopy(data, ivSize, in, 0, in.length);
return decrypt(aesEngine, aesKey, aesIV, in, logger);
}
/**
* AES decrypt (if the aes IV is included in the data. IV must be a nonce (unique value)
*
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
public static
boolean decryptStreamWithIV(GCMBlockCipher aesEngine, byte[] aesKey, InputStream in, OutputStream out, Logger logger) {
byte[] aesIV = new byte[ivSize];
try {
in.read(aesIV, 0, ivSize);
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return decryptStream(aesEngine, aesKey, aesIV, in, out, logger);
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES decrypt (if the aes IV is included in the data). IV must be a nonce (unique value)
*
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
@Deprecated
public static
boolean decryptStreamWithIV(BufferedBlockCipher aesEngine, byte[] aesKey, InputStream in, OutputStream out, Logger logger) {
byte[] aesIV = new byte[ivSize];
try {
in.read(aesIV, 0, ivSize);
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return decryptStream(aesEngine, aesKey, aesIV, in, out, logger);
}
/**
* AES decrypt (if we already know the aes IV -- and it's NOT included in the data)
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
public static
byte[] decrypt(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data, Logger logger) {
int length = data.length;
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(false, aesIVAndKey);
int minSize = aesEngine.getOutputSize(length);
byte[] outBuf = new byte[minSize];
int actualLength = aesEngine.processBytes(data, 0, length, outBuf, 0);
try {
actualLength += aesEngine.doFinal(outBuf, actualLength);
} catch (Exception e) {
if (logger != null) {
logger.debug("Unable to perform AES cipher.", e);
}
return new byte[0];
}
if (outBuf.length == actualLength) {
return outBuf;
}
else {
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES decrypt (if we already know the aes IV -- and it's NOT included in the data)
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return empty byte[] if error
*/
@Deprecated
public static
byte[] decrypt(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, byte[] data, Logger logger) {
int length = data.length;
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(false, aesIVAndKey);
int minSize = aesEngine.getOutputSize(length);
byte[] outBuf = new byte[minSize];
int actualLength = aesEngine.processBytes(data, 0, length, outBuf, 0);
try {
actualLength += aesEngine.doFinal(outBuf, actualLength);
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return new byte[0];
}
if (outBuf.length == actualLength) {
return outBuf;
}
else {
byte[] result = new byte[actualLength];
System.arraycopy(outBuf, 0, result, 0, result.length);
return result;
}
}
/**
* AES decrypt from one stream to another.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
public static
boolean decryptStream(GCMBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out, Logger logger) {
byte[] buf = new byte[ivSize];
byte[] outbuf = new byte[512];
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(false, aesIVAndKey);
try {
int bytesRead;
int bytesProcessed;
while ((bytesRead = in.read(buf)) >= 0) {
bytesProcessed = aesEngine.processBytes(buf, 0, bytesRead, outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
}
bytesProcessed = aesEngine.doFinal(outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
out.flush();
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return true;
}
/**
* CONVENIENCE METHOD ONLY - DO NOT USE UNLESS YOU HAVE TO
*
* Use GCM instead, as it's an authenticated cipher (and "regular" AES is not). This prevents tampering with the blocks of encrypted
* data.
*
* AES decrypt from one stream to another.
*
* @param aesIV
* must be a nonce (unique value) !!
* @param logger
* may be null, if no log output is necessary
*
* @return true if successful
*/
@Deprecated
public static
boolean decryptStream(BufferedBlockCipher aesEngine, byte[] aesKey, byte[] aesIV, InputStream in, OutputStream out, Logger logger) {
byte[] buf = new byte[ivSize];
byte[] outbuf = new byte[512];
CipherParameters aesIVAndKey = new ParametersWithIV(new KeyParameter(aesKey), aesIV);
aesEngine.reset();
aesEngine.init(false, aesIVAndKey);
try {
int bytesRead;
int bytesProcessed;
while ((bytesRead = in.read(buf)) >= 0) {
bytesProcessed = aesEngine.processBytes(buf, 0, bytesRead, outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
}
bytesProcessed = aesEngine.doFinal(outbuf, 0);
out.write(outbuf, 0, bytesProcessed);
out.flush();
} catch (Exception e) {
if (logger != null) {
logger.error("Unable to perform AES cipher.", e);
}
return false;
}
return true;
}
private
CryptoAES() {
}
}