Equivalent of MySQL's Compress function in Java - java

Want to compress text in mysql which uses by default zlib compression algorithm and then encode it to base64 string and then match those results in java so that in java i could decompress the text.Can anyone help me out with these any suggestions?
// Here is the sample java code:
String inputString ="have a good day";
final Cipher encryptCipher = Cipher.getInstance("AES");
encryptCipher.init(Cipher.ENCRYPT_MODE, generateMySQLAESKey("default", "UTF-8"));
String encryptedText =new String(Hex.encodeHex(encryptCipher.doFinal(inputString.getBytes("UTF-8"))));
Deflater deflater = new Deflater();
deflater.setInput(encryptedText );
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer); // returns the generated
// code... index
outputStream.write(buffer, 0, count);
}
outputStream.close();
byte[] output = outputStream.toByteArray();
return Base64.encodeBase64String(output);
//I want it to match mysql query like:
select TO_BASE64(COMPRESS(HEX(AES_ENCRYPT("have a good day",default))) from dual;

Related

Java JCA - Input length must be multiple of 8 for padded decypher

I'm currently doing an assignment for a college course using Java's JCA.
The application takes in a file and encrypts it (or decrypts it) using DES-ECB. I am fully aware that it's not a secure encryption algorithm.
It encrypts fine, I believe, however when decrypting it blows up with a "Input length must be multiple of 8" even though the original message is being padded with PKCS5.
I have read all literature and quetions regarding this problem here on StackOverflow, but none of the answers seem to resolve this issue, which leads me to believe I am somehow corrupting the message/file...
For the encryption:
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, symmetricKey);
File file = new File(filePath);
FileOutputStream outputStream = new FileOutputStream("encrypted_"+file.getName());
CipherInputStream cipherStream = new CipherInputStream( new FileInputStream(file), cipher);
byte[] buffer = new byte[MAX_BUFFER]; //buffer para leitura
int bytes; //bytes a ler
//Encoder base64 - Apache Commons Codec
Base64 encoder = new Base64();
while ( (bytes = cipherStream.read(buffer)) != -1 ) {
byte[] encodedBuffer = encoder.encode(buffer);
outputStream.write(encodedBuffer, 0, bytes);
}
cipherStream.close();
outputStream.flush();
return outputStream;
For the decryption:
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, symmetricKey);
File file = new File(filePath);
FileInputStream cipheredStream = new FileInputStream(file);
FileOutputStream outputStream = new FileOutputStream("decrypted_"+file.getName());
CipherOutputStream cipherOutStream = new CipherOutputStream(outputStream, cipher);
byte[] buffer = new byte[MAX_BUFFER];
int bytes;
//Decoder base 64 - Apache Commons Codec
Base64 decoder = new Base64();
cipheredStream.read(buffer);
byte[] decodedBuffer = decoder.decode(buffer);
byte[] output = cipher.doFinal(decodedBuffer);
cipherOutStream.write(output);
//TODO bug here -> use this for big files
/*while ( (bytes = cipheredStream.read(buffer)) != -1 ) {
byte[] decodedBuffer = decoder.decode(buffer);
cipherOutStream.write(decodedBuffer, 0, bytes);
}*/
cipherOutStream.close();
cipheredStream.close();
return outputStream;
I've tried using AES to no avail; I've tried no padding, obviously it didn't work.
I'm just lost and would appreciate knowing what I'm doing wrong.
Thanks to #Topaco, the solution was found using Base64InputStream.
Because the deciphering was being done BEFORE decoding, it was generating that error. It was fixed by doing this encryption side:
Base64OutputStream encoder = new Base64OutputStream(outputStream);
while ( (nBytes = cipherStream.read(buffer, 0, MAX_BUFFER)) != -1 )
encoder.write(buffer, 0, nBytes);
And decryption side the exact opposite:
Base64InputStream decoder = new Base64InputStream(fileInputStream);
while ( (nBytes = decoder.read(buffer, 0, MAX_BUFFER)) != -1 )
cipherOutStream.write(buffer, 0, nBytes);

Compress then encrypt via buffer in Java

