Source:
Direct:
Table of Contents
Sensitive data that can be observed by foreign eyes should be encrypted.
What is sensitive is your decision to make. It can be any personal data, images that you are sending over the network, your GPS location etc…
Sensitive data is vulnerable when its exposes outside of your program, when it is sent on the internet, or saved to local file system.
This article is not about security, it’s about simple encryption/decryption implementation.
Encryption is a transformation of the plaintext into a cipher text.
Decryption is the opposite; it is a transformation of the cipher text to plain text, to a readable format.
Encryption algorithms can be divided into 2 groups, symmetric and asymmetric. Both have their advantages and drawbacks.
Encryption and decryption are performed by one identical shared key. This key is shared between the sender and the recipient.
In order to encrypt the message, the sender uses the shared key; the recipient must use the same key to decrypt the message.
Symmetric algorithm is very fast but it requires both sides to have a unique identical key, which can be a problem in a big system because of the enormous number of keys management.
The sender and the recipient use different keys to encrypt and decrypt the message, each one has a pair of keys – public and private.
When the sender wants to encrypt a message, he uses the recipient public key. The recipient can then decrypt the message using his private key. This approach is slower but key management is much easier on large systems.
In this example we will use an Android’s SDK class Cipher
for our encryption/decryption purposes.
Cipher
class provides access to implementations of cryptographic ciphers for encryption and decryption. More about this on:
http://developer.android.com/reference/javax/crypto/Cipher.html
Our Cipher
depends on two keys, the first one is the secret key passed as string to constructor, and the second is a raw secret key which is 16-byte long.
Let’s examine our CryptoHandler
class.
<a name="CryptoHandlerClass">
public CryptoHandler(String passphrase)
{
byte[] passwordKey = encodeDigest(passphrase);
try
{
_aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
}
catch (NoSuchAlgorithmException e)
{
Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e);
}
catch (NoSuchPaddingException e)
{
Log.e(TAG, "No such padding PKCS5", e);
}
_secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM);
_ivParameterSpec = new IvParameterSpec(rawSecretKey);
}</a>
In our CryptoHandler
class we will use an AES (Advanced Encryption Standard) encryption on which you can read more here:
http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
The AES instantiation happens in the following line:
private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
_aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
We invoke a Cipher
static method which returns an instantiated object of type Cipher
(if no exceptions were thrown).
“AES/CBC/PKCS5Padding “(passed String transformation argument)
AES – The encryption algorithm (Advanced Encryption Standard).
CBC – The name of a feedback mode (in our case Cipher Block Chaining).
PKCS5Padding – The name of the padding scheme.
In addition to the constructor we also have 3 other methods in our CryptoHandler
class:
<a name="CryptoHandlerClassMethods">
public byte[] Encrypt(byte[] clearData)</a>
Encrypt
method sets the _aesCipher to Encrypt Mode by passing the Cipher.ENCRYPT_MODE constant to init() method.
<a name="CryptoHandlerClassMethods">
public byte[] Decrypt(byte[] data)</a>
Decrypt
method does the same but instead of passing Cipher.ENCRYPT_MODE it passes Cipher.DECRYPT_MODE.
Both Decrypt
and Encrypt
methods are calling the DoWork()
method, the only difference between them is the Cipher
mode constant that each sets.
<a name="CryptoHandlerClassMethods">
public byte[] DoWork(byte[] data)</a>
Calls the _aesCipher.doFinal(data)
method and catches exceptions.
<a name="CryptoHandlerClassMethods">
private byte[] encodeDigest(String text)</a>
Used once in the constructor for password phrase encoding.
The private raw key is stored as a byte array in the class:
<a name="CryptoHandlerClassMethods">
private static byte[] _rawSecretKey =
{
0x12, 0x00, 0x22, 0x55, 0x33, 0x78, 0x25, 0x11,
0x33, 0x45, 0x00, 0x00, 0x34, 0x00, 0x23, 0x28
};</a>
This key must be shared between the sender and the recipient, in our case we are participating as both of them, so we are using the same key instance for encryption and decryption.
On MainActivity
layout you can see two colored areas, the blue one is the one that you enter your text for encryption, the green one is just displaying it.
When you pressing the Encrypt button, the encrypted data will be saved to the internal file system (You can see it under the files folder) and showed as gibberish on the green view (this is the cipher text of the original plaintext).
*The saved data will override the previous and will not be appended to existing data in the file.
<a name="AndroidImplementation">
private void EncryptMessage()
{
String message = _tvMessage.getText().toString();
if(message != null && message.length() > 0)
{
byte[] bytes = _crypto.Encrypt(message.getBytes());
SetTextViewEncryptresult(bytes);
_streamHandler.SaveTextFile
(
FileStreamHandler.ENCRYPTED_TXT_FILENAME,
bytes
);
}
}</a>
* If you don’t know how to view your internal data of Android device, check my article:
http://www.codeproject.com/Articles/825304/Accessing-internal-data-on-Android-device
All file operations is performed through the FileStreamHandler
in handlers package.
There are several methods that are responsible for reading and writing into an internal file.
As you click the Decrypt
button on MainActivity
layout, the message will be read from the saved file and shown to you as Toast message.
private void DecryptMessage()
{
byte[] fileContent = _streamHandler
.ReadFromLocalFile(FileStreamHandler.ENCRYPTED_TXT_FILENAME);
if(fileContent != null && fileContent.length > 0)
{
byte[] decrypted = _crypto.Decrypt(fileContent);
String readableData = StringHandler.GetString(decrypted);
String encrypted = StringHandler.GetString(fileContent);
if(readableData != null && encrypted != null)
{
ShowToast
(
getString(R.string.msg_decrypted) + readableData,
getString(R.string.msg_encrypted) + encrypted
);
}
}
else
{
ShowToast(":(", "!");
}
}
If you clicked on Decrypt button and you got something like this:
That means that you finished the whole cryptographic cycle.
You entered a plain text, which was encoded to a cipher text and saved to local file, which afterwards were read and deciphered to a normal readable text.
In this example we saved the key and the password phrase as hardcoded value in our java class, however this is not an optimal solution, since it can be inspected very easily using reverse engineering, so keep it in mind and store the key in safe place.
Now we’ll see how to decipher the cipher text that we encrypted on Android device, on .NET using C# language. This can be done on other platforms as well because we used standard encryption.
We will pull the file that we saved previously on the Android device to the machine and will import it to basic Console Application on Visual Studio.
Ok, let’s create the file and pull it using adb:
Steps:
- Enter message in the blue area and press the Encrypt button.
Now our message is encrypted and saved to the hard drive.
2. Next we'll run several commands to grand file permissions and pull command to get the file from the device.
*Again, if you don’t understand, please look at my article about adb tool and Android internal files permissions:
http://www.codeproject.com/Articles/825304/Accessing-internal-data-on-Android-device
Since all my adb commands were executed successfully I can now browse my file in my Downloads directory:
Now we are going to import it to our .NET Console Application.
*Do not copy the text, we are dealing here with binary data and coping it as string can change its value! Simply copy the file as is.
In our C# Console Application we got the CryptoHandler class that is basically the same as on Android. Notice that on .NET we used two instances of ICryptoTransform
as the decryption and encryption mechanism. That’s pretty much the same, since on Android we used constants and here we are using factory method of RijndaelManaged
.NET class.
If every thing goes as it should be, run the C# program and you will see the same message as entered on the Android device:
We encrypted and decrypted our simple message on Android and .NET Application. This can be done as part of Client-Server communication (Android as Client, .NET as Server) with text or any other binary file that you wish to encrypt, except that you will need to deal with data transition over network, which we didn’t covered here.
Do not run and encrypt every thing that you have on your hands, especially when you dealing with large binary files. That can decrease your application efficiency, especially if you are defending data that no one is interested in.