How can I implement Base 64 encoding without the Base64 method?

Hello, I was recently given the task in our IT class to create a C# WPF application that converts an input string to a Base64 result.

We were only given the layout of the application and nothing explained about the actual process behind it. I've now learned from Wikipedia that a string is divided into 8 bits each, then subdivided into 6 bits each, and if the result isn't divisible by 6, it's padded with zeros.

Our teaching is not the best and not much is explained, which is why I have the following questions:

  1. How can you divide a string into its 8-bit components?
  2. How can you divide the 8-bit pieces into 6-bit pieces?
  3. How can you then output the corresponding character set as a string from the Base64 table (see Wikipedia: Base64 – Wikipedia )?

I assume the binary values ​​are stored in an array, but I haven't yet learned the workflow with these in the context of WPF applications.

Even though I've probably raised some stupid questions here, I hope someone can still answer them for me.

Thank you in advance.

(1 votes)
Loading...

Similar Posts

Subscribe
Notify of
8 Answers
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
smiregal8472
10 months ago

How to divide a string into its 8 bit components?

With the different classes from system.Text.Encoding.

Example UTF-8:

string message = "Lorem ipsum dolor sit amet";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(message)

How to divide the 8-bit pieces into 6-bit pieces?

Take the smallest common multiple (kgv) of 8 and 6.

The multiplier m for 8*m=kgv then tells you how many 8 bit blocks like many 6 bit blocks correspond to 6*M=kgv.

8*3=24

6*4=24

So: 3 blocks to 8 bits each correspond to 4 blocks to 6 bits each.

Then take your 3 blocks to 8 bits each:

aaaaaaaa bbbbbbbb cccccccc

and divides these into 4 blocks to 6 bits each:

aaaaaa aabbbb bbbbcc cccccc

One way to do this is to combine the 3 bytes with a bitwise shift to the left to form an int32 value and then divide them with bitwise shifts to the right and a bitwise AND into 6 bit blocks.

How can you then output the associated character set again as a string from the Base64 table?

Very simple: 6 bits give exactly 64 possible combinations (from 0 to 63).

The Base64 character set has exactly 64 characters, each having a position of 0 to 63.

Therefore, for each 6 bit block, take the character that is at this index.

I guess the binary values are stored in an array,

Don’t have to, but everything else would be Mumpitz.

However, I have not yet learned the workflow with these, related to WPF applications.

This is exactly the same as in any other type of application also…

P.S.: Example code (extremely untested, but found plausible ^^^):

string message = "Lorem ipsum dolor sit amet";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(message)
string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
int index, block;
for(index = 0; index + 3 < bytes.Length; index += 3){ // die Nachricht in Blöcken von 3 Bytes durchgehen
    block = (bytes[index] << 16) | (bytes[index + 1] << 8) | bytes[index + 2]; //die 3 Bytes zu einer Zahl zusammenfügen
    sb.Append(charset[(block >> 18 ) & 0x3f]); // aus dem Charset das Zeichen nehmen, dessen Index den ersten 6 Bit entspricht
    sb.Append(charset[(block >> 12 ) & 0x3f]); // das gleiche nochmal für die zweiten 6 Bit
    sb.Append(charset[(block >> 6 ) & 0x3f]);  // usw...
    sb.Append(charset[block & 0x3f]);          // ...
}
switch(bytes.Length - index){ // diese Differenz kann 0, 1 oder 2 sein. Bei 0 ist kein weiteres Verfahren nötig.
    case 2: // zwei Bytes sind noch übrig
        block = (bytes[index] << 16) | (bytes[index + 1] << 8); // siehe oben (nur halt mit nur zwei Bytes)
        sb.Append(charset[(block >> 18 ) & 0x3f]);
        sb.Append(charset[(block >> 12 ) & 0x3f]);
        sb.Append(charset[(block >> 6 ) & 0x3f]);
        sb.Append('='); // Füllzeichen anhängen
        break;
    case 1: // ein btye übrig
        block = (bytes[index] << 16); // siehe oben (nur halt mit nur einem Byte)
        sb.Append(charset[(block >> 18 ) & 0x3f]);
        sb.Append(charset[(block >> 12 ) & 0x3f]);
        sb.Append('='); // Füllzeichen anhängen
        sb.Append('='); // Füllzeichen anhängen
        break;
}
System.Console.WriteLine(sb.ToString());
RedByte1608
10 months ago
static void Main(string[] args)
{
  Encoding ascii = Encoding.ASCII;
  Encoding unicode = Encoding.Unicode;


  string unicodeString = "Hello World";




  byte[] unicodeBytes = unicode.GetBytes(unicodeString);
  //1 Byte Array
  byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);
  for(int i = 0; i < asciiBytes.Length; i++)
  {
    //Output each byte in Hex
    Console.Write($"{asciiBytes[i].ToString("X")} ");
  }
  Console.WriteLine();


  List sixBitBytes = new List();
  byte remainingBits = 0;
  for (int i = 0; i < unicodeBytes.Length; i++)
  { 
    int data = remainingBits == 0 ? unicodeBytes[i] : (unicodeBytes[i] << 2) & remainingBits;
    byte sixBitPart = (byte)(data & 63);
    sixBitBytes.Add(sixBitPart);
    remainingBits = (byte)(data << 6);
  }


  foreach (byte b in sixBitBytes)
  {
    Console.Write($"{b} ");
  }
}
RedByte1608
10 months ago
Reply to  RedByte1608

sorry have been a mistake here is the new code:

static void Main(string[] args)

Encoding ascii = Encoding.ASCII;

Encoding unicode = Encoding.Unicode;

string unicodeString = “Hello”;

byte[] unicodeBytes = unicode.GetBytes(unicodeString);

//1 Byte Array

byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);

for(int i = 0; i < asciiBytes.Length; i++)

Console.Write($”{asciiBytes[i].ToString(“X”)}’);

}

Console.WriteLine();

Listbyte> sixBitBytes = new list ();

byte remainingBits = 0;

for (int i = 0; i < unicodeBytes.Length; i++)

int data = remainingBits == 0 ? unicodeBytes[i] : (unicodeBytes[i] < < 2) & remainingBits;

byte sixBitPart = (byte)(data & 63);

sixBitBytes.Add(sixBitPart);

remainingBits = (byte)(data & 192) >> 6);

}

foreach (byte b in sixBitBytes)

Console.Write($”{b} “);

}

}

smiregal8472
10 months ago

This lookup tablet would have for the encoder 16777216 entries for 4 bytes each and for the decoder again as many as 3 bytes each (everything together so 112MiB)…

There would be a few more entries for all possible pudding scenarios.

Functional? Yeah.

Sensual? No…

RedByte1608
10 months ago

I just looked at the link, in this case I would think a lookup table more meaningful

if A then 0

if B then 1

etc…

RedByte1608
10 months ago

Why you need to disassemble the data in 6 bits packages