This site is the archived OWASP Foundation Wiki and is no longer accepting Account Requests.
To view the new OWASP Foundation website, please visit https://owasp.org

Difference between revisions of "Using the Java Cryptographic Extensions"

From OWASP
Jump to: navigation, search
m (AES Encryption and Decryption)
 
(20 intermediate revisions by 7 users not shown)
Line 1: Line 1:
==Note:==
 
''The code included in this article has not been reviewed and should not be used without proper analysis.  If you have reviewed the included code (or portions of it), please post your findings back to this page or to: stephen [at] corsaire.com.''
 
  
 
== Overview ==
 
== Overview ==
Line 100: Line 98:
 
package org.owasp.java.crypto;
 
package org.owasp.java.crypto;
  
import javax.crypto.KeyGenerator;
+
import javax.crypto.*;
import javax.crypto.SecretKey;
+
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
+
import java.io.UnsupportedEncodingException;
 
+
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
+
import java.security.InvalidAlgorithmParameterException;
 
import java.security.InvalidKeyException;
 
import java.security.InvalidKeyException;
import java.security.InvalidAlgorithmParameterException;
 
import javax.crypto.NoSuchPaddingException;
 
import javax.crypto.BadPaddingException;
 
import javax.crypto.IllegalBlockSizeException;
 
 
import sun.misc.BASE64Encoder;
 
 
/**
 
* @author Joe Prasanna Kumar
 
* This program provides the following cryptographic functionalities
 
* 1. Encryption using AES
 
* 2. Decryption using AES
 
*
 
* High Level Algorithm :
 
* 1. Generate a DES key (specify the Key size during this phase)
 
* 2. Create the Cipher
 
* 3. To Encrypt : Initialize the Cipher for Encryption
 
* 4. To Decrypt : Initialize the Cipher for Decryption
 
*
 
*
 
*/
 
 
public class AES {
 
public static void main(String[] args) {
 
 
String strDataToEncrypt = new String();
 
String strCipherText = new String();
 
String strDecryptedText = new String();
 
 
try{
 
/**
 
*  Step 1. Generate an AES key using KeyGenerator
 
*  Initialize the keysize to 128
 
*
 
*/
 
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
 
keyGen.init(128);
 
SecretKey secretKey = keyGen.generateKey();
 
 
/**
 
*  Step2. Create a Cipher by specifying the following parameters
 
* a. Algorithm name - here it is AES
 
*/
 
 
Cipher aesCipher = Cipher.getInstance("AES");
 
 
/**
 
*  Step 3. Initialize the Cipher for Encryption
 
*/
 
 
aesCipher.init(Cipher.ENCRYPT_MODE,secretKey);
 
 
/**
 
*  Step 4. Encrypt the Data
 
*  1. Declare / Initialize the Data. Here the data is of type String
 
*  2. Convert the Input Text to Bytes
 
*  3. Encrypt the bytes using doFinal method
 
*/
 
strDataToEncrypt = "Hello World of Encryption using AES ";
 
byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();
 
byte[] byteCipherText = aesCipher.doFinal(byteDataToEncrypt);
 
strCipherText = new BASE64Encoder().encode(byteCipherText);
 
System.out.println("Cipher Text generated using AES is " +strCipherText);
 
 
/**
 
*  Step 5. Decrypt the Data
 
*  1. Initialize the Cipher for Decryption
 
*  2. Decrypt the cipher bytes using doFinal method
 
*/
 
aesCipher.init(Cipher.DECRYPT_MODE,secretKey,aesCipher.getParameters());
 
byte[] byteDecryptedText = aesCipher.doFinal(byteCipherText);
 
strDecryptedText = new String(byteDecryptedText);
 
System.out.println(" Decrypted Text message is " +strDecryptedText);
 
}
 
 
catch (NoSuchAlgorithmException noSuchAlgo)
 
{
 
System.out.println(" No Such Algorithm exists " + noSuchAlgo);
 
}
 
 
catch (NoSuchPaddingException noSuchPad)
 
{
 
System.out.println(" No Such Padding exists " + noSuchPad);
 
}
 
 
catch (InvalidKeyException invalidKey)
 
{
 
System.out.println(" Invalid Key " + invalidKey);
 
}
 
 
catch (BadPaddingException badPadding)
 
{
 
System.out.println(" Bad Padding " + badPadding);
 
}
 
 
catch (IllegalBlockSizeException illegalBlockSize)
 
{
 
System.out.println(" Illegal Block Size " + illegalBlockSize);
 
}
 
 
catch (InvalidAlgorithmParameterException invalidParam)
 
{
 
System.out.println(" Invalid Parameter " + invalidParam);
 
}
 
}
 
 
}
 
