using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Security.Cryptography;
public static void Main()
using (MD5 md5 = MD5.Create()) {
var hash = md5.ComputeHash(Encoding.ASCII.GetBytes("lol"));
Console.WriteLine($"Hash length: {BitConverter.ToString(hash).Length} - {BitConverter.ToString(hash)}");
Guid guid = new Guid(hash);
Console.WriteLine($"GUID length: {guid.ToString().Length} - {guid}");
ShortGuid shorter = guid;
Console.WriteLine($"ShortGUID length: {shorter.ToString().Length} - {shorter}");
string converted = Convert.ToBase64String(guid.ToByteArray());
Console.WriteLine($"Base64 length: {converted.Length} - {converted}");
string fromHash = Convert.ToBase64String(hash);
Console.WriteLine($"Base64 from hash length: {fromHash.Length} - {fromHash}");
string offbase = Base32.ToBase32String(guid.ToByteArray());
Console.WriteLine($"Base32 length: {offbase.Length} - {offbase}");
public static class Base32
private static readonly char[] _digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".ToCharArray();
private const int _mask = 31;
private const int _shift = 5;
private static int CharToInt(char c)
public static byte[] FromBase32String(string encoded)
throw new ArgumentNullException(nameof(encoded));
encoded = encoded.Trim().TrimEnd('=').ToUpper();
var outLength = encoded.Length * _shift / 8;
var result = new byte[outLength];
foreach (var c in encoded)
charValue = CharToInt(c);
throw new FormatException("Illegal character: `" + c + "`");
buffer |= charValue & _mask;
result[next++] = (byte)(buffer >> (bitsLeft - 8));
public static string ToBase32String(byte[] data, bool padOutput = false)
return ToBase32String(data, 0, data.Length, padOutput);
public static string ToBase32String(byte[] data, int offset, int length, bool padOutput = false)
throw new ArgumentNullException(nameof(data));
throw new ArgumentOutOfRangeException(nameof(offset));
throw new ArgumentOutOfRangeException(nameof(length));
if ((offset + length) > data.Length)
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(data));
var outputLength = (length * 8 + _shift - 1) / _shift;
var result = new StringBuilder(outputLength);
var last = offset + length;
int buffer = data[offset++];
while (bitsLeft > 0 || offset < last)
buffer |= (data[offset++] & 0xff);
int pad = _shift - bitsLeft;
int index = _mask & (buffer >> (bitsLeft - _shift));
result.Append(_digits[index]);
int padding = 8 - (result.Length % 8);
if (padding > 0) result.Append('=', padding == 8 ? 0 : padding);
return result.ToString();
public static readonly ShortGuid Empty = new ShortGuid(Guid.Empty);
public ShortGuid(string value)
public ShortGuid(Guid guid)
public override string ToString()
public override bool Equals(object obj)
return _guid.Equals(((ShortGuid)obj)._guid);
return _guid.Equals((Guid)obj);
return _guid.Equals(((ShortGuid)obj)._guid);
public override int GetHashCode()
return _guid.GetHashCode();
public static ShortGuid NewGuid()
return new ShortGuid(Guid.NewGuid());
public static string Encode(string value)
Guid guid = new Guid(value);
public static string Encode(Guid guid)
string encoded = Convert.ToBase64String(guid.ToByteArray());
return encoded.Substring(0, 22);
public static Guid Decode(string value)
byte[] buffer = Convert.FromBase64String(value + "==");
public static bool operator ==(ShortGuid x, ShortGuid y)
if ((object)x == null) return (object)y == null;
return x._guid == y._guid;
public static bool operator !=(ShortGuid x, ShortGuid y)
public static implicit operator string(ShortGuid shortGuid)
public static implicit operator Guid(ShortGuid shortGuid)
public static implicit operator ShortGuid(string shortGuid)
return new ShortGuid(shortGuid);
public static implicit operator ShortGuid(Guid guid)
return new ShortGuid(guid);