Looking for a way to limit software use to weeks then allow client to reactivate with new serial?

Well you just have to encode the desired timeout time in the serialkey. The problem with such a system is that your clients can quite easily (if they are a little bit familiar with .NET) decompile your code and either figure out how your serial check works, so the can produce valid keys on their own, or they can even change your original code and completely remove the serial check.

That’s why almost nobody uses those old “simple serialkeys” anymore. Most use an authenication that is account and server bound.

However if you want to implement such a simple serial key, just do something like this:

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

public static class SerialGenerator
{
    static RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider();
    static MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();

    public enum SerialResult
    {
        Valid,
        Invalid,
        Expired
    }

    public static byte[] GenerateSerial(System.DateTime aExpires)
    {
        long date = aExpires.Ticks;
        byte[] bytes = System.BitConverter.GetBytes(date);
        if (System.BitConverter.IsLittleEndian)
            System.Array.Reverse(bytes); 
        byte[] randomData = new byte[8];
        rnd.GetBytes(randomData);
        bytes = bytes.Concat(randomData).ToArray();
        byte[] hash1 = md5.ComputeHash(bytes);
        byte[] hash2 = md5.ComputeHash(hash1);
        byte[] result = new byte[32];
        for (int i = 0; i < 16; i++)
            result[i] = hash1[i];
        for (int i = 0; i < 16; i++)
            result[i + 16] = (byte)(bytes[i] ^ hash2[i]);
        return result;
    }
    public static System.TimeSpan T;
    public static SerialResult ValidateSerial(byte[] aSerial)
    {
        long t = long.MinValue;
        
        if (aSerial.Length != 32)
            return SerialResult.Invalid;
        byte[] hash2 = md5.ComputeHash(aSerial,0,16);
        byte[] data = new byte[16];
        for(int i = 0; i < 16; i++)
            data[i] = (byte)(aSerial[16+i] ^ hash2[i]);
        byte[] bytes = new byte[8];
        System.Array.Copy(data, bytes, 8);
        if (System.BitConverter.IsLittleEndian)
            System.Array.Reverse(bytes);
        long date = System.BitConverter.ToInt64(bytes,0);
        byte[] hash1 = md5.ComputeHash(data);
        for(int i = 0; i < 16; i++)
            if (aSerial[i] != hash1[i])
                return SerialResult.Invalid;
        if (System.DateTime.UtcNow.Ticks > date)
            return SerialResult.Expired;
        return SerialResult.Valid;
    }
    public static string GenerateStringSerial(System.DateTime aExpires)
    {
        var serial = GenerateSerial(aExpires);
        return System.Convert.ToBase64String(serial);
    }
    public static SerialResult ValidateStringSerial(string aSerial)
    {
        try
        {
            var data = System.Convert.FromBase64String(aSerial);
            return ValidateSerial(data);
        }
        catch
        {
            return SerialResult.Invalid;
        }
    }
}

With that little class you can create serials which are only valid until the specified expiration time. To make this whole thing international i used the UTC time, so when creating serials keep that in mind.

Create a serial in base64 format which expires in 2 hours and 30 seconds from the moment you create the serial:

string serial = SerialGenerator.GenerateStringSerial(System.DateTime.UtcNow.AddHours(2).AddSeconds(30));

To validate a serial you would simply use:

var state = SerialGenerator.ValidateStringSerial(serial);
if (state == SerialGenerator.SerialResult.Expired)
{
    Debug.Log("the serial has expired");
}
else if (state == SerialGenerator.SerialResult.Valid)
{
    Debug.Log("the serial is valid");
}
else if (state == SerialGenerator.SerialResult.Invalid)
{
    Debug.Log("invalid serial");
}
else
{
    Debug.Log("strange internal error, should never happen :D");
}

Keep in mind that self-validating serials like this can be cracked once you know how it’s calculated. Since .NET can be easily decompiled that’s actually quite easy. It prevents the common user from using the software, but it’s not very safe.

edit
Just changed the class slightly to take the local endianness into account, otherwise a serial generaten on PC might not work on Mac.