Cool PowerShell Script Replicates Telnet

Lee Holmes has a cool script to reproduce telnet-like functionality via the TcpClient object in PowerShell.

## Connect-Computer.ps1 
## Interact with a service on a remote TCP port 
param( 
    [string] $remoteHost = "localhost", 
    [int] $port = 23
     ) 

try
{
    ## Open the socket, and connect to the computer on the specified port 
    write-host "Connecting to $remoteHost on port $port" 
    $socket = new-object System.Net.Sockets.TcpClient($remoteHost, $port) 
    if($socket -eq $null) { return; } 

    $stream = $socket.GetStream() 
    $writer = new-object System.IO.StreamWriter($stream) 

    $buffer = new-object System.Byte[] 1024 
    $encoding = new-object System.Text.AsciiEncoding 

    while($true) 
    { 
       ## Allow data to buffer for a bit 
       start-sleep -m 500 

       ## Read all the data available from the stream, writing it to the 
       ## screen when done. 
       while($stream.DataAvailable)  
       {  
          $read = $stream.Read($buffer, 0, 1024)    
          write-host -n ($encoding.GetString($buffer, 0, $read))  
       } 

       ## Read the user's command, quitting if they hit ^D 
       $command = read-host 
      
       ## Write their command to the remote host      
       $writer.WriteLine($command) 
       $writer.Flush() 
    } 
}
finally
{
    ## Close the streams 
    $writer.Close() 
    $stream.Close()
}

This solves the problem of telnet.exe crashing conhost.exe when using Console2.

Update

I tweaked Lee’s code to use try/finally which obviates the need for a special escape sequence to clean up the TCP resources.

Advertisement

Adapting the Microsoft Chart WebControl to MVC

The Chart control for ASP.Net that comes baked into .NET 4 or as an add-on to .NET 3 is useful but it is built around the WebForms rendering model which is uncomfortable in MVC applications. There is no pretty way to embed the WebChart control out-of-the-box. Solutions I have seen revolve around either giving up on the MVC separation and embedding the control into a View or creating custom web user controls for each chart and treating these as partial views. The former solution will only work with the WebForm view engine and not Razor or other view engines and the latter is just messy. Either way it feels like walking around with toilet paper stuck to your shoe. A third way is to return the image bytes of from a Chart object created in the controller as a FileResult. This works but you lose the image map tooltips.

The crux of the problem is that Chart is a DataBoundControl which is designed to magically generate its own HTML and to serve an image resource to itself when the rendered HTML is interpreted. It isn’t really meant to have an external controller tell it what to do. However, the Chart control has some nice features:

  1. It generates cross-browser friendly output
  2. It generates mouseover tooltips
  3. It doesn’t require Flash, Silverlight or JavaScipt because it uses MAP and AREA elements to create the tooltips
  4. With a little coercion, it will generate its image resource for you as a byte array which means you can alternatively embed the chart in an alternate resource like a PDF or other document envelope

Chart the MVC Way

Having decided that the Chart control does something we want, can we bend it to the MVC rendering model while preserving the nice tooltip image maps? The answer is yes we can. I have created a handful of extension methods that turn Chart on its head and allow you to render it out of a Controller class as an ActionResult. I’ll show you how things look in the View and Controller and then walk you through how it works.

View

<% Html.RenderAction( "PerformanceHistoryChart", new { id = Model.Id, shareClass = Model.ShareClass } ); %>

Controller

[OutputCache( Duration = 10, VaryByParam = "id;shareClass" )]
public ActionResult PerformanceHistoryChart( Guid id, string shareClass )
{
    return this.RenderChartMap( "PerformanceHistoryImage", id, shareClass, NewPerformanceHistoryChart );
}

[OutputCache( Duration = 10, VaryByParam = "id;shareClass" )]
public ActionResult PerformanceHistoryImage( Guid id, string shareClass )
{
    return this.RenderChartImage( id, shareClass, NewPerformanceHistoryChart );
}

private static Chart NewPerformanceHistoryChart( Guid id, string shareClass )
{
    Chart chart = new Chart();
    var series = perfChart.Series.Add( "Default" );
    var area   = perfChart.ChartAreas.Add( "ChartArea" );
    var values = ReportUtility.GetNetReturnOnValuePercentageHistory( id, shareClass );
    series.Points.DataBindXY( values.Item1, values.Item2 );
    series.ToolTip = "Fiscal Year: #VALX, Growth: #VALY{P}";
    area.AxisY.Title = "%";
    area.AxisY.LabelStyle.Format = "{P2}";
    return chart;
}

What’s going on in the View is that we are rendering the result of calling PerformanceHistoryChart on the controller. PerformanceHistoryChart renders HTML which includes an IMG tag reference to the PerformanceHistoryImage action which streams back the chart image as a PNG.PerformanceHistoryChart and PerformanceHistoryImage make use of my Chart to MVC adapter extension methods to do their work. There are two sets of extension method overloads:

  • this.RenderChartMap
  • this.RenderChartImage

In order to render any chart to a browser you need to provide two action methods. One of them calls RenderChartMap which generates HTML and the other calls RenderChartImage which returns the image as a FileResult for the IMG tag generated by RenderChartMap. Both extension methods accept a factory Func delegate which they use to create the Chart object that they manipulate internally. I’ve created overloads which accept 1 to 5 arguments.

MvcChart Extension Method Adapter Class

