Base32 Decoding
Answer :
I had a need for a base32 encoder/decoder, so I spent a couple hours this afternoon throwing this together. I believe it conforms to the standards listed here: http://tools.ietf.org/html/rfc4648#section-6.
public class Base32Encoding { public static byte[] ToBytes(string input) { if (string.IsNullOrEmpty(input)) { throw new ArgumentNullException("input"); } input = input.TrimEnd('='); //remove padding characters int byteCount = input.Length * 5 / 8; //this must be TRUNCATED byte[] returnArray = new byte[byteCount]; byte curByte = 0, bitsRemaining = 8; int mask = 0, arrayIndex = 0; foreach (char c in input) { int cValue = CharToValue(c); if (bitsRemaining > 5) { mask = cValue << (bitsRemaining - 5); curByte = (byte)(curByte | mask); bitsRemaining -= 5; } else { mask = cValue >> (5 - bitsRemaining); curByte = (byte)(curByte | mask); returnArray[arrayIndex++] = curByte; curByte = (byte)(cValue << (3 + bitsRemaining)); bitsRemaining += 3; } } //if we didn't end with a full byte if (arrayIndex != byteCount) { returnArray[arrayIndex] = curByte; } return returnArray; } public static string ToString(byte[] input) { if (input == null || input.Length == 0) { throw new ArgumentNullException("input"); } int charCount = (int)Math.Ceiling(input.Length / 5d) * 8; char[] returnArray = new char[charCount]; byte nextChar = 0, bitsRemaining = 5; int arrayIndex = 0; foreach (byte b in input) { nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining))); returnArray[arrayIndex++] = ValueToChar(nextChar); if (bitsRemaining < 4) { nextChar = (byte)((b >> (3 - bitsRemaining)) & 31); returnArray[arrayIndex++] = ValueToChar(nextChar); bitsRemaining += 5; } bitsRemaining -= 3; nextChar = (byte)((b << bitsRemaining) & 31); } //if we didn't end with a full char if (arrayIndex != charCount) { returnArray[arrayIndex++] = ValueToChar(nextChar); while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding } return new string(returnArray); } private static int CharToValue(char c) { int value = (int)c; //65-90 == uppercase letters if (value < 91 && value > 64) { return value - 65; } //50-55 == numbers 2-7 if (value < 56 && value > 49) { return value - 24; } //97-122 == lowercase letters if (value < 123 && value > 96) { return value - 97; } throw new ArgumentException("Character is not a Base32 character.", "c"); } private static char ValueToChar(byte b) { if (b < 26) { return (char)(b + 65); } if (b < 32) { return (char)(b + 24); } throw new ArgumentException("Byte is not a value Base32 value.", "b"); } }
Check this FromBase32String
implementation for .NET found here.
Edit: The above link was dead; you can find an archived copy at archive.org
The actual code read:
using System; using System.Text; public sealed class Base32 { // the valid chars for the encoding private static string ValidChars = "QAZ2WSX3" + "EDC4RFV5" + "TGB6YHN7" + "UJM8K9LP"; /// <summary> /// Converts an array of bytes to a Base32-k string. /// </summary> public static string ToBase32String(byte[] bytes) { StringBuilder sb = new StringBuilder(); // holds the base32 chars byte index; int hi = 5; int currentByte = 0; while (currentByte < bytes.Length) { // do we need to use the next byte? if (hi > 8) { // get the last piece from the current byte, shift it to the right // and increment the byte counter index = (byte)(bytes[currentByte++] >> (hi - 5)); if (currentByte != bytes.Length) { // if we are not at the end, get the first piece from // the next byte, clear it and shift it to the left index = (byte)(((byte)(bytes[currentByte] << (16 - hi)) >> 3) | index); } hi -= 3; } else if(hi == 8) { index = (byte)(bytes[currentByte++] >> 3); hi -= 3; } else { // simply get the stuff from the current byte index = (byte)((byte)(bytes[currentByte] << (8 - hi)) >> 3); hi += 5; } sb.Append(ValidChars[index]); } return sb.ToString(); } /// <summary> /// Converts a Base32-k string into an array of bytes. /// </summary> /// <exception cref="System.ArgumentException"> /// Input string <paramref name="s">s</paramref> contains invalid Base32-k characters. /// </exception> public static byte[] FromBase32String(string str) { int numBytes = str.Length * 5 / 8; byte[] bytes = new Byte[numBytes]; // all UPPERCASE chars str = str.ToUpper(); int bit_buffer; int currentCharIndex; int bits_in_buffer; if (str.Length < 3) { bytes[0] = (byte)(ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); return bytes; } bit_buffer = (ValidChars.IndexOf(str[0]) | ValidChars.IndexOf(str[1]) << 5); bits_in_buffer = 10; currentCharIndex = 2; for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte)bit_buffer; bit_buffer >>= 8; bits_in_buffer -= 8; while (bits_in_buffer < 8 && currentCharIndex < str.Length) { bit_buffer |= ValidChars.IndexOf(str[currentCharIndex++]) << bits_in_buffer; bits_in_buffer += 5; } } return bytes; } }
This is a really old question, but I happened to stumble on it wanting the same thing for OTP tokens. It turns out that there is base 32 functionality built into the OTP.NET package on NuGet:
Base32Encoding.ToBytes("(your base 32 string here)")
The reverse is also possible:
Base32Encoding.ToString(new byte[] { /* your bytes here */ })
Comments
Post a Comment