Hello,
Through several articles, I would like present the cryptographic mechanisms, types of keys, certificate, types of algorithms …etc:

 


Encryption with AES/CBC, AES/EBC (Encryption of files)
 

  1. Presentation
    The AES (Advanced Encryption Standard), created in January 1997, also known as algorithm Rijndael, is a symmetric encryption standard replacing the Data Encryption Standard (DES), which has become too weak in the face of current attacks. It is currently the most used and the safest.

    This algorithm has the following specifications:

    • The AES is a standard, therefore free to use, without restriction of use or patent
    • The AES is symmetric type algorithm with secret key
    • The AES is block encryption algorithm,
    • The AES supports different combinations of [key length] – [block length]: 128-128, 192-128 and 256-128 bits (in fact, Rijndael also supports variable block sizes, but this is not retained in the standard)

     
    In decimal terms, these different possible sizes concretely mean that:

    • 3.4 x 1038 possible 128-bit keys
    • 6.2 x 1057 possible 192-bit keys
    • 1.1 x 1077 possible 256-bit keys

     
    There are online encryption Tools like http://aesencryption.net/ whici is a web tool to encrypt and decrypt text using AES encryption algorithm. The tool is free, without registration.
     

  2. AES/CBC and AES/EBC
    What are the differences between ECB qnd CBC modes of AES algorithm? Which mode ECB of CBC is better? how to decide which mode to use? Are there any other modes which are better?

    ECB (electronic code book) is basically raw cipher. Each block of plaintext is encrypted independently of others blocks. The problem with this transform is that any resident properties of the plaintext might well show up in the ciphertext – possibly not as clearly – that’s what blocks and key schedules are supposed to protect againt, but analyzing the patterns, it is possible to deduce properties that were hidden.
     
    – With ECB, it is possible to manage a partial decryption and easily fill in the blanks, for example if extracting data from an encrypted hard disk.
    – ECB naturally supports operation in parallel since each block can be encrypted independently of the next
     
     

    CBC (cipher block chaining) needs an initialization vector used with a XOR operator on the first block of plaintext. After the encryption of this first block of plaintext, the next block of plaintext is xor’d against the previous encrypted block.

     
    – With CBC, if a few blocks in the sequence are missing then encryption becomes impossible.
    – CBC doesn’t supports operation in parallel, since it is necessary to wait on each block.
    – CBC can also be considered vulnerable in the use of predictable IVs.
    – CBC is not suitable for transport protocols.

     
    Others AES encryption mode (CBC ECB CTR OCB CFB)?
    See http://stackoverflow.com/questions/1220751/how-to-choose-an-aes-encryption-mode-cbc-ecb-ctr-ocb-cfb
    – CBC, OFB and CFB are similar, however OFB/CFB is better because you only need encryption and not decryption, which can save code space.
    – CTR is used if you want good parallelization (ie. speed), instead of CBC/OFB/CFB.
    – XTS mode is the most common if you are encoding a random accessible data (like a hard disk or RAM).
    – OCB is by far the best mode, as it allows encryption and authentication in a single pass. However there are patents on it in USA.

     

  3. Tools
    As described in the post http://www.javablog.fr/javacrypto-encryption-list-providers-and-algo.html, we could find the available algorithm, tools (cipher, generator) in each reachable provider. In our case, we use the SunJCE Provider which is enough (http://javasearch.developpez.com/sun/j2se/1.6.0/technotes/guides/security/SunProviders.html#SunJCEProvider)
    The following algorithms are available in the SunJCE provider:

    [4] SunJCE v1.6: SunJCE Provider (implements RSA, DES, Triple DES, AES, Blowfish, ARCFOUR, RC2, PBE, Diffie-Hellman, HMAC)
    - AlgorithmParameters.AES -> com.sun.crypto.provider.AESParameters
    aliases: [Rijndael]
    - Cipher.AES -> com.sun.crypto.provider.AESCipher
    aliases: [Rijndael]
    attributes: {SupportedKeyFormats=RAW, SupportedPaddings=NOPADDING|PKCS5PADDING|ISO10126PADDING, SupportedModes=ECB|CBC|PCBC|CTR|CTS|CFB|OFB|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128}
    - Cipher.AESWrap -> com.sun.crypto.provider.AESWrapCipher
    attributes: {SupportedKeyFormats=RAW, SupportedPaddings=NOPADDING, SupportedModes=ECB}
    - KeyGenerator.AES -> com.sun.crypto.provider.AESKeyGenerator
    aliases: [Rijndael]

     
  4. Example 1 : Encryption with “AES/ECB/PKCS5Padding” ALGO on 128bits
    Details:
    – 128 bit-keys
    – No initialization vector
    – 3 solutions to generated the secret key :

    • Solution 1 : Key randomly generated in bytes format. Secret key on 16 characters : random string whose length is the number of characters specified.
      //new byte[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
      byte[] keyValue = RandomStringUtils.randomAscii(16).getBytes("UTF-8");
      return keyValue;
    • Solution 2 : AES key generated using KeyGenerator Initialize the keysize to 128 bits (16 bytes)
      KeyGenerator keyGen = KeyGenerator.getInstance("AES");
      keyGen.init(128);
      SecretKey secretKey = keyGen.generateKey();
      return secretKey.getEncoded();
    • Solution 3 : Wrapped AES key : Generate an AES key using KeyGenerator Initialize the keysize to 128 bits (16 bytes) and wrapped in a AES key generated using KeyGenerator with a keysize of 256 bits.
      For this solution, we need the BouncyCastleProvider provider:
      [9] BC v1.47: BouncyCastle Security Provider v1.47
      ...
      - KeyGenerator.2.16.840.1.101.3.4.1.41 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.42 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.43 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.44 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.45 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.42 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256

      http://www.java2s.com/Tutorial/Java/0490__Security/AESKeygenerator.htm
      About the wrapped key : http://flylib.com/books/en/1.274.1.29/1/

      Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
              	
      // Key to be wrapped
      KeyGenerator generatorAES128ToBeWrapped = KeyGenerator.getInstance("AES", "BC"); // BC = BouncyCastle provider
      generatorAES128ToBeWrapped.init(128);
      Key keyToBeWrapped = generatorAES128ToBeWrapped.generateKey();
      System.out.println("input key to be wrapped : " + new String(keyToBeWrapped.getEncoded()));
      
      // Key wrapper
      KeyGenerator generatorAES256Wrapper = KeyGenerator.getInstance("AES", "BC"); // BC = BouncyCastle provider
      generatorAES256Wrapper.init(256);
      Key wrapperKey = generatorAES256Wrapper.generateKey();
      System.out.println("wrapper key : " + new String(wrapperKey.getEncoded()));
      
      // Cipher
      Cipher cipher = Cipher.getInstance("AESWrap", "BC");
      cipher.init(Cipher.WRAP_MODE, wrapperKey);
      byte[] wrappedKey = cipher.wrap(keyToBeWrapped);
      System.out.println("wrapped key value : " + new String(wrappedKey));
      //
      cipher.init(Cipher.UNWRAP_MODE, wrapperKey);
      Key unWrappedKey = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
      System.out.println("unwrapped key value : " + new String(unWrappedKey.getEncoded()));
                  
      return unWrappedKey.getEncoded();

    … Encryption/ciphering code :

    /**
    * Encrypt PDF file
    * @param keyValue : secret key
    * @param data
    * @return
    * @throws Exception
    */
    public static byte[] encrypt(byte[] keyValue, byte[] data) throws Exception {
         SecretKeySpec keyspec = new SecretKeySpec(keyValue, "AES");
         Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
         c.init(Cipher.ENCRYPT_MODE, keyspec);
         byte[] encVal = c.doFinal(data);
         return encVal;
    }

    … Decryption/deciphering code :

    /**
    * Decrypt PDF file
    * @param keyValue : secret key
    * @param data
    * @return
    * @throws Exception
    */
    public static byte[] decrypt(byte[] keyValue, byte[] encryptedData) throws Exception {
         SecretKeySpec keyspec = new SecretKeySpec(keyValue, "AES");
         Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
         c.init(Cipher.DECRYPT_MODE, keyspec);
         byte[] decValue = c.doFinal(encryptedData);
         return decValue;
    }

    …here the class/method tests:

    /**
     * Class Test of EncryptionAesEcbPkcs5Padding
     * @author Huseyin OZVEREN
     */
    public class EncryptionAesEcbPkcs5PaddingTest {
    
    	public static void main(String[] args) {
    		try{
    			byte[] keyValue = EncryptionAesEcbPkcs5Padding.generateSecretKey(EncryptionAesEcbPkcs5Padding.INTERNAL_KEY_GENERATION_MODE.GENERATED_WRAPPED_KEY);
    			System.out.println("Generation of secret key : "+new String(keyValue));
    	        aEncryptFile(keyValue);
    	        bDecryptFile(keyValue);
    		}catch(Throwable th){
    			th.printStackTrace();
    		}
        }
    
    	/**
    	 * Encrypt PDF file
    	 * @param keyValue : secret key
    	 * @throws Exception
    	 */
        public static void aEncryptFile(byte[] keyValue) throws Exception {
            try {
                File sourceFile = new File(System.getProperty("user.dir") + "/resources/pdf_with_text.pdf");
                System.out.println("Size of source file (to encrypt): " + sourceFile.length());
                byte[] content = Files.readAllBytes(sourceFile.toPath());
                byte[] encryptContent = EncryptionAesEcbPkcs5Padding.encrypt(keyValue, content);
                File targetFile = new File(System.getProperty("user.dir") + "/resources/pdf_with_text_encrypted_aes_ecb.pdf");
                if(targetFile.exists()){
                	targetFile.delete();
                }
                Files.write(targetFile.toPath(), encryptContent, StandardOpenOption.CREATE_NEW);
                System.out.println("Size of encrypted file : " + targetFile.length());
            } catch (Exception e) {
            	e.printStackTrace();
            }
        }
    
        
        /**
    	 * Decrypt PDF file
    	 * @param keyValue : secret key
         * @throws Exception
         */
        public static void bDecryptFile(byte[] keyValue) throws Exception {
            try {
                byte[] encryptContent = Files.readAllBytes(new File(System.getProperty("user.dir") + "/resources/pdf_with_text_encrypted_aes_ecb.pdf").toPath());
                System.out.println("Size of encrypted file (to decrypt): " + encryptContent.length);
                byte[] decryptContent = EncryptionAesEcbPkcs5Padding.decrypt(keyValue, encryptContent);
                File targetFile = new File(System.getProperty("user.dir") + "/resources/pdf_with_text_decrypted_aes_ecb.pdf");
                if(targetFile.exists()){
                	targetFile.delete();
                }
                Files.write(targetFile.toPath(), decryptContent, StandardOpenOption.CREATE_NEW);
                System.out.println("Size of decrypted file : " + targetFile.length());
            } catch (Exception e) {
            	e.printStackTrace();
            }
    
        }
    }
    
    

    …here the outputs:

    input key to be wrapped : ñ'Yn??|Á§HìŠqî
    wrapper key : ÓÌÔLKGÄX\tíÕÛ´éB2-ìW7΋«ˆà‚w
    wrapped key value : ¼te ¶4©%¸NU¢Åç­«–À<›ª unwrapped key value : ñ'Yn??|Á§HìŠqî Generation of secret key : ñ'Yn??|Á§HìŠqî Size of source file (to encrypt): 882 Size of encrypted file : 896 Size of encrypted file (to decrypt): 896 Size of decrypted file : 882

    Notes:
    - the source key (to be wrapped) is equal to the value of unwrapped key;
    - the source file "/resources/pdf_with_text.pdf" and the file resulting of encryption/decryption "/resources/pdf_with_text_decrypted_aes_ecb.pdf" are equals.

     

  5. Example 2 : Encryption with "AES/CBC/PKCS5Padding" ALGO on 128bits with Initialization vector
    Details:
    - 128 bit-keys
    - With initialization vector on 16 bytes
    - Encryption by data block : the data N+1 are encrypted on the basis of data encrypted N
    - 3 solutions to generated the secret key :

    • Solution 1 : Key randomly generated in bytes format. Secret key on 16 characters : random string whose length is the number of characters specified.
      //new byte[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
      byte[] keyValue = RandomStringUtils.randomAscii(16).getBytes("UTF-8");
      return keyValue;
    • Solution 2 : AES key generated using KeyGenerator Initialize the keysize to 128 bits (16 bytes)
      KeyGenerator keyGen = KeyGenerator.getInstance("AES");
      keyGen.init(128);
      SecretKey secretKey = keyGen.generateKey();
      return secretKey.getEncoded();
    • Solution 3 : Wrapped AES key : Generate an AES key using KeyGenerator Initialize the keysize to 128 bits (16 bytes) and wrapped in a AES key generated using KeyGenerator with a keysize of 256 bits.
      For this solution, we need the BouncyCastleProvider provider:
      [9] BC v1.47: BouncyCastle Security Provider v1.47
      ...
      - KeyGenerator.2.16.840.1.101.3.4.1.41 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.42 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.43 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.44 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.1.45 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256
      - KeyGenerator.2.16.840.1.101.3.4.42 -> org.bouncycastle.jcajce.provider.symmetric.AES$KeyGen256

      http://www.java2s.com/Tutorial/Java/0490__Security/AESKeygenerator.htm
      About the wrapped key : http://flylib.com/books/en/1.274.1.29/1/

      Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
              	
      // Key to be wrapped
      KeyGenerator generatorAES128ToBeWrapped = KeyGenerator.getInstance("AES", "BC"); // BC = BouncyCastle provider
      generatorAES128ToBeWrapped.init(128);
      Key keyToBeWrapped = generatorAES128ToBeWrapped.generateKey();
      System.out.println("input key to be wrapped : " + new String(keyToBeWrapped.getEncoded()));
      
      // Key wrapper
      KeyGenerator generatorAES256Wrapper = KeyGenerator.getInstance("AES", "BC"); // BC = BouncyCastle provider
      generatorAES256Wrapper.init(256);
      Key wrapperKey = generatorAES256Wrapper.generateKey();
      System.out.println("wrapper key : " + new String(wrapperKey.getEncoded()));
      
      // Cipher
      Cipher cipher = Cipher.getInstance("AESWrap", "BC");
      cipher.init(Cipher.WRAP_MODE, wrapperKey);
      byte[] wrappedKey = cipher.wrap(keyToBeWrapped);
      System.out.println("wrapped key value : " + new String(wrappedKey));
      //
      cipher.init(Cipher.UNWRAP_MODE, wrapperKey);
      Key unWrappedKey = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
      System.out.println("unwrapped key value : " + new String(unWrappedKey.getEncoded()));
                  
      return unWrappedKey.getEncoded();

    - Creation of the Initialization Vector (IV) via a Secure Random Number Generator and an empty 16byte array (Filling of array).

    public static IvParameterSpec generateIV() throws Exception {
        byte[] ivValue = null;
        //ivValue = new byte[] { '5', 'G', 'X', 'c', 'b', 'a', '9', '8', '7', '6', '5', '4', '3', '2', '1', '0' };
        //ivValue = "HuO12OZ45JAvaLuX".getBytes(UNICODE_FORMAT);
        {
            SecureRandom r = new SecureRandom();
            byte[] newSeed = r.generateSeed(16);
            r.setSeed(newSeed);
            ivValue = new byte[16];
            r.nextBytes(ivValue);
        }
        return new IvParameterSpec(ivValue);
    }

    ... Encryption/ciphering code :

    /**
    * Encrypt PDF file
    * @param keyValue : secret key
    * @param iv : Initialization vector
    * @param data
    * @return
    * @throws Exception
    */
    public static byte[] encrypt(byte[] keyValue, IvParameterSpec IV, byte[] data) throws Exception {
         SecretKeySpec keyspec = new SecretKeySpec(keyValue, "AES");
         Cipher c = Cipher.getInstance(ALGORITHM);
         c.init(Cipher.ENCRYPT_MODE, keyspec, IV);
         byte[] encVal = c.doFinal(data);
         return encVal;
    }

    ... Decryption/deciphering code :

    /**
    * Decrypt PDF file
    * @param keyValue : secret key
    * @param iv : Initialization vector
    * @param data
    * @return
    * @throws Exception
    */
    public static byte[] decrypt(byte[] keyValue, IvParameterSpec IV, byte[] encryptedData) throws Exception {
        SecretKeySpec keyspec = new SecretKeySpec(keyValue, "AES");
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, keyspec, IV);
        byte[] decValue = c.doFinal(encryptedData);
        return decValue;
    }

    ...here the class/method tests:

    /**
     * Class Test of EncryptionAesCbcPkcs5Padding
     * @author Huseyin OZVEREN
     */
    public class EncryptionAesCbcPkcs5PaddingTest {
    
    	public static void main(String[] args) {
    		try{
    			byte[] keyValue = EncryptionAesCbcPkcs5Padding.generateSecretKey(EncryptionAesCbcPkcs5Padding.INTERNAL_KEY_GENERATION_MODE.GENERATED_WRAPPED_KEY);
    			System.out.println("Generation of secret key : "+new String(keyValue));
    			IvParameterSpec iv = EncryptionAesCbcPkcs5Padding.generateIV();
    			System.out.println("Initialization vector used : "+new String(iv.getIV()));
    	        aEncryptFile(keyValue, iv);
    	        bDecryptFile(keyValue, iv);
    		}catch(Throwable th){
    			th.printStackTrace();
    		}
        }
    
    	/**
    	 * Encrypt PDF file
    	 * @param iv : Initialization vector
    	 * @throws Exception
    	 */
        public static void aEncryptFile(byte[] keyValue, IvParameterSpec iv) throws Exception {
            try {
                File sourceFile = new File(System.getProperty("user.dir") + "/resources/pdf_with_text.pdf");
                System.out.println("Size of source file (to encrypt): " + sourceFile.length());
                byte[] content = Files.readAllBytes(sourceFile.toPath());
                byte[] encryptContent = EncryptionAesCbcPkcs5Padding.encrypt(keyValue, iv, content);
                File targetFile = new File(System.getProperty("user.dir") + "/resources/pdf_with_text_encrypted_aes_cbc.pdf");
                if(targetFile.exists()){
                	targetFile.delete();
                }
                Files.write(targetFile.toPath(), encryptContent, StandardOpenOption.CREATE_NEW);
                System.out.println("Size of encrypted file : " + targetFile.length());
            } catch (Exception e) {
            	e.printStackTrace();
            }
        }
    
        
        /**
    	 * Decrypt PDF file
    	 * @param keyValue : secret key
    	 * @param iv : Initialization vector
         * @throws Exception
         */
        public static void bDecryptFile(byte[] keyValue, IvParameterSpec iv) throws Exception {
            try {
                byte[] encryptContent = Files.readAllBytes(new File(System.getProperty("user.dir") + "/resources/pdf_with_text_encrypted_aes_cbc.pdf").toPath());
                System.out.println("Size of encrypted file (to decrypt): " + encryptContent.length);
                byte[] decryptContent = EncryptionAesCbcPkcs5Padding.decrypt(keyValue, iv, encryptContent);
                File targetFile = new File(System.getProperty("user.dir") + "/resources/pdf_with_text_decrypted_aes_cbc.pdf");
                if(targetFile.exists()){
                	targetFile.delete();
                }
                Files.write(targetFile.toPath(), decryptContent, StandardOpenOption.CREATE_NEW);
                System.out.println("Size of decrypted file : " + targetFile.length());
            } catch (Exception e) {
            	e.printStackTrace();
            }
    
        }
    }
    

    ...here the outputs:

    input key to be wrapped : ëÙÀÓÔtT¬óÖNù~ÿÿ
    wrapper key : ’8Ü%LÆÙ”L«w»j#\%%u„@ÆQQ>åÝ„E+‡ÿ¥
    wrapped key value : Sõ|õƒéÌW1ëW@lËs}t¼¦ÕÇ
    unwrapped key value : ëÙÀÓÔtT¬óÖNù~ÿÿ
    Generation of secret key : ëÙÀÓÔtT¬óÖNù~ÿÿ
    Initialization vector used : ÍLê m÷j{;™ù
    Size of source file (to encrypt): 882
    Size of encrypted file : 896
    Size of encrypted file (to decrypt): 896
    Size of decrypted file : 882

    Notes:
    - the source key (to be wrapped) is equal to the value of unwrapped key;
    - the source file "/resources/pdf_with_text.pdf" and the file resulting of encryption/decryption "/resources/pdf_with_text_decrypted_aes_cbc.pdf" are equals.

     

  6. Example 3 : Encryption of PDF file stored in a GED
    Details:
    - Encryption with "AES/CBC/PKCS5Padding" ALGO on 128bits,
    - With initialization vector on 16 bytes
    - Encryption by data block : the data N+1 are encrypted on the basis of data encrypted N
    - The 16-byte initialization vector is available in the BACKEND (server) and on the FRONTEND (user station) via a keystore or in the hard-coded source code.
    - A secret key generated specifically for each document on the BACKEND and sent to the user station at the "same" time as the encrypted data.
    - The exchanges between BACKEND and FRONTEND can be done via an SSL tunnel.
    - The generated / specific secret key may also be encoded in Base64.
     

Sources : aes.zip

That's all!!!

Huseyin OZVEREN