3

I am trying to test CBC with Random IV using (128-bit AES) in C#.

In my question to solve, I have 12-byte input message. The condition is that if PlainText is less than block-size (16-bytes) the padding to be used starts with 0x01 and then upto 6 0x00.

Example:

in ASCII PT     = Pay Bob 100%

in hex PT       = 50 61 79 20 42 6f 62 20 31 30 30 24

PT with Padding = 50 61 79 20 42 6f 62 20 31 30 30 24 01 00 00 00

I don't seem to be able to find this PaddingMode in RijndaelManaged.

Can any one suggest me how to do the following?

  • Variable Length padding

EDIT:

public class CBC
{
    public CBC()
    {

    }

    private static readonly byte[] SALT = new byte[]
        {0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c};

    public static byte[] EncryptCBC(string plainText, string passPhrase, PaddingMode paddingMode )
    {
        byte[] result;
        using (RijndaelManaged cryptoProvider = new RijndaelManaged())
        {
            Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(passPhrase, SALT);
            cryptoProvider.Mode = CipherMode.CBC;
            cryptoProvider.GenerateIV(); // generate random IV

            cryptoProvider.Padding = paddingMode;

            cryptoProvider.Key = derivedKey.GetBytes(cryptoProvider.KeySize / 8);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (ICryptoTransform encryptor = cryptoProvider.CreateEncryptor(cryptoProvider.Key, cryptoProvider.IV))
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }
                    }
                }
                // concatenate iv to ciphertext
                result = cryptoProvider.IV.Concat(msEncrypt.ToArray()).ToArray();
            }
            cryptoProvider.Clear();
        }
        return result;
    }

    public static string DecryptCBC(byte[] cipherTextBytes, string passPhrase, PaddingMode paddingMode)
    {
        string result = null;
        using (RijndaelManaged cryptoProvider = new RijndaelManaged())
        {
            Rfc2898DeriveBytes derivedKey = new Rfc2898DeriveBytes(passPhrase, SALT);
            cryptoProvider.Mode = CipherMode.CBC;
            // take the iv off the beginning of the ciphertext message
            cryptoProvider.IV = cipherTextBytes.Take(cryptoProvider.BlockSize / 8).ToArray();


            cryptoProvider.Padding = paddingMode;//PaddingMode.ANSIX923;



            cryptoProvider.Key = derivedKey.GetBytes(cryptoProvider.KeySize / 8);

            using (MemoryStream msEncrypt = new MemoryStream(cipherTextBytes.Skip(cryptoProvider.BlockSize / 8).ToArray())) // skip the IV bytes
            {
                using (ICryptoTransform encryptor = cryptoProvider.CreateDecryptor(cryptoProvider.Key, cryptoProvider.IV))
                {
                    using (CryptoStream cryptoStream = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Read))
                    {
                        byte[] plainTextBytes = new byte[cipherTextBytes.Length - cryptoProvider.BlockSize / 8];
                        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

                        result = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                        cryptoStream.Close();
                    }
                }
            }

            cryptoProvider.Clear();
        }
        return result;
    }

}

My Padding function

        private byte[] PaddPlainTextBytes(byte[] plainTextBytes )
    {
        byte[] padding = utils.HexToBytes("01000000");
        MemoryStream s = new MemoryStream();

        s.Write(plainTextBytes, 0, plainTextBytes.Length);
        s.Write(padding, 0, padding.Length);

        byte[] paddedPt = s.ToArray();

        return paddedPt;
    }

Method to test my CBC

        private void btnTestCBC_Click(object sender, EventArgs e)
    {
        string plainText = "Pay Bob 100%";

        string passPhrase = "Thisismypassphrase";
        ShowMessage(@"Plain Text = " + plainText);

        byte[] pBytes = PaddPlainTextBytes(Encoding.ASCII.GetBytes(plainText));

        string message = Encoding.ASCII.GetString(pBytes);

        byte[] encryptedBytes = CBC.EncryptCBC(plainText: message, passPhrase: passPhrase, paddingMode: PaddingMode.None);

        ShowMessage("Encrypted String = " + Encoding.ASCII.GetString(encryptedBytes));
        ShowMessage("Encrypted HEX = " + utils.BytesToHex(encryptedBytes));


        string decryptedString = CBC.DecryptCBC(encryptedBytes, passPhrase, PaddingMode.None);
        ShowMessage("Deccrypted String = " + decryptedString);
    }
Khurram Majeed
  • 2,291
  • 8
  • 37
  • 59
  • You also could use a mode of operation that does not require padding, like CTR. Not built-in, alas. – usr Dec 31 '12 at 17:28
  • 1
    You seem to assume padding is always a fixed length, and not an alignment function. – leppie Dec 31 '12 at 17:42

2 Answers2

5

I'm not familiar with your padding scheme, but it's not built in to .net for sure. You should be able to set the PaddingMode to None, and post pend your pad to your input message, should have the same result for whatever is decrypting it. If you are decrypting it you'll have to remove the pad yourself.

jbtule
  • 31,383
  • 12
  • 95
  • 128
  • Well your output worked, what is your question, your padding function doesn't work variable length messages there's no "`..`" in the `100..00`. – jbtule Dec 31 '12 at 17:44
  • Not doing chosen ciphertext attacks homework, the first question was how to do a certain padding in c#, the modified question is not a stack overflow question, it's possibly a crypto.stackoverflow question if you ask question you really want related to how CBC works. – jbtule Dec 31 '12 at 18:18
  • So how do I move this question to crypto.stackoverflow? – Khurram Majeed Dec 31 '12 at 18:42
  • Revert this question to your question about padding, and then ask a new question on crypto about how to modify the padded block of a CBC encryption with your padding scheme. – jbtule Dec 31 '12 at 19:18
  • I have updated the question. Can you provide an example for padding function that deals with variable length of the last block? – Khurram Majeed Dec 31 '12 at 20:02
1

The padding scheme you've described looks a lot like "ISO/IEC 7816-4 Padding" , see the Wikipedia page on paddings (which I've just edited) for the padding method. Normally you start with a single bit set to one, not a byte, so that would be 0x80 instead of 0x01 for the first byte.

This padding node is probably not build in. If you want to experiment I would recommend the Bouncy Castle libs, otherwise switch over to to the almost ubiquitous PKCS#7 padding.

Khurram Majeed
  • 2,291
  • 8
  • 37
  • 59
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263