1
\$\begingroup\$

I have been working to create an easy-to-use set of methods to encrypt configuration objects for my client application. It will contain username and passwords to databases and similar vaults of data, so it's rather important that I've got the fundamentals correct.

I'm fairly new to this form of encryption, and I certainly haven't done this in .NET before. So I am curious - is there any given, open caveats in the attached code? I'll greatly appreciate your comments!

Also, please don't mind the comments in the code. This is a late-night side-project for me, and I'll look into sprucing it all up once I've got it all examined.

 public byte[] CalculatePasswordHash(byte[] salt)
 {
     var hash = Encoding.UTF8.GetBytes(Password);
     var hashing = SHA256.Create();
     var iterations = 10000;

     while (iterations > 0)
     {
         // Compute the hash
         hash = hashing.ComputeHash(hash);

         // Apply the salt
         for (int position = 0, cursor = 0; position < hash.Length; position += 1)
         {
             hash[position] ^= salt[cursor];

             cursor += 1;
             if (cursor >= salt.Length)
                 cursor = 0;
         }

         iterations -= 1;
     }

     return hash;
 }

 public byte[] CreateSalt()
 {
     return CreateSalt(SaltLength);
 }

 public byte[] CreateSalt(int size)
 {
     var random = new RNGCryptoServiceProvider();
     var buf = new byte[size];
     random.GetBytes(buf);

     return buf;
 }

 public void Lock(string filePath, byte[] source)
 {
     // Ensure that the path is rooted
     filePath = RootPath(filePath);

     // Generate salt as well as the encryption key
     var salt = CreateSalt();
     var key = CalculatePasswordHash(salt);

     // Initialize the Rijndael encryption tool
     var crypto = Rijndael.Create();
     var iv = CreateSalt(crypto.BlockSize / 8);

     using (var mem = new MemoryStream())
     {

         // Encrypt the source array 
         crypto.Key = key;
         crypto.IV = iv;

         var desc = crypto.CreateEncryptor();
         using (var cryptoStream = new CryptoStream(mem, desc, CryptoStreamMode.Write))
         {
             cryptoStream.Write(source, 0, source.Length);
         }

         desc.Dispose();

         // Append the salt and iv to the end of the file
         using (var fs = new FileStream(filePath, FileMode.Create))
         {
             var encrypted = mem.ToArray();
             fs.Write(encrypted, 0, encrypted.Length);
             fs.Write(salt, 0, salt.Length);
             fs.Write(iv, 0, iv.Length);
         }
     }
 }
\$\endgroup\$
1
\$\begingroup\$
  1. CalculatePasswordHash is inadvertently reimplementing (and probably not as well) a standard primitive. You should use System.Security.Cryptography.Rfc2898DeriveBytes instead.

  2. The code

        var desc = crypto.CreateEncryptor();
        ...
        desc.Dispose();
    

    raises a red flag. Why isn't it using using?

  3. You write to a memory stream and then write the contents of the memory stream unmodified to a file. It seems that you could simplify this just skipping the middle-man.

\$\endgroup\$
  • \$\begingroup\$ Yes, I found out about Rfc2898DeriveBytes after I had implemented my solution. I'll definitely replace my own with that. Thank you so much for your help and time! :) \$\endgroup\$ – Zanathel Aug 5 '13 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.