I’m sure this could be made more elegant but my first cut is working well. One limitation of my implementation is that you need a pair of extension method overloads that has enough arguments for your Chart factory Func  to work. Another issue is that you need to have an explicit route defined for the Actions which return the chart image FileContentResult. The reason is that the Chart control always appends a ?<some-guid> which is part of the caching mechanism it uses for storing images when it is rendering itself as a WebForms control. Therefore, I need to have an explicit route without any query string and allow the query string the Chart control generates to dangle off the end. My assumption is that the arguments will be passed in order from left to right in the URL as they appear in the method call. Also, since we are taking over rendering the Chart control via our Controller we give up the baked-in image caching. This is probably not much of an issue but it makes sense to use OutputCaching attributes to reduce the hits on the Chart factory Funcs and therefore your database.

Here’s my MvcChart class which contains the adapter extension methods. Happy coding.

using System.IO;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;

namespace System.Web.Mvc
{
    /// <summary>
    /// <para>This class adapts the System.Web.UI.DataVisualization.Charting.Chart API to something
    /// more friendly to ASP.Net MVC by attaching extension methods to the Controller type.Requires
    /// an explicit route mapping for all arguments. The arguments will be inserted into the Image 
    /// generating URL in order.</para>
    /// <para>In each controller we need a pair of ActionMethods. One generates the IMG, MAP and AREA tags.
    /// The other streams the chart PNG. The URL to the chart PNG method is referenced by the imageActionName
    /// parameter in the RenderChartMap() method call. We also need a factory method which generates the Chart
    /// object instance. The chart factory is passed as a delegate to these adapter extension methods.</para>
    /// <remarks>In order to render each chart in a browser, the factory method must be executed twice.
    /// Consider using the OutputCache attribute to reduce hits on the data backend.</remarks>
    /// </summary>
    public static class MvcChart
    {
        /// <summary>
        /// Render img tag and associated image map for a chart.
        /// </summary>
        /// <typeparam name="T">Type of the factory argument.</typeparam>
        /// <param name="imageActionName">Method name in this controller that streams the chart image.</param>
        /// <param name="arg">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns>ContentResult that generates HTML for the chart.</returns>
        public static ContentResult RenderChartMap<T>( this Controller controller, string imageActionName,
            T arg, Func<T, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg );
            //FWIW: ImageLocation URL will have ?{some-guid} appended which is part of its classic WebForms ASP.Net
            //web control rendering model
            chart.ImageLocation = string.Format( "{0}{1}/{2}/{3}/", 
                GetApplicationPath( controller ), 
                GetControllerName( controller ), 
                imageActionName, 
                arg );
            return RenderChartMap( chart );
        }

