Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Revised compliant solutions in light of Maarten Bodewes' comments.

Security-intensive applications must avoid use of insecure or weak cryptographic primitives to protect sensitive information. The computational capacity of modern computers permits circumvention of such cryptography via brute-force attacks. For example, the Data Encryption Standard (DES) encryption algorithm is considered highly insecure; messages encrypted using DES have been decrypted by brute force within a single day by machines such as the Electronic Frontier Foundation's (EFF) Deep Crack.

...

Code Block
bgColor#FFCCCC
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key); 

// Encode bytes as UTF8; strToBeEncrypted contains
// the input string that is to be encrypted 
byte[] encoded = strToBeEncrypted.getBytes("UTF8");
    
// Perform encryption
byte[] encrypted = cipher.doFinal(encoded);

...

Noncompliant Code Example

This compliant solution noncompliant code example uses the more secure Advanced Encryption Standard (AES) algorithm to perform the encryptionElectronic Codebook (ECB) mode of operation, which is generally insecure.

Code Block
bgColor#ccccff
Cipher cipher = Cipher.getInstance("AES");             
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may be unavailable

SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();

SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");  // defaults to ECB mode
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

// Encode bytes as UTF8; strToBeEncrypted contains
// the input string that is to be encrypted 
byte[] encoded = strToBeEncrypted.getBytes("UTF8");
    
// Perform encryption
byte[] encrypted = cipher.doFinal(encoded);   

Compliant Solution

This compliant solution uses the Advanced Encryption Standard (AES) algorithm in Galois/Counter Mode (GCM) to perform the encryption.  GCM has the benefit of providing authenticity (integrity) in addition to confidentiality.  The same secret key can be used to encrypt multiple messages in GCM mode, but it is very important that a different initialization vector (IV) be used for each message.  The below encrypt method uses SecureRandom to generate a unique (with very high probability) IV for each message encrypted.  Logically, the encrypt method produces a pair of (IV, ciphertext), which the decrypt method consumes.  However, at the Java level, the encrypt method returns a single byte array that consists of the IV followed by the ciphertext, since in practice this is often easier to handle than a pair of byte arrays.

Code Block
bgColor#ccccff
import java.util.Arrays;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.SecureRandom;
import java.security.GeneralSecurityException;

class Msc61 {
    public static final int GCM_TAG_LENGTH = 12;
    public static final int GCM_IV_LENGTH = 16;

    public static SecretKey generateKey() throws GeneralSecurityException {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        return kgen.generateKey();
    }

    public static byte[] encrypt_gcm(SecretKey skey, String plaintext) throws GeneralSecurityException {
        byte[] ciphertext = null;
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");            
        byte[] initVector = new byte[GCM_IV_LENGTH];
        (new SecureRandom()).nextBytes(initVector);
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, initVector);
        cipher.init(Cipher.ENCRYPT_MODE, skey, spec);
        byte[] encoded = plaintext.getBytes(java.nio.charset.StandardCharsets.UTF_8);
        ciphertext = new byte[GCM_TAG_LENGTH + GCM_IV_LENGTH + encoded.length];
        for (int i=0; i < GCM_IV_LENGTH; i++) {
            ciphertext[i] = initVector[i];
        }
        // Perform encryption
        cipher.doFinal(encoded, 0, encoded.length, ciphertext, GCM_IV_LENGTH);
        return ciphertext;
    }

    public static String decrypt_gcm(SecretKey skey, byte[] ciphertext) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");            
        byte[] initVector = Arrays.copyOfRange(ciphertext, 0, GCM_IV_LENGTH);
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, initVector);
        cipher.init(Cipher.DECRYPT_MODE, skey, spec);
        byte[] plaintext = cipher.doFinal(ciphertext, GCM_IV_LENGTH, ciphertext.length - GCM_IV_LENGTH);
        return new String(plaintext);
    }
} 

Compliant Solution

This compliant solution uses the Advanced Encryption Standard (AES) algorithm in Cipher Block Chaining (CBC) mode to perform the encryption.

Code Block
bgColor#ccccff
import java.util.Arrays;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.SecureRandom;
import java.security.GeneralSecurityException;

class Msc61 {
    public static SecretKey generateKey() throws GeneralSecurityException {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        kgen.init(128);
        return kgen.generateKey();
    }

    public static byte[] encrypt_cbc(SecretKey skey, String plaintext) throws GeneralSecurityException {
        byte[] ciphertext = null;
        Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding");            
        final int blockSize = cipher.getBlockSize();
        byte[] initVector = new byte[blockSize];
        (new SecureRandom()).nextBytes(initVector);
        IvParameterSpec ivSpec = new IvParameterSpec(initVector);
        cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);
        byte[] encoded = plaintext.getBytes(java.nio.charset.StandardCharsets.UTF_8);
        ciphertext = new byte[initVector.length + ((encoded.length / blockSize) + 1) * blockSize];
        for (int i=0; i < initVector.length; i++) {
            ciphertext[i] = initVector[i];
        }
        // Perform encryption
        cipher.doFinal(encoded, 0, encoded.length, ciphertext, initVector.length);
        return ciphertext;
    }

    public static String decrypt_cbc(SecretKey skey, byte[] ciphertext) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/CBC/ISO10126Padding");            
        final int blockSize = cipher.getBlockSize();
        byte[] initVector = Arrays.copyOfRange(ciphertext, 0, blockSize);
        IvParameterSpec ivSpec = new IvParameterSpec(initVector);
        cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
        byte[] plaintext = cipher.doFinal(ciphertext, blockSize, ciphertext.length - blockSize);
        return new String(plaintext);
    }
} 

 

The above compliant solutions use 128-bit AES keys.  Longer keys (192-bit and 256-bit) may be available if the "Unlimited Strength Jurisdiction Policy" files are installed and available to the Java runtime environment.

Applicability

Use of mathematically and computationally insecure cryptographic algorithms can result in the disclosure of sensitive information.

Weak cryptographic algorithms can be disabled in Java SE 7; see the Java PKI Programmer's Guide, Appendix D: Disabling Cryptographic Algorithms [Oracle 2011a].Weak cryptographic algorithms may be used in scenarios that specifically call for a breakable cipher. For example, the ROT13 cipher is commonly used on bulletin boards and websites when the purpose of encryption is to protect people from the information rather than protect information from the people.

Bibliography

...