Why not? http://songsincsharp.net

And of course, here is my own lame attempt at keeping up with the cool kids:

    class Me : Person
    {
        public override IEnumerable<Child> GetChildren()
        {
            return from lover in GetLovers()
                   from child in lover.GetChildren(child => child.Father == this)
                   where lover.Name != "Billie Jean"
                   select child;
        }
    }
 

Background: I get a lot of traffic looking for details on running a process and collecting the process output. If you haven’t already done so, you should read “How to use System.Diagnostics.Process correctly“. It outlines the major pitfalls of using this class. Another post on “Using the ProcessRunner class” will demonstrate using the helper class I wrote: CSharpTest.Net.Processes.ProcessRunner.

So again I find myself writing about using System.Diagnostics.Process and the Process.Start method. This time it’s not to provide any more information, but rather a simplified example. This example will build upon the previous two posts “How to search the environment’s path for an exe or dll“, and “How to correctly escape command line arguments” to use those methods for solving those needs. Otherwise this example is a relatively stand-alone method for running a process and capturing it’s output.

    /// <summary>
    /// Runs the specified executable with the provided arguments and returns the process' exit code.
    /// </summary>
    /// <param name="output">Recieves the output of either std/err or std/out</param>
    /// <param name="input">Provides the line-by-line input that will be written to std/in, null for empty</param>
    /// <param name="exe">The executable to run, may be unqualified or contain environment variables</param>
    /// <param name="args">The list of unescaped arguments to provide to the executable</param>
    /// <returns>Returns process' exit code after the program exits</returns>
    /// <exception cref="System.IO.FileNotFoundException">Raised when the exe was not found</exception>
    /// <exception cref="System.ArgumentNullException">Raised when one of the arguments is null</exception>
    /// <exception cref="System.ArgumentOutOfRangeException">Raised if an argument contains '\0', '\r', or '\n'
    public static int Run(Action<string> output, TextReader input, string exe, params string[] args)
    {
        if (String.IsNullOrEmpty(exe))
            throw new FileNotFoundException();
        if (output == null)
            throw new ArgumentNullException("output");

        ProcessStartInfo psi = new ProcessStartInfo();
        psi.UseShellExecute = false;
        psi.RedirectStandardError = true;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardInput = true;
        psi.WindowStyle = ProcessWindowStyle.Hidden;
        psi.CreateNoWindow = true;
        psi.ErrorDialog = false;
        psi.WorkingDirectory = Environment.CurrentDirectory;
        psi.FileName = FindExePath(exe); //see http://csharptest.net/?p=526
        psi.Arguments = EscapeArguments(args); // see http://csharptest.net/?p=529

        using (Process process = Process.Start(psi))
        using (ManualResetEvent mreOut = new ManualResetEvent(false),
             mreErr = new ManualResetEvent(false))
        {
            process.OutputDataReceived += (o, e) => { if (e.Data == null) mreOut.Set(); else output(e.Data); };
            process.BeginOutputReadLine();
            process.ErrorDataReceived += (o, e) => { if (e.Data == null) mreErr.Set(); else output(e.Data); };
            process.BeginErrorReadLine();

            string line;
            while (input != null && null != (line = input.ReadLine()))
                process.StandardInput.WriteLine(line);

            process.StandardInput.Close();
            process.WaitForExit();

            mreOut.WaitOne();
            mreErr.WaitOne();
            return process.ExitCode;
        }
    }

Though most people won’t require writing to std::in, it is demonstrated here. If you do decide to remove this be careful that you still set psi.RedirectStandardInput to true, and call process.StandardInput.Close() before you call process.WaitForExit().

If you want to read a single character at a time (so as not to wait for a new line) that can also be done. Unfortunately it does require more work. The following sample class reads one character at a time and writes it to the console:

    //In the above example you would remove the event subscription and the call to
    //process.BeginOutputReadLine() and replace it with the following:
    new ReadOutput(process.StandardInput, mreOut);

    private class ReadOutput
    {
        private StreamReader _reader;
        private ManualResetEvent _complete;

        public ReadOutput(StreamReader reader, ManualResetEvent complete)
        {
            _reader = reader;
            _complete = complete;
            Thread t = new Thread(ReadAll);
            t.Start();
        }

        void ReadAll()
        {
            int ch;
            while(-1 != (ch = _reader.Read()))
            {
                Console.Write((char) ch);
            }
            _complete.Set();
        }
    }

Always remember you need two threads reading both std::out and std::err or you run into the possibility of hanging the process.

 

