PowerShell, as most of the scripting languages has a built-in function for Base64 encoding and decoding. If you are only interested in this quick way, here's the syntax. If you want to dive deeper in the algorithm, keep reading!
# Encode 'a' [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('a')) # Decode 'YQA=' [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('YQA='))
Encoding
The idea of encoding and decoding to- and from Base64 using PowerShell is based on the very same algorithm as we used in our Python example.
In this short article we go through the process of encoding and then decoding the single letter 'a'.
Spoiler alert: the resulting Base64 string will be 'YUFB=='. Look at that, six times longer than the original one letter text we started with!
To be fair, it is an extreme example. The average Base64 encoded string is only 33% longer than the original input, as the algorithm takes 3byte long blocks of characters and converts them into a 4byte large encoded output. For more explanation and examples, click here.
Let's see how we get from 'a' to 'YUFB=='
function Base64Encode($s) { $i = 0 $base64 = $ending = '' $base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' # Add padding if string is not dividable by 3 $pad = 3 - ($s.length % 3) if ($pad -ne 3) { $s += "A" * $pad $ending = "=" * $pad } # Iterate though the whole input string while ($i -lt $s.length) { # Take 3 characters at a time, convert them to 4 base64 chars $b = 0 for ($j=0; $j -lt 3; $j++) { # get ASCII code of the next character in line $ascii = [int][char]$s[$i] $i++ # Concatenate the three characters together $b += $ascii -shl 8 * (2-$j) } # Convert the 3 chars to four Base64 chars $base64 += $base64chars[ ($b -shr 18) -band 63 ] $base64 += $base64chars[ ($b -shr 12) -band 63 ] $base64 += $base64chars[ ($b -shr 6) -band 63 ] $base64 += $base64chars[ $b -band 63 ] } # Add the actual padding to the end after removing the same number of characters if ($pad -ne 3) { $base64 = $base64.SubString(0, $base64.length - $pad) $base64 += $ending } # Return the Base64 encoded result return $base64 }
The program first takes the first 3 bytes of the string (as the minimum length of code that can be encrypted is 24bit). Here we have only one ASCII character, which is 8bit large. So two padding character needs to be added to the original string, and we use 'A' as the padding character. Note that it can be anything you like as it is discarded at the end of the encoding process.
Next, the 24bit long block is built out of the 'aAA' string, and stored in variable $b.
When the block is ready, the script divides it into four 6bit pieces, by shifting the bits in the block first 18times to place the desired 6bit in the rightmost position in the variable, then masks it with the decimal 63, that translates to the binary ..0000111111. This way all the bits after the first 6bits will be discarded.
The procedure is repeated with the second piece, shifting the block only 12 times that time, then getting the third piece by shifting 6 times. The last piece doesn't need shifting as the last 6bits in the block is already in the right position.
The last step is mapping the corresponding character in the base64char array to the 6bit number we get. It is YUFB, and the script appends two '==' characters to the end so the decoder will know how many characters to discard from the end after decoding. Remember, the string 'aAA' was encoded, the last two 'AA' piece needs to be omitted to get the original input back.
Decoding
The decoding steps are the exact reverse of the encoding procedure.
Decoder Script
function Base64Decode($s) { $i = 0 $base64 = $decoded = '' $base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' # Replace padding with "A" characters for the decoder to work and save the length of the padding to be dropped from the end later if ($s.substring($s.length - 2,2) -like "==") { $s = $s.substring(0, $s.length - 2) + "AA" $padd = 2 } elseif ($s.substring($s.length - 1,1) -like "=") { $s = $s.substring(0, $s.length - 1) + "A" $padd = 1 } # Take 4 characters at a time while ($i -lt $s.length) { $d = 0 for ($j=0; $j -lt 4; $j++) { $d += $base64chars.indexof($s[$i]) -shl (18 - $j * 6) $i++ } # Convert the 4 chars back to ASCII $decoded += [char](($d -shr 16) -band 255) $decoded += [char](($d -shr 8) -band 255) $decoded += [char]($d -band 255) } # Remove padding $decoded = $decoded.substring(0, $decoded.length - $padd) # Return the Base64 encoded result return $decoded }
The algorithm first removes the trailing '==' which are markers only, not part of the encoded text. They show how many characters to remove from the end after the decoding process. The number of the padding bytes are stored for later use.
The numeric values of the 6bit building pieces are retrieved using the base64chars array. Then the resulting numbers are concatenated into a 24bit block. That block is divided into three pieces, getting back the actual ASCII codes of the original string that was encoded before.
The division happens by shifting bits right and masking them, this time using the decimal 255, as that will cover the desired 8bits (..0011111111).
After the original characters are decoded, the program discards that many characters from the end as the number of '=' character was put after the encoded string. Here it needs to remove two padding characters as there were two trailing '=' after the base64 code.
Comments