</pre>
 
=== Des Encryption and Decryption ===
 
<pre>
 
package org.owasp.crypto;
 
 
import javax.crypto.KeyGenerator;
 
import javax.crypto.SecretKey;
 
import javax.crypto.Cipher;
 
 
 
import java.security.NoSuchAlgorithmException;
 
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
+
import java.security.SecureRandom;
import java.security.InvalidAlgorithmParameterException;
+
import java.util.Base64;
import javax.crypto.NoSuchPaddingException;
 
import javax.crypto.BadPaddingException;
 
import javax.crypto.IllegalBlockSizeException;
 
 
 
import sun.misc.BASE64Encoder;
 
  
 +
// @formatter:off
 
/**
 
/**
  * @author Joe Prasanna Kumar
+
  * @author Chuck Eastus
  * This program provides the following cryptographic functionalities
+
* Reworked from Joe Prasanna Kumar's sample with suggestions and notes made by Kevin W. Wall.
  * 1. Encryption using DES
+
  * This class demonstrates encrypting and decrypting a string message using the AES algorithm.
  * 2. Decryption using DES
+
* Steps:
  *  
+
  * 1. Generate an AES key of the desired length (in bits) using an AES KeyGenerator.
  * The following modes of DES encryption are supported by SUNJce provider
+
  * 2. Get a Cipher instance of the desired algorithm, mode, and padding.
  * 1. ECB (Electronic code Book) - Every plaintext block is encrypted separately
+
  * 3. Generate an initialization vector for our message of the same size as the Cipher's blocksize.
  * 2. CBC (Cipher Block Chaining) - Every plaintext block is XORed with the previous ciphertext block
+
  * 4. Initialize the Cipher instance for encryption using the key and initialization vector.
  * 3. PCBC (Propogating Cipher Block Chaining) -
+
  * 5. Use the Cipher to encrypt the message (after encoding it to a byte[] using the named Charset), and then append
  * 4. CFB (Cipher Feedback Mode) - The previous ciphertext block is encrypted and this enciphered block is XORed with the plaintext block to produce the corresponding ciphertext block
+
* the encrypted data to the IV and Base64-encode the result.
  * 5. OFB (Output Feedback Mode) -
+
  * 6. Get a new Cipher instance of the same algorithm, mode, and padding used for encryption.
 +
* 7. Base64-decode and split the data into the IV and the encrypted data, and then initialize the cipher for
 +
  * decryption with the same key used for encryption (symmetric), the IV, and the encrypted data.
 +
  * 8. Use the Cipher to decrypt the data, convert it to a String using the named Charset, and display the message.
 +
*
 +
* Notes on padding:
 +
* PKCS7 padding is actually technically the correct padding name, but Java blew it and called it PKCS5PADDING.
 +
* Technically, PKCS5 padding only applies to ciphers with a cipher block size of 64-bits, not 128-bits, but both PKCS5
 +
* and PKCS7 padding act identically for block sizes <= 255 bits.
 +
* Be sure to specify the mode explicitly as most JCE providers default to ECB mode, which is not secure!
 +
  * For this example, we are use CFB mode with no padding in order to avoid padding attacks.
 
  *
 
  *
  * High Level Algorithm :
+
  * Notes on initialization vectors (IVs):
* 1. Generate a DES key
+
  * The IV must be saved for later decryption and should not be reused for other encryption operations. It can be stored
* 2. Create the Cipher (Specify the Mode and Padding)
+
  * separately or sent along with the encrypted data. Usually, the encrypted data is appended to the IV and the result
* 3. To Encrypt : Initialize the Cipher for Encryption
+
  * is encoded then stored or transmitted.
  * 4. To Decrypt : Initialize the Cipher for Decryption
 
*
 
* Need for Padding :
 
  * Block ciphers operates on data blocks on fixed size n.  
 
* Since the data to be encrypted might not always be a multiple of n, the remainder of the bits are padded.
 
  * PKCS#5 Padding is what will be used in this program
 
*
 
 
  */
 
  */
 +
