2009-03-13 15 views
24

Tengo una cadena base32 que necesito convertir a una matriz de bytes. Y tengo problemas para encontrar un método de conversión en .NET Framework. Puedo encontrar métodos para base64 pero no para base32.Decodificación Base32

Convert.FromBase64String - algo como esto para base32 sería perfecto.

¿Existe tal método en el marco o tengo que hacer el mío?

Respuesta

10

Compruebe esto FromBase32String implementación para .NET encontrado here.


Editar: El enlace de arriba estaba muerto; se puede encontrar una copia archivada en archive.org

El código real lee:

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; 
     } 
} 
+1

+1 Niza ... él probablemente tendrá que cambiar los dígitos de codificación para los "estándar", pero eso no es malo. –

+1

No me da los resultados esperados –

+5

Parece un enlace inactivo ... – Skuld

2

Aquí está mi solución apuntado rápidamente. Solo funciona en cadenas que son un múltiplo de 8 caracteres base32. Funciona, sin embargo.

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"); 
    } 
} 
+3

CharToValue se puede simplificar mucho utilizando operaciones de fundición y sustracción; -] Por ejemplo, 'b' - 'a' = 1 –

+1

¡CharToValue es una WTF! ¿También cuál es el uso de un decodificador sin un codificador? – leppie

+0

¡Buen punto, Daniel, no estoy seguro de lo que estaba fumando en ese momento! – Chris

5

He escrito algunas implementaciones basadas en estándares flexibles de varios métodos de codificación/decodificación Base32 y Base64. Notablemente: base64url (por rfc4648) y su base32 equivalente.

De manera predeterminada, la clase Base32Url codifica con solo los caracteres de la A a la Z y de 2 a 7. No se usan guiones, guiones bajos, más, barras o iguales, lo que lo hace utilizable como token de URL en casi todas las circunstancias. Base32Url también es compatible con alfabetos personalizados, mayúsculas y minúsculas/insensibilidad, relleno/no-padding etc.

This is posted up on code project.

77

que tenía una necesidad de un base32 codificador/decodificador, así que pasé un par de horas por la tarde lanzando esto juntos. Creo que cumple con los estándares enumerados aquí: 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"); 
    } 

} 
+5

+1 Código impresionante. He estado buscando una buena base 32 codificador/decodificador. Configuré un montón de pruebas unitarias de los vectores de prueba de RFC y nada aquí (que yo había intentado) los pasó a todos. Lo suyo fue el primer disparo. Buen trabajo. Me sorprende que no haya más votos a favor. – Devin

+1

Mi sugerencia: "charCount = (int) Math.Ceiling (input.Length/5d) * 8;" debe ser "(int) Math.Ceiling (input.Length/5d * 8)" para eliminar el relleno redundante "=". – Darkthread

+1

Hola, utilicé su código en una aplicación que estoy creando, ¿puedo volver a licenciarlo bajo la licencia MIT (con el debido crédito)? Puede encontrar el código en https://github.com/kappa7194/otp/blob/master/Albireo.Otp.Library/Base32.cs – Albireo

0

He creado mi propia implementación genérica de codificador/decodificador Base32 para VB.NET. He verificado los resultados a través de sitios web independientes, por lo que parece ser bastante preciso.

Cualquier comentario sobre cómo se pueden hacer mejoras en el código será bienvenido.

Option Compare Text 
Imports System.ComponentModel 

Public Structure Base32(Of T) 

     Private Const csValidStandardBase32Chars As String = "ABCDEFGHIJKLMNOPQRSTUV" 

     <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 

Aquí es un ejemplo de la conversión de 123.456.789 a Base32

Dim value As Base32(Of Int64) = 123456789 
Console.WriteLine("123456789 in Base32 = " & value.Value) 
0

Aquí están mis funciones para la codificación y decodificación. Siento que son mucho más cortas y concisas que las otras sugerencias. Entonces, si necesitas uno pequeño, prueba estos.

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(); 
}