How to encrypt with 3DES – DESede from Bouncy Castle API in J2ME applications

3 comments -

In this post we will see how to use the 3DES (Triple Data Encryption Standard in EDE mode) or DESede algorithm implementation from the Bouncy Castle API for J2ME platform. The example will use the 3DES lightweight engine to encrypt and decrypt a file managed by a J2ME (MIDlet) application.

The Bouncy Castle Crypto API for Java provides a lightweight cryptographic API that works with everything from the J2ME to the JDK 1.6 platform. The API is different for J2ME platform than the one for JDK platform. For example, the lightweight API has different implementations for the two platforms:

and also, at functions level, the situation in also different:

  • for the JDK platform the main class for cryptographic algorithms is Cipher;
  • for the J2ME platform there are classes for each cryptographic algorithm; e.g. for 3DES there is DESedeEngine.

In order to understand this example, you must have basic knowledge about:

I recommend:

 

The 3DES (Triple Data Encryption Standard in EDE mode) or DESede algorithm has some important characteristics:

  • improve the security of DES by modifying how the algorithm is used (doesn’t modify the algorithm); it is a multiple encryption system because it uses 2 encryptions and one decryption on the same message in this sequence Encryption – Decryption – Encryption (EDE); for this, it uses 2 keys, one for the two encryptions and one for the decryption;
  • uses keys with size equal to 128 or 192 bits;
  • is a symmetric cryptographic algorithm (the same key is used both for encryption and decryption);
  • processes blocks of 64 bits;
  • effective both on Intel platforms and other software or hardware platforms;
  • it can be implemented on 32 bit processors and smart cards (8-bitprocessors);
  • slower than AES; an implementation of AES is available in How to encrypt / decrypt with AES from Bouncy Castle API in J2ME applications;
  • it is more secure than DES but less secure than AES;

For 3DES, the Bouncy Castle Crypto API for J2ME platform provides one implementation, DESedeEngine that provides a basic DESede (or Triple DES) engine that will process 64 bits (8 bytes) blocks and will use a 128 or 192 bits key.

Because, the files that are going to be encrypted may have or NOT (most of the times) a dimension that is multiple of block size (64 bits), we must use padding for the last block. In this case we will use the PaddedBufferedBlockCipher class, which is “a wrapper class that allows block ciphers to be used to process data in a piecemeal fashion with padding” [Bouncy Castle API documentation].

The encryption solution (complete encryption/decryption solution file) is defined by these steps:

1. define the PaddedBufferedBlockCipher instance used for encryption – encryptCipher in this solution; the PaddedBufferedBlockCipher class provides 2 constructors; both require a BlockCipher instance; one uses by default PKCS7 padding (used by this solution), the other one requires a BlockCipherPadding instance; for the BlockCipher instance we will create a DESedeEngine object;

2. init the cipher for encryption with a key; the key could be predefined or received; these 2 first steps are implemented by the constructors:

public class DESede_BC {
 
    PaddedBufferedBlockCipher encryptCipher;
    PaddedBufferedBlockCipher decryptCipher;
 
    // Buffers used to transport the bytes from one stream to another
    byte[] buf = new byte[8];       //input buffer - block size length
    byte[] obuf = new byte[512];    //output buffer
 
    byte[] key = null;              //the key
 
    public DESede_BC(){
        //use a default 192 bit key
        key = "SECRET_1SECRET_2SECRET_3".getBytes();
        InitCiphers();
    }
    public DESede_BC(byte[] keyBytes){
        key = new byte[keyBytes.length];
        System.arraycopy(keyBytes, 0 , key, 0, keyBytes.length);
        InitCiphers();
    }
 
    private void InitCiphers(){
        encryptCipher = new PaddedBufferedBlockCipher(new DESedeEngine());
        encryptCipher.init(true, new KeyParameter(key));
        decryptCipher =  new PaddedBufferedBlockCipher(new DESedeEngine());
        decryptCipher.init(false, new KeyParameter(key));
    }
}

 

3. read bytes from the file; in the solution, we read 16 bytes blocks from the file; each block is processed by the int processBytes(byte[] in,int inOff, int len, byte[] out, int outOff)method; the output of the processed block is put in the out buffer which is then written in the encrypted file.

4. VERY IMPORTANT STEP call the doFinal function which will process the last block in the buffer; the internal mechanism of the algorithm implementation, based on its encryption mode (ECB, CBC, or other) keeps an internal buffer which must be also discarded into the output file (this is NOT the last block of the input file); the doFinal() it is a MUST DO step.

The last two steps are implemented by the encrypt function:

public void encrypt(InputStream in, long length, OutputStream out)
throws ShortBufferException, 
        IllegalBlockSizeException,  
        BadPaddingException,
        DataLengthException, 
        IllegalStateException, 
        InvalidCipherTextException
{
    try {
        // Bytes written to out will be encrypted
        // Read in the cleartext bytes from in InputStream and
        //      write them encrypted to out OutputStream
 
        int noBytesRead = 0;        //number of bytes read from input
        int noBytesProcessed = 0;   //number of bytes processed
 
        while ((noBytesRead = in.read(buf)) >= 0) {
            noBytesProcessed = 
                    encryptCipher.processBytes(buf, 0, noBytesRead, obuf, 0);
            out.write(obuf, 0, noBytesProcessed);
        }
         noBytesProcessed = 
                 encryptCipher.doFinal(obuf, 0);
 
         out.write(obuf, 0, noBytesProcessed);
 
        out.flush();
    }
    catch (java.io.IOException e) {
        System.out.println(e.getMessage());
    }
}

The decryption solution is similar to the encryption one and is implemented by the decrypt function.

The complete solution is implemented by the DESede_BC class in this complete encryption/decryption solution file.

In order to use these two functions you must open the cleartext file and the encrypted one. These is a sample for use of encryption from a running MIDlet:

void encryptFile(String fileName)
    {
         try {
            FileConnection fci =
                (FileConnection)Connector.open("file://localhost/" + 
                currDirName + fileName);
            if (!fci.exists()) {
                throw new IOException("File does not exists");
            }
             //createFile("encrypt.txt", false);
             FileConnection fco =
                (FileConnection)Connector.open("file://localhost/" + 
                currDirName + "encrypt.txt");
 
             if (!fco.exists())
                 fco.create();
 
            if (!fco.exists()) {
                throw new IOException("Can not create encrypted file");
            }
 
            InputStream fis = fci.openInputStream();
            OutputStream fos = fco.openOutputStream();
 
            DESede_BC encrypter = new DESede_BC();
 
	    // Encrypt
            encrypter.encrypt(fis, fci.fileSize(), fos);
 
            fis.close();
            fos.close();
 
            Alert alert =
                new Alert("Confirmation",
                "File encryption terminated", 
                null, 
                AlertType.INFO);
            alert.setTimeout(Alert.FOREVER);
            Display.getDisplay(this).setCurrent(alert);
         }
         catch (Exception e) {
            Alert alert =
                new Alert("Encryption error!",
                    "Can not access file " + fileName + 
                    " in directory " + currDirName +
                    "Exception: " + e.getMessage(), 
                    null, 
                    AlertType.ERROR);
            alert.setTimeout(Alert.FOREVER);
            Display.getDisplay(this).setCurrent(alert);
        }
    }

Other implementation of the Bouncy Castle API for J2ME can be found in How to encrypt / decrypt with AES from Bouncy Castle API in J2ME applications.

The complete solution is implemented by the DESede_BC class in this complete encryption/decryption solution file.

Like it? Then share this post or check the external adds. Sharing is the best way to appreciate the author.

, , , , ,