Cross Platform Encryption Decryption
Encryption and Decryption have been very important modules for any enterprise application. Whether is a file on our system or the data travelling via the wire everything is encrypted. Encryption is needed to ensure that only the intended user gains access over the information and all other malicious users/programs are blocked.
In this post we would be talking about encryption/decryption mechanism on a cross platform scenario. We would consider Java and C# as our programming languages to discuss the cross platform compatibility. We would be discussing about the Rijndael and AES implementations supported by C# and Java respectively.
Rijndael is a class of cipher developed by two Belgium cryptographers, Joan Daemen and Vincent Rijmen. Rijndael talked about the encryption mechanism with different block size and key sizes.
AES is an implementation of Rijndael cipher with a fixed block size of 128 bits but can have different key length of 128, 192 and 256 bits.
The detailed algorithm/design of AES can be found here at Wikipedia:
Fortunately we do not have to implement the algorithms from scratch and all the popular programming languages have in-house libraries to support them.
C# has got support for the Rijndael cipher and similarly Java has got support for the AES cipher. The implementations for both Java and C# are pretty straight forward but if we need to get both the code working together we come across the scenario of cross platform compatibility issues for both the ciphers. Hence we need to tune our code for making both of them compatible.
As we know that AES is just another specialized implementation of the Rijndael cipher, we can initialize the Rijndael cipher in our C# code such as the transformations over data while encryption/decryption process are consistent with that AES would use.
Configurations for enabling cross platform compatibility
These are the few things that should be consistent in both the C# and Java code:
- Character encoding format: UTF8/UTF16 etc.
- Padding Mode: Padding of data blocks is done when the data block is shorter than expected.
- Initialization Vector: The start variable to be used by cipher.
- Cipher mode: Mode of ciphering – Electronic codebook (ECB), Cipher-block chaining (CBC) etc.
- Key Size
- Block Size
All the above parameters should be same for both the Java and C# code.
We can manually initialize our ciphers for both Java and C# so that they have the same values for the above parameters.
Cipher ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte iv = strkey.getBytes("UTF-8");
byte IV = Encoding.UTF8.GetBytes(skey); aes.Padding = PaddingMode.PKCS7; aes.Mode = CipherMode.CBC; aes.KeySize = 128; aes.BlockSize = 128;
#Note: Here sKey and strkey both refer to the user provided password. The iv(IV) is the initialization vector and is generated from the key itself. All the bytes derived from key are again in UTF-8 format to maintain consistency.
Key size can be ensured to be same by having the same key for both the Java/C# code. The block size for AES is 128 bits so just specifying a block size of 128 bytes is enough for solving our purpose.
The entire implementation for the Java and C# code can be found here at github.
C# Implementation: https://gist.github.com/yssharma/8178524
Using Hadoop HDFS as data source
For my scenario the data files were present on the HDFS. The C# and Java code read the file from the HDFS and put the encrypted/decrypted files back on the HDFS.
The modules read the files from the HDFS and perform their actions respectively. The modules do not spawn Map-Reduce jobs rather use HDFS as any other file system.
The entire code for the Java Module on HDFS can be fetched from:
Feel free to play around with the code and share your findings.