// @formatter:on
  
public class DES {
+
public class AES {
public static void main(String[] args) {
 
 
String strDataToEncrypt = new String();
 
String strCipherText = new String();
 
String strDecryptedText = new String();
 
 
try{
 
/**
 
*  Step 1. Generate a DES key using KeyGenerator
 
*
 
*/
 
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
 
SecretKey secretKey = keyGen.generateKey();
 
 
/**
 
*  Step2. Create a Cipher by specifying the following parameters
 
* a. Algorithm name - here it is DES
 
* b. Mode - here it is CBC
 
* c. Padding - PKCS5Padding
 
*/
 
 
Cipher desCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
 
 
/**
 
*  Step 3. Initialize the Cipher for Encryption
 
*/
 
 
desCipher.init(Cipher.ENCRYPT_MODE,secretKey);
 
 
/**
 
*  Step 4. Encrypt the Data
 
*  1. Declare / Initialize the Data. Here the data is of type String
 
*  2. Convert the Input Text to Bytes
 
*  3. Encrypt the bytes using doFinal method
 
*/
 
strDataToEncrypt = "Hello World of Encryption using DES ";
 
byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();
 
byte[] byteCipherText = desCipher.doFinal(byteDataToEncrypt);
 
strCipherText = new BASE64Encoder().encode(byteCipherText);
 
System.out.println("Cipher Text generated using DES with CBC mode and PKCS5 Padding is " +strCipherText);
 
 
/**
 
*  Step 5. Decrypt the Data
 
*  1. Initialize the Cipher for Decryption
 
*  2. Decrypt the cipher bytes using doFinal method
 
*/
 
desCipher.init(Cipher.DECRYPT_MODE,secretKey,desCipher.getParameters());
 
//desCipher.init(Cipher.DECRYPT_MODE,secretKey);
 
byte[] byteDecryptedText = desCipher.doFinal(byteCipherText);
 
strDecryptedText = new String(byteDecryptedText);
 
System.out.println(" Decrypted Text message is " +strDecryptedText);
 
}
 
 
catch (NoSuchAlgorithmException noSuchAlgo)
 
{
 
System.out.println(" No Such Algorithm exists " + noSuchAlgo);
 
}
 
 
catch (NoSuchPaddingException noSuchPad)
 
{
 
System.out.println(" No Such Padding exists " + noSuchPad);
 
}
 
 
catch (InvalidKeyException invalidKey)
 
{
 
System.out.println(" Invalid Key " + invalidKey);
 
}
 
 
catch (BadPaddingException badPadding)
 
{
 
System.out.println(" Bad Padding " + badPadding);
 
}
 
 
catch (IllegalBlockSizeException illegalBlockSize)
 
{
 
System.out.println(" Illegal Block Size " + illegalBlockSize);
 
}
 
 
catch (InvalidAlgorithmParameterException invalidParam)
 
{
 
System.out.println(" Invalid Parameter " + invalidParam);
 
}
 
}
 
 
 
}
 
</pre>
 
[[Category:OWASP Java Project]]
 
  
'''Uso de las Extensiones Criptográficas de Java'''
+
  public static final int keyLength = 128;
 +
  public static final String charEnc = "UTF-8";
 +
  public static final String transformationString = "AES/CFB/NoPadding";
  
'''Contenido'''
+
  public static void main(String[] args) {
  
''1 Nota:
+
    String message = "Hello World of Encryption using AES";
2 Descripción general
+
    String cipherText;
2.1 Algoritmos de cifrado simétrico proporcionados por SunJCE
 
2.2 Modos de cifrado
 
2.3 Algoritmos de cifrado asimétricos implementadas por SunJCE
 
2,4 hashing / Message Digest algoritmos implementados por SunJCE
 
3 Ejemplos
 
3.1 Seguridad Randómica
 
3.2 AES de cifrado y descifrado
 
3.3 DES cifrado y descifrado''
 
  
'''Nota:'''
+
    try {
 +
      // Step 1
 +
      KeyGenerator keyGen = KeyGenerator.getInstance("AES");
 +
      keyGen.init(keyLength);
 +
      SecretKey secretKey = keyGen.generateKey();
  
El código incluido en este artículo no ha sido revisado y no se debe utilizar sin un análisis adecuado. Si ha revisado el código incluido (o partes de ellos), por favor enviar sus conclusiones a esta página o a: stephen [at] corsaire.com.
+
      // Step 2
'''
+
      Cipher aesCipherForEncryption = Cipher.getInstance(transformationString);
Descripción General'''
 
  
Extensiones Criptográficas Java (JCE) es un conjunto de API’s de Java, que proporciona servicios criptográficos como el cifrado, la generación de claves secretas, código de autenticación de mensajes y el Acuerdo clave. Los sistemas de cifrado soportados por JCE incluyen simetría, asimetría, bloque y cifrado de flujos. JCE fue un paquete opcional para JDK v 1.2.x y 1.3.x. JCE ha sido integrado en JDK v1.4.
+
      // Step 3
 +
      byte[] iv = new byte[aesCipherForEncryption.getBlockSize()];
 +
      SecureRandom prng = new SecureRandom();
 +
      prng.nextBytes(iv);
  
JCE API’s se implementan los proveedores de servicios criptográficos. Cada uno de estos proveedores de servicios criptográficos implementa la interfaz del proveedor de servicio que especifican las funcionalidades que deben ser implementadas por los proveedores de servicios. Los programadores pueden obtener los plugin de cualquier proveedor de servicios para la realización de funcionalidades criptográficas proporcionadas por JCE. J2SE viene con un proveedor predeterminado, llamado SunJCE.
+
      // Step 4
 +
      aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
  
'''Algoritmos simétricos de cifrado proporcionadas por SunJCE'''
+
      // Step 5
 +
      byte[] encrypted = aesCipherForEncryption.doFinal(message.getBytes(charEnc));
 +
      ByteBuffer cipherData = ByteBuffer.allocate(iv.length + encrypted.length);
 +
      cipherData.put(iv);
 +
      cipherData.put(encrypted);
 +
      cipherText = new String(Base64.getEncoder().encode(cipherData.array()), charEnc);
 +
      System.out
 +
        .println("Encrypted and encoded message is: " + new String(Base64.getEncoder().encode(encrypted), charEnc));
 +
      System.out.println(cipherText);
 +
      System.out.println("\nThe receiver will now initialize the cipher using the IV and decrypt the ciphertext");
  
1. DES - KeyLength predeterminado de 56 bits (longitud)
+
      // Step 6
2. AES
+
      Cipher aesCipherForDecryption = Cipher.getInstance(transformationString);
3. RC2, RC4 y RC5
 
4. IDEA
 
5. Triple DES - KeyLength por defecto 112 bits
 
6. Blowfish - KeyLength defecto 56 bits
 
7. PBE con MD5 y DES
 
8. PBE con HmacSHA1 y DESede
 
9. DES ede
 
  
'''Modos de Encriptación'''
+
      // Step 7
 +
      cipherData = ByteBuffer.wrap(Base64.getDecoder().decode(cipherText.getBytes(charEnc)));
 +
      iv = new byte[aesCipherForDecryption.getBlockSize()];
 +
      cipherData.get(iv);
 +
      encrypted = new byte[cipherData.remaining()];
 +
      cipherData.get(encrypted);
 +
      aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
  
1. BCE
+
      // Step 8
2. CBC
+
      byte[] decrypted = aesCipherForDecryption.doFinal(encrypted);
3. CFB
+
      System.out.println("Decrypted text message is: " + new String(decrypted, charEnc));
4. OFB
+
    } catch(NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | UnsupportedEncodingException ex) {
5. PCBC
+
      System.err.println(ex);
 +
    }
 +
  }
  
'''Algoritmos de cifrado asimétricos implementados por SunJCE'''
+
}
 
