Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Encryption, Part 1B: Symmetric Encryption of Voluminous Files

DZone 's Guide to

Encryption, Part 1B: Symmetric Encryption of Voluminous Files

Check out this post to learn more about the symmetric encryption of voluminous files.

· Security Zone ·
Free Resource

In my recent article, Encryption Part 1: Symmetric Encryption, I covered the symmetric encryption of data and shared example Java code.

The method I covered in that article operates on the complete data/string. Obviously, this method is not suitable when dealing with voluminous files — MBs, GBs, TBs — particularly in the world of Big Data. Ideally, I should have also shared the code to encrypt and decrypt voluminous files, which I am doing in this article.

When faced with voluminous files, the only logical mechanism available is to read the files in suitably-sized blocks, encrypt them, and then write the encrypted data to the new file. In this method, it is important that the reader and the writer use the same block length. Otherwise, decryption will not give us the original file.

So, here is the source code of the class that can be used for encryption and decryption

package edsf;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class EncDecSymmetricFile
{
// Symmetric encryption algorithms supported - AES, RC4, DES
protected static String DEFAULT_ENCRYPTION_ALGORITHM = "AES";
protected static int DEFAULT_ENCRYPTION_KEY_LENGTH = 256;

protected SecretKey mSecretKey;
protected String mEncryptionAlgorithm, mKeyEncryptionAlgorithm, mTransformation;
protected int mEncryptionKeyLength, mKeyEncryptionKeyLength;
protected PublicKey mPublicKey;
protected PrivateKey mPrivateKey;

EncDecSymmetricFile()
{
mSecretKey = null;
mEncryptionAlgorithm = EncDecSymmetricFile.DEFAULT_ENCRYPTION_ALGORITHM;
mEncryptionKeyLength = EncDecSymmetricFile.DEFAULT_ENCRYPTION_KEY_LENGTH;
}

public static BigInteger keyToNumber(byte[] byteArray)
{
return new BigInteger(1, byteArray);
}

public SecretKey getSecretKey()
{
return mSecretKey;
}

public byte[] getSecretKeyAsByteArray()
{
return mSecretKey.getEncoded();
}

public String getEncodedPublicKey()
{
String encodedKey = Base64.getEncoder().encodeToString(mPublicKey.getEncoded());
return encodedKey;
}

// get base64 encoded version of the key
public String getEncodedSecretKey()
{
String encodedKey = Base64.getEncoder().encodeToString(mSecretKey.getEncoded());
return encodedKey;
}

public void generateSymmetricKey()
{
KeyGenerator generator;
try {
generator = KeyGenerator.getInstance(mEncryptionAlgorithm);
generator.init(mEncryptionKeyLength);

mSecretKey = generator.generateKey();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}

public byte[] encryptText(byte[] textToEncrypt)
{
byte[] byteCipherText = null;

try {
Cipher encCipher = Cipher.getInstance(mEncryptionAlgorithm);
encCipher.init(Cipher.ENCRYPT_MODE, mSecretKey);
byteCipherText = encCipher.doFinal(textToEncrypt);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}

return byteCipherText;
}

public byte[] encryptText(String textToEncrypt)
{
return encryptText(textToEncrypt.getBytes());
}

public byte[] decryptTextToByteArray(byte[] decryptedKey, byte[] encryptedText)
{
byte[] bytePlainText = null;

try {
SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey.length, mEncryptionAlgorithm);
Cipher aesCipher2 = Cipher.getInstance(mEncryptionAlgorithm);
aesCipher2.init(Cipher.DECRYPT_MODE, originalKey);
bytePlainText = aesCipher2.doFinal(encryptedText);

} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}

return bytePlainText;
}

public String decryptTextToString(byte[] decryptedKey, byte[] encryptedText)
{
String decryptedPlainText = null;

byte[] bytePlainText = decryptTextToByteArray(decryptedKey, encryptedText);
decryptedPlainText = new String(bytePlainText);

return decryptedPlainText;
}
}


And here is the code that can be used to perform encryption and/or decryption:

package edsf;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;

public class Main
{
public static void main(String[] args)
{
try {
EncDecSymmetricFile sed = new EncDecSymmetricFile();

sed.generateSymmetricKey();
byte[] secretKeyByteArray = sed.getSecretKeyAsByteArray();
System.out.println("secret key: '" + EncDecSymmetricFile.keyToNumber(secretKeyByteArray).toString() + "'" );

File inputFile = new File(args[0]);

byte[] inputContent = Files.readAllBytes(inputFile.toPath());

byte[] encryptedText = sed.encryptText(inputContent);
System.out.println("encrypted text: '" + EncDecSymmetricFile.keyToNumber(encryptedText).toString() + "'" );

FileOutputStream fenc = new FileOutputStream(args[1]);
fenc.write(encryptedText);
fenc.close();

byte[] encryptedContent = Files.readAllBytes(new File(args[1]).toPath());

byte[] decryptedText = sed.decryptTextToByteArray(secretKeyByteArray, encryptedContent);
FileOutputStream fdec = new FileOutputStream(args[2]);
fdec.write(decryptedText);
fdec.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


Symmetric encryption, while being a relatively simple encryption/decryption mechanism, can be tedious to maintain. Because both the sender and the receiver need to possess the encryption/decryption key, exchanging encrypted data between multiple parties becomes complex and the chances of the key being compromised increases. To overcome the limitations of symmetric key encryption, I will cover the concept of Public Key — Private Key Encryption in the next part of the series, along with the supporting Java code.

Stay tuned!

Topics:
security ,java ,encryption ,files ,decryption ,example code ,symmetric encryption ,syymetric

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}