13.5 Extending the .NET Framework

In this section, we extend the .NET Framework by adding a new algorithm. Unfortunately, cryptographic hashing algorithms usually include large tables of random numbers, making them unsuitable for listing in a book such as this.

Because we want to focus on the process of adding an algorithm rather than on the algorithm itself, we have selected a simple, noncryptographic hashing scheme to use, known as Alder32.

13.5.1 The Alder32 Algorithm Explained

The Adler32 algorithm generates a 32-bit hash code and is included as part of GZIP-compressed files to guard against inadvertent modification (for example, errors introduced in copying a compressed file over a network connection).

Adler32 is a simple algorithm, which operates on 8-bit blocks of message data to create hash codes, as follows:

  1. Define a 16-bit value called Sum1 with an initial value of 1.

  2. Define a 16-bit value called Sum2 with an initial value of 0.

  3. Process each 8-bit message block in turn:

  4. Add the numeric value of the message block to Sum 1, modulo 65521.

  5. Add the value of Sum 1 to Sum 2, modulo 65521.

  6. Concatenate Sum 2 and Sum 1 together to create a 32-bit hash code.

The Adler32 algorithm is not suitable for cryptographic uses because it produces hash codes that are susceptible to attack. Adler32 produces short hash codes that easily succumb to birthday attacks and, more importantly, it is easy to generate a message that results in a specific Adler32 hash code.

13.5.2 Defining the Abstract Class

The first step is to create an abstract class representing the Adler32 algorithm. The abstract class extends the System.Security.Cryptography.HashAlgorithm class but does not need to implement any members. Here is the definition of the abstract Adler32 algorithm class:

# C#
using System.Security.Cryptography;
        
public abstract class Adler32 : HashAlgorithm {

}

# Visual Basic .NET

Imports System.Security.Cryptography
 
Public MustInherit Class Adler32
         Inherits HashAlgorithm
 
End Class

We have created the abstract class to conform to the .NET class model, allowing you to add other Adler32 implementations in the future. You can omit the abstract class, but we feel that the extra flexibility of this model is well worth the effort.

13.5.3 Defining the Implementation Class

The abstract HashAlgorithm class contains a lot of functionality that makes writing a new algorithm a simple process. For example, the details of the ComputeHash method are hidden from the implementer, and only a small number of methods need to be written in order to create a fully functional implementation.

13.5.3.1 Creating the implementation class

We have named our implementation class Adler32Managed, because it is written using a managed .NET language. The following listing shows the initial version of the implementation class extending the abstract Adler32 class. We have defined the two 16-bit values as o_sum_1 and o_sum_2. For Visual Basic .NET, we have used 32-bit integers to represent the 16-bit sums, because Visual Basic .NET does not support unsigned data types:

# C#

using System;
using System.Security.Cryptography;

public class Adler32Managed : HashAlgorithm {
    private ushort o_sum_1;
    private ushort o_sum_2;

}

# Visual Basic .NET
Imports System
Imports System.Security.Cryptography

Public Class Adler32Managed
    Inherits Adler32

    Private o_sum_1 As Integer
    Private o_sum_2 As Integer

End Class
13.5.3.2 Implementing the Initialize method

You should use the Initialize method to set the initial state of any algorithm; an algorithm will produce unexpected hash code values unless correctly reset between invocations. For Adler32, we use this method to set the initial sum values. We have also added a class constructor that calls the Initialize method to ensure that the values are correctly set before the class is first used:

# C#

using System;
using System.Security.Cryptography;

public class Adler32Managed : HashAlgorithm {
    private ushort o_sum_1;
    private ushort o_sum_2;

    public Adler32Managed(  ) {
                Initialize(  );
    }

    public override void Initialize(  ) {
        // reset the sum values
        o_sum_1 = 1;
        o_sum_2 = 0;
   
}

# Visual Basic .NET

Imports System
Imports System.Security.Cryptography

Public Class Adler32Managed
    Inherits Adler32

    Private o_sum_1 As Integer
    Private o_sum_2 As Integer

    Public Sub New(  )
        Initialize(  )
    End Sub

    Public Overrides Sub Initialize(  )
        ' reset the sum values
        o_sum_1 = 1
        o_sum_2 = 0
    End Sub

End Class
13.5.3.3 Implementing the HashCore and HashFinal methods

The HashCore method receives message data into the algorithm class; the amount of data to process can vary from a single byte to very large arrays. Always ensure that you process only the region of the array indicated by the p_start_index and p_count parameters. This method may be invoked multiple times, and you must make sure that your algorithm can process data blocks incrementally, rather then assuming that all of the message data will arrive at once:

# C#

protected override void HashCore(byte[] p_array, int p_start_index, int p_count) {
    // process each byte in the array
    for (int i = p_start_index; i < p_count; i++) {
        o_sum_1 = (ushort)((o_sum_1 + p_array[i]) % 65521);
        o_sum_2 = (ushort)((o_sum_1 + o_sum_2)    % 65521);
    }
}

# Visual Basic .NET

Protected Overrides Sub HashCore(ByVal p_array(  ) As Byte, _
ByVal p_start_index As Integer, ByVal p_count As Integer)

