Cryptography hash and a class - to go
One of the things I appreciate the most in OOP is the concept of classes. I have found that the use of classes allows for code to be easily maintained and reused. I look at classes as neat little packaged objects that can be ‘moved around’ and ‘worked with’ as their own. Another big benefit of classes is the concept of inheritance and polymorphism. In three previous posts (1, 2, 3) I discussed using the System.Security.Cryptography Namespace to calculate the hash values of text (strings) and files. I actually did create a class (that I actively use) from that sample.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace BPSoftware.BPCrypto
{
public class CryptoHash
{
/// <summary>
/// public enum hashtypes { MD5, SHA1, SHA256, SHA384, SHA512 };
/// </summary>
public enum hashtypes
{
MD5, SHA1, SHA256, SHA384, SHA512
};
#region Properties
private Int64 _bytesread;
/// <summary>
/// Int64 Bytesread returns the number of bytes read when calculating the hash
/// value.
/// </summary>
public Int64 Bytesread
{
get
{
return _bytesread;
}
}
private hashtypes _hashtype;
/// <summary>
/// hashtypes Hashtype specifies the type of hash to calculate.
/// </summary>
public hashtypes Hashtype
{
get
{
return _hashtype;
}
set
{
_hashtype = value;
}
}
#endregion
#region Constructors
public CryptoHash()
{
}
public CryptoHash( hashtypes inhashtype )
{
_hashtype = inhashtype;
}
#endregion
#region Methods
private string GetByteString( byte[] data )
{
StringBuilder sb = new StringBuilder ();
for ( int i = 0; i < data.Length; i++ )
{
sb.Append ( data[i].ToString ( "x2" ) );
}
string bytestring = sb.ToString ();
return bytestring.ToUpper ();
}
private string GetHash( byte[] data )
{
HashAlgorithm ha;
switch ( _hashtype )
{
case hashtypes.MD5:
ha = MD5CryptoServiceProvider.Create ();
break;
case hashtypes.SHA1:
ha = SHA1Managed.Create ();
break;
case hashtypes.SHA256:
ha = SHA256Managed.Create ();
break;
case hashtypes.SHA384:
ha = SHA384Managed.Create ();
break;
case hashtypes.SHA512:
ha = SHA512Managed.Create ();
break;
default:
ha = MD5CryptoServiceProvider.Create ();
break;
}
_bytesread = data.Length;
byte[] res = ha.ComputeHash ( data );
return GetByteString ( res );
}
/// <summary>
/// GetStringHash calculates the hash value for a string.
/// </summary>
/// <param name="inputtext">String value.</param>
/// <returns>Returns the hash value of a file.</returns>
public string GetStringHash( string inputtext )
{
return GetHash ( Encoding.Default.GetBytes ( inputtext ) );
}
/// <summary>
/// GetFileHash calculates the hash value for a file.
/// </summary>
/// <param name="filename">Full file path for the file.</param>
/// <returns>Returns the hash value of a file.</returns>
public string GetFileHash( string filename )
{
_bytesread = 0;
byte[] filecontents;
FileInfo instance = new FileInfo ( filename );
if ( !instance.Exists )
{
throw new FileNotFoundException ();
}
else
{
try
{
FileStream ofs = instance.OpenRead ();
filecontents = new byte[ofs.Length];
int offset = 0;
int count = filecontents.Length;
while ( count > 0 )
{
int bytesread = ofs.Read ( filecontents, offset, count );
count -= bytesread;
offset += bytesread;
}
// ofs.Read(filecontents, 0, filecontents.Length);
ofs.Close ();
}
catch ( Exception e )
{
throw e;
}
}
return GetHash ( filecontents );
}
/// <summary>
/// CompareStrings compares the hash value of two strings to determine
/// if they are the same.
/// </summary>
/// <param name="string1">The first string to compare.</param>
/// <param name="string2">The second string to compare.</param>
/// <returns>Returns True if the strings are identical (same hash value).</returns>
public bool CompareStrings( string string1, string string2 )
{
string1 = GetStringHash ( string1 );
string2 = GetStringHash ( string2 );
return ( ( string1.CompareTo ( string2 ) == 0 ) );
}
/// <summary>
/// CompareFiles compares the hash value of the contents of two files to determine
/// if they are the same.
/// </summary>
/// <param name="filename1">Full file path for the first file to compare.</param>
/// <param name="filename2">Full file path for the second file to compare.</param>
/// <returns>Returns True if the files are identical (same hash value).</returns>
public bool CompareFiles( string filename1, string filename2 )
{
filename1 = GetFileHash ( filename1 );
filename2 = GetFileHash ( filename2 );
return ( ( filename1.CompareTo ( filename2 ) == 0 ) );
}
/// <summary>
/// CompareStringToHash compares a string's hash with a hash to determine if the hash values are the same.
/// </summary>
/// <param name="string1">The string to compare.</param>
/// <param name="hash">The hash to compare to.</param>
/// <returns>Returns True if the string1 hash and hash match.</returns>
public bool CompareStringtoHash( string string1, string hash )
{
return ( hash.CompareTo ( GetStringHash ( string1 ) ) == 0 );
}
/// <summary>
/// CompareFileToHash compares a file's hash with a hash to determine if the hash values are the same.
/// </summary>
/// <param name="filename1">Full file path for the file to compare.</param>
/// <param name="hash">The hash to compare to.</param>
/// <returns>Returns True if the filename1 hash and hash match.</returns>
public bool CompareFiletoHash( string filename1, string hash )
{
return ( hash.CompareTo ( GetFileHash ( filename1 ) ) == 0 );
}
#endregion
}
}
C# LocalAdapterInformation
As I continue to enhance some of my exisiting utilities (and port them to C# ) I found myself working on a utilitiy that determines the Local Network Adapter Information.
public void RetrieveLocalAdapterInformation( TextBox text )
{
NetworkInterface[] interfaces; // NIC
IPInterfaceProperties properties;
PhysicalAddress address;
text.Clear ();
try
{
if ( NetworkInterface.GetIsNetworkAvailable () )
{
interfaces = NetworkInterface.GetAllNetworkInterfaces ();
if ( interfaces.GetLength ( 0 ) > 0 )
{
foreach ( NetworkInterface netInterface in interfaces )
{
properties = netInterface.GetIPProperties ();
text.AppendText ( netInterface.Name + Environment.NewLine );
text.AppendText ( "Id: " + netInterface.Id.ToString () + Environment.NewLine );
address = netInterface.GetPhysicalAddress ();
text.AppendText ( "MAC Address: " +
( address.ToString () == String.Empty ? "None" : address.ToString () ) +
Environment.NewLine );
foreach ( IPAddressInformation ipinfo in properties.UnicastAddresses )
{
text.AppendText ( "IP: " + ipinfo.Address.ToString () +
Environment.NewLine );
}
foreach ( IPAddress ip in properties.DhcpServerAddresses )
{
text.AppendText ( "DHCP Server: " + ip.ToString () +
Environment.NewLine );
}
foreach ( IPAddress ip in properties.DnsAddresses )
{
text.AppendText ( "DNS Server: " + ip.ToString () + Environment.NewLine );
}
text.AppendText ( "Type: " + netInterface.NetworkInterfaceType.ToString () + Environment.NewLine );
text.AppendText ( "Operational Status: " + netInterface.OperationalStatus.ToString () + Environment.NewLine );
text.AppendText ( "Speed: " + netInterface.Speed.ToString ( "N" ) + " bytes" + Environment.NewLine );
// XP Only
System.OperatingSystem osInfo = System.Environment.OSVersion;
if ( ( osInfo.Version.Major == 5 ) & ( osInfo.Version.Minor > 0 ) )
{
text.AppendText ( "Receive Only: " +
netInterface.IsReceiveOnly.ToString () +
Environment.NewLine );
text.AppendText ( "Support Multicast: " +
netInterface.SupportsMulticast.ToString () +
Environment.NewLine );
}
text.AppendText ( "Support IPv4: " +
netInterface.Supports ( NetworkInterfaceComponent.IPv4 ).ToString () +
Environment.NewLine );
text.AppendText ( "Support IPv6: " +
netInterface.Supports ( NetworkInterfaceComponent.IPv6 ).ToString () +
Environment.NewLine );
text.AppendText ( "DnsSuffix: " +
properties.DnsSuffix.ToString () + Environment.NewLine );
text.AppendText ( Environment.NewLine );
}
}
}
}
catch ( Exception e )
{
MessageBox.Show ( e.Message, e.Source, MessageBoxButtons.OK,
MessageBoxIcon.Error );
}
}
PInvoke WIN32 and .NET
The WIN32 API has been around for quite sometime and has a large number of 'calls' and 'mechanisms' that have not yet been
ported over to the .NET world. There are also still quite a few valuable WIN32 libraries/exports that have yet to be 'upgraded'. When integration is needed with existing WIN32 applications or APIs from a .NET application the unmanaged WIN32 DLL exports can be accessed using Platform Invoke (also referred to as PInvoke or P/Invoke). I am in the process of moving pieces of code to use the .NET framework. One of the first pieces on my list was the About Box class that I use in my personal applications. This base About Box class I created and use through out most (if not all) of my personal applications. The setting of a few properties has the About Box up and running for a new application in moments. In this About Box class I use the GlobalMemoryStatus function to display virtual and physical memory information. In order to still use this function in my new and 'improved' .NET About Box I needed to use PInvoke.
C#
using System.Runtime.InteropServices;
// define the structure
public struct _MEMORYSTATUS //http://msdn2.microsoft.com/en-us/library/aa366772.aspx
{
public uint dwLength;
public uint dwMemoryLoad;
public uint dwTotalPhys;
public uint dwAvailPhys;
public uint dwTotalPageFile;
public uint dwAvailPageFile;
public uint dwTotalVirtual;
public uint dwAvailVirtual;
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern void GlobalMemoryStatus(out _MEMORYSTATUS memorystatus);
// for simplicity of demonstration
_MEMORYSTATUS memorystatus = new _MEMORYSTATUS();
GlobalMemoryStatus(out memorystatus);
ulong totalVirtualMemory = memorystatus.dwTotalVirtual;
ulong availablePhysicalMemory = memorystatus.dwAvailPhys;
ulong availableVirtualMemory = memorystatus.dwAvailVirtual;
ulong totalPhysicalMemory = memorystatus.dwTotalPhys; VB.NET
Imports System.Runtime.InteropServices
Public Structure _MEMORYSTATUS
Dim dwLength As Integer
Dim dwMemoryLoad As Integer
Dim dwTotalPhys As Integer
Dim dwAvailPhys As Integer
Dim dwTotalPageFile As Integer
Dim dwAvailPageFile As Integer
Dim dwTotalVirtual As Integer
Dim dwAvailVirtual As Integer
End Structure
'In VB.NET there are two ways to call this
' Public Shared Sub _
' GlobalMemoryStatus1(ByVal memorystatus As _MEMORYSTATUS)
'End Sub
Declare Auto Sub GlobalMemoryStatus Lib "kernel32" (ByRef lpBuffer As _MEMORYSTATUS)
Dim memorystatus As New _MEMORYSTATUS
GlobalMemoryStatus(memorystatus)
Dim totalVirtualMemory As Integer = memorystatus.dwTotalVirtual
Dim availablePhysicalMemory As Integer = memorystatus.dwAvailPhys
Dim availableVirtualMemory As Integer = memorystatus.dwAvailVirtual
Dim totalPhysicalMemory As Integer = memorystatus.dwTotalPhys
Side Note: After having problems with
Windows Live Writer after I '
upgraded' to the
'new' Blogger I published this blog entry using
Google Docs & Spreadsheets. Curiosity got the best of me and I wanted to see how it worked.