        /// <summary>
        /// Render img tag and associated image map for a chart.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory argument.</typeparam>
        /// <typeparam name="T2">Type of the second factory argument.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="imageActionName">Method name in this controller that streams the chart image.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns>ContentResult that generates HTML for the chart.</returns>
        public static ContentResult RenderChartMap<T1,T2>( this Controller controller, string imageActionName, 
            T1 arg1, T2 arg2, Func<T1, T2, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2 );
            chart.ImageLocation = string.Format( "{0}{1}/{2}/{3}/{4}/", 
                GetApplicationPath( controller ), 
                GetControllerName( controller ), 
                imageActionName, 
                arg1, 
                arg2 );
            return RenderChartMap( chart );
        }

        /// <summary>
        /// Render img tag and associated image map for a chart.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory argument.</typeparam>
        /// <typeparam name="T2">Type of the second factory argument.</typeparam>
        /// <typeparam name="T3">Type of the third factory argument.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="imageActionName">Method name in this controller that streams the chart image.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="arg3">Third parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns>ContentResult that generates HTML for the chart.</returns>
        public static ContentResult RenderChartMap<T1, T2, T3>( this Controller controller, string imageActionName,
            T1 arg1, T2 arg2, T3 arg3, Func<T1, T2, T3, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2, arg3 );
            chart.ImageLocation = string.Format( "{0}{1}/{2}/{3}/{4}/{5}/",
                GetApplicationPath( controller ),
                GetControllerName( controller ),
                imageActionName,
                arg1,
                arg2,
                arg3 );
            return RenderChartMap( chart );
        }

        /// <summary>
        /// Render img tag and associated image map for a chart.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory argument.</typeparam>
        /// <typeparam name="T2">Type of the second factory argument.</typeparam>
        /// <typeparam name="T3">Type of the third factory argument.</typeparam>
        /// <typeparam name="T4">Type of the fourth factory argument.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="imageActionName">Method name in this controller that streams the chart image.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="arg3">Third parameter used by the chart factory.</param>
        /// <param name="arg4">Fourth parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns>ContentResult that generates HTML for the chart.</returns>
        public static ContentResult RenderChartMap<T1, T2, T3, T4>( this Controller controller, string imageActionName,
            T1 arg1, T2 arg2, T3 arg3, T4 arg4, Func<T1, T2, T3, T4, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2, arg3, arg4 );
            chart.ImageLocation = string.Format( "{0}{1}/{2}/{3}/{4}/{5}/{6}/",
                GetApplicationPath( controller ),
                GetControllerName( controller ),
                imageActionName,
                arg1,
                arg2,
                arg3,
                arg4);
            return RenderChartMap( chart );
        }

        /// <summary>
        /// Render img tag and associated image map for a chart.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory argument.</typeparam>
        /// <typeparam name="T2">Type of the second factory argument.</typeparam>
        /// <typeparam name="T3">Type of the third factory argument.</typeparam>
        /// <typeparam name="T4">Type of the fourth factory argument.</typeparam>
        /// <typeparam name="T5">Type of the fifth factory argument.</typeparam>
        /// <param name="imageActionName">Method name in this controller that streams the chart image.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="arg3">Third parameter used by the chart factory.</param>
        /// <param name="arg4">Fourth parameter used by the chart factory.</param>
        /// <param name="arg5">Fifth parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns>ContentResult that generates HTML for the chart.</returns>
        public static ContentResult RenderChartMap<T1, T2, T3, T4, T5>( this Controller controller, string imageActionName,
            T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, Func<T1, T2, T3, T4, T5, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2, arg3, arg4, arg5 );
            chart.ImageLocation = string.Format( "{0}{1}/{2}/{3}/{4}/{5}/{6}/{7}/",
                GetApplicationPath( controller ),
                GetControllerName( controller ),
                imageActionName,
                arg1,
                arg2,
                arg3,
                arg4,
                arg5 );
            return RenderChartMap( chart );
        }

        /// <summary>
        /// Render chart image byte stream as a PNG file.
        /// </summary>
        /// <typeparam name="T">Type of the id.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="arg">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns></returns>
        public static FileContentResult RenderChartImage<T>( this Controller controller, T arg, Func<T, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg );
            return RenderChartImage( chart );
        }

        /// <summary>
        /// Render chart image byte stream as a PNG file.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory parameter.</typeparam>
        /// <typeparam name="T2">Type of the second factory parameter.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns></returns>
        public static FileContentResult RenderChartImage<T1, T2>( this Controller controller, 
            T1 arg1, T2 arg2, Func<T1, T2, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2 );
            return RenderChartImage( chart );
        }

        /// <summary>
        /// Render chart image byte stream as a PNG file.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory parameter.</typeparam>
        /// <typeparam name="T2">Type of the second factory parameter.</typeparam>
        /// <typeparam name="T3">Type of the third factory argument.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="arg3">Third parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns></returns>
        public static FileContentResult RenderChartImage<T1, T2, T3>( this Controller controller, 
            T1 arg1, T2 arg2, T3 arg3, Func<T1, T2, T3, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2, arg3 );
            return RenderChartImage( chart );
        }

        /// <summary>
        /// Render chart image byte stream as a PNG file.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory parameter.</typeparam>
        /// <typeparam name="T2">Type of the second factory parameter.</typeparam>
        /// <typeparam name="T3">Type of the third factory argument.</typeparam>
        /// <typeparam name="T4">Type of the fourth factory argument.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="arg3">Third parameter used by the chart factory.</param>
        /// <param name="arg4">Fourth parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns></returns>
        public static FileContentResult RenderChartImage<T1, T2, T3, T4>( this Controller controller,
            T1 arg1, T2 arg2, T3 arg3, T4 arg4, Func<T1, T2, T3, T4,  Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2, arg3, arg4 );
            return RenderChartImage( chart );
        }

        /// <summary>
        /// Render chart image byte stream as a PNG file.
        /// </summary>
        /// <typeparam name="T1">Type of the first factory parameter.</typeparam>
        /// <typeparam name="T2">Type of the second factory parameter.</typeparam>
        /// <typeparam name="T3">Type of the third factory argument.</typeparam>
        /// <typeparam name="T4">Type of the fourth factory argument.</typeparam>
        /// <typeparam name="T5">Type of the fifth factory argument.</typeparam>
        /// <param name="controller">Controller instance.</param>
        /// <param name="arg1">Id used by the chart factory to find the data to generate the chart.</param>
        /// <param name="arg2">Second parameter used by the chart factory.</param>
        /// <param name="arg3">Third parameter used by the chart factory.</param>
        /// <param name="arg4">Fourth parameter used by the chart factory.</param>
        /// <param name="arg5">Fourth parameter used by the chart factory.</param>
        /// <param name="chartFactory">Delegate capable of generating a new Chart instance.</param>
        /// <returns></returns>
        public static FileContentResult RenderChartImage<T1, T2, T3, T4, T5>( this Controller controller,
            T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, Func<T1, T2, T3, T4, T5, Chart> chartFactory )
        {
            Chart chart = chartFactory.Invoke( arg1, arg2, arg3, arg4, arg5 );
            return RenderChartImage( chart );
        }
        
        private static ContentResult RenderChartMap( Chart chart )
        {
            chart.RenderType = RenderType.ImageMap;
            //Make sure that each chart rendered into the page has a unique ID in HTML by
            //assigning a Guid to the ID property. Otherwise, they will all have the same
            //ID and the image map will only work for the first chart at best.
            chart.ID = Guid.NewGuid().ToString( "N" );
            using( var writer = new StringWriter() )
            using( var htmlTextWriter = new HtmlTextWriter( writer ) )
            {
                chart.RenderControl( htmlTextWriter );
                return new ContentResult() { Content = writer.ToString() };
            }
        }

        private static FileContentResult RenderChartImage( Chart chart )
        {
            using( MemoryStream chartStream = new MemoryStream() )
            {
                chart.SaveImage( chartStream, ChartImageFormat.Png );
                return new FileContentResult( chartStream.ToArray(), "image/png" ) { FileDownloadName = "chart.png" };
            }
        }

        private static string GetApplicationPath( Controller controller )
        {
            var applicationPath = controller.HttpContext.Request.ApplicationPath;
            applicationPath = applicationPath.EndsWith( "/" ) ? applicationPath : applicationPath + "/";
            return applicationPath;
        }

        private static string GetControllerName( Controller controller )
        {
            var controllerName = controller.GetType().Name;
            if( !controllerName.EndsWith( "Controller" ) )
                throw new InvalidOperationException( "Controller names must end with \"Controller\"" );

            controllerName = controllerName.Substring( 0, controllerName.Length - 10 ); ;
            return controllerName;
        }
    }
}