I'm new to encryption/compression in Java and I'm working on a test project where the goal is to compress and then encrypt files via a buffered input in Java. At no point should the file be stored on disk in a non-encrypted format, therefore I want to do the compression and encryption solely on a buffer until the file is fully written.
So the progression would be: read part of file into memory (buffer, 1024 bytes) -> compress (~32 bytes)-> encrypt -> output to disk -> repeat until entire file is written
The issue I'm facing is that once I perform the reverse operations to read the compressed/encrypted file back, only part of the data is there.
To accomplish my goal, I've been combining the Inflater/Deflater classes and a block cipher with AES 256 encryption.
Encryption setup:
byte[] randomSalt = new byte[8];
SecureRandom secRand = new SecureRandom();
secRand.nextBytes(randomSalt);
String randomPassword = new BigInteger(130, secRand).toString(32);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(randomPassword.toCharArray(), randomSalt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
Getting input / writing output:
BufferedInputStream bufferedInput = new BufferedInputStream(
new FileInputStream("file.txt"));
BufferedOutputStream bufferedOutput = new BufferedOutputStream(
new FileOutputStream("encrypted file"));
byte[] buffer = new byte[1024];
try {
while (bufferedInput.read(buffer) != -1) {
byte[] encryptedBuffer = cipher.doFinal(compress(buffer));
bufferedOutput.write(encryptedBuffer);
bufferedOutput.flush();
}
} catch (Exception e) {
//snip
} finally {
bufferedInput.close();
bufferedOutput.close();
}
Compress method:
public static byte[] compress(byte[] data) throws IOException{
Deflater deflater = new Deflater();
deflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while(!deflater.finished()){
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
return outputStream.toByteArray();
}
What can I do to be able to compress and encrypt a file 1KB at a time and get the file back in its entirety when I perform the reverse operations?

Incremental Encryption with BouncyCastle PGP Utilities in Java

I'm trying to write an encrypted file that will be decrypted using gpg and will be writing lines incrementally instead of in one chunk. I've generated the keys in GnuPG and am using the public key to encrypt. Here's the method I'm using to encrypt:
public static byte[] encrypt(byte[] clearData, PGPPublicKey encKey,
String fileName,boolean withIntegrityCheck, boolean armor)
throws IOException, PGPException, NoSuchProviderException {
if (fileName == null) {
fileName = PGPLiteralData.CONSOLE;
}
ByteArrayOutputStream encOut = new ByteArrayOutputStream();
OutputStream out = encOut;
if (armor) {
out = new ArmoredOutputStream(out);
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(
PGPCompressedDataGenerator.ZIP);
OutputStream cos = comData.open(bOut); // open it with the final
// destination
PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
// we want to generate compressed data. This might be a user option
// later,
// in which case we would pass in bOut.
OutputStream pOut = lData.open(cos, // the compressed output stream
PGPLiteralData.BINARY, fileName, // "filename" to store
clearData.length, // length of clear data
new Date() // current time
);
pOut.write(clearData);
lData.close();
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_192).setSecureRandom(new SecureRandom()));
cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes); // obtain the actual bytes from the compressed stream
cOut.close();
out.close();
return encOut.toByteArray();
}
And I have a small prototype test class to use that method like this:
PGPPublicKey pubKey = PGPEncryptionTools.readPublicKeyFromCol(new FileInputStream(appProp.getKeyFileName()));
byte[] encryptbytes = PGPEncryptionTools.encrypt("\nthis is some test text".getBytes(), pubKey, null, true, false);
byte[] encryptbytes2 = PGPEncryptionTools.encrypt("\nmore test text".getBytes(), pubKey, null, true, false);
FileOutputStream fos = new FileOutputStream("C:/Users/me/workspace/workspace/spring-batch-project/resources/encryptedfile.gpg");
fos.write(encryptbytes);
fos.write(encryptbytes2);
fos.flush();
fos.close();
So this creates encryptedfile.gpg, but when I go to GnuPG to decrypt the file, it works but it only outputs the first line "this is some test text".
How can I modify this code to be able to encrypt both lines and have GnuPG decrypt them?
You're producing multiple, independent OpenPGP messages each time calling your PGPEncryptionTools.encrypt(...) method. To only output a single OpenPGP message (which GnuPG also decrypt in a single run), write all plain text to a single stream (called pOut in your code) and do not close this before finally writing the last byte into the stream.

Read different inputs from InputStream JAVA