+
</pre>
1. RSA
 
2. Diffie-Hellman - KeyLength defecto 1024 bits
 
 
 
'''Hashing / Message Digest algoritmos implementados por SunJCE'''
 
  
1. MD5 - por defecto 64 bytes de tamaño
+
[[Category:Java]]
2. SHA1 - por defecto 64 bytes de tamaño
 

Latest revision as of 16:38, 10 July 2019

Overview

Java Cryptographic Extensions (JCE) is a set of Java API's which provides cryptographic services such as encryption, secret Key Generation, Message Authentication code and Key Agreement. The ciphers supported by JCE include symmetric, asymmetric, block and stream ciphers. JCE was an optional package to JDK v 1.2.x and 1.3.x. JCE has been integrated into JDK v1.4.

JCE API's are implemented by Cryptographic Service Providers. Each of these cryptographic service providers implements the Service Provider Interface which specifies the functionalities which needs to be implemented by the service providers. Programmers can plugin any Service Providers for performing cryptographic functionalities provided by JCE. J2SE comes with a default provider named SunJCE.

Symmetric Encryption Algorithms provided by SunJCE

  1. DES - default keylength of 56 bits
  2. AES -
  3. RC2, RC4 and RC5
  4. IDEA
  5. Triple DES – default keylength 112 bits
  6. Blowfish – default keylength 56 bits
  7. PBEWithMD5AndDES
  8. PBEWithHmacSHA1AndDESede
  9. DES ede