JSLint.VS2010: Automatic JavaScript Static Analysis

Recently, I was working on a project that used some asynchronous JSON-to-HTML databiding. Testers sent a bug that the site was working in Chrome, Firefox, Safari and IE9 but nothing was happening in IE8. The IE8 javascript debugger didn’t report any errors, it just didn’t do anything.

This sort of thing is no fun to debug and I spent an increasingly desperate evening staring at code that couldn’t possibly be wrong  failing to see the problem. Eventually, in desperation, I pasted the code into Douglas Crockford’s jslint and it quickly pointed out a stray comma which made all the difference.

I later discovered that there is a jslint extension available for Visual Studio 2010.

jslint-options

The really cool thing about the JSLint Visual Studio extension is that it reports its warnings and errors into the Visual Studio Error List window where they work just like other code errors. Even better, it has the option to cancel the build on error. That means if jslint finds an error, the project build dies. In my world, this is fantastic. It means I don’t even try to test something if jslint finds something wrong with it. I consider this to be a huge productivity win.skip-on-build

The following JSLint global options were key for me to use jslint as a build-time checker:

  • Output: Errors – causes Visual Studio to interpret JSLint output as errors
  • Run JSLint on build: true – causes JSLint to test all .JS files during build
  • Cancel build on error true– causes JSLint errors to cancel the build, just like C# compiler errors
  • Assume a browser: true
  • Predefined Vars: jQuery, $
  • Strict whitespace: false
  • Maximum line length: 999
    One issue with cancelling the build on error is that jslint is pedantic and some of its warnings are not strictly errors which means that standard libraries like jquery aren’t going to pass jslint. Fortunately, you can exclude individual .js files from build-time testing by right-clicking on the files you want to exclude in the Solution Explorer window. (Note that jslint doesn’t plug its menus into the Solution Navigator window from the “Productivity Power Tools” extension. You have to use the Solution Explorer.)
    Happy linting.

Secure Password Hashing in C#

Long-term storage of logon credentials in computer systems is a serious point of vulnerability. Too many systems store credentials in an unencrypted or weakly encrypted form that system administrators or database power-users can view or edit. This may seem OK as long as a set of conditions were true:

  • The administrators of the system are known to be trustworthy and no untrusted users have the ability to view, alter or copy the password file or table.
  • The normal execution flow of the system could not be used to reveal plaintext passwords.
  • The online and backup repositories of authentication data are secure.
    Employee turnover, the increasing complexity of internet-connected systems, and the spread of knowledge and tools for executing simple security exploits all work together to change the rules of the game so that storing passwords in plaintext is no longer acceptable.  Disgruntled employees are now widely acknowledged to be the single largest vulnerability for most companies, and are the most common attackers of computer systems.  Defects in production software, runtimes and platforms can also disclose sensitive information to attackers. A litany of recent headlines where a wide range of organizations have lost control of their authentication database prove that systems that store “secret” but plaintext logon information are unsafe.

Theory of Password Hashing in Brief

The key to hardening authentication systems to use a strong cryptographic function to hash passwords into an unrecoverable blob. A strong hashing algorithm must guard against brute force offline attack via a rainbow tables precompiled hashes on dictionary words. Rainbow tables and software to use them are publicly available which lowers the password cracking bar to the level of script kiddie.

Niels Furguson and Bruce Schneier in Practical Cryptography describe strong a strong hashing technique for safe storage of passwords which requires.

  • A publicly tested secure hashing algorithm such as SHA-256. Neither MD5 nor SHA-1 are good enough anymore.
  • A randomly-generated value known as a Salt is mixed with the plaintext. The salt value is not a secret, it exists to make the output of the hash non-deterministic. There should be a unique salt for each user and a new random salt value should be generated every time a password is set.
  • The hash is stretched, meaning that the output is fed back through the algorithm a large number of times in order to slow down the hashing algorithm to make brute force attacks impractical.

In order to authenticate a user, the system retrieves the salt for the username, calculates the hash for the password the user provided and compares that hash to the value in the authentication database. If the hashes match, then access is granted.

Implementation in C#

In hope of making it easy for .NET developers to implement good authentication security, my company published a secure password hashing algorithm in C# under the BSD license in 2005. This algorithm is a part of the security subsystem of our PeopleMatrix product.

Because the code is no longer available on thoughtfulcomputing.com, so I’m republishing hit here.

Download HashManager source with a sample application.

//*****************************************************************
// <copyright file="HashManager.cs" company="WolfeReiter">
// Copyright (c) 2005 WolfeReiter, LLC.
// </copyright>
//*****************************************************************

/*
** Copyright (c) 2005 WolfeReiter, LLC
**
** This software is provided 'as-is', without any express or implied warranty. In no 
** event will the authors be held liable for any damages arising from the use of 
** this software.
**
** Permission is granted to anyone to use this software for any purpose, including 
** commercial applications, and to alter it and redistribute it freely, subject to 
** the following restrictions:
**
**    1. The origin of this software must not be misrepresented; you must not claim 
**       that you wrote the original software. If you use this software in a product,
**       an acknowledgment in the product documentation would be appreciated but is 
**       not required.
**
**    2. Altered source versions must be plainly marked as such, and must not be 
**       misrepresented as being the original software.
**
**    3. This notice may not be removed or altered from any source distribution.
**
*/

using System;
using System.Globalization;
using System.Text;
using System.Security.Cryptography;