Most people believe escaping arguments to a process is easy. Surround it with quotes, right? Nope. Escape the quotes and surround it with quotes? Nope. Escape the quotes and backslashes and then surround it with quotes? Nope. It’s actually a lot more strange than that.

When do you need to escape and quote an argument? You need to escape and quote any string that either contains whitespace, or a quote. So why would you escape a single quote (A”B)?Actually this would be fine, it’s really two consecutive quotes that are problem (A”"B). These are interpreted as a single quote character unless quoted and escaped. Of course if it begins with a quote then you’d also need to escape it. So to make life easier, just escape anything with whitespace or a quote.

How do you escape a command line argument? Once you’ve determined that your going to escape and quote the program argument it get’s more interesting. You will need to find and escape all consecutive backslash ‘\’ characters that are immediately followed by either a quote, or appear at the end of the argument. You will also need to escape all the quote characters, again by prefixing a new backslash. So (\asdf\) becomes (“\asdf\\”) and (as\”df) becomes (“as\\\”df”). Then there are a few characters you cannot represent, null ‘\0′, newline ‘\n’, and linefeed ‘\r’.

So here it is all together, tested, and ready to go:

    /// <summary>
    /// Quotes all arguments that contain whitespace, or begin with a quote and returns a single
    /// argument string for use with Process.Start().
    /// </summary>
    /// <param name="args">A list of strings for arguments, may not contain null, '\0', '\r', or '\n'</param>
    /// <returns>The combined list of escaped/quoted strings</returns>
    /// <exception cref="System.ArgumentNullException">Raised when one of the arguments is null</exception>
    /// Raised if an argument contains '\0', '\r', or '\n'
    public static string EscapeArguments(params string[] args)
    {
        StringBuilder arguments = new StringBuilder();
        Regex invalidChar = new Regex("[\x00\x0a\x0d]");//  these can not be escaped
        Regex needsQuotes = new Regex(@"\s|""");//          contains whitespace or two quote characters
        Regex escapeQuote = new Regex(@"(\\*)(""|$)");//    one or more '\' followed with a quote or end of string
        for (int carg = 0; args != null && carg < args.Length; carg++)
        {
            if (args[carg] == null) { throw new ArgumentNullException("args[" + carg + "]"); }
            if (invalidChar.IsMatch(args[carg])) { throw new ArgumentOutOfRangeException("args[" + carg + "]"); }
            if (args[carg] == String.Empty) { arguments.Append("\"\""); }
            else if (!needsQuotes.IsMatch(args[carg])) { arguments.Append(args[carg]); }
            else
            {
                arguments.Append('"');
                arguments.Append(escapeQuote.Replace(args[carg], m =>
                                 m.Groups[1].Value + m.Groups[1].Value +
                                 (m.Groups[2].Value == "\"" ? "\\\"" : "")
                    ));
                arguments.Append('"');
            }
            if (carg + 1 < args.Length)
                arguments.Append(' ');
        }
        return arguments.ToString();
    }

Of course you could improve on the performance here by moving the Regex instances to statics and/or compiling or even replacing them. Performance wasn't exactly a major consideration here since spawning the process will be several orders of magnitude more time consuming.

If your interested, the following are some of the test patterns used. The above method was also tested with random arguments used to spawn a process that echoed each argument back for verification.

    Assert.AreEqual("\"\"", EscapeArguments(""));
    Assert.AreEqual("\"\\\"\"", EscapeArguments("\""));
    Assert.AreEqual("\"\\\"\\\"\"", EscapeArguments("\"\""));
    Assert.AreEqual("\"\\\"a\\\"\"", EscapeArguments("\"a\""));
    Assert.AreEqual("\\", EscapeArguments("\\"));
    Assert.AreEqual("\"a b\"", EscapeArguments("a b"));
    Assert.AreEqual("a \" b\"", EscapeArguments("a", " b"));
    Assert.AreEqual("a\\\\b", EscapeArguments("a\\\\b"));
    Assert.AreEqual("\"a\\\\b c\"", EscapeArguments("a\\\\b c"));
    Assert.AreEqual("\" \\\\\"", EscapeArguments(" \\"));
    Assert.AreEqual("\" \\\\\\\"\"", EscapeArguments(" \\\""));
    Assert.AreEqual("\" \\\\\\\\\"", EscapeArguments(" \\\\"));
    Assert.AreEqual("\"C:\\Program Files\\\\\"", EscapeArguments("C:\\Program Files\\"));
    Assert.AreEqual("\"dafc\\\"\\\"\\\"a\"", EscapeArguments("dafc\"\"\"a"));

		
 

I’d love it if there was a nice clean way to do this; however, there isn’t. When running a process via the Process.Start(…) call one must provide a fully qualified path to an executable. The problem is that hard-coding the full path to the exe isn’t always the best option. This is why there is a “PATH” environment variable. The following expands the provided file name to the full qualified path by looking in the current directory and environment path variable:

    /// <summary>
    /// Expands environment variables and, if unqualified, locates the exe in the working directory
    /// or the evironment's path.
    /// </summary>
    /// <param name="exe">The name of the executable file</param>
    /// <returns>The fully-qualified path to the file</returns>
    /// <exception cref="System.IO.FileNotFoundException">Raised when the exe was not found</exception>
    public static string FindExePath(string exe)
    {
        exe = Environment.ExpandEnvironmentVariables(exe);
        if (!File.Exists(exe))
        {
            if (Path.GetDirectoryName(exe) == String.Empty)
            {
                foreach (string test in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(';'))
                {
                    string path = test.Trim();
                    if (!String.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exe)))
                        return Path.GetFullPath(path);
                }
            }
            throw new FileNotFoundException(new FileNotFoundException().Message, exe);
        }
        return Path.GetFullPath(exe);
    }

