Password Based Encryption

Save/Share Google Yahoo! Digg It Reddit del.icio.us
My Zimbio

Password Based Encryption (PBE) is a mechanism for protecting sensitive data using a symmetric cryptographic key derived from a password or passphrase. The use of a passphrase allows the data owner to use a self-selected, easy to remember secret expression instead of 32 random bytes (in the case of a 256 bit key). If coded improperly, even with the use of strong passwords, password encrypted data is easily cracked. Therefore, the use of a proven cryptographic library is essential.

Here, we’ll look at a simple example of PBE to encode plaintext data using a password of arbitrary length. The example is in C# and uses the .Net version of the BouncyCastle cryptographic library. However, there is also a Java version of BouncyCastle which allows for a similar solution.

Select Symmetric Encryption Algorithm

The first task is to select the symmetric encryption algorithm and parameters that the password-generated key will be applied to. Below, we select the Advanced Encryption Standard (AES), used by the US Government, with a key size of 256 bits.

using System;

using System.IO;

using System.Text;

using Org.BouncyCastle.Asn1;

using Org.BouncyCastle.Crypto;

using Org.BouncyCastle.Crypto.Digests;

using Org.BouncyCastle.Crypto.Generators;

using Org.BouncyCastle.Crypto.Parameters;

using Org.BouncyCastle.Crypto.IO;

using Org.BouncyCastle.Security;

static public readonly string ENCRYPTION_ALGORITHM = “AES”;

const int KEY_SIZE = 256;

static public readonly string DECRYPTION_ALGORITHM

= “PBEWithSHA256And256BitAES-CBC-BC”;

When we ultimately build the ciphers that will be used for encryption and decryption, we’ll use a SHA256 hash and cipher-block chaining (CBC). This is important to specify because it will determine how the data will later be decrypted. Above, DECRYPTION_ALGORITMH indicates 1) Password based encryption, 2) SHA256 hash, 3) AES with 256 bit key, 4) cipher-block chaining, and 5) the BouncyCastle implementation.

Build the Encryption Cipher

Now that a symmetric encryption algorithm has been selected, we need to build a BouncyCastle IBufferedCipher instance based on the encryption parameters.  We’ll assume the hashing algorithm, key size, and block chaining parameters are fixed.  This leaves three more parameters that must be defined:

password

A 256-bit key can represent 2256 unique combinations.  However, if a password is selected using only ASCII numbers and letters, the encrypted message can become susceptible to brute force attacks.  For example, an 8 character password selected from only lowercase letters will provide less than 238 unique passwords.  This may seem like a large number, but it is small even by the standards of an early 21st century desktop computer.  Therefore, a lengthy passphrase derived from mixed case letters, numbers, and special characters is far more secure.

iterations

This is the number of times the hashing algorithm will be applied.  The larger the number of iterations, the longer it will take to decrypt the data.  This helps slow down the progress of a dictionary attack.

salt

The salt is pure random data used to protected the encrypted data against dictionary and rainbow table attacks.  A new, random salt should be used every time.  This causes the same plaintext and password combination to generate different cipher text on subsequent encryptions.

private static IBufferedCipher BuildEncryptionCipher(

string password,

int iterations,

byte[] salt

)

{

// get the password bytes

char[] passwordChars = password.ToCharArray();

byte[] passwordBytes

= PbeParametersGenerator.Pkcs12PasswordToBytes(passwordChars);

// select the digest algorithm.

// if you change the digest algorithm, you must change DECRYPTION_ALGORITHM

IDigest digest = new Sha256Digest();

PbeParametersGenerator pbeParamGen = new Pkcs12ParametersGenerator(digest);

pbeParamGen.Init(passwordBytes, salt, iterations);

// 128-bit initialization vector

ParametersWithIV parameters = (ParametersWithIV)pbeParamGen.GenerateDerivedParameters(ENCRYPTION_ALGORITHM, KEY_SIZE, 128);

KeyParameter encKey = (KeyParameter)parameters.Parameters;

// we’ll use CBC and PKCS7Padding

IBufferedCipher cipher;

= CipherUtilities.GetCipher(ENCRYPTION_ALGORITHM + “/CBC/PKCS7Padding”);

cipher.Init(true, parameters);

return cipher;

}

In the code above, the string password is first converted to char array. The char array is then converted to a byte array according to the PKCS #12 encoding scheme (unicode, big endian, and two zero pad bytes at the end).

Next, a SHA256 digester is created and handed to a PBE parameter generator which is initialized with the password, salt, and iterations.

The derived parameters (including the initialization vector) are generated from the selected encryption algorithm.

Finally, the cipher is built from the derived PBE parameters and configured to use CBC and PKCS #7 padding (to fill incomplete blocks). The true value passed to the cipher indicates this is an encryption, rather than decryption, cipher.

Performing the Encryption

With the cipher created, encrypting the plaintext is as simple as wrapping a target stream with a BouncyCastle CipherStream:

private static byte[] Encrypt(IBufferedCipher cipher, string plainText)

{

byte[] encrypted;

using (MemoryStream writeStr = new MemoryStream())

{

using (CipherStream cstr = new CipherStream(writeStr, null, cipher))

{

byte[] data = Encoding.UTF8.GetBytes(plainText);

cstr.Write(data, 0, data.Length);

}

encrypted = writeStr.ToArray();

}

return encrypted;

}

Be aware that the encryption process does not store the salt. If you were storing your ciphertext to a stream, you’d want to write out the salt first so it’s available to the decryption process. There’s no security risk in your attacker having access to the salt.

Making the Call

With the utility methods in place, you can begin encrypting plaintext as demonstrated below.

static void Main(string[] args)

{

// create the message that we want to encrypt, and the password to use

string plainText = “Hello, World!”;

string password = “abc123”;

// select hash iterations and build random salt to increase security

int iterations = 100;

byte[] salt = new byte[KEY_SIZE >> 3];

SecureRandom random = new SecureRandom();

random.NextBytes(salt);

// build the encryption cipher, then use it to encrypt our message

IBufferedCipher encCipher

= BuildEncryptionCipher(password, iterations, salt);

byte[] encryptedText = Encrypt(encCipher, plainText);

for (int i = 0; i < encryptedText.Length; i++)

{

Console.Write(String.Format(“{0:X2}”, encryptedText[i]));

}

Console.WriteLine();

}

The code begins by selecting the plaintext and password. A reasonably safe (based on current computing power) iteration count of 100 is specified. Lastly, a random salt array is created with a length of one byte per bit in the key.

The cipher is built, the plaintext is encrypted, and the ciphertext is written out as a string of hex characters. Notice how, when this is executed multiple times, the output is very different due to the random salt.

Again, note that you’ll require the salt to decrypt the message. There’s no security risk if an attacker knows the salt that was used. It’s simplest to just write out the salt bytes to a stream just before the ciphertext.

How to Decipher

The code to decipher the ciphertext closely mirrors the encryption process: create a cipher, instantiate a CipherStream, and write out the ciphertext. Rather than present the code here, you may download the source code and check it out for yourself.

PBEStream Utility

The source project also contains a utility class called PBEStream which allows for encryption and decryption using the standard .NET Stream API.

Save/Share Google Yahoo! Add to Technorati Favorites Digg It Reddit
del.icio.us My Zimbio

Leave a Reply