0

Is it possible encode IPV4 into 6 or less ASCII Printable Characters to create an ultra portable ID that users can tell to each other, which really represents an IP.

Dan Mašek
  • 14,606
  • 6
  • 49
  • 73
DOSLuke
  • 61
  • 1
  • 8
  • You can't compress such small data. But you can represent it in another base, per example base16, hexadecimal, an IP would be like C0A80A01 – Gusman Mar 18 '18 at 23:54
  • 1
    There are 95 printable characters. With 6 of them, there are about 7.3e11 possible combinations. There are only about 4.3e9 IPv4 addresses, so yes it is possible. – Dave M Mar 19 '18 at 00:01
  • You could theoretically get away with only 5 printable characters, there would be about 7 billion combinations (you only need 4.3 billion) – Dave M Mar 19 '18 at 00:04
  • @DaveM You could even reduce it to 85 different characters to express all 4.3 billion combinations with just 5 character positions (as 85^5 = 4.4 billion different combinations). – ckuri Mar 19 '18 at 00:30
  • isnt it obvious im just using compress as a way to get my idea across? I explain in the body – DOSLuke Mar 19 '18 at 00:31

3 Answers3

2

You could try this base95 implementation it will get it down to 5 printable characters

public static class Base95Extension
{
   private const string PrintableChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !?\"'`^#$%@&*+=/.,:;|\\_<>[]{}()~-";

   private const int Length = 95;

   public static uint ToUInt32(this IPAddress ip)
   {
      return BitConverter.ToUInt32(ip.GetAddressBytes(), 0);
   }

   public static IPAddress ToIpAddress(this uint source)
   {
      return new IPAddress(BitConverter.GetBytes(source));
   }

   public static string ToBase95(this IPAddress ip)
   {
      var num = ip.ToUInt32();
      var result = string.Empty;
      uint index = 0;

      while (num >= Math.Pow(Length, index))
      {
         index++;
      }

      while (index-- > 0)
      {
         var pow = (uint)Math.Pow(Length, index);
         var div = num / pow;
         result += PrintableChars[(int)div];
         num -= pow * div;
      }

      return result;
   }

   public static IPAddress ToIpAddress(this string s)
   {
      uint result = 0;

      var chars = s.Reverse()
                   .ToArray();

      for (var i = 0; i < chars.Length; i++)
      {
         var pow = Math.Pow(Length, i);
         var ind = PrintableChars.IndexOf(chars[i]);
         result += (uint)(pow * ind);
      }

      return new IPAddress(BitConverter.GetBytes(result));
   }

}

Usage

var ip = "255.255.255.255";
var ipAddress = IPAddress.Parse(ip);
var result = ipAddress.ToBase95();
Console.WriteLine(ip);
Console.WriteLine(result);
Console.WriteLine(result.ToIpAddress());

Output

255.255.255.255
Q#F 5
255.255.255.255

[Demo Here][1]

TheGeneral
  • 69,477
  • 8
  • 65
  • 107
  • You can easily get 6 digits if you use at least 41 different characters as this allows for 41^6=4.7 billion different combinations which is sufficient to cover all 2^32=4.3 billion possible IP addresses. – ckuri Mar 19 '18 at 00:08
  • Base64 would be only 6 characters, but this is easier to read and harder to mistype since it uses only the characters 0-9, A-F. – Dave S Mar 19 '18 at 00:09
  • Thanks. Ive done the same thing with some similar, if not easier to read code. Ill post when i get home. – DOSLuke Mar 19 '18 at 00:34
  • Also you can get rid of the == at the end as its just padding. You can add it later easily. – DOSLuke Mar 19 '18 at 00:35
0

You can either try:

uint iaddress = BitConverter.ToUInt32(IPAddress.Parse(address).GetAddressBytes(), 0);

or use the structure here

or use the formula:

a.b.c.d => a*2^24 + b*2^16 + c*2^8 + d (which I think is faster)

see a similar question with reasonable answers

  • I actually used that im my solution to the problem. After getting the int, i turn it into a byte array and then into base 64 – DOSLuke Mar 19 '18 at 00:39
0

So I have figured something out. it accomplishes the same thing as Michael Randall's answer, in essence. His is probably more efficient, and uses less dependencies. this is just what I came up with. the main upside I see with mine is less special chars are included in the encoded string, so its easy for people to verbally communicate.

public static string Base64EncodeIP(string ip)
{
    UInt32 ipasint = BitConverter.ToUInt32(IPAddress.Parse(ip).GetAddressBytes(), 0);
    byte[] ipasbytes = BitConverter.GetBytes(ipasint);
    string encodedip = Convert.ToBase64String(ipasbytes);
    return encodedip.Replace("=", "");
}

public static string Base64DecodeIP(string encodedIP)
{
    //re-add however much padding is needed, to make the length a multiple of 4
    if (encodedIP.Length % 4 != 0)
        encodedIP += new string('=', 4 - encodedIP.Length % 4);

    byte[] ipasbytes = Convert.FromBase64String(encodedIP);
    UInt32 ipasint = BitConverter.ToUInt32(ipasbytes, 0);
    return new IPAddress(BitConverter.GetBytes(ipasint)).ToString();
}

EDIT

Links for some code I used:
How to convert an IPv4 address into a integer in C#?
Remove trailing "=" when base64 encoding

DOSLuke
  • 61
  • 1
  • 8
  • side note, if anyone wants to do a speed comparison, plz post the results :) – DOSLuke Mar 19 '18 at 03:35
  • you are trying to decode it twice. typo? i think line 36 should use the encode function? it runs perfectly after changing it to the encode function. – DOSLuke Mar 20 '18 at 02:30