Most of this method is self-explanatory except the second if condition “Path.GetDirectoryName(exe) == String.Empty”. The reason for this is to determine if the name provided contains a ‘/’, ‘\’, ‘:’ or other path information. You might be able to replace it with an IndexOfAny(Path.GetInvalidFileNameChars()) or similar expression, but I thought this would produce more accurate results.

 

Last year I ran across this 2009 post by Bruce Schneier entitled “Another New AES Attack“. It got me thinking about and dissecting the Rijndael algorithm which most of you know as AES (Advanced Encryption Standard). This research surprised me, I found that AES has only three variants. These variants are best known by their key sizes of 128, 192, or 256 bits, but they also specify the rounds, or iterations, made during the transformation. The surprise was the underlying algorithm, Rijndael, has no such limitation. Funny enough this is exactly Schneier’s recommendation from the above article:

… At this point, I suggest AES-128 at 16 rounds, AES-192 at 20 rounds, and AES-256 at 28 rounds. Or maybe even more; we don’t want to be revising the standard again and again.

Then today, two years later, another related post from the same author “New Attack on AES” with the same recommendation.

So what does this mean for me and my software?

Well that depends on how sensitive the data is, how long you intend to store it, and how accessible is the stored cipher.

For instance, SSL uses AES-128 after the initial key exchange; however, this does not mean SSL is broken (ok it is, but for other reasons). Since the SSL session key is short-lived, and the data is not stored anywhere (well, not suppose to be), there really isn’t a major concern here. The same is likely true even for your own software, transient data encrypted for short periods of time.

Well wait a minute you ask, “what about those credit cards I have encrypted in my database?” Frankly this still isn’t much of a concern. Credit cards actually aren’t that ‘sensitive’ to begin with, they get compromised all the time (Thanks Sony). Further most credit cards expire within two years, which is about how long the most gratuitously over optimistic attack could occur. So no, I would not reinvent the way you store credit cards. I would however make sure your not storing the encryption key in that database :)

So why would I concern myself with this? Well we are well within the era of SaSS/Cloud computing and often enough we need to encrypt and store data for our users. So we have to ask ourselves how sensitive this data is, how much damage can be done by accessing the data. Thinking of services like LastPass and 1Password, they store potentially sensitive data for long periods of time. Of course if I were going to attack those services, I’d likely go after the pass phrase, not the raw crypto key, but still. These services could easily benefit from extended rounds of Rijndael algorithm.

Another classic place to improve is locally encrypted storage. This was what I was playing with when I wrote the ModifiedRijndael class. It allows you to specify key sizes from 128~4k in 64bit increments, and any compatible number of Rounds. So if you want to play around with unlocking the Rijndael algorithm from the AES constraints try it out:

        ModifiedRijndael r = new ModifiedRijndael();
        r.BlockSize = 128;
        r.KeySize = 128;
        r.Rounds = 20;
        r.GenerateIV();
        r.GenerateKey();
        ICryptoTransform alg = r.CreateEncryptor();

Sum it up: The above articles and information is really only just that right now, information. I don’t see many people needing this kind of added security when encrypting data. A classic place for me to want something like this would be when uploading a file to something like DropBox. The problem is, I would likely generate the key from a password. The password is much easier to attack than the AES-128 algorithm. So until we can solve the password entropy issue there just doesn’t seem like much point in moving beyond AES for *most* cases.