    ' process each byte in the array
    Dim i As Integer
    For i = p_start_index To p_count - 1 Step i + 1
        o_sum_1 = (o_sum_1 + p_array(i)) Mod 65521
        o_sum_2 = (o_sum_1 + o_sum_2) Mod 65521
    Next
End Sub

The HashFinal method is called when all of the message data has been processed by the HashCore method and returns the computed hash code value as a byte array. This method allows you to complete any pending calculations before computing the final hash code. For Alder32, you simply need to concatenate the two sum values together to form the 32-bit hash code, and convert the result into a byte array:

# C#

protected override byte[] HashFinal(  ) {
    // concat the two 16 bit values to form
    // one 32-bit value
    uint x_concat_value = (uint)((o_sum_2 << 16) | o_sum_1);
    // use the bitconverter class to render the
    // 32-bit integer into an array of bytes
    return BitConverter.GetBytes(x_concat_value);
}

# Visual Basic .NET

Protected Overrides Function HashFinal(  ) As Byte(  )
    ' concat the two 16 bit values to form
    ' one 32-bit value
    Dim x_concat_value As Integer = (o_sum_2 * 65536) Or o_sum_1
    ' use the bitconverter class to render the
    ' 32-bit integer into an array of bytes
    Return BitConverter.GetBytes(x_concat_value)
End Function
13.5.3.4 Completing the class

The final step is to implement the HashSize property to specify the size (in bits) of the hash code that you are generating. Example 13-3 is the complete listing for the Alder32Managed class:

Example 13-3. algorithm
# C#

using System;
using System.Security.Cryptography;

public class Adler32Managed : HashAlgorithm {
    private ushort o_sum_1;
    private ushort o_sum_2;

    public Adler32Managed(  ) {
                Initialize(  );
    }

    public override int HashSize {
        get {
            return 32;
        }
    }

    public override void Initialize(  ) {
        // reset the sum values
        o_sum_1 = 1;
        o_sum_2 = 0;
    }

    protected override void HashCore(byte[] p_array, int p_start_index, 
    int p_count) {
        // process each byte in the array
        for (int i = p_start_index; i < p_count; i++) {
            o_sum_1 = (ushort)((o_sum_1 + p_array[i]) % 65521);
            o_sum_2 = (ushort)((o_sum_1 + o_sum_2)    % 65521);
        }
    }

    protected override byte[] HashFinal(  ) {
        // concat the two 16 bit values to form
        // one 32-bit value
        uint x_concat_value = (uint)((o_sum_2 << 16) | o_sum_1);
        // use the bitconverter class to render the
        // 32-bit integer into an array of bytes
        return BitConverter.GetBytes(x_concat_value);
   
}

# Visual Basic .NET

Imports System
Imports System.Security.Cryptography

Public Class Adler32Managed
    Inherits Adler32

    Private o_sum_1 As Integer
    Private o_sum_2 As Integer

    Public Sub New(  )
        Initialize(  )
    End Sub

    Public Overrides ReadOnly Property HashSize(  ) As Integer
        Get
            Return 32
        End Get
    End Property

    Public Overrides Sub Initialize(  )
        ' reset the sum values
        o_sum_1 = 1
        o_sum_2 = 0
    End Sub

    Protected Overrides Sub HashCore(ByVal p_array(  ) As Byte, _
    ByVal p_start_index As Integer, ByVal p_count As Integer)

        ' process each byte in the array
        Dim i As Integer
        For i = p_start_index To p_count - 1 Step i + 1
            o_sum_1 = (o_sum_1 + p_array(i)) Mod 65521
            o_sum_2 = (o_sum_1 + o_sum_2) Mod 65521
        Next
    End Sub

    Protected Overrides Function HashFinal(  ) As Byte(  )
        ' concat the two 16 bit values to form
        ' one 32-bit value
        Dim x_concat_value As Integer = (o_sum_2 * 65536) Or o_sum_1
        ' use the bitconverter class to render the
        ' 32-bit integer into an array of bytes
        Return BitConverter.GetBytes(x_concat_value)
    End Function

End Class
13.5.3.5 Testing the implementation

Now that you have created the implementation class, you can use the Adler32 algorithm in exactly the same way as the other classes covered in this chapter. The following listing details how to create an Adler32 hash code for the message "Programming .NET Security":

# C#

// define the message string that we will create a hash code for
string x_message_string = "Programming .NET Security";
// convert the message string into bytes
byte[] x_message_bytes = Encoding.Default.GetBytes(x_message_string);

HashAlgorithm x_hash_alg = new Adler32Managed(  );
byte[] x_hash_code = x_hash_alg.ComputeHash(x_message_bytes);

// print out the hash code
foreach (byte x_byte in x_hash_code) {
    Console.Write("{0:X2} ", x_byte);
}

# Visual Basic .NET 

' define the message string that we will create a hash code for
Dim x_message_string As String = "Programming .NET Security"
' convert the message string into bytes
Dim x_message_bytes(  ) As Byte = Encoding.Default.GetBytes(x_message_string)

Dim x_hash_alg As HashAlgorithm = New Adler32Managed(  )
Dim x_hash_code(  ) As Byte = x_hash_alg.ComputeHash(x_message_bytes)

' print out the hash code
Dim x_byte As Byte
For Each x_byte In x_hash_code
    Console.Write("{0:X2} ", x_byte)
Next


    Part V: API Quick Reference