I'm writing a code that send encrypted file from client to server
but first the client send the encrypted message digest of the file to the server and then send the name of the file and at the end it will send the bytes of encrypted file,
but in the server side it read all these variables as one variable which is the digest ,
and when the server trying to decrypt the digest it throws Illegal Block Size Exception
My question here is how can the server read and save them in different variables ??
Client
// set mode to encrypt
AesCipher.init(Cipher.ENCRYPT_MODE, key);
DataOutputStream toServer = new DataOutputStream(socket.getOutputStream());
// get the digest of the file
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(bytes);
// encrypt digest and write it to file
byte [] encryptedHash = AesCipher.doFinal(hash);
toServer.write(encryptedHash);
// write file name to server
toServer.writeUTF(fileName);
//encrypt file
byte[] encryptedByte = AesCipher.doFinal(bytes);
// write file to server
toServer.write(encryptedByte);
toServer.flush();
socket.close();
Server
// read digest of the file
byte [] digest =IOUtils.toByteArray(fromClient);
// decrypt it
AesCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedDigest = AesCipher.doFinal(digest);
// read file name to be received
String fileName = fromClient.readUTF();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// read file bytes from client
byte[] fileBytes = IOUtils.toByteArray(fromClient);
AesCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedByte = AesCipher.doFinal(fileBytes);
bos.write(decryptedByte, 0, decryptedByte.length);
bos.close();
also I tried this code but it didn't works too
// read digest of the file
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = fromClient.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] digest = buffer.toByteArray();
// decrypt it
AesCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedDigest = AesCipher.doFinal(digest);
// read file name to be received
String fileName = fromClient.readUTF();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// read file bytes from client
byte[] fileBytes = IOUtils.toByteArray(fromClient);
AesCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedByte = AesCipher.doFinal(fileBytes);
bos.write(decryptedByte, 0, decryptedByte.length);
bos.close();
IOUtils.toByteArray(InputStream) reads the entire stream. So instead of just getting the hash bytes, you got the whole stream, and there was nothing left for the filename or the ciphertext, and the hash didn't check.
You don't need external libraries for this. You can do it all with DataInputStream and DataOutputStream. But you do need to send the length of the hash ahead of the hash.
Client:
// set mode to encrypt
AesCipher.init(Cipher.ENCRYPT_MODE, key);
DataOutputStream toServer = new DataOutputStream(socket.getOutputStream());
// get the digest of the file
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest(bytes);
// encrypt digest and write it to file
byte [] encryptedHash = AesCipher.doFinal(hash);
toServer.writeInt(encryptedHash.length);
toServer.write(encryptedHash);
// write file name to server
toServer.writeUTF(fileName);
//encrypt file
byte[] encryptedByte = AesCipher.doFinal(bytes);
// write file to server
toServer.writeInt(encryptedByte.length);
toServer.write(encryptedByte);
socket.close();
Server:
// read digest of the file
int digestLength = fromClient.readInt();
byte[] digest = new byte[digestLength];
fromClient.readFully(digest);
// decrypt it
AesCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedDigest = AesCipher.doFinal(digest);
// read file name to be received
String fileName = fromClient.readUTF();
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// read file bytes from client
int fileLength = fromClient.readInt();
byte[] fileBytes = new byte[fileLength];
fromClient.readFully(fileBytes);
AesCipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedByte = AesCipher.doFinal(fileBytes);
bos.write(decryptedByte, 0, decryptedByte.length);
bos.close();
However the encryption and decryption parts of this would be much better done with CipherInputStream and CipherOutputStream. You shouldn't load entire files into memory.
Note that the file.createNewFile() call was redundant before new FileOutputStream(...).
Why you're encrypting a message digest is another mystery. You should be using it as a final step to compare with a locally-generated digest after decryption.

Encrypt/decrypt byte array > 256 bytes using AES-128

The following code encrypts a byte array SOURCE_DATA using AES-128 to another byte array ENCRYPTED_DATA, and then decrypts it again to DECRYPTED_DATA. With a byte array size of <= 256 bytes, the code works just fine, but if the byte array is longer, DECRYPTED_DATA only contains zeros after byte 256 and is not equal to the SOURCE_DATA array. What am I missing?
Output:
Source Data: ...fbfcfdfeff0001
Decrypted Data: ...fbfcfdfeff0000
Code:
// Create data array with size greater 256 bytes
byte[] SOURCE_DATA = new byte[257];
for (int i=0;i<SOURCE_DATA.length; i++) {
SOURCE_DATA[i] = (byte)((i+1) & 0xff);
}
// Init ciphers
Cipher encC = Cipher.getInstance("AES/ECB/PKCS5Padding");
Cipher decC = Cipher.getInstance("AES/ECB/PKCS5Padding");
encC.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[] {0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6}, "AES"));
decC.init(Cipher.DECRYPT_MODE, new SecretKeySpec(new byte[] {0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6}, "AES"));
// Encrypt
ByteArrayOutputStream bos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(bos, encC);
DataOutputStream dos = new DataOutputStream(cos);
dos.write(SOURCE_DATA, 0, SOURCE_DATA.length);
dos.close();
byte[] ENCRYPTED_DATA = bos.toByteArray();
// Decrypt
ByteArrayInputStream bis = new ByteArrayInputStream(ENCRYPTED_DATA);
CipherInputStream cis = new CipherInputStream(bis, decC);
DataInputStream dis = new DataInputStream(cis);
byte[] DECRYPTED_DATA = new byte[SOURCE_DATA.length];
dis.read(DECRYPTED_DATA, 0, DECRYPTED_DATA.length);
cis.close();
System.out.println("Source Data: "+toHex(SOURCE_DATA));
System.out.println("Decrypted Data: "+toHex(DECRYPTED_DATA));
Try using DataInputStream.readFully (i.e. you are only reading part of the result, which is why you always call InputStream.read in a while loop).

Categories

Resources