namespace WolfeReiter.Security.Cryptography
{
	/// <summary>
	/// HashManager provides the service of cryptographically hashing and verifying strings
	/// against an existing hash. HashManager uses the SHA-256 hashing transform by default.
	/// </summary>
	/// <remarks>
	/// <para>The MD5 and SHA1 algorithms should be avoided because they are not strong enough
	/// to resist attack with modern processors. Also, it appears that the algorithms for MD5 and SHA1
	/// may have a flaw known as "collision". The short story is that  an attacker can discover the 
	/// plaintext used to generate the hash in much fewer steps than expected.</para>
	/// <para>For example, SHA1 should theoretically require 2<sup>80</sup> steps to brute-force recover 
	/// the original plaintext. Researchers have recently claimed to have a method of recovering SHA1 plaintext
	/// in 2<sup>33</sup> steps.</para></remarks>
	[Serializable]
	public sealed class HashManager 
	{
		private HashAlgorithm _transform;
		private readonly ulong _iterations;

		/// <summary>
		/// CTOR. Creates a new HashManager object that uses the SHA-256 algorithm and stretches the entropy in the hash
		/// with 2<sup>16</sup> iterations.
		/// </summary>
		public HashManager() : this("SHA-256",65536){}
		/// <summary>
		/// CTOR. Creates a new HashManager object that uses the specified well-known hash transform algorithm.
		/// </summary>
		/// <param name="transform">Well-known transform algorithm (eg. MD5, SHA-1, SHA-256, SHA-384, SHA-512, etc.).</param>
		/// <param name="iterations">Number of iterations used to sretch the entropy of the plaintext. 2<sup>16</sup> iterations
		/// is a recommended minimum.</param>
		/// <exception cref="ArgumentOutOfRangeException">Throws if iterations is less than 1.</exception>
		public HashManager(string transform, ulong iterations) : this(HashAlgorithm.Create(transform),iterations){}

		/// <summary>
		/// CTOR. Creates a new HashManager object that uses provided transform hash algorithm.
		/// </summary>
		/// <param name="transform">HashAlgorithm object to use.</param>
		/// <param name="iterations">Number of iterations used to sretch the entropy of the plaintext. 2<sup>16</sup> iterations
		/// is a recommended minimum.</param>
		/// <exception cref="ArgumentOutOfRangeException">Throws if iterations is less than 1.</exception>
		public HashManager(HashAlgorithm transform, ulong iterations)
		{
			if( iterations < 1 )
				throw new ArgumentOutOfRangeException("iterations", iterations, "The number of iterations cannot be less than 1");
			_transform  = transform;
			_iterations = iterations;
		}
		/// <summary>
		/// CTOR. Creates a new HashManager object that uses the specified well-known hash transform algorithm.
		/// </summary>
		/// <param name="transform">Well-known transform algorithm (eg. MD5, SHA-1, SHA-256, SHA-384, SHA-512, etc.).</param>
		/// <param name="iterations">Number of iterations used to sretch the entropy of the plaintext. 2<sup>16</sup> iterations
		/// is a recommended minimum.</param>
		/// <exception cref="ArgumentOutOfRangeException">Throws if iterations is less than 1.</exception>
		public HashManager(string transform, long iterations) : this(HashAlgorithm.Create(transform),iterations){}

		/// <summary>
		/// CTOR. Creates a new HashManager object that uses provided transform hash algorithm.
		/// </summary>
		/// <param name="transform">HashAlgorithm object to use.</param>
		/// <param name="iterations">Number of iterations used to sretch the entropy of the plaintext. 2<sup>16</sup> iterations
		/// is a recommended minimum.</param>
		/// <exception cref="ArgumentOutOfRangeException">Throws if iterations is less than 1.</exception>
		public HashManager(HashAlgorithm transform, long iterations)
		{
			if( iterations < 1 )
				throw new ArgumentOutOfRangeException("iterations", iterations, "The number of iterations cannot be less than 1");
			_transform  = transform;
			_iterations = (ulong)iterations;
		}
		/// <summary>
		/// Hashes a plaintext string.
		/// </summary>
		/// <param name="s">Plaintext to hash. (not nullable)</param>
		/// <param name="salt">Salt entropy to mix with the s. (not nullable)</param>
		/// <returns>HashManager byte array.</returns>
		/// <exception cref="ArgumentNullException">Throws if either the s or salt arguments are null.</exception>
		public byte[] Encode( string s, byte[] salt )
		{
			if( s==null )
				throw new ArgumentNullException("s");
			if( salt==null )
				throw new ArgumentNullException("salt");

            return Encode( ConvertStringToByteArray( s ), salt );
		}

        public byte[] Encode( byte[] plaintext, byte[] salt )
        {
            byte[] sp = salt;
            byte[] hash = plaintext;
            //stretching via multiple iterations injects entropy that makes collision plaintext recovery much
            //more difficult.
            for( ulong i = 0; i < _iterations; i++ )
            {
                sp = Salt( hash, salt );
                hash = _transform.ComputeHash( sp );
            }

            return hash;
        }

		private byte[] Salt( byte[] p, byte[] salt )
		{
			byte[] buff = new byte[p.Length + salt.Length];
			for( int i=0; i<p.Length; i++ )
				buff[i] = p[i];
			for( int i=0; i<salt.Length; i++ )
				buff[i + p.Length] = salt[i];
			
			return buff;
		}

		/// <summary>
		/// Verifies a plaintext string against an existing hash. This is a case-sensitive operation.
		/// </summary>
		/// <param name="s">Plaintext to verify</param>
		/// <param name="hash">HashManager to compare with the s</param>
		/// <param name="salt">Salt that was used with the original s to generate the hash</param>
		/// <returns>True if the s is the same as the one used to generate the original hash.
		/// Otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Throws if any of the s, hash or salt arguments are null.</exception>
		public bool Verify( string s, byte[] hash, byte[] salt )
		{
			if( s == null )
				throw new ArgumentNullException("s");
			if( salt == null )
				throw new ArgumentNullException("salt");
			if( hash == null )
				throw new ArgumentNullException("hash");

            byte[] testhash = Encode( s, salt );
            return _Verify( testhash, hash );
		}