Modes of Encryption

  1. ECB
  2. CBC
  3. CFB
  4. OFB
  5. PCBC

Asymmetric Encryption Algorithms implemented by SunJCE

  1. RSA
  2. Diffie-Hellman – default keylength 1024 bits

Hashing / Message Digest Algorithms implemented by SunJCE

  1. MD5 – default size 64 bytes
  2. SHA1 - default size 64 bytes

Examples

SecureRandom

SecureRandom class is used to generate a cryptographically strong pseudo random number by using a PRNG Algorithm. The following are the advantages of using SecureRandom over Random. 1. SecureRandom produces a cryptographically strong pseudo random number generator. 2. SecureRandom produces cryptographically strong sequences as described in RFC 1750: Randomness Recommendations for Security

package org.owasp.java.crypto;

import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;

import sun.misc.BASE64Encoder;

/**
 * @author Joe Prasanna Kumar
 * This program provides the functionality for Generating a Secure Random Number.
 *  
 * There are 2 ways to generate a  Random number through SecureRandom.
 * 1. By calling nextBytes method to generate Random Bytes
 * 2. Using setSeed(byte[]) to reseed a Random object
 * 
 */


public class SecureRandomGen {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
	        // Initialize a secure random number generator
	        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
	    
	        // Method 1 - Calling nextBytes method to generate Random Bytes
	        byte[] bytes = new byte[512];
	        secureRandom.nextBytes(bytes); 
	        
	        // Printing the SecureRandom number by calling secureRandom.nextDouble()
	        System.out.println(" Secure Random # generated by calling nextBytes() is " + secureRandom.nextDouble());
	    
	        // Method 2 - Using setSeed(byte[]) to reseed a Random object
	        int seedByteCount = 10;
	        byte[] seed = secureRandom.generateSeed(seedByteCount);   
	        
	        // TBR System.out.println(" Seed value is " + new BASE64Encoder().encode(seed));
	    
	        secureRandom.setSeed(seed);
	        
	        System.out.println(" Secure Random # generated using setSeed(byte[]) is  " + secureRandom.nextDouble());
	        
	    } catch (NoSuchAlgorithmException noSuchAlgo)
		{
			System.out.println(" No Such Algorithm exists " + noSuchAlgo);
		}
	}

}

AES Encryption and Decryption

