0

I'm using Rijndael Algorithm to encrypt strings (user passwords), but when I decrypt them, it returns me "System.SecureString", and not my decrypted password.

I'm using this basic code:

public static string DecryptString(string cipherText, string password)
    {
        byte[] key, iv;
        Rfc2898DeriveBytes rfcDb = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(password));
        key = rfcDb.GetBytes(16);
        iv = rfcDb.GetBytes(16);

        byte[] cipheredData = Convert.FromBase64String(cipherText);

        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.Mode = CipherMode.CBC;

        ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv);
        MemoryStream ms = new MemoryStream(cipheredData);
        CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);

        byte[] plainTextData = new byte[cipheredData.Length];

        int decryptedByteCount = cs.Read(plainTextData, 0, plainTextData.Length);

        ms.Close();
        cs.Close();

        return Encoding.UTF8.GetString(plainTextData, 0, decryptedByteCount);
    }

The real problem is that it's sending me back "System.SecureString", and I can't do anything.

I think it comes from the conversion at the end but I really don't know how to change that (it seems good btw)

return Encoding.UTF8.GetString(plainTextData, 0, decryptedByteCount);

So if you have an idea or a working code sample, I'm interested.

Have a nice day

Christian Phillips
  • 18,399
  • 8
  • 53
  • 82
crocteamgg
  • 65
  • 2
  • 7
  • The cause of your problem is outside the code you posted. There are no secure strings in it. I suspect you call `password.ToString()` somewhere, attempting to convert from `SecureString` to `String`. But you can't convert like that. – CodesInChaos Jul 27 '13 at 16:31

1 Answers1

1

I have implemented rijndael in the past, and here is my version if this is any help:

private static string Encrypt(string plainText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
        {
            // Convert strings into byte arrays.
            // Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8 
            // encoding.
            var initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            var saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our plaintext into a byte array.
            // Let us assume that plaintext contains UTF8-encoded characters.
            var plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            // First, we must create a password, from which the key will be derived.
            // This password will be generated from the specified passphrase and 
            // salt value. The password will be created using the specified hash 
            // algorithm. Password creation can be done in several iterations.
            var password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            var keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            var symmetricKey = new RijndaelManaged { Mode = CipherMode.CBC };

            // Generate encryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            var encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            var memoryStream = new MemoryStream();

            // Define cryptographic stream (always use Write mode for encryption).
            var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

            // Start encrypting.
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

            // Finish encrypting.
            cryptoStream.FlushFinalBlock();

            // Convert our encrypted data from a memory stream into a byte array.
            var cipherTextBytes = memoryStream.ToArray();

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert encrypted data into a base64-encoded string.
            var cipherText = Convert.ToBase64String(cipherTextBytes);

            // Return encrypted string.
            return cipherText;
        }


private static string Decrypt(string cipherText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
        {
            // Convert strings defining encryption key characteristics into byte
            // arrays. Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8
            // encoding.
            var initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            var saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our ciphertext into a byte array.
            var cipherTextBytes = Convert.FromBase64String(cipherText);

            // First, we must create a password, from which the key will be 
            // derived. This password will be generated from the specified 
            // passphrase and salt value. The password will be created using
            // the specified hash algorithm. Password creation can be done in
            // several iterations.
            var password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            var keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            var symmetricKey = new RijndaelManaged { Mode = CipherMode.CBC };

            // Generate decryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            var decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            var memoryStream = new MemoryStream(cipherTextBytes);

            // Define cryptographic stream (always use Read mode for encryption).
            var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

            // Since at this point we don't know what the size of decrypted data
            // will be, allocate the buffer long enough to hold ciphertext;
            // plaintext is never longer than ciphertext.
            var plainTextBytes = new byte[cipherTextBytes.Length];

            // Start decrypting.
            var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert decrypted data into a string. 
            // Let us assume that the original plaintext string was UTF8-encoded.
            var plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);

            // Return decrypted string.   
            return plainText;
        }

public static string EncryptData(string encryptText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
    return Encrypt(encryptText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
}

public static string DecryptData(string decryptText, string passPhrase, string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
{
    return Decrypt(decryptText, passPhrase, saltValue, hashAlgorithm, passwordIterations, initVector, keySize);
}

I then had some public methods that call into the above methods...

public static string EncryptData(string encryptText)
{
    return EncryptionHelper.EncryptData(encryptText, ConfigHelper.PassPhrase, ConfigHelper.SaltValue, ConfigHelper.HashAlgorithm, ConfigHelper.PasswordIterations, ConfigHelper.InitVector, ConfigHelper.KeySize);
}

public static string DecryptData(string decryptText)
{
    return EncryptionHelper.DecryptData(decryptText, ConfigHelper.PassPhrase, ConfigHelper.SaltValue, ConfigHelper.HashAlgorithm, ConfigHelper.PasswordIterations, ConfigHelper.InitVector, ConfigHelper.KeySize);
}

I then had these in a config file...

<add key="passPhrase" value=""/>
<add key="saltValue" value=""/>
<add key="hashAlgorithm" value="SHA1"/>
<add key="passwordIterations" value="5"/>
<add key="initVector" value=""/>
<add key="keySize" value="256"/>
Christian Phillips
  • 18,399
  • 8
  • 53
  • 82
  • So my code is right, I'm just stupid. I send my password with passwordBox.SecurePassword and not passwordBox.Password to my function. So it was sending "System.SecurePassword" (why ?, idk) instead of my password. So it was normal for me to find "System.SecurePassword" because it was actually what was crypted. So thank you christiandev, my code is right but it's yours which made me realize this Have a nice day – crocteamgg Jul 26 '13 at 09:32
  • @crocteamgg Please post that as an answer, it is useful enough for people that do the same thing. That's not so far fetched at all. – Maarten Bodewes Jul 26 '13 at 14:51