        public bool Verify( byte[] plaintext, byte[] hash, byte[] salt )
        {
            if( plaintext == null )
                throw new ArgumentNullException( "plaintext" );
            if( salt == null )
                throw new ArgumentNullException( "salt" );
            if( hash == null )
                throw new ArgumentNullException( "hash" );

            byte[] testhash = Encode( plaintext, salt );
            return _Verify( testhash, hash );
        }

        private bool _Verify( byte[] a, byte[] b )
        {
            if( a.Length != b.Length )
                return false;
            for( int i = 0; i < a.Length; i++ )
            {
                if( a[i] != b[i] )
                    return false;
            }
            return true;
        }

		/// <summary>
		/// Generates a 32 byte (256 bit) cryptographically random salt.
		/// </summary>
		/// <returns>256 element Byte array containing cryptographically random bytes.</returns>
		public static byte[] GenerateSalt()
		{
			return GenerateSalt(32);
		}
		/// <summary>
		/// Generates a cryptogrpahically random salt of arbirary size.
		/// </summary>
		/// <param name="size">size of the salt</param>
		/// <returns>Byte array containing cryptographically random bytes.</returns>
		public static byte[] GenerateSalt(int size)
		{
			Byte[] saltBuff = new Byte[size];
			RandomNumberGenerator.Create().GetBytes( saltBuff );
			return saltBuff;
		}

		/// <summary>
		/// Convert a hash (or salt or any other) byte[] to a hexadecimal string.
		/// </summary>
		/// <param name="hash">Byte[] to convert to hex.</param>
		/// <returns></returns>
		public static string ConvertToHexString( byte[] hash )
		{
			StringBuilder sb = new StringBuilder();
			foreach( byte b in hash )
			{
				string bytestr = Convert.ToInt32(b).ToString("X").ToLower();
				if( bytestr.Length==1)
					bytestr = '0' + bytestr;
				sb.Append( bytestr );
			}
			return sb.ToString();
		}

		/// <summary>
		/// Convert a hexadecimal string to byte[].
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		public static byte[] ConvertFromHexString( string s )
		{
			string hex = s.ToLower();
			if( hex.StartsWith("0x") )
				hex = hex.Substring(2);

			//ensure an even hex number
			hex = (hex.Length % 2 == 0) ? hex : '0' + hex;
			//2 hex digits per byte
			byte[] b = new byte[hex.Length/2];
			for(int i=0,j=0; i<hex.Length; i+=2,j++)
			{
				b[j] = byte.Parse( hex.Substring(i,2), NumberStyles.HexNumber );
			}
			return b;
		}

		/// <summary>
		/// Convert a hash (or salt or any other) byte[] to a base64 string.
		/// </summary>
		/// <param name="hash">Byte[] to convert to base64</param>
		/// <returns></returns>
		public static string ConvertToBase64String( byte[] hash )
		{
			return Convert.ToBase64String(hash);
		}
		
		/// <summary>
		/// Convert a base64 encoded string into a byte array.
		/// </summary>
		/// <param name="s">Base64 string.</param>
		/// <returns>Byte array.</returns>
		public static byte[] ConvertFromBase64String( string s )
		{
			return Convert.FromBase64String( s );
		}

		/// <summary>
		/// Converts a String to a Byte array.
		/// </summary>
		/// <remarks>Only works on .NET string objects or Unicode encoded strings.</remarks>
		/// <param name="s">String to convert</param>
		/// <returns>Byte array.</returns>
		public static byte[] ConvertStringToByteArray( string s )
		{
			if (s == null)
				return null;
			Char[] chars = s.ToCharArray();
			Encoder encoder = Encoding.Unicode.GetEncoder();
			int bytecount = encoder.GetByteCount( chars, 0, chars.Length, true );
			byte[] outbuff = new byte[bytecount];
			encoder.GetBytes(chars, 0, chars.Length, outbuff, 0, true );
			return outbuff;
		}
	}
}

Ximian is Dead, Long Live Xamarin

I was depressed when I heard that Attachmate disbanded the Mono team as a part of it’s acquisition of Novell but Miguel de Icaza has a lot of chutzpa. He has reformed his team in nothing flat and launched a new company to continue the development of Mono and its associated C#-based mobile toolkits, MonoToch (iOS) and  MonoDriod (Android) and Moonlight (Silverlight for Linux).

To make a long story short, the plan to spin off was not executed. Instead on Monday May 2nd, the Canadian and American teams were laid off; Europe, Brazil and Japan followed a few days later. These layoffs included all the MonoTouch and MonoDroid engineers and other key Mono developers. Although Attachmate allowed us to go home that day, we opted to provide technical support to our users until our last day at Novell, which was Friday last week.

Now, two weeks later, we have a plan in place, which includes both angel funding for keeping the team together, as well as a couple of engineering contracts that will help us stay together as a team while we ship our revenue generating products.

~Miguel de Icaza

All the best Miguel.

Fail: Useless IE8 Compatibility VM

I downloaded a virtual disk image today—May 11, 2011—from Microsoft that is purported to be configured specifically for testing compatibility with IE8. The readme had a nasty gram in it.

This image will expire on May 18, 2011.  At that time the Operating System will no longer boot, and you will be locked out of the VHD.  Please ensure you back up any relevant data before May 18, 2011.

