Code Examples – En-/Decryption with symmetric ciphers

Introduction  |  Message Digest  |  Symmetric ciphers  |  RSA  |  ECIES  |  Digital signatures (S/MIME)

Download code

En-/decryption with symmetric ciphers: We want to use a symmetric cipher to encrypt and decrypt a file. Symmetric ciphers use symmetric keys to encrypt and decrypt data. The encryption and decryption keys are trivially related to each other, which means that they may be identical or there is a simple transformation to get one key from the other. Symmetric key encryption is sometimes called single key or private key encryption.

The FlexiProvider package provides implementations of the following symmetric algorithms: AES (Rijndael), Camellia, DESede (TripleDES), IDEA, MARS, RC2, RC5, RC6, Safer+, Safer++, Serpent, and Twofish.
In this example, we use the AES cipher to encrypt and decrypt a file stored on the local disk.

First, we do the necessary imports:

01 import java.io.FileInputStream;
02 import java.io.FileOutputStream;
03 import java.security.Security;
04
05 import javax.crypto.Cipher;
06 import javax.crypto.CipherInputStream;
07 import javax.crypto.CipherOutputStream;
08 import javax.crypto.KeyGenerator;
09 import javax.crypto.SecretKey;
10
11 import de.flexiprovider.core.FlexiCoreProvider;
12
13 public final class ExampleCrypt {
14
15 public static void main(String[] args) throws Exception {
16
17 Security.addProvider(new FlexiCoreProvider());

Next, we create an instance of the JCE classes Cipher and KeyGenerator. The Cipher class provides the functionality of a cryptographic cipher used for encryption and decryption. The KeyGenerator class can be used to generate secret keys for symmetric algorithms.

19 Cipher cipher = Cipher.getInstance("AES128_CBC", "FlexiCore");
20 KeyGenerator keyGen = KeyGenerator.getInstance("AES", "FlexiCore");
21 SecretKey secKey = keyGen.generateKey();

The cipher object is created by using the static factory method getInstance(String transformation, String provider) from the Cipher class (line 19). The first parameter is the name of the requested transformation, where a transformation is of the form:

  • "algorithm/mode/padding" or
  • "algorithm"

So in this example, we use the AES cipher in CFB mode with PKCS5Padding (mode options: ECB, CBC, CFB, OFB, CTR; padding options: PKCS5Padding, OneAndZeroesPadding, NoPadding). The second parameter indicates the provider used for the implementation of the algoritm, in this example the FlexiCoreProvider.

In line 20, we analoguesly create an instance of the KeyGenerator class which now can generate secret keys for the AES algorithm. The secret key is generated in line 21 with the generateKey() method and is later used for encryption/decryption.

The cipher object is now ready to use:

25 cipher.init(Cipher.ENCRYPT_MODE, secKey);
26
27 String cleartextFile = "cleartext.txt";
28 String ciphertextFile = "ciphertextSymm.txt";
29
30 FileInputStream fis = new FileInputStream(cleartextFile);
31 FileOutputStream fos = new FileOutputStream(ciphertextFile);
32 CipherOutputStream cos = new CipherOutputStream(fos, cipher);
33
34 byte[] block = new byte[8];
35 int i;
36 while ((i = fis.read(block)) != -1) {
37 cos.write(block, 0, i);
38 }
39 cos.close();

First, the cipher object is initialized since the getInstance() method returns uninitialized objects. The initialization is done in line 25 with the init(int opmode, Key key) method. The first parameter determines the operation mode of the cipher. As we want to encrypt a file, we use the ENCRYPT_MODE. The second parameter is the secret key which should be used for encryption.

In this example, we use cipher streams to operate with the cipher. Cipher streams are secure streams which combine an InputStream or an OutputStream with a cipher. In line 32, we instantiate a CipherOutputStream which is an implementation of a secure stream. A CipherOutputStream is a FilterOutputStream which encrypts or decrypts the data passing through it (whether encrypting or decrypting is done depends on how the given cipher has been initialized). The CipherOutputStream gets as first parameter an OutputStream which is used to write the file and as second parameter a fully initialized cipher object to do the encrypting or decrypting.

The encryption is finally done in lines 36–38: the file is read by a FileInputStream and written by the previously instantiated CipherOutputStream. The data now is encrypted and written to the file specified (here: "ciphertextSymm.txt") by the OutputStream (make sure that all files can be found by your Java environment).

Next, we want to decrypt the data to restore our cleartext:

43 String cleartextAgainFile = "cleartextAgainSymm.txt";
44
45 cipher.init(Cipher.DECRYPT_MODE, secKey);
46
47 fis = new FileInputStream(ciphertextFile);
48 CipherInputStream cis = new CipherInputStream(fis, cipher);
49 fos = new FileOutputStream(cleartextAgainFile);
50
51 while ((i = cis.read(block)) != -1) {
52 fos.write(block, 0, i);
53 }
54 fos.close();
55 }
56
57 }

We use the same cipher as for encryption, but we initialize it for decryption with the previously generated secret key in line 45. Be aware of the fact that in the real world, you actually would have exchanged the secret key via a secure channel (e.g., using public key encryption).

As we see, a CipherInputStream is used for decrypting which is used in a similar way as the CipherOutputStream explained above. In contrast to the CipherOutputStream, the encryption or decryption is done when reading a file, which you can see in lines 51–53. First, the ciphertext file is read by the CipherInputStream and decrypted simultaneously since the given cipher is initialized for decryption. The computed cleartext is then written to the file specified by the FileOutputStream (here: "cleartextAgainSymm.txt").

Druckerenglisch deutsche Flagge   Impressum