Tuesday 9 October 2012

Creating a Powershell Module in C#

I'd like to take the SHA1Crypt powershell script I posted yesterday and create a C# module - it was a lot easier than I thought:

  1. Create the usual windows class Library Project
  2. Change the project to .NET Framework 3.5. If you leave as .NET 4, you will need to force powershell to start using .NET4 (default is 2.0.5 viewed with [environment]::Version)
  3. Add following references:
    •     System.Management
    •     System.Security
    •     System.Management.Automation - Download Powershell 2.0 SDK (PowerShellV2_SDK_Samples.msi) from http://www.microsoft.com/en-us/download/details.aspx?id=2560
  4. Remove the default public class Class1
  5. Create your classes as below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace SHA1Crypt
{
    [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommon.Get, "Encrypted")]
    public class Encrypt : System.Management.Automation.PSCmdlet
    {
        [System.Management.Automation.Parameter(Position = 0, Mandatory = true, HelpMessage = "String to be encrypted")]
        public string PlainString;
        [System.Management.Automation.Parameter(Position = 1, Mandatory = true, HelpMessage = "Pass Key should be the same as used to encrypt if decrypting")]
        public string passKey;

        protected override void ProcessRecord()
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            SHA1CryptoServiceProvider HashProvider = new SHA1CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(passKey));
            byte[] key = new byte[24];
            TDESKey.CopyTo(key, 0);
            TDESAlgorithm.Key = key;
            
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            byte[] DataToEncrypt = UTF8.GetBytes(PlainString);

            try
            {
                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
            }
            finally
            {
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            this.WriteObject(Convert.ToBase64String(Results), true);
        }
    }

    [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommon.Get, "Decrypted")]
    public class Decrypt : System.Management.Automation.PSCmdlet
    {
        [System.Management.Automation.Parameter(Position = 0, Mandatory = true, HelpMessage = "Encrypted string to be decrypted")]
        public string EncryptedString;
        [System.Management.Automation.Parameter(Position = 1, Mandatory = true, HelpMessage = "Pass Key should be the same as used to encrypt if decrypting")]
        public string passKey;

        protected override void ProcessRecord()
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            SHA1CryptoServiceProvider HashProvider = new SHA1CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(passKey));
            byte[] key = new byte[24];
            TDESKey.CopyTo(key, 0);
            TDESAlgorithm.Key = key;

            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            byte[] DataToDecrypt = Convert.FromBase64String(EncryptedString);

            try
            {
                ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
                Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
            }
            finally
            {
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            this.WriteObject(UTF8.GetString(Results), true);
        }
    }
}


Import the module in the usual way:
Import-Module .\SHA1Crypt.dll
Get-Module

ModuleType Name                      ExportedCommands
---------- ----                      ----------------
Binary     SHA1Crypt                 {Get-Decrypted, Get-Encrypted}

Get-Encrypted -PlainString woohoo -passKey thisismykey
xhWWiEyQDhs=

Get-Decrypted -EncryptedString xhWWiEyQDhs= -passKey thisismykey
woohoo



As an alternative to passing the passKey as a parameter, if it's not likely to change, add it to your module as bytes (NB a string can be viewed by opening the dll in Notepad!! Bytes are more tricky to work out ;) )

Nice advantage is you can reuse the exact same code + key in an ASP.NET page for administrative purposes.

No comments:

Post a Comment