Using Cipher to implement Cryptography in Android.

Data encryption is an interesting topic in android application development. We come across scenarios where we need to encrypt the data critical to our application. Whether it be credentials, storage values, or for the sake be an entire text paragraph.

This can be achieved by using a class called Cipher. This class provides access to implementations of cryptographic ciphers for encryption and decryption.

When using a cipher the original information is known as plaintext, and the encrypted form as ciphertext. The ciphertext message contains all the information of the plaintext message, but is not in a format readable by a human or computer without the proper mechanism to decrypt it.

 

The code snippet below explains the encryption and decryption of a text,

package com.abc.xyz;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class MCrypt {

private String iv = "fedcba9876543210";            // Dummy iv (CHANGE IT!)
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "0123456789abcdef";     // Dummy secretKey (CHANGE IT!)

 

Cipher classes can not be instantiated directly, one has to call the Cipher’s getInstance method with the name of a requested transformation, optionally with a provider. A transformation specifies an operation (or a set of operations) as a string in the form:

                                     “algorithm/mode/padding” or “algorithm”

  1. Create a new IvParameterSpec instance with the bytes from the specified buffer iv used as initialization vector.
  2. Create a new SecretKeySpec instance for the specified key data and algorithm name.

 

public MCrypt() {
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");

try {

// cipher = Cipher.getInstance("AES/CBC/NoPadding");
   cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} 
catch (NoSuchPaddingException e) {
e.printStackTrace();
}
}

 

The below methods perform the actual encryption & decryption by taking the desired String as input parameter. Two method calls as explained below are important for the process,

  1. init() = Initializes this cipher instance with the specified key and algorithm parameters. The cipher is initialized for the specified operational mode (one of: encryption, decryption, key wrapping or key unwrapping). When a cipher instance is initialized by a call to any of the init methods, the state of the instance is overridden, means it is equivalent to creating a new instance and calling it init method.
  2. doFinal() = Finishes a multi-part transformation (encryption or decryption). Processes the bytes in input buffer, and any bytes that have been buffered in previous update calls.

Encryption Method:

public byte[] encrypt(String text) throws Exception {
if (text == null || text.length() == 0)
throw new Exception("Empty string");

byte[] encrypted = null;
try {
// Cipher.ENCRYPT_MODE = Constant for encryption operation mode.
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);   

encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e) {
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}

Decryption Method:

public byte[] decrypt(String text) throws Exception {
if (text == null || text.length() == 0)
throw new Exception("Empty string");

byte[] decrypted = null;
try {
// Cipher.DECRYPT_MODE = Constant for decryption operation mode.
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

decrypted = cipher.doFinal(hexToBytes(text));
} catch (Exception e) {
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}

 

  1. You can not print byte array as String because they may contain non printable characters e.g. 0 is NUL, 5 is ENQ and 6 is ACK in ASCII format.
  2. The encrypt() method above returns a byte array.  Below code method can be used for conversion of this byte array to Hex String in Java for printing.
public static String byteArrayToHexString(byte[] array) {
StringBuffer hexString = new StringBuffer();
for (byte b : array) {
int intVal = b & 0xff;
if (intVal < 0x10)
hexString.append("0");
hexString.append(Integer.toHexString(intVal));
}
return hexString.toString();
}

 

Get byte array from hex string and return the byte form of the hex string using the below method. This method is used during the decryption process (decrypt()) above,

public static byte[] hexToBytes(String str) {
if (str == null) {
return null;
} else if (str.length() < 2) {
return null;
} else {

int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
buffer[i] = (byte) Integer.parseInt(
str.substring(i * 2, i * 2 + 2), 16);

}
return buffer;
}
}

 

This method applies character padding to the input String while encryption process.

private static String padString(String source) {
char paddingChar = 0;
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++) {
source += paddingChar;
}
return source;
}
}

 

 

Now lets see, how to use the above class to perform encryption and decryption,

  • Encryption:
MCrypt mcrypt = new MCrypt();
String dummyStr = "asfaesdf237263923902;/.’;./>23y283g2k3nre”D;ASdsn;fnddffk";    

// Encrypting our dummy String
String encryptedStr = MCrypt.byteArrayToHexString(dummyStr));

The result of above encryption gives us the below encrypted String,

cb9d04dcf1ea63128ab46672f4172fff836ad66dceba0824d7e79e7cb30091f87b250dd4e8c08789a9ef5007202103d865af6f1e90d45c356c41929916f9ebf46c2cc9622da5765484e7af895f1e9a59
  • Decryption:
String decryptedStr = new String(mcrypt.decrypt(encryptedStr));

The above decryption process gives us the original “dummyStr”.