I guess the date was a little optimistic because I am already locked out. All I get is a perpetual loop of Windows Product Activation and I cannot log in. Fail!.

useless-vhd

These pre-built virtual machine images seem to be more of a time suck than a time saver. I should have—and now will—install Windows XP from MSDN ISO and patch it to IE8.

Smashed Nexus One, RIP

After having survived being drowned, my Nexus One has finally succumbed to my (unintentional) abuse. It fell off my night stand this morning and landed face down exactly wrong on the tile floor, shattering the glass touch screen. To be fair, the N1 is still working, it’s just that I’m in serious danger of glass splinters and sliced fingertips using it.

IMG_0094

This happened just a day after getting the latest Gingerbread. Arg! I will miss this phone while I “suffer” with my iPhone 3Gs until I can get a Nexus S shipped to me in Ghana or when I am in the UK. For all its cache and cool hardware, the iPhone doesn’t do the things I love in Android:

  • Background services (used to great effect by Google Listen and Google Voice) not just multitasking
  • Unobtrusive notifications
  • Custom status icons (WeatherBug and BBC do a great job with these)
  • Native SIP client support (gingerbread)
  • Unlocked without jailbreak ultrasn0w shenanigans

IP Address is Not Identity

whois

When TCP/IP first developed by DARPA in the 1970s, every host on the ARPANET got an IP address. The “hosts” file which still exists on every computer mapped addresses to hosts until it was superseded by the Domain Name System (DNS). Certainly it was possible to do tricks like mapping more than one name (A record) to an IP address or provide CNAME aliases and multihomed hosts with multiple IP addresses are allowed. But more-or-less, historically an IP address maps to a computer. Furthermore, until recently IP addresses were doled out by ARIN and others in big blocks. Anyone who had a hint of a need could get IP addresses in lots of 256 addresses, sometimes called a Class C subnet or a “/24”. In the late 1990s in the Mid-Atlantic region of the USA, a T-1 came with 256 IP addresses and it was easy to get another 256 or more with the most modest excuse.

Historically, therefore, there is a notion that an IP address is pretty much a host and that host is part of a block of IP addresses which are managed by some entity which owns that computer and all the others in the subnet.

We are out of IP addresses and this world where a host is an IP address and a /24 is controlled by a single entity  no longer exists.

IPv6 may be the solution but the reality is that nobody is using it. In today’s world IP addresses are shared by multiple computers and even multiple companies using a variety of schemes including

  • Virtual hosting
  • Network Address Translation (NAT)
  • Proxies
  • Dynamic address allocation (DHCP)
  • Shared service computing (SaaS, Application Service Provider, Cloud Computing, etc) The bottom line is that an IP address is no longer reliably associated with any kind of identity. That email you just got might be coming from a Google Apps IP address or maybe one from Office 365 that is originating mail for hundreds of companies. The IP address behind this web server is most assuredly being used to host hundreds or thousands of sites. On the client end, if you have a Verizon LTE device, then you have a publically un-routable 10.x.x.x address and are being NATed onto the public Internet with some IP address shared by many others.This new reality complicates Internet security decisions because these days IP addresses are more granular than hosts and maybe more granular than organizations. The bottom line is that manipulating access control by IP address should be considered a blunt instrument virtually guaranteed to carry unintended side-effects unless the parties owning the addresses are well-known to each other.

    Related

Reducing the Need for Manual Reload of Color Calibration when Docking in Windows 7

Windows 7 has native support for monitor color calibration (though the OS X calibration wizard is more advanced). Unfortunately, at least with my MacBook Pro 5,3 and Apple Cinema display, Windows unloads the calibrations every time the external display is hot-plugged into my laptop. This forces me to go to Control Panel | Color Management | Advanced and click Reload current calibrations on a regular basis. I’ve even pinned this applet to my start menu for this purpose.

I’ve been looking for a command-line way to invoke this so that I can automate it and haven’t come up with anything other than possibly invoking colorcpl.exe and programmatically selecting the Advanced tab and sending a click to the Reload current calibrations button. However, poking around, I recently discovered that there is a scheduled task “\Microsoft\Windows\WindowsColorSystem\Calibration Loader”. This thing appears to do exactly what I want: reload the current calibrations.

The Action of the task is a “Custom Hander” which means it’s a COM handler. The XML definition of this task is in “%systemroot%\System32\Tasks\Microsoft\Windows\WindowsColorSystem\Calibration Loader”. Looking in there you will find the COM CLSID:

  <Actions Context="Group">
    <ComHandler>
      <ClassId>{B210D694-C8DF-490D-9576-9E20CDBC20BD}</ClassId>
    </ComHandler>
  </Actions>

I’ll have to dig into that at a later time.

Meanwhile, my main use-case is docking my laptop which usually has a closed lid or has just been re-opened so it is waking from sleep and locked. There are system events defined for those cases. The other case is just hot-plugging my monitor which is comparatively rare and doesn’t seem to generate an event. In any case, I can add the resume-from-sleep and workstation-unlocked events to the triggers for the calibration re-load task. This largely addresses my issues.

In Scheduled Tasks, navigate to \Microsoft\Windows\WindowsColorSystem and open Calibration Loader. Go to Triggers and add two new events to trigger the task.

Add On Wakeup Event Trigger

resume-from-sleep

  • Begin the task: On an event
      • Basic
      • Log: System
      • Source: Power-Troubleshooter
      • Event ID: 1
      • [check] Delay task for: 5 seconds (optional, I’m experimenting with this)

Add On Workstation Unlock Event Trigger

on-workstation-unlock

  • Begin the task: On workstation unlock
  • Any user

