Base32 Decoding

后端 未结 7 615
遥遥无期
遥遥无期 2020-11-27 15:52

I have a base32 string which I need to convert to a byte array. And I\'m having trouble finding a conversion method in the .NET framework. I can find methods for base64 but

相关标签:
7条回答
  • 2020-11-27 16:12

    Here are my functions for encoding and decoding. I feel that they are much shorter and concise than the other suggestions. So if you need a small one, try these.

    public static string BytesToBase32(byte[] bytes) {
        const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        string output = "";
        for (int bitIndex = 0; bitIndex < bytes.Length * 8; bitIndex += 5) {
            int dualbyte = bytes[bitIndex / 8] << 8;
            if (bitIndex / 8 + 1 < bytes.Length)
                dualbyte |= bytes[bitIndex / 8 + 1];
            dualbyte = 0x1f & (dualbyte >> (16 - bitIndex % 8 - 5));
            output += alphabet[dualbyte];
        }
    
        return output;
    }
    
    public static byte[] Base32ToBytes(string base32) {
        const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        List<byte> output = new List<byte>();
        char[] bytes = base32.ToCharArray();
        for (int bitIndex = 0; bitIndex < base32.Length * 5; bitIndex += 8) {
            int dualbyte = alphabet.IndexOf(bytes[bitIndex / 5]) << 10;
            if (bitIndex / 5 + 1 < bytes.Length)
                dualbyte |= alphabet.IndexOf(bytes[bitIndex / 5 + 1]) << 5;
            if (bitIndex / 5 + 2 < bytes.Length)
                dualbyte |= alphabet.IndexOf(bytes[bitIndex / 5 + 2]);
    
            dualbyte = 0xff & (dualbyte >> (15 - bitIndex % 5 - 8));
            output.Add((byte)(dualbyte));
        }
        return output.ToArray();
    }
    
    0 讨论(0)
  • 2020-11-27 16:20

    I've written some flexible standards based implementations of various Base32 and Base64 encoding/decoding methods. Notably: base64url (per rfc4648) and its base32 equivalent.

    By default the Base32Url class encodes with only the characters A to Z and 2 to 7. No hyphens, underscores, pluses, slashes or equals are used, making it usable as a URL token in almost all circumstances. Base32Url also supports custom alphabets, case sensitivity/insensitivity, padding/no-padding etc.

    This is posted up on code project.

    0 讨论(0)
  • 2020-11-27 16:21

    Here's my quickly jotted solution. It only works on strings that are a multiple of 8 base32 characters. Does work, though.

    public class Base32
    {
      /// <summary>
      /// Decode a Base32 string
      /// This will only work on a multiple of 40 bits (5 bytes)
      /// http://www.garykessler.net/library/base64.html
      /// </summary>
      public static byte[] Decode(string Base32String)
      {
        // Ignore hyphens
        string str = Base32String.Replace("-", "");
    
        // Convert it to bits
        List<byte> bits = new List<byte>();
        foreach (char c in str)
        {
          int i = CharToValue(c);
          bits.Add((byte)((i & 16) > 0 ? 1 : 0));
          bits.Add((byte)((i & 8) > 0 ? 1 : 0));
          bits.Add((byte)((i & 4) > 0 ? 1 : 0));
          bits.Add((byte)((i & 2) > 0 ? 1 : 0));
          bits.Add((byte)((i & 1) > 0 ? 1 : 0));
        }
    
        // Convert bits into bytes
        List<byte> bytes = new List<byte>();
        for (int i = 0; i < bits.Count; i += 8)
        {
          bytes.Add((byte)(
            (bits[i + 0] << 7) +
            (bits[i + 1] << 6) +
            (bits[i + 2] << 5) +
            (bits[i + 3] << 4) +
            (bits[i + 4] << 3) +
            (bits[i + 5] << 2) +
            (bits[i + 6] << 1) +
            (bits[i + 7] << 0)));
        }
    
        return bytes.ToArray();
      }
    
      static int CharToValue(char c)
      {
        char cl = char.ToLower(c);
        if (cl == 'a') return 0;
        if (cl == 'b') return 1;
        if (cl == 'c') return 2;
        if (cl == 'd') return 3;
        if (cl == 'e') return 4;
        if (cl == 'f') return 5;
        if (cl == 'g') return 6;
        if (cl == 'h') return 7;
        if (cl == 'i') return 8;
        if (cl == 'j') return 9;
        if (cl == 'k') return 10;
        if (cl == 'l') return 11;
        if (cl == 'm') return 12;
        if (cl == 'n') return 13;
        if (cl == 'o') return 14;
        if (cl == 'p') return 15;
        if (cl == 'q') return 16;
        if (cl == 'r') return 17;
        if (cl == 's') return 18;
        if (cl == 't') return 19;
        if (cl == 'u') return 20;
        if (cl == 'v') return 21;
        if (cl == 'w') return 22;
        if (cl == 'x') return 23;
        if (cl == 'y') return 24;
        if (cl == 'z') return 25;
        if (cl == '2') return 26;
        if (cl == '3') return 27;
        if (cl == '4') return 28;
        if (cl == '5') return 29;
        if (cl == '6') return 30;
        if (cl == '7') return 31;
        throw new Exception("Not a base32 string");
      }
    }
    
    0 讨论(0)
  • 2020-11-27 16:24

    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;
          }
    }
    
    0 讨论(0)
  • 2020-11-27 16:28

    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");
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 16:29

    I have come up with my own generic Base32 encoder/decoder implementation for VB.NET. I have verified the results through independent web sites so it does appear to be quite accurate.

    Any comments on how improvements could be made to the code will be welcomed.

    Option Compare Text
    Imports System.ComponentModel
    
    Public Structure Base32(Of T)
    
            Private Const csValidStandardBase32Chars As String = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
    
            <EditorBrowsable(EditorBrowsableState.Never)> _
            Class Base32Nibble
    
                    <EditorBrowsable(EditorBrowsableState.Never)> _
                    Friend mStore As New BitArray(5, False)
    
                    Public ReadOnly Property Value As Byte
                            Get
                                    Dim result As Byte = 0
                                    For index As Byte = 0 To mStore.Count - 1
                                            If mStore(index) Then
                                                    result += (2 ^ index)
                                            End If
                                    Next
                                    Return result
                            End Get
                    End Property
    
                    Public Overrides Function ToString() As String
                            Dim nibbleString As String = Nothing
                            For Each bit As Boolean In mStore
                                    nibbleString = Math.Abs(CInt(bit)).ToString() & nibbleString
                            Next
                            Return nibbleString
                    End Function
    
            End Class
    
            Private Shared mNibbles As List(Of Base32Nibble)
    
            Public ReadOnly Property Count As Long
                    Get
                            Return mNibbles.Count
                    End Get
            End Property
    
            Default Public ReadOnly Property Item(ByVal index As Integer) As Base32Nibble
                    Get
                            Return DirectCast(mNibbles(index), Base32Nibble)
                    End Get
            End Property
    
            Public Sub New(ByVal Value As T)
                    Dim temp As Object = CType(Value, T)
                    getNibbles(BitConverter.GetBytes(temp))
            End Sub
    
            Public Sub New(ByVal Value As Byte())
                    getNibbles(Value)
            End Sub
    
            Public Shared Widening Operator CType(ByVal Value As T) As Base32(Of T)
                    Return New Base32(Of T)(Value)
            End Operator
    
            Public Shared Widening Operator CType(ByVal Value As Byte()) As Base32(Of T)
                    Return New Base32(Of T)(Value)
            End Operator
    
            Public ReadOnly Property Value As String
                    Get
                            Dim result As String = Nothing
                            For Each Nib As Base32(Of T).Base32Nibble In mNibbles
                                    result = csValidStandardBase32Chars(Nib.Value) & result
                            Next
                            Return result.TrimStart("0")
                    End Get
            End Property
    
            Public Function ToNumeric(ByVal Base32String As String) As T
                    Dim result As T = CType(CType(0, Object), T)
                    Try
                            If Base32String.Trim.Length > 0 Then
                                    Dim pos As Integer = 0
                                    Do
                                            Dim temp As Object = getBase32Value(Base32String, pos)
                                            result = result + temp
                                            pos += 1
                                    Loop While (pos < Base32String.Length)
                            End If
                    Catch ex As Exception
                            ' Catch overflow errors if the generic type T doesn't have enough
                            ' room to store the result
                            System.Diagnostics.Debug.Print(ex.Message)
                    End Try
                    Return result
            End Function
    
            Private Shared Sub getNibbles(ByVal Value As Byte())
    
                    Dim valueBytes As New BitArray(Value)
                    Dim nib As Base32Nibble = Nothing
    
                    mNibbles = New List(Of Base32Nibble)
    
                    Dim padding As Byte = (1 - (valueBytes.Length / 5 - (valueBytes.Length \ 5))) * 5
                    valueBytes.Length = valueBytes.Length + padding
    
                    For element As Short = 0 To valueBytes.Count - 1
                            If (element Mod 5 = 0) Then
                                    nib = New Base32Nibble()
                                    mNibbles.Add(nib)
                            End If
                            nib.mStore.Item(element Mod 5) = valueBytes.Item(element)
                    Next
    
            End Sub
    
            Private Function getBase32Char(ByVal InputString As String, ByVal InputPosition As Integer) As String
                    Return csValidStandardBase32Chars.IndexOf(Mid(InputString, InputPosition + 1, 1))
            End Function
    
            Private Function getBase32Value(ByVal InputString As String, ByVal InputPosition As Integer) As T
                    Return CType(CType((getBase32Char(InputString, InputPosition) * (32 ^ (InputString.Length - 1 - InputPosition))), Object), T)
            End Function
    
    End Structure
    

    Here is an example of converting 123456789 to Base32

    Dim value As Base32(Of Int64) = 123456789
    Console.WriteLine( "123456789 in Base32 = " & value.Value)
    
    0 讨论(0)
提交回复
热议问题