package org.owasp.java.crypto;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

// @formatter:off
/**
 * @author Chuck Eastus
 * Reworked from Joe Prasanna Kumar's sample with suggestions and notes made by Kevin W. Wall.
 * This class demonstrates encrypting and decrypting a string message using the AES algorithm.
 * Steps:
 * 1. Generate an AES key of the desired length (in bits) using an AES KeyGenerator.
 * 2. Get a Cipher instance of the desired algorithm, mode, and padding.
 * 3. Generate an initialization vector for our message of the same size as the Cipher's blocksize.
 * 4. Initialize the Cipher instance for encryption using the key and initialization vector.
 * 5. Use the Cipher to encrypt the message (after encoding it to a byte[] using the named Charset), and then append
 * the encrypted data to the IV and Base64-encode the result.
 * 6. Get a new Cipher instance of the same algorithm, mode, and padding used for encryption.
 * 7. Base64-decode and split the data into the IV and the encrypted data, and then initialize the cipher for
 * decryption with the same key used for encryption (symmetric), the IV, and the encrypted data.
 * 8. Use the Cipher to decrypt the data, convert it to a String using the named Charset, and display the message.
 *
 * Notes on padding:
 * PKCS7 padding is actually technically the correct padding name, but Java blew it and called it PKCS5PADDING.
 * Technically, PKCS5 padding only applies to ciphers with a cipher block size of 64-bits, not 128-bits, but both PKCS5
 * and PKCS7 padding act identically for block sizes <= 255 bits.
 * Be sure to specify the mode explicitly as most JCE providers default to ECB mode, which is not secure!
 * For this example, we are use CFB mode with no padding in order to avoid padding attacks.
 *
 * Notes on initialization vectors (IVs):
 * The IV must be saved for later decryption and should not be reused for other encryption operations. It can be stored
 * separately or sent along with the encrypted data. Usually, the encrypted data is appended to the IV and the result
 * is encoded then stored or transmitted.
 */
// @formatter:on

public class AES {

  public static final int keyLength = 128;
  public static final String charEnc = "UTF-8";
  public static final String transformationString = "AES/CFB/NoPadding";

  public static void main(String[] args) {

    String message = "Hello World of Encryption using AES";
    String cipherText;

    try {
      // Step 1
      KeyGenerator keyGen = KeyGenerator.getInstance("AES");
      keyGen.init(keyLength);
      SecretKey secretKey = keyGen.generateKey();

      // Step 2
      Cipher aesCipherForEncryption = Cipher.getInstance(transformationString);

      // Step 3
      byte[] iv = new byte[aesCipherForEncryption.getBlockSize()];
      SecureRandom prng = new SecureRandom();
      prng.nextBytes(iv);

      // Step 4
      aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));

      // Step 5
      byte[] encrypted = aesCipherForEncryption.doFinal(message.getBytes(charEnc));
      ByteBuffer cipherData = ByteBuffer.allocate(iv.length + encrypted.length);
      cipherData.put(iv);
      cipherData.put(encrypted);
      cipherText = new String(Base64.getEncoder().encode(cipherData.array()), charEnc);
      System.out
        .println("Encrypted and encoded message is: " + new String(Base64.getEncoder().encode(encrypted), charEnc));
      System.out.println(cipherText);
      System.out.println("\nThe receiver will now initialize the cipher using the IV and decrypt the ciphertext");

      // Step 6
      Cipher aesCipherForDecryption = Cipher.getInstance(transformationString);

      // Step 7
      cipherData = ByteBuffer.wrap(Base64.getDecoder().decode(cipherText.getBytes(charEnc)));
      iv = new byte[aesCipherForDecryption.getBlockSize()];
      cipherData.get(iv);
      encrypted = new byte[cipherData.remaining()];
      cipherData.get(encrypted);
      aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));

      // Step 8
      byte[] decrypted = aesCipherForDecryption.doFinal(encrypted);
      System.out.println("Decrypted text message is: " + new String(decrypted, charEnc));
    } catch(NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | UnsupportedEncodingException ex) {
      System.err.println(ex);
    }
  }

}