Remaining Annoyances

If you have a MacBook and like to customize the brightness of your external Cinematic Display and/or you like have overridden the default behavior so that function keys behave like function keys rather than Mac OS X-like macro keys by default, then you find when you hot dock your settings aren’t respected. The problem is that when a monitor or keyboard is hot docked, the bootcamp.exe process that interfaces with the Apple system controller doesn’t apply your settings. The solution is to restart bootcamp.exe.

I have a simple convenience powershell script to restart bootcamp.exe.

get-process | where { $_.Name -eq 'bootcamp' } | stop-process
start-process 'C:\Program Files\Boot Camp\Bootcamp.exe'

You may wish to have this also run on an event trigger. However, if you do, the annoyance is that it will litter your system tray with dead “Boot Camp” black diamond icons. I tend to have a powershell console open all the time, so I just invoke the script manually whenever I dock my monitor and keyboard.

“Security Suite” Subscriptions are the Dumbest Idea in Computer Security

I recently came across a 2005 essay by Marcus Ranum entitled “The Six Dumbest Ideas in Computer Security”. #1 on Ranum’s list is “Default Permit”.

Another place where "Default Permit" crops up is in how we typically approach code execution on our systems. The default is to permit anything on your machine to execute if you click on it, unless its execution is denied by something like an antivirus program or a spyware blocker. If you think about that for a few seconds, you’ll realize what a dumb idea that is. On my computer here I run about 15 different applications on a regular basis. There are probably another 20 or 30 installed that I use every couple of months or so. I still don’t understand why operating systems are so dumb that they let any old virus or piece of spyware execute without even asking me. That’s "Default Permit."

#2 on Ranum’s list is a special case of #1 which he calls “Enumerating Badness”. Basically what that boils down to is keeping a running list of “bad” stuff and preventing that from happening.

"Enumerating Badness" is the idea behind a huge number of security products and systems, from anti-virus to intrusion detection, intrusion prevention, application security, and "deep packet inspection" firewalls. What these programs and devices do is outsource your process of knowing what’s good. Instead of you taking the time to list the 30 or so legitimate things you need to do, it’s easier to pay $29.95/year to someone else who will try to maintain an exhaustive list of all the evil in the world. Except, unfortunately, your badness expert will get $29.95/year for the antivirus list, another $29.95/year for the spyware list, and you’ll buy a $19.95 "personal firewall" that has application control for network applications. By the time you’re done paying other people to enumerate all the malware your system could come in contact with, you’ll more than double the cost of your "inexpensive" desktop operating system.

The prices have gone up a bit with inflation:

  • Norton Internet Security Suite $70/year
  • Kaspersky PURE Total Security $90/year
  • McAfee Total Protection $90/year

Basically what you get for your $60-90/year is a system that double-checks everything that you try to do isn’t something bad that it knows about and if it is tries to stop it and if it lets something nasty happen tries to fix it later. You have no guarantee that something bad won’t happen because your computer still defaults to executing all code and, as a bonus, your expensive new computer now runs like molasses.

Default Deny is an Available Option in Windows 7 (but not by default)

Windows 7 ships with a semi-obscure enterprise feature called AppLocker. What AppLocker can do is deny execution to all programs, scripts, installers and DLLs by default. Instead of the normal situation where everything runs, only the code that matches ApplLockers known-good rules is allowed to execute. It works in conjunction with non-administrator user accounts to ensure that the only code executing on your system is code you want executing. This sleeper that nobody has ever heard of is more effective at stopping malware than any security suite on the market can ever be.

Why does this work? Your every day account has limited rights so it can’t write files into protected parts of the operating system but only software installed into protected parts of the operating system are allowed to execute. That means its impossible to execute downloads, email attachments, files on USB drives or whatever. Even if your browser or a plugin like Flash is exploited by malicious code in a web page, it is severely limited in the damage it can do. The usual end game of browser exploit code is to download malware onto your computer, install it somewhere and execute it. With an AppLocker default deny policy the end game can’t happen. This makes an anti-malware system something of an afterthought. Antimalware software becomes nothing more than good hygiene rather than the beachhead of your computer security, so make sure to use something that is free, lightweight and unobtrusive.

The catch is that AppLocker is an “Enterprise” feature that is only available in Windows 7 Enterprise or Ultimate editions. Also, there is configured through the Group Policy enterprise management tool which is targeted at professional systems administrators rather than normal people.

It turns out to also be cheaper to upgrade to Windows 7 Ultimate than to pay for 3 years of anti-malware. Let’s assume that your computer has a 3-year life.

Windows Anytime Upgrade Price List

  • Windows 7 Starter to Windows 7 Ultimate: $164.99 or $55/year amortized over 3 years
  • Windows 7 Home Premium to Windows 7 Ultimate: $139.99 or $47/year amortized over 3 years
  • Windows 7 Professional to Windows 7 Ultimate: $129.99 or $43/year amortized over 3 years

Even if it weren’t cheaper than massive security suites, enabling a default deny execution policy is so fundamentally right it is crazy not to do it. Any corporate IT department deploying Windows 7 without enabling AppLocker is either incompetent or the organization places no value on information security. For home users, the configuration is doable but it is “enterprisey” which means the configuration interface is too daunting for most people.

If Microsoft cares about protecting its users, it should enhance AppLocker so that it has a consumer-friendly configuration interface and it should turn on AppLocker by default in all SKUs, just like the Windows Firewall is on by default.

The day can’t come soon enough that Windows ships with a default deny firewall and a default deny execution policy and limited rights users by default. Maybe it will all come together in Windows 8.

%d bloggers like this: