Thomas 的个人资料Blogs日志列表 工具 帮助
12月2日

Symmetric Encryption with windows mobile

 
The .NET Framework offers a lot of different symmetric and asymetric encryption algorithm, as well as the compact framework for window mobile. But one important class is missing in the compact framework:

Rfc2898DeriveBytes

This class provides functionality to create key data from an arbitary password string, which is required for every encryption algorithm. You cannot simply convert the password string to a byte[] array using e.g. Encoding.Default.ToArray(password), since the key must  be of a specific size. The size can vary by different blocks and it depends on the algorithm you are using. For instance, the prefered AES or Rijndael algorithm requires a key size of 128, 256, 384, etc. but nothing between. Therefore you need an algorithm that encodes any string to a byte array of at least 128 bytes and not less or more.

Fortunately, this is what hashing algorithm's do! So as a replacement for the missing Rfc2898DeriveBytes, we can use a has algorithm, that belongs to the compact framework, and that creates a size that matches the requirements for the encryption algorithm. In this case, since we are  using AES, we need a hash with a size of 128 or 256, and the qualified match is the MD5 algorithm. It is not the strongest though, and SH256 would be the better choice, but unfortunately, the compact framework does not include this hash algorithm, so we need to use MD5.

 Here comes an example of how to implement encryption/decryption for windows mobile:

/// <summary>
/// Encrypts a string using symmetric encryption.
/// </summary>
/// <param name="message">The message string to be encrypted.</param>
/// <param name="password">The password for encryption.</param>
/// <returns>A byte array with the encrypted message.</returns>
public byte[] EncryptSymmetric(string message, string password)
{
   // RijndaelManages is the prefered symmetric algorithm, since it has the strongest encryption and it is completely managed code:
   SymmetricAlgorithm sa = new RijndaelManaged();
  
   // apply key and IV to the algorithm, depending on password:
   PasswordToKey(password, sa);
  
   byte
[] binary = Encoding.Unicode.GetBytes(message);
   MemoryStream ms = new MemoryStream();
   CryptoStream stream = new CryptoStream(ms, sa.CreateEncryptor(), CryptoStreamMode.Write);
   stream.Write(binary, 0, binary.Length);
   stream.FlushFinalBlock();
   stream.Close();
   byte[] encrypted = ms.ToArray();
  
   return
encrypted;
}

/// <summary>
/// Decrypts a byte array to a string, using symmetric encryption.
/// </summary>
/// <param name="encrypted">The encrypted data as byte array.</param>
/// <param name="password">The password for decryption.</param>
/// <returns>A string with the decrypted message.</returns>
public string DecryptSymmetric(byte[] encrypted, string password)
{
   // RijndaelManages is the prefered symmetric algorithm, since it has the strongest encryption and it is completely managed code:
   SymmetricAlgorithm sa = new RijndaelManaged();

   // apply key and IV to the algorithm, depending on password:
   PasswordToKey(password, sa);
   using (MemoryStream ms = new MemoryStream())
   {
      using (CryptoStream stream = new CryptoStream(ms, sa.CreateDecryptor(), CryptoStreamMode.Write))
      {
         stream.Write(encrypted, 0, encrypted.Length);
         stream.Flush();
         stream.Close();
      }
      byte[] decrypted = ms.ToArray();
      string s = Encoding.Unicode.GetString(decrypted);
      return s;
   }
}


/// <summary>
/// Generates key and IV from the specified password, using an MD5 hash.
/// </summary>
/// <remarks>
/// Usually you would prefer to use Rfc2898DeriveBytes for this purpose but since
/// .net compact framework (for windows mobile) does not have any implementation
/// for Rcf2898DeriveBytes or even PasswordDeriveBytes, this is a simple workaround
/// for it.
/// </remarks>
/// <param name="password">The password to generate a key/ITfrom it.</param>
/// <param name="sa">The SymmetricAlgorithm class for which to create a key/IV pair.</param>
private static void PasswordToKey(string password, SymmetricAlgorithm sa)
{
   HashAlgorithm hashAlgo = new MD5CryptoServiceProvider();
   byte[] hash = hashAlgo.ComputeHash(Encoding.UTF8.GetBytes(password));
   sa.BlockSize = hash.Length * 8;
   sa.Key = hash;
   sa.IV = hash;
}


private void button1_Click(object sender, EventArgs e)
{
   string message = "This is the message to be encrypted";
   string password = p@ssw0rD;

   byte
[] encrypted = EncryptSymmetric(message, password);
   string decrypted = DecryptSymmetric(encrypted, password);

   MessageBox.Show(decrypted);
}