Translate PBE Codes from Java to C#

It’s great to accept online payment via your website, right? However, during the implementation of payment gateway on e-commerce website, we sometimes will receive requests from bank to enhance the security of our payment process.

Payment gateway is important on e-commerce.
Payment gateway is important on e-commerce.

One of the requests we received is to provide their API a new value to verify the integrity of the payment process request. According to the requirement, the new value is using a Password-Based Encryption (PBE). The value must be encrypted using MD5 and DES algorithm with Base64 encoding.

The bank provided us a sample code of the encryption in Java.

private static int ITERATIONS = 1000;

public static String encrypt(char[] password, String plaintext, String algorithm)
    throws Exception {
    byte[] salt = new byte[8]; 
    Random random = new Random(); 
    random.nextBytes(salt);

    PBEKeySpec keySpec = new PBEKeySpec(password);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
    SecretKey key = keyFactory.generateSecret(keySpec);
    PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATIONS); 

    Cipher cipher = Cipher.getInstance(algorithm); 
    cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
    byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8"));

    BASE64Encoder encoder = new BASE64Encoder();
    String saltString = encoder.encode(salt);
    String ciphertextString = encoder.encode(ciphertext); 

    return saltString + ciphertextString;
}

To use that, the documentation suggests us the following codes.

import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
...
    String password = "xxxxxxxxxx";
    String textToEncrypt = "Hallo, world!";
    String algorithm = "PBEWithMD5AndDES";
...
    encrypt(password, textToEncrypt, algorithm);

As stated in the sample above, the algorithm is called “PBEWithMD5AndDES”, the password-based encryption as defined in RSA Security Inc. It takes a user-chosen password string and combine it with salt to generate the key by doing MDF hashing. It then applies the key on DES (Data Encryption Standard) cipher.

It looks complicated to me. Fortunately, I found a diagram describing the PBE encryption. I re-draw it so that it looks clearer.

PBE Encryption
PBE Encryption

What interest me are two items. One of them is Iteration, which has a value 1000 set to it without further explanation in the given sample code. There is already a discussion about this on StackOverflow. According to the discussion, iteration count is the number of times that the password is hashed during the generation of key. It is said that a higher iteration count will make the brute force hacking the key harder.

Another item that interests me is the salt. As shown in the diagram above, it does not use raw password to generate the key. Salt, a randomly generated bytes, is appended to the password. This is to prevent dictionary attacks.

Emulating PBE with C#

Unfortunately, our e-commerce website is built with .NET technology. Hence, I need to find out a way to encrypt data in C# in the same way as Java PBEWithMD5AndDES algorithm.

Firstly, I found a very helpful code from Bob Janova, a graduate from the University of Cambridge, on CodeProject. The code basically helps us to handle the key generation with MD5. It also takes care of the DES part with the help of DESCryptoServiceProvider class. As stated in the web page, it is very easy to use.

PKCSKeyGenerator kp = new PKCSKeyGenerator();
ICryptoTransform crypt = kp.Generate(
    password,
    salt, // salt
    1000, // iterations of MD5 hashing
    1); // number of 16-byte segments to create. 1 to mimic Java behaviour.

Right after crypt is instantiated, I do the following to make sure it is Base64 encoded. Similar code can be found on a discussion on StackOverflow regarding how to encrypt a string in .NET.

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream, crypt, CryptoStreamMode.Write);

byte[] plainBytes = Encoding.ASCII.GetBytes(textToEncrypt);

// Encrypt the input textToEncrypt string
cryptoStream.Write(textToEncrypt, 0, plainBytes.Length);

// Complete the encryption process
cryptoStream.FlushFinalBlock();

// Convert the encrypted data from a MemoryStream to a byte array
byte[] cipherBytes = memoryStream.ToArray();

memoryStream.Close();
cryptoStream.Close();

// Convert the encrypted byte array to a base64 encoded string
string cipherText = Convert.ToBase64String(cipherBytes, 0, cipherBytes.Length);

Finally, we get the encrypted data as stored in cipherText.

Yup, it is quite straight-forward, right? =)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s