views:

1144

answers:

3

Hi,

I am using the AES methods here: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged.aspx

I want to have a string value that I will convert to byte array and pass it to the AES encrypt method. How many characters should the string be to produce the correct byte array size that the method expects?

static byte[] encryptStringToBytes_AES(string plainText, byte[] Key, byte[] IV)
    {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");

        // Declare the stream used to encrypt to an in memory
        // array of bytes.
        MemoryStream msEncrypt = null;

        // Declare the RijndaelManaged object
        // used to encrypt the data.
        RijndaelManaged aesAlg = null;

        try
        {
            // Create a RijndaelManaged object
            // with the specified key and IV.
            aesAlg = new RijndaelManaged();
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            // Create a decrytor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for encryption.
            msEncrypt = new MemoryStream();
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {

                    //Write all data to the stream.
                    swEncrypt.Write(plainText);
                }
            }

        }
        finally
        {

            // Clear the RijndaelManaged object.
            if (aesAlg != null)
                aesAlg.Clear();
        }

        // Return the encrypted bytes from the memory stream.
        return msEncrypt.ToArray();

    }
A: 

You need padding for that. Actually, the page you linked have an example on padding (in C++).

With paddings, you can encrypt non standard block sizes.

J-16 SDiZ
+1  A: 

The size of the plain text does not matter. Just make sure you use the exact same IV and Key along with the encrypted bytes in the decryptStringFromBytes_AES(byte[] cipherText, byte[] Key, byte[] IV) method. That will return back to you the entered plain text.

For example:


string plain_text = "Cool this works";
byte[] iv = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                           0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
byte[] key = new byte[] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                                           0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
byte[] encrytped_text = encryptStringToBytes_AES(plain_text, key, iv);
string plain_text_again = decryptStringFromBytes_AES(encrypted_text, key, iv);

Here you should see that plain-text and plain-text-again are the same. Now go ahead and change plain_text to anything you want and see that this works fine.

The default values for RijndaelManaged are:
BlockSize: 128
KeySize: 256
Mode: CipherMode.CBC
Padding: PaddingMode.PKCS7

The valid IV sizes are:
128, 192, 256 bits (This is the BlockSize, make sure to set it to size IV you are using)
The valid Key sizes are:
128, 192, 256 bits (This is the KeySize, make sure to set it to the size key you are using)

This means that the byte[] iv can be 16, 24, or 32 bytes (in my above example its 16 bytes) and the byte[] key can also be 16, 24, or 32 bytes (in my above example its 16 bytes).

Hope that helps.

SwDevMan81
A: 

Do not convert a string into its Unicode byte representation. It will be too hard to check for the right length, and not provide enough randomization.

You could do the following: use a key derivation function. You want a fixed length byte array for the input of the function. This is what Rfc2898 is best at.

So, create a new Rfc2898 object:

using PBKDF2 = System.Security.Cryptography.Rfc2898DeriveBytes;

class Example {
    byte[] mySalt = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };

    void Initialize( string password ) {
        PBKDF2 kdf = new PBKDF2( password, mySalt );
        // Then you have your algorithm
        // When you need a key: use:
        byte[] key = kdf.GetBytes( 16 ); // for a 128-bit key (16*8=128)

        // You can specify how many bytes you need. Same for IV.
        byte[] iv = kdf.GetBytes( 16 ); // 128 bits again.

        // And then call your constructor, etc.
        // ...
    }
}

For an example of how I've used this, check out my project using Rijndael. I have a password step where I take a string and get the key and iv byte arrays using the above method.

maxwellb
Additionally, you could use a random salt with this method to generate nearly unlimited different keys from the same password. It is common practice to store the salt in the clear with the encrypted data.For example, you have your password. You generate an encryption key+iv with the KDF. The Rfc2898 class lets you specify a "salt size" in the constructor. Get the salt that it generated. Store your encrypted data as (SALT BYTES)+"DELIMETER"+(ENCRYPTED BYTES).When you need to decode, you can take the plain password, use the stored salt, and be able to re-generate the same key+iv.
maxwellb